Version xon XML funcionando. Revisar si se estan encontrando todos los miembros
This commit is contained in:
parent
ebbee5414d
commit
3282dd8f2d
|
@ -19,8 +19,8 @@ namespace NetDocsForLLM
|
||||||
|
|
||||||
private void ConfigureServices(ServiceCollection services)
|
private void ConfigureServices(ServiceCollection services)
|
||||||
{
|
{
|
||||||
// Register services
|
// Registramos el XmlDocGenerator sin dependencia de LogService
|
||||||
services.AddSingleton<IDocFxService, XmlDocGenerator>(); // Usar el generador XML
|
services.AddSingleton<IDocFxService, XmlDocGenerator>();
|
||||||
services.AddSingleton<IDocumentationGenerator, DocumentationGenerator>();
|
services.AddSingleton<IDocumentationGenerator, DocumentationGenerator>();
|
||||||
services.AddSingleton<IAssemblyAnalyzer, AssemblyAnalyzer>();
|
services.AddSingleton<IAssemblyAnalyzer, AssemblyAnalyzer>();
|
||||||
|
|
||||||
|
|
160
MainWindow.xaml
160
MainWindow.xaml
|
@ -1,13 +1,10 @@
|
||||||
<Window x:Class="NetDocsForLLM.MainWindow"
|
<Window x:Class="NetDocsForLLM.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:NetDocsForLLM"
|
||||||
xmlns:local="clr-namespace:NetDocsForLLM"
|
xmlns:views="clr-namespace:NetDocsForLLM.Views" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||||
xmlns:conv="clr-namespace:NetDocsForLLM.Converters"
|
xmlns:conv="clr-namespace:NetDocsForLLM.Converters"
|
||||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
mc:Ignorable="d" Title="NetDocs para LLMs" Height="650" Width="800">
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="NetDocs para LLMs" Height="650" Width="800">
|
|
||||||
|
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<conv:EnumBooleanConverter x:Key="EnumBooleanConverter"/>
|
<conv:EnumBooleanConverter x:Key="EnumBooleanConverter"/>
|
||||||
|
@ -15,23 +12,18 @@
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Encabezado -->
|
<!-- Encabezado -->
|
||||||
<Border Background="#2c3e50" Padding="15">
|
<Border Background="#2c3e50" Padding="15">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="Generador de Documentación .NET para LLMs"
|
<TextBlock Text="Generador de Documentación .NET para LLMs" Foreground="White" FontSize="22"
|
||||||
Foreground="White"
|
HorizontalAlignment="Center" />
|
||||||
FontSize="22"
|
|
||||||
HorizontalAlignment="Center"/>
|
|
||||||
<TextBlock Text="Extraiga y estructure documentación de librerías .NET para uso con modelos de lenguaje"
|
<TextBlock Text="Extraiga y estructure documentación de librerías .NET para uso con modelos de lenguaje"
|
||||||
Foreground="#ecf0f1"
|
Foreground="#ecf0f1" FontSize="12" HorizontalAlignment="Center" Margin="0,5,0,0" />
|
||||||
FontSize="12"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Margin="0,5,0,0"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
@ -40,54 +32,40 @@
|
||||||
<TabItem Header="Selección de Librería">
|
<TabItem Header="Selección de Librería">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Button Content="Seleccionar Archivos DLL..."
|
<Button Content="Seleccionar Archivos DLL..." Command="{Binding SelectAssembliesCommand}"
|
||||||
Command="{Binding SelectAssembliesCommand}"
|
Padding="10,5" Margin="0,0,0,10" />
|
||||||
Padding="10,5"
|
|
||||||
Margin="0,0,0,10"/>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="1"
|
<TextBlock Grid.Row="1" Text="Librerías seleccionadas:" FontWeight="Bold" Margin="0,10,0,5" />
|
||||||
Text="Librerías seleccionadas:"
|
|
||||||
FontWeight="Bold"
|
|
||||||
Margin="0,10,0,5"/>
|
|
||||||
|
|
||||||
<ListView Grid.Row="2"
|
<ListView Grid.Row="2" ItemsSource="{Binding SelectedAssemblies}" Margin="0,5">
|
||||||
ItemsSource="{Binding SelectedAssemblies}"
|
|
||||||
Margin="0,5">
|
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
|
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
|
||||||
<TextBlock Text="{Binding FilePath}" FontSize="11" TextWrapping="Wrap"/>
|
<TextBlock Text="{Binding FilePath}" FontSize="11" TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1" Content="X"
|
||||||
Content="X"
|
|
||||||
Command="{Binding DataContext.RemoveAssemblyCommand, RelativeSource={RelativeSource AncestorType=ListView}}"
|
Command="{Binding DataContext.RemoveAssemblyCommand, RelativeSource={RelativeSource AncestorType=ListView}}"
|
||||||
CommandParameter="{Binding}"
|
CommandParameter="{Binding}" Margin="5,0,0,0" />
|
||||||
Margin="5,0,0,0"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.ItemTemplate>
|
</ListView.ItemTemplate>
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
<Button Grid.Row="3"
|
<Button Grid.Row="3" Content="Analizar y Generar Documentación"
|
||||||
Content="Analizar y Generar Documentación"
|
Command="{Binding GenerateDocumentationCommand}" IsEnabled="{Binding HasSelectedAssemblies}"
|
||||||
Command="{Binding GenerateDocumentationCommand}"
|
Padding="10,5" Margin="0,10,0,0" Background="#2980b9" Foreground="White" />
|
||||||
IsEnabled="{Binding HasSelectedAssemblies}"
|
|
||||||
Padding="10,5"
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
Background="#2980b9"
|
|
||||||
Foreground="White"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
@ -97,53 +75,48 @@
|
||||||
<GroupBox Header="Opciones de documentación">
|
<GroupBox Header="Opciones de documentación">
|
||||||
<StackPanel Margin="5">
|
<StackPanel Margin="5">
|
||||||
<CheckBox Content="Incluir métodos privados"
|
<CheckBox Content="Incluir métodos privados"
|
||||||
IsChecked="{Binding Settings.IncludePrivateMembers}"
|
IsChecked="{Binding Settings.IncludePrivateMembers}" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
|
|
||||||
<CheckBox Content="Incluir miembros heredados"
|
<CheckBox Content="Incluir miembros heredados"
|
||||||
IsChecked="{Binding Settings.IncludeInheritedMembers}"
|
IsChecked="{Binding Settings.IncludeInheritedMembers}" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
|
|
||||||
<CheckBox Content="Incluir ejemplos de código"
|
<CheckBox Content="Incluir ejemplos de código"
|
||||||
IsChecked="{Binding Settings.IncludeExamples}"
|
IsChecked="{Binding Settings.IncludeExamples}" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
|
|
||||||
<CheckBox Content="Procesamiento detallado de comentarios XML"
|
<CheckBox Content="Procesamiento detallado de comentarios XML"
|
||||||
IsChecked="{Binding Settings.DetailedXmlComments}"
|
IsChecked="{Binding Settings.DetailedXmlComments}" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<GroupBox Header="Nivel de detalle" Margin="0,10,0,0">
|
<GroupBox Header="Nivel de detalle" Margin="0,10,0,0">
|
||||||
<StackPanel Margin="5">
|
<StackPanel Margin="5">
|
||||||
<RadioButton Content="Básico - Solo información esencial"
|
<RadioButton Content="Básico - Solo información esencial"
|
||||||
IsChecked="{Binding Settings.DetailLevel, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Basic}"
|
IsChecked="{Binding Settings.DetailLevel, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Basic}"
|
||||||
GroupName="DetailLevel"
|
GroupName="DetailLevel" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
|
|
||||||
<RadioButton Content="Estándar - Equilibrio entre detalle y tamaño"
|
<RadioButton Content="Estándar - Equilibrio entre detalle y tamaño"
|
||||||
IsChecked="{Binding Settings.DetailLevel, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Standard}"
|
IsChecked="{Binding Settings.DetailLevel, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Standard}"
|
||||||
GroupName="DetailLevel"
|
GroupName="DetailLevel" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
|
|
||||||
<RadioButton Content="Completo - Toda la información disponible"
|
<RadioButton Content="Completo - Toda la información disponible"
|
||||||
IsChecked="{Binding Settings.DetailLevel, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Full}"
|
IsChecked="{Binding Settings.DetailLevel, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Full}"
|
||||||
GroupName="DetailLevel"
|
GroupName="DetailLevel" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<GroupBox Header="Formato de salida" Margin="0,10,0,0">
|
<GroupBox Header="Formato de salida" Margin="0,10,0,0">
|
||||||
<StackPanel Margin="5">
|
<StackPanel Margin="5">
|
||||||
<RadioButton Content="JSON"
|
<RadioButton Content="JSON"
|
||||||
IsChecked="{Binding Settings.OutputFormat, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Json}"
|
IsChecked="{Binding Settings.OutputFormat, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Json}"
|
||||||
GroupName="OutputFormat"
|
GroupName="OutputFormat" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
|
<RadioButton Content="XML (Recomendado para LLMs)"
|
||||||
|
IsChecked="{Binding Settings.OutputFormat, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Xml}"
|
||||||
|
GroupName="OutputFormat" Margin="0,5" />
|
||||||
|
|
||||||
<RadioButton Content="YAML"
|
<RadioButton Content="YAML"
|
||||||
IsChecked="{Binding Settings.OutputFormat, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Yaml}"
|
IsChecked="{Binding Settings.OutputFormat, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=Yaml}"
|
||||||
GroupName="OutputFormat"
|
GroupName="OutputFormat" Margin="0,5" />
|
||||||
Margin="0,5"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@ -153,50 +126,41 @@
|
||||||
<TabItem Header="Previsualización" IsEnabled="{Binding HasGeneratedDocumentation}">
|
<TabItem Header="Previsualización" IsEnabled="{Binding HasGeneratedDocumentation}">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
|
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
|
||||||
<Button Content="Copiar al portapapeles"
|
<Button Content="Copiar al portapapeles" Command="{Binding CopyToClipboardCommand}"
|
||||||
Command="{Binding CopyToClipboardCommand}"
|
Padding="10,5" Margin="0,0,10,0" />
|
||||||
Padding="10,5"
|
|
||||||
Margin="0,0,10,0"
|
|
||||||
IsEnabled="{Binding HasGeneratedDocumentation}"/>
|
|
||||||
|
|
||||||
<Button Content="Exportar..."
|
<Button Content="Exportar..." Command="{Binding ExportDocumentationCommand}" Padding="10,5" />
|
||||||
Command="{Binding ExportDocumentationCommand}"
|
|
||||||
Padding="10,5"
|
|
||||||
IsEnabled="{Binding HasGeneratedDocumentation}"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Eliminamos el PropertyGrid que estaba en conflicto con el Border -->
|
|
||||||
|
|
||||||
<Border Grid.Row="1" Background="#f5f5f5" BorderBrush="#ddd" BorderThickness="1">
|
<Border Grid.Row="1" Background="#f5f5f5" BorderBrush="#ddd" BorderThickness="1">
|
||||||
<TextBox Text="{Binding DocumentationPreview, Mode=OneWay}"
|
<TextBox Text="{Binding DocumentationPreview, Mode=OneWay}" IsReadOnly="True"
|
||||||
IsReadOnly="True"
|
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
|
||||||
VerticalScrollBarVisibility="Auto"
|
FontFamily="Consolas" AcceptsReturn="True" Padding="10" />
|
||||||
HorizontalScrollBarVisibility="Auto"
|
|
||||||
FontFamily="Consolas"
|
|
||||||
AcceptsReturn="True"
|
|
||||||
Padding="10"/>
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<TextBlock Grid.Row="2"
|
<TextBlock Grid.Row="2" Text="{Binding DocumentationStats}" Margin="0,10,0,0" />
|
||||||
Text="{Binding DocumentationStats}"
|
|
||||||
Margin="0,10,0,0"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
<!-- Nueva pestaña de Log -->
|
||||||
|
<TabItem Header="Log de Análisis">
|
||||||
|
<views:LogView />
|
||||||
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
|
|
||||||
<!-- Pie de página -->
|
<!-- Pie de página -->
|
||||||
<StatusBar Grid.Row="2">
|
<StatusBar Grid.Row="2">
|
||||||
<StatusBarItem>
|
<StatusBarItem>
|
||||||
<TextBlock Text="{Binding StatusMessage}"/>
|
<TextBlock Text="{Binding StatusMessage}" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<StatusBarItem HorizontalAlignment="Right">
|
<StatusBarItem HorizontalAlignment="Right">
|
||||||
<ProgressBar Width="100" Height="15" IsIndeterminate="{Binding IsProcessing}"/>
|
<ProgressBar Width="100" Height="15" IsIndeterminate="{Binding IsProcessing}" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
</StatusBar>
|
</StatusBar>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace NetDocsForLLM.Models
|
||||||
public enum OutputFormat
|
public enum OutputFormat
|
||||||
{
|
{
|
||||||
Json,
|
Json,
|
||||||
|
Xml,
|
||||||
Yaml
|
Yaml
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ namespace NetDocsForLLM.Models
|
||||||
_includeExamples = true;
|
_includeExamples = true;
|
||||||
_detailedXmlComments = true;
|
_detailedXmlComments = true;
|
||||||
_detailLevel = DetailLevel.Standard;
|
_detailLevel = DetailLevel.Standard;
|
||||||
_outputFormat = OutputFormat.Json;
|
_outputFormat = OutputFormat.Xml; // Cambiado a XML por defecto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,182 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace NetDocsForLLM.Services
|
||||||
|
{
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
Error = 0,
|
||||||
|
Warning = 1,
|
||||||
|
Info = 2,
|
||||||
|
Debug = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clase estática para logs que no depende de inyección de dependencias
|
||||||
|
/// </summary>
|
||||||
|
public static class AppLogger
|
||||||
|
{
|
||||||
|
private static readonly List<LogEntry> _logEntries = new List<LogEntry>();
|
||||||
|
private static int _errorCount = 0;
|
||||||
|
private static int _warningCount = 0;
|
||||||
|
private static int _typeCount = 0;
|
||||||
|
private static int _memberCount = 0;
|
||||||
|
private static string _logFilePath;
|
||||||
|
private static StreamWriter _fileWriter;
|
||||||
|
|
||||||
|
// Evento que se dispara cuando hay nuevos mensajes
|
||||||
|
public static event EventHandler LogUpdated;
|
||||||
|
|
||||||
|
static AppLogger()
|
||||||
|
{
|
||||||
|
// Configurar archivo de log
|
||||||
|
string tempFolder = Path.Combine(Path.GetTempPath(), "NetDocsForLLM_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"));
|
||||||
|
Directory.CreateDirectory(tempFolder);
|
||||||
|
_logFilePath = Path.Combine(tempFolder, "app_log.txt");
|
||||||
|
_fileWriter = new StreamWriter(_logFilePath, true) { AutoFlush = true };
|
||||||
|
|
||||||
|
LogInfo($"Log inicializado en: {_logFilePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogDebug(string message)
|
||||||
|
{
|
||||||
|
AddLogEntry(LogLevel.Debug, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogInfo(string message)
|
||||||
|
{
|
||||||
|
AddLogEntry(LogLevel.Info, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogWarning(string message)
|
||||||
|
{
|
||||||
|
_warningCount++;
|
||||||
|
AddLogEntry(LogLevel.Warning, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogError(string message)
|
||||||
|
{
|
||||||
|
_errorCount++;
|
||||||
|
AddLogEntry(LogLevel.Error, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogException(Exception ex)
|
||||||
|
{
|
||||||
|
_errorCount++;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.AppendLine($"Excepción: {ex.Message}");
|
||||||
|
|
||||||
|
if (ex.StackTrace != null)
|
||||||
|
{
|
||||||
|
sb.AppendLine("Stack Trace:");
|
||||||
|
sb.AppendLine(ex.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.InnerException != null)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"Inner Exception: {ex.InnerException.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLogEntry(LogLevel.Error, sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ErrorCount => _errorCount;
|
||||||
|
public static int WarningCount => _warningCount;
|
||||||
|
public static int TypeCount => _typeCount;
|
||||||
|
public static int MemberCount => _memberCount;
|
||||||
|
|
||||||
|
public static void IncrementTypeCount()
|
||||||
|
{
|
||||||
|
_typeCount++;
|
||||||
|
NotifyLogUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void IncrementMemberCount()
|
||||||
|
{
|
||||||
|
_memberCount++;
|
||||||
|
NotifyLogUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddLogEntry(LogLevel level, string message)
|
||||||
|
{
|
||||||
|
var entry = new LogEntry
|
||||||
|
{
|
||||||
|
Timestamp = DateTime.Now,
|
||||||
|
Level = level,
|
||||||
|
Message = message
|
||||||
|
};
|
||||||
|
|
||||||
|
_logEntries.Add(entry);
|
||||||
|
|
||||||
|
// Escribir al archivo de log
|
||||||
|
string levelText = GetLevelText(level);
|
||||||
|
string logMessage = $"[{entry.Timestamp:yyyy-MM-dd HH:mm:ss}] [{levelText}] {message}";
|
||||||
|
|
||||||
|
_fileWriter.WriteLine(logMessage);
|
||||||
|
|
||||||
|
// Notificar a los escuchadores
|
||||||
|
NotifyLogUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void NotifyLogUpdated()
|
||||||
|
{
|
||||||
|
// Invocar el evento en el hilo de la UI si está disponible
|
||||||
|
LogUpdated?.Invoke(null, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetContent(LogLevel maxLevel = LogLevel.Debug)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (var entry in _logEntries)
|
||||||
|
{
|
||||||
|
if (entry.Level <= maxLevel)
|
||||||
|
{
|
||||||
|
string levelText = GetLevelText(entry.Level);
|
||||||
|
sb.AppendLine($"[{entry.Timestamp:yyyy-MM-dd HH:mm:ss}] [{levelText}] {entry.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetLevelText(LogLevel level)
|
||||||
|
{
|
||||||
|
switch (level)
|
||||||
|
{
|
||||||
|
case LogLevel.Error:
|
||||||
|
return "ERROR";
|
||||||
|
case LogLevel.Warning:
|
||||||
|
return "WARN";
|
||||||
|
case LogLevel.Info:
|
||||||
|
return "INFO";
|
||||||
|
case LogLevel.Debug:
|
||||||
|
return "DEBUG";
|
||||||
|
default:
|
||||||
|
return level.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Clear()
|
||||||
|
{
|
||||||
|
_logEntries.Clear();
|
||||||
|
_errorCount = 0;
|
||||||
|
_warningCount = 0;
|
||||||
|
|
||||||
|
// No reiniciar los contadores de tipos y miembros
|
||||||
|
// ya que representan el progreso del análisis
|
||||||
|
|
||||||
|
NotifyLogUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LogEntry
|
||||||
|
{
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
public LogLevel Level { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -380,152 +380,22 @@ namespace NetDocsForLLM.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (settings.OutputFormat == OutputFormat.Json)
|
switch (settings.OutputFormat)
|
||||||
{
|
{
|
||||||
return JsonConvert.SerializeObject(documentation, Formatting.Indented,
|
case OutputFormat.Json:
|
||||||
new JsonSerializerSettings
|
return JsonConvert.SerializeObject(documentation, Formatting.Indented,
|
||||||
{
|
new JsonSerializerSettings
|
||||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
|
||||||
NullValueHandling = NullValueHandling.Ignore
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else // YAML
|
|
||||||
{
|
|
||||||
// En un escenario real, usaríamos YamlDotNet
|
|
||||||
// Para esta implementación, usaremos una conversión manual simplificada a XML
|
|
||||||
var doc = new XDocument(
|
|
||||||
new XDeclaration("1.0", "utf-8", null),
|
|
||||||
new XElement("documentation",
|
|
||||||
new XElement("namespaces")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
var namespacesElement = doc.Root.Element("namespaces");
|
|
||||||
|
|
||||||
foreach (var ns in documentation.Namespaces)
|
|
||||||
{
|
|
||||||
var nsElement = new XElement("namespace",
|
|
||||||
new XAttribute("name", ns.Name),
|
|
||||||
new XElement("description", ns.Description),
|
|
||||||
new XElement("types")
|
|
||||||
);
|
|
||||||
|
|
||||||
var typesElement = nsElement.Element("types");
|
|
||||||
|
|
||||||
foreach (var type in ns.Types)
|
|
||||||
{
|
|
||||||
var typeElement = new XElement("type",
|
|
||||||
new XAttribute("name", type.Name),
|
|
||||||
new XAttribute("fullName", type.FullName),
|
|
||||||
new XAttribute("kind", type.TypeKind),
|
|
||||||
new XElement("description", type.Description),
|
|
||||||
new XElement("members")
|
|
||||||
);
|
|
||||||
|
|
||||||
if (type.BaseTypes.Count > 0)
|
|
||||||
{
|
{
|
||||||
var baseTypesElement = new XElement("baseTypes");
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||||
foreach (var baseType in type.BaseTypes)
|
NullValueHandling = NullValueHandling.Ignore
|
||||||
{
|
});
|
||||||
baseTypesElement.Add(new XElement("baseType", baseType));
|
|
||||||
}
|
|
||||||
typeElement.Add(baseTypesElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type.Interfaces.Count > 0)
|
case OutputFormat.Xml:
|
||||||
{
|
return GenerateXmlOutput(documentation);
|
||||||
var interfacesElement = new XElement("interfaces");
|
|
||||||
foreach (var iface in type.Interfaces)
|
|
||||||
{
|
|
||||||
interfacesElement.Add(new XElement("interface", iface));
|
|
||||||
}
|
|
||||||
typeElement.Add(interfacesElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
var membersElement = typeElement.Element("members");
|
case OutputFormat.Yaml:
|
||||||
|
default:
|
||||||
foreach (var member in type.Members)
|
return GenerateYamlOutput(documentation);
|
||||||
{
|
|
||||||
var memberElement = new XElement("member",
|
|
||||||
new XAttribute("name", member.Name),
|
|
||||||
new XAttribute("type", member.MemberType),
|
|
||||||
new XElement("description", member.Description),
|
|
||||||
new XElement("signature", member.Signature)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(member.ReturnType))
|
|
||||||
{
|
|
||||||
memberElement.Add(new XElement("returnType", member.ReturnType));
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(member.ReturnDescription))
|
|
||||||
{
|
|
||||||
memberElement.Add(new XElement("returnDescription", member.ReturnDescription));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (member.Parameters.Count > 0)
|
|
||||||
{
|
|
||||||
var paramsElement = new XElement("parameters");
|
|
||||||
|
|
||||||
foreach (var param in member.Parameters)
|
|
||||||
{
|
|
||||||
var paramElement = new XElement("parameter",
|
|
||||||
new XAttribute("name", param.Name),
|
|
||||||
new XAttribute("type", param.Type),
|
|
||||||
new XElement("description", param.Description ?? "")
|
|
||||||
);
|
|
||||||
|
|
||||||
if (param.IsOptional)
|
|
||||||
{
|
|
||||||
paramElement.Add(new XAttribute("optional", "true"));
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(param.DefaultValue))
|
|
||||||
{
|
|
||||||
paramElement.Add(new XAttribute("defaultValue", param.DefaultValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
paramsElement.Add(paramElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
memberElement.Add(paramsElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (member.Examples.Count > 0)
|
|
||||||
{
|
|
||||||
var examplesElement = new XElement("examples");
|
|
||||||
|
|
||||||
foreach (var example in member.Examples)
|
|
||||||
{
|
|
||||||
examplesElement.Add(new XElement("example", example));
|
|
||||||
}
|
|
||||||
|
|
||||||
memberElement.Add(examplesElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
membersElement.Add(memberElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
typesElement.Add(typeElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespacesElement.Add(nsElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convertir a string con formato
|
|
||||||
using (var stringWriter = new StringWriter())
|
|
||||||
{
|
|
||||||
using (var xmlWriter = new XmlTextWriter(stringWriter)
|
|
||||||
{
|
|
||||||
Formatting = (System.Xml.Formatting)Formatting.Indented,
|
|
||||||
Indentation = 2
|
|
||||||
})
|
|
||||||
{
|
|
||||||
doc.Save(xmlWriter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringWriter.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -533,5 +403,265 @@ namespace NetDocsForLLM.Services
|
||||||
throw new InvalidOperationException($"Error al generar vista previa: {ex.Message}", ex);
|
throw new InvalidOperationException($"Error al generar vista previa: {ex.Message}", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private string GenerateXmlOutput(DocumentationModel documentation)
|
||||||
|
{
|
||||||
|
var doc = new XDocument(
|
||||||
|
new XDeclaration("1.0", "utf-8", null),
|
||||||
|
new XElement("doc",
|
||||||
|
new XElement("assembly",
|
||||||
|
new XElement("name", "DocumentationForLLM")
|
||||||
|
),
|
||||||
|
new XElement("members")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var membersElement = doc.Root.Element("members");
|
||||||
|
|
||||||
|
// Agregar tipos
|
||||||
|
foreach (var ns in documentation.Namespaces)
|
||||||
|
{
|
||||||
|
foreach (var type in ns.Types)
|
||||||
|
{
|
||||||
|
// Agregar elemento de tipo
|
||||||
|
var typeMember = new XElement("member",
|
||||||
|
new XAttribute("name", $"T:{type.FullName}"),
|
||||||
|
new XElement("summary", type.Description)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Agregar información de base y interfaces si corresponde
|
||||||
|
if (type.BaseTypes.Count > 0 || type.Interfaces.Count > 0)
|
||||||
|
{
|
||||||
|
var remarks = new XElement("remarks");
|
||||||
|
|
||||||
|
if (type.BaseTypes.Count > 0)
|
||||||
|
{
|
||||||
|
remarks.Add(new XText($"Inherits from {type.BaseTypes[0]}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.Interfaces.Count > 0)
|
||||||
|
{
|
||||||
|
if (type.BaseTypes.Count > 0)
|
||||||
|
remarks.Add(new XText("\n"));
|
||||||
|
|
||||||
|
remarks.Add(new XText($"Implements: {string.Join(", ", type.Interfaces)}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
typeMember.Add(remarks);
|
||||||
|
}
|
||||||
|
|
||||||
|
membersElement.Add(typeMember);
|
||||||
|
|
||||||
|
// Agregar miembros
|
||||||
|
foreach (var member in type.Members)
|
||||||
|
{
|
||||||
|
XElement memberElement;
|
||||||
|
|
||||||
|
// Agregar con formato correcto según el tipo
|
||||||
|
switch (member.MemberType)
|
||||||
|
{
|
||||||
|
case "Method":
|
||||||
|
memberElement = CreateMethodElement(type, member);
|
||||||
|
break;
|
||||||
|
case "Property":
|
||||||
|
memberElement = CreatePropertyElement(type, member);
|
||||||
|
break;
|
||||||
|
case "Event":
|
||||||
|
memberElement = CreateEventElement(type, member);
|
||||||
|
break;
|
||||||
|
case "Field":
|
||||||
|
memberElement = CreateFieldElement(type, member);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue; // Tipo no soportado
|
||||||
|
}
|
||||||
|
|
||||||
|
membersElement.Add(memberElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usar un StringWriter para convertir el XML a texto
|
||||||
|
using (var stringWriter = new StringWriter())
|
||||||
|
{
|
||||||
|
using (var writer = new XmlTextWriter(stringWriter))
|
||||||
|
{
|
||||||
|
writer.Formatting = (System.Xml.Formatting)Formatting.Indented;
|
||||||
|
writer.Indentation = 4;
|
||||||
|
doc.Save(writer);
|
||||||
|
}
|
||||||
|
return stringWriter.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private XElement CreateMethodElement(TypeDocumentation type, MemberDocumentation method)
|
||||||
|
{
|
||||||
|
// Crear ID XML para el método
|
||||||
|
string methodId;
|
||||||
|
|
||||||
|
if (method.Parameters.Count > 0)
|
||||||
|
{
|
||||||
|
var paramTypes = string.Join(",", method.Parameters.Select(p => p.Type));
|
||||||
|
methodId = $"M:{type.FullName}.{method.Name}({paramTypes})";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
methodId = $"M:{type.FullName}.{method.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var element = new XElement("member",
|
||||||
|
new XAttribute("name", methodId),
|
||||||
|
new XElement("summary", method.Description)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Agregar parámetros
|
||||||
|
foreach (var param in method.Parameters)
|
||||||
|
{
|
||||||
|
element.Add(new XElement("param",
|
||||||
|
new XAttribute("name", param.Name),
|
||||||
|
new XText(param.Description ?? $"A {param.Type} parameter.")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar información de retorno si no es void
|
||||||
|
if (!string.IsNullOrEmpty(method.ReturnType) && method.ReturnType != "void")
|
||||||
|
{
|
||||||
|
element.Add(new XElement("returns",
|
||||||
|
method.ReturnDescription ?? $"A {method.ReturnType} value."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar ejemplos si hay
|
||||||
|
foreach (var example in method.Examples)
|
||||||
|
{
|
||||||
|
element.Add(new XElement("example", example));
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
private XElement CreatePropertyElement(TypeDocumentation type, MemberDocumentation property)
|
||||||
|
{
|
||||||
|
var element = new XElement("member",
|
||||||
|
new XAttribute("name", $"P:{type.FullName}.{property.Name}"),
|
||||||
|
new XElement("summary", property.Description)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(property.ReturnType))
|
||||||
|
{
|
||||||
|
element.Add(new XElement("value",
|
||||||
|
$"A {property.ReturnType} representing the property value."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
private XElement CreateEventElement(TypeDocumentation type, MemberDocumentation eventMember)
|
||||||
|
{
|
||||||
|
var element = new XElement("member",
|
||||||
|
new XAttribute("name", $"E:{type.FullName}.{eventMember.Name}"),
|
||||||
|
new XElement("summary", eventMember.Description)
|
||||||
|
);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
private XElement CreateFieldElement(TypeDocumentation type, MemberDocumentation field)
|
||||||
|
{
|
||||||
|
var element = new XElement("member",
|
||||||
|
new XAttribute("name", $"F:{type.FullName}.{field.Name}"),
|
||||||
|
new XElement("summary", field.Description)
|
||||||
|
);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateYamlOutput(DocumentationModel documentation)
|
||||||
|
{
|
||||||
|
// Implementación simplificada de YAML (mantenemos la existente)
|
||||||
|
// Deserialize JSON primero, luego a YAML
|
||||||
|
var json = JsonConvert.SerializeObject(documentation, Formatting.None,
|
||||||
|
new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||||
|
NullValueHandling = NullValueHandling.Ignore
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convierte a YAML usando una implementación simple
|
||||||
|
var yaml = new System.Text.StringBuilder();
|
||||||
|
yaml.AppendLine("namespaces:");
|
||||||
|
|
||||||
|
var obj = JsonConvert.DeserializeObject<dynamic>(json);
|
||||||
|
foreach (var ns in obj.Namespaces)
|
||||||
|
{
|
||||||
|
yaml.AppendLine($" - name: {ns.Name}");
|
||||||
|
yaml.AppendLine($" description: {ns.Description}");
|
||||||
|
yaml.AppendLine(" types:");
|
||||||
|
|
||||||
|
foreach (var type in ns.Types)
|
||||||
|
{
|
||||||
|
yaml.AppendLine($" - name: {type.Name}");
|
||||||
|
yaml.AppendLine($" fullName: {type.FullName}");
|
||||||
|
yaml.AppendLine($" typeKind: {type.TypeKind}");
|
||||||
|
yaml.AppendLine($" description: {EscapeYamlString(type.Description)}");
|
||||||
|
yaml.AppendLine(" members:");
|
||||||
|
|
||||||
|
foreach (var member in type.Members)
|
||||||
|
{
|
||||||
|
yaml.AppendLine($" - name: {member.Name}");
|
||||||
|
yaml.AppendLine($" memberType: {member.MemberType}");
|
||||||
|
yaml.AppendLine($" signature: \"{EscapeYamlString(member.Signature)}\"");
|
||||||
|
yaml.AppendLine($" description: \"{EscapeYamlString(member.Description)}\"");
|
||||||
|
|
||||||
|
if (member.Parameters != null && member.Parameters.Count > 0)
|
||||||
|
{
|
||||||
|
yaml.AppendLine(" parameters:");
|
||||||
|
foreach (var param in member.Parameters)
|
||||||
|
{
|
||||||
|
yaml.AppendLine($" - name: {param.Name}");
|
||||||
|
yaml.AppendLine($" type: {param.Type}");
|
||||||
|
yaml.AppendLine($" description: \"{EscapeYamlString(param.Description)}\"");
|
||||||
|
yaml.AppendLine($" isOptional: {param.IsOptional.ToString().ToLower()}");
|
||||||
|
if (!string.IsNullOrEmpty(param.DefaultValue))
|
||||||
|
yaml.AppendLine($" defaultValue: \"{EscapeYamlString(param.DefaultValue)}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(member.ReturnType))
|
||||||
|
{
|
||||||
|
yaml.AppendLine($" returnType: {member.ReturnType}");
|
||||||
|
if (!string.IsNullOrEmpty(member.ReturnDescription))
|
||||||
|
yaml.AppendLine($" returnDescription: \"{EscapeYamlString(member.ReturnDescription)}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (member.Examples != null && member.Examples.Count > 0)
|
||||||
|
{
|
||||||
|
yaml.AppendLine(" examples:");
|
||||||
|
foreach (var example in member.Examples)
|
||||||
|
{
|
||||||
|
yaml.AppendLine($" - |\n {example.Replace("\n", "\n ")}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return yaml.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string EscapeYamlString(string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return input
|
||||||
|
.Replace("\\", "\\\\")
|
||||||
|
.Replace("\"", "\\\"")
|
||||||
|
.Replace("\n", "\\n")
|
||||||
|
.Replace("\r", "\\r")
|
||||||
|
.Replace("\t", "\\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -14,13 +14,14 @@ namespace NetDocsForLLM.Services
|
||||||
public class XmlDocGenerator : IDocFxService
|
public class XmlDocGenerator : IDocFxService
|
||||||
{
|
{
|
||||||
private readonly string _workingDirectory;
|
private readonly string _workingDirectory;
|
||||||
private TextWriter _logWriter;
|
|
||||||
|
|
||||||
public XmlDocGenerator()
|
public XmlDocGenerator()
|
||||||
{
|
{
|
||||||
// Crear un directorio temporal para trabajar
|
// Crear un directorio temporal para trabajar
|
||||||
_workingDirectory = Path.Combine(Path.GetTempPath(), "NetDocsForLLM_" + Guid.NewGuid().ToString("N"));
|
_workingDirectory = Path.Combine(Path.GetTempPath(), "NetDocsForLLM_" + Guid.NewGuid().ToString("N"));
|
||||||
Directory.CreateDirectory(_workingDirectory);
|
Directory.CreateDirectory(_workingDirectory);
|
||||||
|
|
||||||
|
AppLogger.LogInfo($"Directorio de trabajo creado: {_workingDirectory}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GenerateMetadataAsync(IEnumerable<AssemblyModel> assemblies)
|
public async Task<string> GenerateMetadataAsync(IEnumerable<AssemblyModel> assemblies)
|
||||||
|
@ -29,17 +30,14 @@ namespace NetDocsForLLM.Services
|
||||||
var metadataPath = Path.Combine(_workingDirectory, "metadata");
|
var metadataPath = Path.Combine(_workingDirectory, "metadata");
|
||||||
Directory.CreateDirectory(metadataPath);
|
Directory.CreateDirectory(metadataPath);
|
||||||
|
|
||||||
// Crear archivo de log
|
AppLogger.LogInfo($"Directorio de metadatos creado: {metadataPath}");
|
||||||
var logPath = Path.Combine(metadataPath, "analysis_log.txt");
|
AppLogger.LogInfo($"Iniciando análisis en {DateTime.Now}");
|
||||||
using (_logWriter = new StreamWriter(logPath, false))
|
AppLogger.LogInfo($"Ensamblados a procesar: {assemblies.Count()}");
|
||||||
{
|
|
||||||
_logWriter.WriteLine($"Iniciando generación de documentación XML: {DateTime.Now}");
|
|
||||||
|
|
||||||
// Para cada ensamblado, generar documentación XML
|
// Para cada ensamblado, generar documentación XML
|
||||||
foreach (var assembly in assemblies)
|
foreach (var assembly in assemblies)
|
||||||
{
|
{
|
||||||
await Task.Run(() => GenerateXmlDocumentation(assembly, metadataPath));
|
await Task.Run(() => GenerateXmlDocumentation(assembly, metadataPath));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadataPath;
|
return metadataPath;
|
||||||
|
@ -52,11 +50,13 @@ namespace NetDocsForLLM.Services
|
||||||
Assembly assembly = assemblyModel.LoadedAssembly;
|
Assembly assembly = assemblyModel.LoadedAssembly;
|
||||||
if (assembly == null)
|
if (assembly == null)
|
||||||
{
|
{
|
||||||
_logWriter.WriteLine($"ERROR: El ensamblado {assemblyModel.Name} no está cargado");
|
AppLogger.LogError($"ERROR: El ensamblado {assemblyModel.Name} no está cargado");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logWriter.WriteLine($"\n=== Procesando ensamblado: {assemblyModel.Name} ===");
|
AppLogger.LogInfo($"\n=== Procesando ensamblado: {assemblyModel.Name} ===");
|
||||||
|
AppLogger.LogInfo($"Ruta: {assemblyModel.FilePath}");
|
||||||
|
AppLogger.LogInfo($"Versión: {assemblyModel.Version}");
|
||||||
|
|
||||||
// Crear el documento XML
|
// Crear el documento XML
|
||||||
XDocument doc = new XDocument(
|
XDocument doc = new XDocument(
|
||||||
|
@ -72,192 +72,427 @@ namespace NetDocsForLLM.Services
|
||||||
// Obtener el elemento members para agregar miembros
|
// Obtener el elemento members para agregar miembros
|
||||||
var membersElement = doc.Root.Element("members");
|
var membersElement = doc.Root.Element("members");
|
||||||
|
|
||||||
// Procesar todos los tipos exportados
|
// Cargar documentación XML existente si hay
|
||||||
foreach (var type in assembly.GetExportedTypes().Where(t => t.IsPublic))
|
XDocument existingXmlDoc = null;
|
||||||
|
if (assemblyModel.HasXmlDocumentation && File.Exists(assemblyModel.XmlDocPath))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Generar documentación para el tipo
|
existingXmlDoc = XDocument.Load(assemblyModel.XmlDocPath);
|
||||||
GenerateTypeDocumentation(type, membersElement);
|
AppLogger.LogInfo($"Documentación XML cargada: {assemblyModel.XmlDocPath}");
|
||||||
|
|
||||||
// Generar documentación para métodos
|
// Mostrar estadísticas del XML existente
|
||||||
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)
|
var memberNodes = existingXmlDoc.Descendants("member").ToList();
|
||||||
.Where(m => !m.IsSpecialName))
|
AppLogger.LogInfo($"Entradas en XML existente: {memberNodes.Count}");
|
||||||
{
|
|
||||||
GenerateMethodDocumentation(method, membersElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generar documentación para propiedades
|
// Log de los primeros miembros para depuración
|
||||||
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
|
foreach (var node in memberNodes.Take(5))
|
||||||
{
|
{
|
||||||
GeneratePropertyDocumentation(property, membersElement);
|
string id = node.Attribute("name")?.Value;
|
||||||
}
|
AppLogger.LogDebug($" Miembro XML: {id}");
|
||||||
|
|
||||||
// Generar documentación para eventos
|
|
||||||
foreach (var eventInfo in type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
|
|
||||||
{
|
|
||||||
GenerateEventDocumentation(eventInfo, membersElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generar documentación para campos
|
|
||||||
foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
|
|
||||||
{
|
|
||||||
GenerateFieldDocumentation(field, membersElement);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logWriter.WriteLine($"Error procesando tipo {type.FullName}: {ex.Message}");
|
AppLogger.LogWarning($"Error al cargar XML: {ex.Message}");
|
||||||
|
existingXmlDoc = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppLogger.LogWarning("No se encontró documentación XML para este ensamblado");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Procesar todos los tipos exportados
|
||||||
|
var exportedTypes = assembly.GetExportedTypes().ToList();
|
||||||
|
AppLogger.LogInfo($"Tipos exportados encontrados: {exportedTypes.Count}");
|
||||||
|
|
||||||
|
// Procesar todos los tipos exportados
|
||||||
|
int typesWithMembers = 0;
|
||||||
|
int typesWithoutMembers = 0;
|
||||||
|
int totalMethods = 0;
|
||||||
|
int totalProperties = 0;
|
||||||
|
int totalEvents = 0;
|
||||||
|
int totalFields = 0;
|
||||||
|
|
||||||
|
foreach (var type in exportedTypes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AppLogger.IncrementTypeCount();
|
||||||
|
AppLogger.LogDebug($"Procesando tipo: {type.FullName}");
|
||||||
|
|
||||||
|
// Generar documentación para el tipo
|
||||||
|
bool hasMembers = GenerateTypeDocumentation(type, membersElement, existingXmlDoc);
|
||||||
|
|
||||||
|
if (hasMembers)
|
||||||
|
{
|
||||||
|
typesWithMembers++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
typesWithoutMembers++;
|
||||||
|
AppLogger.LogWarning($"⚠️ No se encontraron miembros para el tipo: {type.FullName}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contar miembros por tipo para estadísticas
|
||||||
|
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)
|
||||||
|
.Where(m => !m.IsSpecialName).ToList();
|
||||||
|
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).ToList();
|
||||||
|
var events = type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).ToList();
|
||||||
|
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).ToList();
|
||||||
|
|
||||||
|
totalMethods += methods.Count;
|
||||||
|
totalProperties += properties.Count;
|
||||||
|
totalEvents += events.Count;
|
||||||
|
totalFields += fields.Count;
|
||||||
|
|
||||||
|
AppLogger.LogDebug($" Miembros del tipo {type.Name}: Métodos={methods.Count}, Propiedades={properties.Count}, Eventos={events.Count}, Campos={fields.Count}");
|
||||||
|
|
||||||
|
// Generar entradas XML para los miembros
|
||||||
|
if (methods.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
AppLogger.IncrementMemberCount();
|
||||||
|
GenerateMethodDocumentation(method, membersElement, existingXmlDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var property in properties)
|
||||||
|
{
|
||||||
|
AppLogger.IncrementMemberCount();
|
||||||
|
GeneratePropertyDocumentation(property, membersElement, existingXmlDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var eventInfo in events)
|
||||||
|
{
|
||||||
|
AppLogger.IncrementMemberCount();
|
||||||
|
GenerateEventDocumentation(eventInfo, membersElement, existingXmlDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
|
AppLogger.IncrementMemberCount();
|
||||||
|
GenerateFieldDocumentation(field, membersElement, existingXmlDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AppLogger.LogError($"Error procesando tipo {type.FullName}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guardar la documentación XML
|
// Estadísticas finales
|
||||||
string xmlFileName = $"{assembly.GetName().Name}.xml";
|
AppLogger.LogInfo($"Estadísticas de procesamiento para {assemblyModel.Name}:");
|
||||||
|
AppLogger.LogInfo($" Tipos totales: {exportedTypes.Count}");
|
||||||
|
AppLogger.LogInfo($" Tipos con miembros: {typesWithMembers}");
|
||||||
|
AppLogger.LogInfo($" Tipos sin miembros: {typesWithoutMembers}");
|
||||||
|
AppLogger.LogInfo($" Total de métodos: {totalMethods}");
|
||||||
|
AppLogger.LogInfo($" Total de propiedades: {totalProperties}");
|
||||||
|
AppLogger.LogInfo($" Total de eventos: {totalEvents}");
|
||||||
|
AppLogger.LogInfo($" Total de campos: {totalFields}");
|
||||||
|
|
||||||
|
// Guardar la documentación XML generada
|
||||||
|
string xmlFileName = $"{assembly.GetName().Name}_generated.xml";
|
||||||
string xmlFilePath = Path.Combine(outputPath, xmlFileName);
|
string xmlFilePath = Path.Combine(outputPath, xmlFileName);
|
||||||
|
|
||||||
// Guardar con formato
|
// Guardar con formato
|
||||||
using (var writer = new XmlTextWriter(xmlFilePath, Encoding.UTF8))
|
using (var writer = new XmlTextWriter(xmlFilePath, Encoding.UTF8))
|
||||||
{
|
{
|
||||||
writer.Formatting = Formatting.Indented;
|
writer.Formatting = System.Xml.Formatting.Indented;
|
||||||
writer.Indentation = 4;
|
writer.Indentation = 4;
|
||||||
doc.Save(writer);
|
doc.Save(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logWriter.WriteLine($"Documentación XML guardada en: {xmlFilePath}");
|
AppLogger.LogInfo($"Documentación XML guardada en: {xmlFilePath}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logWriter.WriteLine($"ERROR general procesando ensamblado {assemblyModel.Name}: {ex.Message}");
|
AppLogger.LogError($"ERROR general procesando ensamblado {assemblyModel.Name}: {ex.Message}");
|
||||||
_logWriter.WriteLine(ex.StackTrace);
|
AppLogger.LogError(ex.StackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateTypeDocumentation(Type type, XElement membersElement)
|
private bool GenerateTypeDocumentation(Type type, XElement membersElement, XDocument existingXmlDoc)
|
||||||
{
|
{
|
||||||
string typeId = $"T:{type.FullName}";
|
string typeId = $"T:{type.FullName}";
|
||||||
var memberElement = new XElement("member", new XAttribute("name", typeId));
|
|
||||||
|
|
||||||
// Agregar summary
|
// Intentar encontrar documentación existente
|
||||||
memberElement.Add(new XElement("summary",
|
string summary = null;
|
||||||
$"Represents a {GetTypeKindDescription(type)}: {type.Name}"));
|
string remarks = null;
|
||||||
|
|
||||||
// Si es una clase que hereda de otra (excepto Object), agregar esa información
|
if (existingXmlDoc != null)
|
||||||
if (type.IsClass && type.BaseType != null && type.BaseType != typeof(object))
|
|
||||||
{
|
{
|
||||||
memberElement.Add(new XElement("remarks",
|
var existingMember = existingXmlDoc.Descendants("member")
|
||||||
$"Inherits from {type.BaseType.Name}"));
|
.FirstOrDefault(m => m.Attribute("name")?.Value == typeId);
|
||||||
|
|
||||||
|
if (existingMember != null)
|
||||||
|
{
|
||||||
|
AppLogger.LogDebug($" Encontrada documentación XML existente para {typeId}");
|
||||||
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
||||||
|
remarks = existingMember.Element("remarks")?.Value?.Trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si implementa interfaces, mencionarlas
|
// Si no hay documentación existente, generar una descripción genérica
|
||||||
var interfaces = type.GetInterfaces();
|
if (string.IsNullOrEmpty(summary))
|
||||||
if (interfaces.Length > 0)
|
|
||||||
{
|
{
|
||||||
var implementsText = $"Implements: {string.Join(", ", interfaces.Select(i => i.Name))}";
|
summary = $"Represents a {GetTypeKindDescription(type)}: {type.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
if (memberElement.Element("remarks") != null)
|
var memberElement = new XElement("member", new XAttribute("name", typeId));
|
||||||
|
memberElement.Add(new XElement("summary", summary));
|
||||||
|
|
||||||
|
// Agregar observaciones si están disponibles o generarlas
|
||||||
|
if (!string.IsNullOrEmpty(remarks))
|
||||||
|
{
|
||||||
|
memberElement.Add(new XElement("remarks", remarks));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var remarksBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
// Si es una clase que hereda de otra (excepto Object), agregar esa información
|
||||||
|
if (type.IsClass && type.BaseType != null && type.BaseType != typeof(object))
|
||||||
{
|
{
|
||||||
memberElement.Element("remarks").Value += $"\n{implementsText}";
|
remarksBuilder.AppendLine($"Inherits from {type.BaseType.Name}");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Si implementa interfaces, mencionarlas
|
||||||
|
var interfaces = type.GetInterfaces();
|
||||||
|
if (interfaces.Length > 0)
|
||||||
{
|
{
|
||||||
memberElement.Add(new XElement("remarks", implementsText));
|
if (remarksBuilder.Length > 0)
|
||||||
|
remarksBuilder.AppendLine();
|
||||||
|
|
||||||
|
remarksBuilder.Append($"Implements: {string.Join(", ", interfaces.Select(i => i.Name))}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remarksBuilder.Length > 0)
|
||||||
|
{
|
||||||
|
memberElement.Add(new XElement("remarks", remarksBuilder.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
membersElement.Add(memberElement);
|
membersElement.Add(memberElement);
|
||||||
|
|
||||||
|
// Verificar si el tipo tiene miembros
|
||||||
|
bool hasMembers =
|
||||||
|
type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Any(m => !m.IsSpecialName) ||
|
||||||
|
type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Any() ||
|
||||||
|
type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Any() ||
|
||||||
|
type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Any();
|
||||||
|
|
||||||
|
return hasMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateMethodDocumentation(MethodInfo method, XElement membersElement)
|
private void GenerateMethodDocumentation(MethodInfo method, XElement membersElement, XDocument existingXmlDoc)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Generar ID XML para el método
|
||||||
string methodId = GetMethodXmlId(method);
|
string methodId = GetMethodXmlId(method);
|
||||||
var memberElement = new XElement("member", new XAttribute("name", methodId));
|
AppLogger.LogDebug($" Procesando método: {methodId}");
|
||||||
|
|
||||||
// Agregar summary básico
|
// Intentar encontrar documentación existente
|
||||||
memberElement.Add(new XElement("summary",
|
string summary = null;
|
||||||
$"{method.Name} {GetMethodDescription(method)}"));
|
string returns = null;
|
||||||
|
Dictionary<string, string> paramDescriptions = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
if (existingXmlDoc != null)
|
||||||
|
{
|
||||||
|
var existingMember = existingXmlDoc.Descendants("member")
|
||||||
|
.FirstOrDefault(m => m.Attribute("name")?.Value == methodId);
|
||||||
|
|
||||||
|
if (existingMember != null)
|
||||||
|
{
|
||||||
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
||||||
|
returns = existingMember.Element("returns")?.Value?.Trim();
|
||||||
|
|
||||||
|
foreach (var paramElement in existingMember.Elements("param"))
|
||||||
|
{
|
||||||
|
string paramName = paramElement.Attribute("name")?.Value;
|
||||||
|
string paramDesc = paramElement.Value?.Trim();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(paramName) && !string.IsNullOrEmpty(paramDesc))
|
||||||
|
{
|
||||||
|
paramDescriptions[paramName] = paramDesc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no hay documentación existente, generar una descripción genérica
|
||||||
|
if (string.IsNullOrEmpty(summary))
|
||||||
|
{
|
||||||
|
summary = $"{method.Name} {GetMethodDescription(method)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var element = new XElement("member",
|
||||||
|
new XAttribute("name", methodId),
|
||||||
|
new XElement("summary", summary)
|
||||||
|
);
|
||||||
|
|
||||||
// Agregar parámetros
|
// Agregar parámetros
|
||||||
foreach (var param in method.GetParameters())
|
var parameters = method.GetParameters();
|
||||||
|
foreach (var param in parameters)
|
||||||
{
|
{
|
||||||
memberElement.Add(new XElement("param",
|
string paramDesc;
|
||||||
|
if (!paramDescriptions.TryGetValue(param.Name, out paramDesc))
|
||||||
|
{
|
||||||
|
paramDesc = GetParameterDescription(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
element.Add(new XElement("param",
|
||||||
new XAttribute("name", param.Name),
|
new XAttribute("name", param.Name),
|
||||||
GetParameterDescription(param)));
|
new XText(paramDesc)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Agregar returns si no es void
|
// Agregar información de retorno si no es void
|
||||||
if (method.ReturnType != typeof(void))
|
if (method.ReturnType != typeof(void))
|
||||||
{
|
{
|
||||||
memberElement.Add(new XElement("returns",
|
if (string.IsNullOrEmpty(returns))
|
||||||
$"A {GetSimpleTypeName(method.ReturnType)} value."));
|
{
|
||||||
|
returns = $"A {GetSimpleTypeName(method.ReturnType)} value.";
|
||||||
|
}
|
||||||
|
|
||||||
|
element.Add(new XElement("returns", returns));
|
||||||
}
|
}
|
||||||
|
|
||||||
membersElement.Add(memberElement);
|
membersElement.Add(element);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logWriter.WriteLine($"Error generando documentación para método {method.Name}: {ex.Message}");
|
AppLogger.LogError($"Error generando documentación para método {method.Name}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GeneratePropertyDocumentation(PropertyInfo property, XElement membersElement)
|
private void GeneratePropertyDocumentation(PropertyInfo property, XElement membersElement, XDocument existingXmlDoc)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string propertyId = $"P:{property.DeclaringType.FullName}.{property.Name}";
|
string propertyId = $"P:{property.DeclaringType.FullName}.{property.Name}";
|
||||||
var memberElement = new XElement("member", new XAttribute("name", propertyId));
|
AppLogger.LogDebug($" Procesando propiedad: {propertyId}");
|
||||||
|
|
||||||
// Accesibilidad (get/set)
|
// Intentar encontrar documentación existente
|
||||||
string access = "";
|
string summary = null;
|
||||||
if (property.CanRead) access += "get; ";
|
string value = null;
|
||||||
if (property.CanWrite) access += "set; ";
|
|
||||||
|
|
||||||
// Agregar summary
|
if (existingXmlDoc != null)
|
||||||
memberElement.Add(new XElement("summary",
|
{
|
||||||
$"Gets{(property.CanWrite ? " or sets" : "")} the {property.Name} property."));
|
var existingMember = existingXmlDoc.Descendants("member")
|
||||||
|
.FirstOrDefault(m => m.Attribute("name")?.Value == propertyId);
|
||||||
|
|
||||||
// Agregar valor
|
if (existingMember != null)
|
||||||
memberElement.Add(new XElement("value",
|
{
|
||||||
$"A {GetSimpleTypeName(property.PropertyType)} representing the {property.Name}."));
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
||||||
|
value = existingMember.Element("value")?.Value?.Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
membersElement.Add(memberElement);
|
// Si no hay documentación existente, generar una descripción genérica
|
||||||
|
if (string.IsNullOrEmpty(summary))
|
||||||
|
{
|
||||||
|
summary = $"Gets{(property.CanWrite ? " or sets" : "")} the {property.Name} property.";
|
||||||
|
}
|
||||||
|
|
||||||
|
var element = new XElement("member",
|
||||||
|
new XAttribute("name", propertyId),
|
||||||
|
new XElement("summary", summary)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Agregar descripción de valor si está disponible o generarla
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
value = $"A {GetSimpleTypeName(property.PropertyType)} representing the {property.Name}.";
|
||||||
|
}
|
||||||
|
|
||||||
|
element.Add(new XElement("value", value));
|
||||||
|
|
||||||
|
membersElement.Add(element);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logWriter.WriteLine($"Error generando documentación para propiedad {property.Name}: {ex.Message}");
|
AppLogger.LogError($"Error generando documentación para propiedad {property.Name}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateEventDocumentation(EventInfo eventInfo, XElement membersElement)
|
private void GenerateEventDocumentation(EventInfo eventInfo, XElement membersElement, XDocument existingXmlDoc)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string eventId = $"E:{eventInfo.DeclaringType.FullName}.{eventInfo.Name}";
|
string eventId = $"E:{eventInfo.DeclaringType.FullName}.{eventInfo.Name}";
|
||||||
var memberElement = new XElement("member", new XAttribute("name", eventId));
|
AppLogger.LogDebug($" Procesando evento: {eventId}");
|
||||||
|
|
||||||
// Agregar summary
|
// Intentar encontrar documentación existente
|
||||||
memberElement.Add(new XElement("summary",
|
string summary = null;
|
||||||
$"Occurs when {eventInfo.Name} is raised."));
|
|
||||||
|
if (existingXmlDoc != null)
|
||||||
|
{
|
||||||
|
var existingMember = existingXmlDoc.Descendants("member")
|
||||||
|
.FirstOrDefault(m => m.Attribute("name")?.Value == eventId);
|
||||||
|
|
||||||
|
if (existingMember != null)
|
||||||
|
{
|
||||||
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no hay documentación existente, generar una descripción genérica
|
||||||
|
if (string.IsNullOrEmpty(summary))
|
||||||
|
{
|
||||||
|
summary = $"Occurs when {eventInfo.Name} is raised.";
|
||||||
|
}
|
||||||
|
|
||||||
|
var element = new XElement("member",
|
||||||
|
new XAttribute("name", eventId),
|
||||||
|
new XElement("summary", summary)
|
||||||
|
);
|
||||||
|
|
||||||
// Agregar remarks con el tipo del handler
|
// Agregar remarks con el tipo del handler
|
||||||
memberElement.Add(new XElement("remarks",
|
element.Add(new XElement("remarks",
|
||||||
$"Event handler type: {GetSimpleTypeName(eventInfo.EventHandlerType)}"));
|
$"Event handler type: {GetSimpleTypeName(eventInfo.EventHandlerType)}"
|
||||||
|
));
|
||||||
|
|
||||||
membersElement.Add(memberElement);
|
membersElement.Add(element);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logWriter.WriteLine($"Error generando documentación para evento {eventInfo.Name}: {ex.Message}");
|
AppLogger.LogError($"Error generando documentación para evento {eventInfo.Name}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateFieldDocumentation(FieldInfo field, XElement membersElement)
|
private void GenerateFieldDocumentation(FieldInfo field, XElement membersElement, XDocument existingXmlDoc)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string fieldId = $"F:{field.DeclaringType.FullName}.{field.Name}";
|
string fieldId = $"F:{field.DeclaringType.FullName}.{field.Name}";
|
||||||
var memberElement = new XElement("member", new XAttribute("name", fieldId));
|
AppLogger.LogDebug($" Procesando campo: {fieldId}");
|
||||||
|
|
||||||
|
// Intentar encontrar documentación existente
|
||||||
|
string summary = null;
|
||||||
|
|
||||||
|
if (existingXmlDoc != null)
|
||||||
|
{
|
||||||
|
var existingMember = existingXmlDoc.Descendants("member")
|
||||||
|
.FirstOrDefault(m => m.Attribute("name")?.Value == fieldId);
|
||||||
|
|
||||||
|
if (existingMember != null)
|
||||||
|
{
|
||||||
|
summary = existingMember.Element("summary")?.Value?.Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Modificadores
|
// Modificadores
|
||||||
string modifiers = "";
|
string modifiers = "";
|
||||||
|
@ -265,15 +500,22 @@ namespace NetDocsForLLM.Services
|
||||||
if (field.IsInitOnly) modifiers += "readonly ";
|
if (field.IsInitOnly) modifiers += "readonly ";
|
||||||
if (field.IsLiteral) modifiers += "constant ";
|
if (field.IsLiteral) modifiers += "constant ";
|
||||||
|
|
||||||
// Agregar summary
|
// Si no hay documentación existente, generar una descripción genérica
|
||||||
memberElement.Add(new XElement("summary",
|
if (string.IsNullOrEmpty(summary))
|
||||||
$"Represents the {modifiers}{field.Name} field."));
|
{
|
||||||
|
summary = $"Represents the {modifiers}{field.Name} field.";
|
||||||
|
}
|
||||||
|
|
||||||
membersElement.Add(memberElement);
|
var element = new XElement("member",
|
||||||
|
new XAttribute("name", fieldId),
|
||||||
|
new XElement("summary", summary)
|
||||||
|
);
|
||||||
|
|
||||||
|
membersElement.Add(element);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logWriter.WriteLine($"Error generando documentación para campo {field.Name}: {ex.Message}");
|
AppLogger.LogError($"Error generando documentación para campo {field.Name}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,44 +523,64 @@ namespace NetDocsForLLM.Services
|
||||||
|
|
||||||
private string GetMethodXmlId(MethodInfo method)
|
private string GetMethodXmlId(MethodInfo method)
|
||||||
{
|
{
|
||||||
var parameters = method.GetParameters();
|
try
|
||||||
if (parameters.Length == 0)
|
|
||||||
{
|
{
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
if (parameters.Length == 0)
|
||||||
|
{
|
||||||
|
return $"M:{method.DeclaringType.FullName}.{method.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var paramTypes = string.Join(",", parameters.Select(p => GetParameterTypeName(p.ParameterType)));
|
||||||
|
return $"M:{method.DeclaringType.FullName}.{method.Name}({paramTypes})";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AppLogger.LogError($"Error generando XML ID para método {method.Name}: {ex.Message}");
|
||||||
return $"M:{method.DeclaringType.FullName}.{method.Name}";
|
return $"M:{method.DeclaringType.FullName}.{method.Name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramTypes = string.Join(",", parameters.Select(p => GetParameterTypeName(p.ParameterType)));
|
|
||||||
return $"M:{method.DeclaringType.FullName}.{method.Name}({paramTypes})";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetParameterTypeName(Type type)
|
private string GetParameterTypeName(Type type)
|
||||||
{
|
{
|
||||||
// El formato de los parámetros en los IDs XML de documentación es específico
|
try
|
||||||
|
|
||||||
// Arrays
|
|
||||||
if (type.IsArray)
|
|
||||||
{
|
{
|
||||||
return $"{GetParameterTypeName(type.GetElementType())}[]";
|
// El formato de los parámetros en los IDs XML de documentación es específico
|
||||||
}
|
|
||||||
|
|
||||||
// Genéricos
|
// Arrays
|
||||||
if (type.IsGenericType)
|
if (type.IsArray)
|
||||||
{
|
|
||||||
var genericTypeDef = type.GetGenericTypeDefinition();
|
|
||||||
var genericArgs = string.Join(",", type.GetGenericArguments().Select(GetParameterTypeName));
|
|
||||||
|
|
||||||
// Para tipos como List<T>, devolver algo como System.Collections.Generic.List{T}
|
|
||||||
if (genericTypeDef == typeof(System.Collections.Generic.List<>))
|
|
||||||
{
|
{
|
||||||
return $"System.Collections.Generic.List{{{genericArgs}}}";
|
return $"{GetParameterTypeName(type.GetElementType())}[]";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Para otros tipos genéricos, usar el nombre completo con {}
|
// Genéricos
|
||||||
return $"{genericTypeDef.FullName.Split('`')[0]}{{{genericArgs}}}";
|
if (type.IsGenericType)
|
||||||
}
|
{
|
||||||
|
var genericTypeDef = type.GetGenericTypeDefinition();
|
||||||
|
var genericArgs = string.Join(",", type.GetGenericArguments().Select(GetParameterTypeName));
|
||||||
|
|
||||||
// Para tipos normales, usar el nombre completo
|
// Para tipos como List<T>, devolver algo como System.Collections.Generic.List{T}
|
||||||
return type.FullName;
|
string baseTypeName;
|
||||||
|
if (genericTypeDef.FullName != null && genericTypeDef.FullName.Contains('`'))
|
||||||
|
{
|
||||||
|
baseTypeName = genericTypeDef.FullName.Split('`')[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
baseTypeName = genericTypeDef.Namespace + "." + genericTypeDef.Name.Split('`')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{baseTypeName}{{{genericArgs}}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Para tipos normales, usar el nombre completo
|
||||||
|
return type.FullName;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// En caso de error, devolver un nombre genérico
|
||||||
|
return "System.Object";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetTypeKindDescription(Type type)
|
private string GetTypeKindDescription(Type type)
|
||||||
|
@ -346,7 +608,7 @@ namespace NetDocsForLLM.Services
|
||||||
{
|
{
|
||||||
return "performs an operation.";
|
return "performs an operation.";
|
||||||
}
|
}
|
||||||
return $"gets a {GetSimpleTypeName(method.ReturnType)} value.";
|
return $"returns a {GetSimpleTypeName(method.ReturnType)} value.";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"with {parameters.Length} parameter{(parameters.Length > 1 ? "s" : "")}.";
|
return $"with {parameters.Length} parameter{(parameters.Length > 1 ? "s" : "")}.";
|
||||||
|
@ -383,49 +645,57 @@ namespace NetDocsForLLM.Services
|
||||||
|
|
||||||
private string GetSimpleTypeName(Type type)
|
private string GetSimpleTypeName(Type type)
|
||||||
{
|
{
|
||||||
if (type == null) return "void";
|
try
|
||||||
|
|
||||||
// Si es un tipo por referencia (como out o ref parámetros)
|
|
||||||
if (type.IsByRef)
|
|
||||||
{
|
{
|
||||||
return GetSimpleTypeName(type.GetElementType());
|
if (type == null) return "void";
|
||||||
}
|
|
||||||
|
|
||||||
// Tipos primitivos
|
// Si es un tipo por referencia (como out o ref parámetros)
|
||||||
if (type == typeof(void)) return "void";
|
if (type.IsByRef)
|
||||||
if (type == typeof(int)) return "int";
|
|
||||||
if (type == typeof(string)) return "string";
|
|
||||||
if (type == typeof(bool)) return "bool";
|
|
||||||
if (type == typeof(double)) return "double";
|
|
||||||
if (type == typeof(float)) return "float";
|
|
||||||
if (type == typeof(decimal)) return "decimal";
|
|
||||||
if (type == typeof(object)) return "object";
|
|
||||||
|
|
||||||
// Arrays
|
|
||||||
if (type.IsArray)
|
|
||||||
{
|
|
||||||
return $"{GetSimpleTypeName(type.GetElementType())}[]";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Genéricos
|
|
||||||
if (type.IsGenericType)
|
|
||||||
{
|
|
||||||
string baseName = type.Name;
|
|
||||||
int tickIndex = baseName.IndexOf('`');
|
|
||||||
if (tickIndex > 0)
|
|
||||||
{
|
{
|
||||||
baseName = baseName.Substring(0, tickIndex);
|
return GetSimpleTypeName(type.GetElementType());
|
||||||
}
|
}
|
||||||
|
|
||||||
var argTypes = type.GetGenericArguments()
|
// Tipos primitivos
|
||||||
.Select(GetSimpleTypeName)
|
if (type == typeof(void)) return "void";
|
||||||
.ToArray();
|
if (type == typeof(int)) return "int";
|
||||||
|
if (type == typeof(string)) return "string";
|
||||||
|
if (type == typeof(bool)) return "bool";
|
||||||
|
if (type == typeof(double)) return "double";
|
||||||
|
if (type == typeof(float)) return "float";
|
||||||
|
if (type == typeof(decimal)) return "decimal";
|
||||||
|
if (type == typeof(object)) return "object";
|
||||||
|
|
||||||
return $"{baseName}<{string.Join(", ", argTypes)}>";
|
// Arrays
|
||||||
|
if (type.IsArray)
|
||||||
|
{
|
||||||
|
return $"{GetSimpleTypeName(type.GetElementType())}[]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Genéricos
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
string baseName = type.Name;
|
||||||
|
int tickIndex = baseName.IndexOf('`');
|
||||||
|
if (tickIndex > 0)
|
||||||
|
{
|
||||||
|
baseName = baseName.Substring(0, tickIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var argTypes = type.GetGenericArguments()
|
||||||
|
.Select(GetSimpleTypeName)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return $"{baseName}<{string.Join(", ", argTypes)}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Para tipos normales, usar solo el nombre simple
|
||||||
|
return type.Name;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// En caso de error, devolver un nombre genérico
|
||||||
|
return "object";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Para tipos normales, usar solo el nombre simple
|
|
||||||
return type.Name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
//--- LogViewModel.cs ---
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using NetDocsForLLM.Services;
|
||||||
|
using NetDocsForLLM.ViewModels;
|
||||||
|
using Ookii.Dialogs.Wpf;
|
||||||
|
using System;
|
||||||
|
using System.Drawing.Printing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Windows.Media.Media3D;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using static System.Net.Mime.MediaTypeNames;
|
||||||
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrayNotify;
|
||||||
|
|
||||||
|
namespace NetDocsForLLM.ViewModels
|
||||||
|
{
|
||||||
|
public class LogViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private string _logContent;
|
||||||
|
private int _logLevel;
|
||||||
|
private readonly DispatcherTimer _refreshTimer;
|
||||||
|
|
||||||
|
public string LogContent
|
||||||
|
{
|
||||||
|
get => _logContent;
|
||||||
|
set => SetProperty(ref _logContent, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int LogLevel
|
||||||
|
{
|
||||||
|
get => _logLevel;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _logLevel, value))
|
||||||
|
{
|
||||||
|
UpdateLogContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ErrorCount => AppLogger.ErrorCount;
|
||||||
|
public int WarningCount => AppLogger.WarningCount;
|
||||||
|
public int TypeCount => AppLogger.TypeCount;
|
||||||
|
public int MemberCount => AppLogger.MemberCount;
|
||||||
|
|
||||||
|
public IRelayCommand ClearLogCommand { get; }
|
||||||
|
public IRelayCommand SaveLogCommand { get; }
|
||||||
|
public IRelayCommand RefreshLogCommand { get; }
|
||||||
|
|
||||||
|
public LogViewModel()
|
||||||
|
{
|
||||||
|
_logLevel = LogLevel; // Por defecto, mostrar INFO y errores
|
||||||
|
_logContent = "";
|
||||||
|
|
||||||
|
ClearLogCommand = new RelayCommand(ClearLog);
|
||||||
|
SaveLogCommand = new RelayCommand(SaveLog);
|
||||||
|
RefreshLogCommand = new RelayCommand(UpdateLogContent);
|
||||||
|
|
||||||
|
// Crear timer para actualizar el contenido
|
||||||
|
_refreshTimer = new DispatcherTimer
|
||||||
|
{
|
||||||
|
Interval = TimeSpan.FromSeconds(1)
|
||||||
|
};
|
||||||
|
|
||||||
|
_refreshTimer.Tick += (s, e) => UpdateProperties();
|
||||||
|
_refreshTimer.Start();
|
||||||
|
|
||||||
|
// Suscribirse al evento de actualización de logs
|
||||||
|
AppLogger.LogUpdated += OnLogUpdated;
|
||||||
|
|
||||||
|
UpdateLogContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLogUpdated(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// Este método podría ser llamado desde otro hilo, así que usamos el Dispatcher
|
||||||
|
App.Current.Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
UpdateLogContent();
|
||||||
|
UpdateProperties();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateProperties()
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(ErrorCount));
|
||||||
|
OnPropertyChanged(nameof(WarningCount));
|
||||||
|
OnPropertyChanged(nameof(TypeCount));
|
||||||
|
OnPropertyChanged(nameof(MemberCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLogContent()
|
||||||
|
{
|
||||||
|
LogContent = AppLogger.GetContent((LogLevel)_logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearLog()
|
||||||
|
{
|
||||||
|
AppLogger.Clear();
|
||||||
|
UpdateLogContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveLog()
|
||||||
|
{
|
||||||
|
var dialog = new VistaSaveFileDialog
|
||||||
|
{
|
||||||
|
Filter = "Archivos de texto (*.txt)|*.txt|Archivos de log (*.log)|*.log",
|
||||||
|
DefaultExt = ".txt",
|
||||||
|
Title = "Guardar archivo de log"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dialog.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText(dialog.FileName, AppLogger.GetContent());
|
||||||
|
AppLogger.LogInfo($"Log guardado en: {dialog.FileName}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AppLogger.LogError($"Error al guardar el log: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ using System.Windows;
|
||||||
|
|
||||||
namespace NetDocsForLLM.ViewModels
|
namespace NetDocsForLLM.ViewModels
|
||||||
{
|
{
|
||||||
public class MainViewModel : ObservableObject
|
public partial class MainViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
private readonly IAssemblyAnalyzer _assemblyAnalyzer;
|
private readonly IAssemblyAnalyzer _assemblyAnalyzer;
|
||||||
private readonly IDocumentationGenerator _documentationGenerator;
|
private readonly IDocumentationGenerator _documentationGenerator;
|
||||||
|
@ -24,6 +24,8 @@ namespace NetDocsForLLM.ViewModels
|
||||||
private string _documentationStats;
|
private string _documentationStats;
|
||||||
private string _statusMessage;
|
private string _statusMessage;
|
||||||
private bool _isProcessing;
|
private bool _isProcessing;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
private bool _hasGeneratedDocumentation;
|
private bool _hasGeneratedDocumentation;
|
||||||
|
|
||||||
public ObservableCollection<AssemblyModel> SelectedAssemblies
|
public ObservableCollection<AssemblyModel> SelectedAssemblies
|
||||||
|
@ -68,20 +70,25 @@ namespace NetDocsForLLM.ViewModels
|
||||||
set => SetProperty(ref _isProcessing, value);
|
set => SetProperty(ref _isProcessing, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasGeneratedDocumentation
|
|
||||||
{
|
|
||||||
get => _hasGeneratedDocumentation;
|
|
||||||
set => SetProperty(ref _hasGeneratedDocumentation, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasSelectedAssemblies => SelectedAssemblies.Count > 0;
|
public bool HasSelectedAssemblies => SelectedAssemblies.Count > 0;
|
||||||
|
|
||||||
|
// Comandos
|
||||||
public IRelayCommand SelectAssembliesCommand { get; }
|
public IRelayCommand SelectAssembliesCommand { get; }
|
||||||
public IRelayCommand<AssemblyModel> RemoveAssemblyCommand { get; }
|
public IRelayCommand<AssemblyModel> RemoveAssemblyCommand { get; }
|
||||||
public IRelayCommand GenerateDocumentationCommand { get; }
|
public IRelayCommand GenerateDocumentationCommand { get; }
|
||||||
public IRelayCommand CopyToClipboardCommand { get; }
|
|
||||||
public IRelayCommand ExportDocumentationCommand { get; }
|
|
||||||
|
|
||||||
|
// Estos campos se actualizan desde propiedades computadas
|
||||||
|
private IRelayCommand _copyToClipboardCommand;
|
||||||
|
private IRelayCommand _exportDocumentationCommand;
|
||||||
|
|
||||||
|
// Redefine los comandos con canExecute actualizado
|
||||||
|
public IRelayCommand CopyToClipboardCommand =>
|
||||||
|
_copyToClipboardCommand ??= new RelayCommand(CopyToClipboard, () => HasGeneratedDocumentation);
|
||||||
|
|
||||||
|
public IRelayCommand ExportDocumentationCommand =>
|
||||||
|
_exportDocumentationCommand ??= new RelayCommand(ExportDocumentation, () => HasGeneratedDocumentation);
|
||||||
|
|
||||||
|
// Constructor
|
||||||
public MainViewModel(IAssemblyAnalyzer assemblyAnalyzer, IDocumentationGenerator documentationGenerator)
|
public MainViewModel(IAssemblyAnalyzer assemblyAnalyzer, IDocumentationGenerator documentationGenerator)
|
||||||
{
|
{
|
||||||
_assemblyAnalyzer = assemblyAnalyzer ?? throw new ArgumentNullException(nameof(assemblyAnalyzer));
|
_assemblyAnalyzer = assemblyAnalyzer ?? throw new ArgumentNullException(nameof(assemblyAnalyzer));
|
||||||
|
@ -99,8 +106,6 @@ namespace NetDocsForLLM.ViewModels
|
||||||
SelectAssembliesCommand = new RelayCommand(SelectAssemblies);
|
SelectAssembliesCommand = new RelayCommand(SelectAssemblies);
|
||||||
RemoveAssemblyCommand = new RelayCommand<AssemblyModel>(RemoveAssembly);
|
RemoveAssemblyCommand = new RelayCommand<AssemblyModel>(RemoveAssembly);
|
||||||
GenerateDocumentationCommand = new AsyncRelayCommand(GenerateDocumentationAsync);
|
GenerateDocumentationCommand = new AsyncRelayCommand(GenerateDocumentationAsync);
|
||||||
CopyToClipboardCommand = new RelayCommand(CopyToClipboard, () => HasGeneratedDocumentation);
|
|
||||||
ExportDocumentationCommand = new RelayCommand(ExportDocumentation, () => HasGeneratedDocumentation);
|
|
||||||
|
|
||||||
// Subscribe to collection changes to update HasSelectedAssemblies
|
// Subscribe to collection changes to update HasSelectedAssemblies
|
||||||
_selectedAssemblies.CollectionChanged += (sender, e) =>
|
_selectedAssemblies.CollectionChanged += (sender, e) =>
|
||||||
|
@ -109,6 +114,19 @@ namespace NetDocsForLLM.ViewModels
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Asegúrate de que UpdateCanExecuteForCommands se llame cuando cambie HasGeneratedDocumentation
|
||||||
|
partial void OnHasGeneratedDocumentationChanged(bool value)
|
||||||
|
{
|
||||||
|
UpdateCanExecuteForCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Método para actualizar el CanExecute de los comandos
|
||||||
|
private void UpdateCanExecuteForCommands()
|
||||||
|
{
|
||||||
|
(CopyToClipboardCommand as RelayCommand)?.NotifyCanExecuteChanged();
|
||||||
|
(ExportDocumentationCommand as RelayCommand)?.NotifyCanExecuteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private void SelectAssemblies()
|
private void SelectAssemblies()
|
||||||
{
|
{
|
||||||
var dialog = new VistaOpenFileDialog
|
var dialog = new VistaOpenFileDialog
|
||||||
|
@ -182,7 +200,11 @@ namespace NetDocsForLLM.ViewModels
|
||||||
DocumentationStats = $"Resumen: {DocumentationModel.Namespaces.Count} namespaces, " +
|
DocumentationStats = $"Resumen: {DocumentationModel.Namespaces.Count} namespaces, " +
|
||||||
$"{totalTypes} tipos, {totalMembers} miembros";
|
$"{totalTypes} tipos, {totalMembers} miembros";
|
||||||
|
|
||||||
|
// Estas dos líneas son cruciales - aseguran que HasGeneratedDocumentation se actualice
|
||||||
|
// y que los comandos se habiliten
|
||||||
HasGeneratedDocumentation = true;
|
HasGeneratedDocumentation = true;
|
||||||
|
UpdateCanExecuteForCommands();
|
||||||
|
|
||||||
StatusMessage = "Documentación generada correctamente";
|
StatusMessage = "Documentación generada correctamente";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -219,13 +241,33 @@ namespace NetDocsForLLM.ViewModels
|
||||||
if (string.IsNullOrEmpty(DocumentationPreview))
|
if (string.IsNullOrEmpty(DocumentationPreview))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Determinar extensión y filtro basado en formato seleccionado
|
||||||
|
string extension;
|
||||||
|
string filter;
|
||||||
|
|
||||||
|
switch (Settings.OutputFormat)
|
||||||
|
{
|
||||||
|
case OutputFormat.Xml:
|
||||||
|
extension = ".xml";
|
||||||
|
filter = "Archivos XML (*.xml)|*.xml";
|
||||||
|
break;
|
||||||
|
case OutputFormat.Json:
|
||||||
|
extension = ".json";
|
||||||
|
filter = "Archivos JSON (*.json)|*.json";
|
||||||
|
break;
|
||||||
|
case OutputFormat.Yaml:
|
||||||
|
default:
|
||||||
|
extension = ".yaml";
|
||||||
|
filter = "Archivos YAML (*.yaml;*.yml)|*.yaml;*.yml";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
var dialog = new VistaSaveFileDialog
|
var dialog = new VistaSaveFileDialog
|
||||||
{
|
{
|
||||||
Filter = Settings.OutputFormat == OutputFormat.Json
|
Filter = filter,
|
||||||
? "Archivos JSON (*.json)|*.json"
|
DefaultExt = extension,
|
||||||
: "Archivos YAML (*.yaml;*.yml)|*.yaml;*.yml",
|
Title = "Guardar documentación",
|
||||||
DefaultExt = Settings.OutputFormat == OutputFormat.Json ? ".json" : ".yaml",
|
OverwritePrompt = true
|
||||||
Title = "Guardar documentación"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dialog.ShowDialog() == true)
|
if (dialog.ShowDialog() == true)
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<UserControl x:Class="NetDocsForLLM.Views.LogView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:NetDocsForLLM.Views"
|
||||||
|
mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<Grid Margin="10">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
|
||||||
|
<Button Content="Limpiar Log" Command="{Binding ClearLogCommand}" Padding="10,5" Margin="0,0,10,0" />
|
||||||
|
|
||||||
|
<Button Content="Guardar Log" Command="{Binding SaveLogCommand}" Padding="10,5" Margin="0,0,10,0" />
|
||||||
|
|
||||||
|
<Button Content="Actualizar" Command="{Binding RefreshLogCommand}" Padding="10,5" Margin="0,0,10,0" />
|
||||||
|
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="Nivel de detalle:" />
|
||||||
|
<ComboBox Margin="5,0,0,0" SelectedIndex="{Binding LogLevel}" Width="120">
|
||||||
|
<ComboBoxItem Content="Errores" />
|
||||||
|
<ComboBoxItem Content="Advertencias" />
|
||||||
|
<ComboBoxItem Content="Información" />
|
||||||
|
<ComboBoxItem Content="Depuración" />
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBox Grid.Row="1" Text="{Binding LogContent, Mode=OneWay}" IsReadOnly="True"
|
||||||
|
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" FontFamily="Consolas"
|
||||||
|
FontSize="12" AcceptsReturn="True" TextWrapping="NoWrap" Background="#f5f5f5" Padding="10" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Margin="0,10,0,0" Orientation="Horizontal">
|
||||||
|
<TextBlock Text="Errores:" Foreground="Red" FontWeight="Bold" Margin="0,0,5,0" />
|
||||||
|
<TextBlock Text="{Binding ErrorCount}" />
|
||||||
|
|
||||||
|
<TextBlock Text="Advertencias:" Foreground="Orange" FontWeight="Bold" Margin="15,0,5,0" />
|
||||||
|
<TextBlock Text="{Binding WarningCount}" />
|
||||||
|
|
||||||
|
<TextBlock Text="Total tipos analizados:" FontWeight="Bold" Margin="15,0,5,0" />
|
||||||
|
<TextBlock Text="{Binding TypeCount}" />
|
||||||
|
|
||||||
|
<TextBlock Text="Total miembros analizados:" FontWeight="Bold" Margin="15,0,5,0" />
|
||||||
|
<TextBlock Text="{Binding MemberCount}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,15 @@
|
||||||
|
//--- LogView.xaml.cs ---
|
||||||
|
using NetDocsForLLM.ViewModels;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace NetDocsForLLM.Views
|
||||||
|
{
|
||||||
|
public partial class LogView : UserControl
|
||||||
|
{
|
||||||
|
public LogView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = new LogViewModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue