Cambio a Reflection porque la libreria DocFX no es compatible
This commit is contained in:
parent
93b0f39a24
commit
641bb7baf1
9
App.xaml
9
App.xaml
|
@ -1,13 +1,10 @@
|
||||||
<Application x:Class="NetDocsForLLM.App"
|
<Application x:Class="NetDocsForLLM.App" 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:local="clr-namespace:NetDocsForLLM"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:local="clr-namespace:NetDocsForLLM"
|
|
||||||
xmlns:converters="clr-namespace:NetDocsForLLM.Converters">
|
xmlns:converters="clr-namespace:NetDocsForLLM.Converters">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<!-- Converters -->
|
<!-- Converters -->
|
||||||
<converters:EnumBooleanConverter x:Key="EnumBooleanConverter"/>
|
<converters:EnumBooleanConverter x:Key="EnumBooleanConverter" />
|
||||||
|
|
||||||
<!-- Other resources -->
|
<!-- Other resources -->
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using NetDocsForLLM.Services;
|
using NetDocsForLLM.Services;
|
||||||
using NetDocsForLLM.ViewModels;
|
using NetDocsForLLM.ViewModels;
|
||||||
using System;
|
using System;
|
||||||
|
@ -20,7 +20,7 @@ namespace NetDocsForLLM
|
||||||
private void ConfigureServices(ServiceCollection services)
|
private void ConfigureServices(ServiceCollection services)
|
||||||
{
|
{
|
||||||
// Register services
|
// Register services
|
||||||
services.AddSingleton<IDocFxService, DocFxService>();
|
services.AddSingleton<IDocFxService, ReflectionAnalyzerService>(); // <- Cambio aquí
|
||||||
services.AddSingleton<IDocumentationGenerator, DocumentationGenerator>();
|
services.AddSingleton<IDocumentationGenerator, DocumentationGenerator>();
|
||||||
services.AddSingleton<IAssemblyAnalyzer, AssemblyAnalyzer>();
|
services.AddSingleton<IAssemblyAnalyzer, AssemblyAnalyzer>();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
@ -11,31 +11,25 @@ namespace NetDocsForLLM.Converters
|
||||||
{
|
{
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (value == null || parameter == null)
|
if (parameter == null || value == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
string checkValue = parameter.ToString();
|
string parameterString = parameter.ToString();
|
||||||
string currentValue = value.ToString();
|
if (Enum.IsDefined(value.GetType(), value))
|
||||||
|
{
|
||||||
|
return value.ToString().Equals(parameterString, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
return checkValue.Equals(currentValue, StringComparison.InvariantCultureIgnoreCase);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (value == null || parameter == null)
|
if (parameter == null || !(bool)value)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
bool isChecked = (bool)value;
|
string parameterString = parameter.ToString();
|
||||||
if (isChecked)
|
|
||||||
{
|
|
||||||
if (parameter is string parameterString)
|
|
||||||
{
|
|
||||||
return Enum.Parse(targetType, parameterString);
|
return Enum.Parse(targetType, parameterString);
|
||||||
}
|
}
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Binding.DoNothing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace NetDocsForLLM.Helpers
|
namespace NetDocsForLLM.Helpers
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using NetDocsForLLM.Models;
|
using NetDocsForLLM.Models;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -4,9 +4,15 @@
|
||||||
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:conv="clr-namespace:NetDocsForLLM.Converters"
|
||||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="NetDocs para LLMs" Height="650" Width="800">
|
Title="NetDocs para LLMs" Height="650" Width="800">
|
||||||
|
|
||||||
|
<Window.Resources>
|
||||||
|
<conv:EnumBooleanConverter x:Key="EnumBooleanConverter"/>
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace NetDocsForLLM
|
namespace NetDocsForLLM
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace NetDocsForLLM.Models
|
namespace NetDocsForLLM.Models
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace NetDocsForLLM.Models
|
namespace NetDocsForLLM.Models
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,343 @@
|
||||||
|
using NetDocsForLLM.Models;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace NetDocsForLLM.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Implementación del servicio de análisis de ensamblados basado en Reflection
|
||||||
|
/// </summary>
|
||||||
|
public class ReflectionAnalyzerService : IDocFxService
|
||||||
|
{
|
||||||
|
private readonly string _workingDirectory;
|
||||||
|
|
||||||
|
public ReflectionAnalyzerService()
|
||||||
|
{
|
||||||
|
// Crear un directorio temporal para trabajar
|
||||||
|
_workingDirectory = Path.Combine(Path.GetTempPath(), "NetDocsForLLM_" + Guid.NewGuid().ToString("N"));
|
||||||
|
Directory.CreateDirectory(_workingDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GenerateMetadataAsync(IEnumerable<AssemblyModel> assemblies)
|
||||||
|
{
|
||||||
|
// Crear directorio para metadatos
|
||||||
|
var metadataPath = Path.Combine(_workingDirectory, "metadata");
|
||||||
|
Directory.CreateDirectory(metadataPath);
|
||||||
|
|
||||||
|
// Para cada ensamblado, generar archivo de metadatos
|
||||||
|
foreach (var assembly in assemblies)
|
||||||
|
{
|
||||||
|
await Task.Run(() => ProcessAssembly(assembly, metadataPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadataPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessAssembly(AssemblyModel assemblyModel, string outputPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var assembly = assemblyModel.LoadedAssembly;
|
||||||
|
if (assembly == null)
|
||||||
|
throw new ArgumentException("El ensamblado no está cargado", nameof(assemblyModel));
|
||||||
|
|
||||||
|
// Cargar comentarios XML si existen
|
||||||
|
XDocument xmlDoc = null;
|
||||||
|
if (assemblyModel.HasXmlDocumentation && File.Exists(assemblyModel.XmlDocPath))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
xmlDoc = XDocument.Load(assemblyModel.XmlDocPath);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Si hay error al cargar XML, continuar sin comentarios
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Procesar todos los tipos exportados
|
||||||
|
foreach (var type in assembly.GetExportedTypes())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Generar archivo de metadatos para cada tipo
|
||||||
|
var typeInfo = new
|
||||||
|
{
|
||||||
|
Name = type.Name,
|
||||||
|
FullName = type.FullName,
|
||||||
|
Namespace = type.Namespace,
|
||||||
|
IsClass = type.IsClass,
|
||||||
|
IsInterface = type.IsInterface,
|
||||||
|
IsEnum = type.IsEnum,
|
||||||
|
IsAbstract = type.IsAbstract,
|
||||||
|
IsSealed = type.IsSealed,
|
||||||
|
IsPublic = type.IsPublic,
|
||||||
|
BaseType = type.BaseType?.FullName,
|
||||||
|
Interfaces = type.GetInterfaces().Select(i => i.FullName).ToArray(),
|
||||||
|
XmlDocumentation = GetXmlDocumentation(xmlDoc, GetMemberXmlId(type)),
|
||||||
|
Members = GetMembers(type, xmlDoc)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Guardar en archivo JSON
|
||||||
|
string typePath = Path.Combine(outputPath, $"{type.FullName.Replace('+', '_')}.json");
|
||||||
|
File.WriteAllText(typePath, JsonConvert.SerializeObject(typeInfo, Formatting.Indented));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Registrar error para este tipo pero continuar con otros
|
||||||
|
File.WriteAllText(
|
||||||
|
Path.Combine(outputPath, $"error_{type.FullName.Replace('+', '_')}.txt"),
|
||||||
|
$"Error procesando tipo {type.FullName}: {ex.Message}\n{ex.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Registrar el error pero continuar con otros ensamblados
|
||||||
|
File.WriteAllText(
|
||||||
|
Path.Combine(outputPath, $"error_{Path.GetFileNameWithoutExtension(assemblyModel.FilePath)}.txt"),
|
||||||
|
$"Error procesando ensamblado: {ex.Message}\n{ex.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object[] GetMembers(Type type, XDocument xmlDoc)
|
||||||
|
{
|
||||||
|
var result = new List<object>();
|
||||||
|
|
||||||
|
// Obtener métodos
|
||||||
|
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (method.IsSpecialName) // Excluir getters/setters de propiedades
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var parameters = method.GetParameters().Select(p => new
|
||||||
|
{
|
||||||
|
Name = p.Name,
|
||||||
|
Type = GetFriendlyTypeName(p.ParameterType),
|
||||||
|
IsOptional = p.IsOptional,
|
||||||
|
DefaultValue = p.IsOptional ? ConvertDefaultValueToString(p.DefaultValue) : null
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
var methodInfo = new
|
||||||
|
{
|
||||||
|
Name = method.Name,
|
||||||
|
MemberType = "Method",
|
||||||
|
ReturnType = GetFriendlyTypeName(method.ReturnType),
|
||||||
|
IsStatic = method.IsStatic,
|
||||||
|
IsPublic = method.IsPublic,
|
||||||
|
Parameters = parameters,
|
||||||
|
XmlDocumentation = GetXmlDocumentation(xmlDoc, GetMemberXmlId(method))
|
||||||
|
};
|
||||||
|
|
||||||
|
result.Add(methodInfo);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignorar métodos con problemas
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener propiedades
|
||||||
|
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var propertyInfo = new
|
||||||
|
{
|
||||||
|
Name = property.Name,
|
||||||
|
MemberType = "Property",
|
||||||
|
Type = GetFriendlyTypeName(property.PropertyType),
|
||||||
|
CanRead = property.CanRead,
|
||||||
|
CanWrite = property.CanWrite,
|
||||||
|
IsStatic = property.GetAccessors(true).FirstOrDefault()?.IsStatic ?? false,
|
||||||
|
XmlDocumentation = GetXmlDocumentation(xmlDoc, GetMemberXmlId(property))
|
||||||
|
};
|
||||||
|
|
||||||
|
result.Add(propertyInfo);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignorar propiedades con problemas
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener eventos
|
||||||
|
foreach (var eventInfo in type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var eventData = new
|
||||||
|
{
|
||||||
|
Name = eventInfo.Name,
|
||||||
|
MemberType = "Event",
|
||||||
|
EventHandlerType = GetFriendlyTypeName(eventInfo.EventHandlerType),
|
||||||
|
IsStatic = eventInfo.GetAddMethod()?.IsStatic ?? false,
|
||||||
|
XmlDocumentation = GetXmlDocumentation(xmlDoc, GetMemberXmlId(eventInfo))
|
||||||
|
};
|
||||||
|
|
||||||
|
result.Add(eventData);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignorar eventos con problemas
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener campos
|
||||||
|
foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fieldInfo = new
|
||||||
|
{
|
||||||
|
Name = field.Name,
|
||||||
|
MemberType = "Field",
|
||||||
|
Type = GetFriendlyTypeName(field.FieldType),
|
||||||
|
IsStatic = field.IsStatic,
|
||||||
|
IsConstant = field.IsLiteral && !field.IsInitOnly,
|
||||||
|
Value = field.IsLiteral ? ConvertDefaultValueToString(field.GetValue(null)) : null,
|
||||||
|
XmlDocumentation = GetXmlDocumentation(xmlDoc, GetMemberXmlId(field))
|
||||||
|
};
|
||||||
|
|
||||||
|
result.Add(fieldInfo);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignorar campos con problemas
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFriendlyTypeName(Type type)
|
||||||
|
{
|
||||||
|
if (type == null) return "void";
|
||||||
|
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
var genericArgs = string.Join(", ", type.GetGenericArguments().Select(GetFriendlyTypeName));
|
||||||
|
return $"{type.Name.Split('`')[0]}<{genericArgs}>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usar nombres simplificados para tipos comunes
|
||||||
|
if (type == typeof(void)) return "void";
|
||||||
|
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(long)) return "long";
|
||||||
|
if (type == typeof(short)) return "short";
|
||||||
|
if (type == typeof(byte)) return "byte";
|
||||||
|
if (type == typeof(char)) return "char";
|
||||||
|
if (type == typeof(object)) return "object";
|
||||||
|
|
||||||
|
return type.FullName ?? type.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ConvertDefaultValueToString(object defaultValue)
|
||||||
|
{
|
||||||
|
if (defaultValue == null) return "null";
|
||||||
|
|
||||||
|
// Para strings, agregar comillas
|
||||||
|
if (defaultValue is string stringValue)
|
||||||
|
return $"\"{stringValue}\"";
|
||||||
|
|
||||||
|
return defaultValue.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetMemberXmlId(MemberInfo member)
|
||||||
|
{
|
||||||
|
// Generar ID XML según el formato estándar de documentación XML
|
||||||
|
string prefix = "";
|
||||||
|
if (member is MethodInfo)
|
||||||
|
prefix = "M:";
|
||||||
|
else if (member is PropertyInfo)
|
||||||
|
prefix = "P:";
|
||||||
|
else if (member is EventInfo)
|
||||||
|
prefix = "E:";
|
||||||
|
else if (member is FieldInfo)
|
||||||
|
prefix = "F:";
|
||||||
|
else if (member is Type)
|
||||||
|
prefix = "T:";
|
||||||
|
|
||||||
|
// Manejar tipos anidados
|
||||||
|
string declaringFullName;
|
||||||
|
if (member.DeclaringType != null)
|
||||||
|
{
|
||||||
|
declaringFullName = member.DeclaringType.FullName;
|
||||||
|
}
|
||||||
|
else if (member is Type typeInfo)
|
||||||
|
{
|
||||||
|
declaringFullName = typeInfo.FullName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
declaringFullName = "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix + declaringFullName + "." + member.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object GetXmlDocumentation(XDocument xmlDoc, string memberId)
|
||||||
|
{
|
||||||
|
if (xmlDoc == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Buscar nodo de miembro por ID
|
||||||
|
var memberNode = xmlDoc.Descendants("member")
|
||||||
|
.FirstOrDefault(m => m.Attribute("name")?.Value == memberId);
|
||||||
|
|
||||||
|
if (memberNode == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Extraer elementos de documentación
|
||||||
|
var summary = memberNode.Element("summary")?.Value.Trim();
|
||||||
|
var remarks = memberNode.Element("remarks")?.Value.Trim();
|
||||||
|
var returns = memberNode.Element("returns")?.Value.Trim();
|
||||||
|
|
||||||
|
var parameters = memberNode.Elements("param")
|
||||||
|
.Select(p => new
|
||||||
|
{
|
||||||
|
Name = p.Attribute("name")?.Value,
|
||||||
|
Description = p.Value.Trim()
|
||||||
|
})
|
||||||
|
.Where(p => !string.IsNullOrEmpty(p.Name))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var examples = memberNode.Elements("example")
|
||||||
|
.Select(e => e.Value.Trim())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
Summary = summary,
|
||||||
|
Remarks = remarks,
|
||||||
|
Returns = returns,
|
||||||
|
Parameters = parameters,
|
||||||
|
Examples = examples
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using NetDocsForLLM.Models;
|
using NetDocsForLLM.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
|
@ -1,203 +0,0 @@
|
||||||
using NetDocsForLLM.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NetDocsForLLM.Services
|
|
||||||
{
|
|
||||||
public interface IDocFxService
|
|
||||||
{
|
|
||||||
Task<string> GenerateMetadataAsync(IEnumerable<AssemblyModel> assemblies);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DocFxService : IDocFxService
|
|
||||||
{
|
|
||||||
private readonly string _workingDirectory;
|
|
||||||
private readonly string _docfxPath;
|
|
||||||
|
|
||||||
public DocFxService()
|
|
||||||
{
|
|
||||||
// Create a temporary working directory
|
|
||||||
_workingDirectory = Path.Combine(Path.GetTempPath(), "NetDocsForLLM_" + Guid.NewGuid().ToString("N"));
|
|
||||||
Directory.CreateDirectory(_workingDirectory);
|
|
||||||
|
|
||||||
// Locate DocFX executable in the packages directory
|
|
||||||
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
|
||||||
_docfxPath = Path.Combine(baseDir, "docfx", "docfx.exe");
|
|
||||||
|
|
||||||
// If not found in the default location, try to locate it in the packages directory
|
|
||||||
if (!File.Exists(_docfxPath))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var packagesDir = Path.Combine(baseDir, "..", "..", "..", "packages");
|
|
||||||
|
|
||||||
// Check if packages directory exists before attempting to search it
|
|
||||||
if (Directory.Exists(packagesDir))
|
|
||||||
{
|
|
||||||
var docfxPaths = Directory.GetFiles(packagesDir, "docfx.exe", SearchOption.AllDirectories);
|
|
||||||
if (docfxPaths.Length > 0)
|
|
||||||
{
|
|
||||||
_docfxPath = docfxPaths[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check embedded docfx in dotnet tools
|
|
||||||
if (!File.Exists(_docfxPath))
|
|
||||||
{
|
|
||||||
var toolsDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".dotnet", "tools");
|
|
||||||
if (Directory.Exists(toolsDir))
|
|
||||||
{
|
|
||||||
var docfxToolPath = Path.Combine(toolsDir, "docfx.exe");
|
|
||||||
if (File.Exists(docfxToolPath))
|
|
||||||
{
|
|
||||||
_docfxPath = docfxToolPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (DirectoryNotFoundException)
|
|
||||||
{
|
|
||||||
// Directory not found, continue to the check below
|
|
||||||
}
|
|
||||||
|
|
||||||
// If still not found, throw an exception
|
|
||||||
if (!File.Exists(_docfxPath))
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException("No se pudo encontrar docfx.exe. Asegúrese de que el paquete docfx.console esté instalado.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> GenerateMetadataAsync(IEnumerable<AssemblyModel> assemblies)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Create DocFX configuration
|
|
||||||
var configPath = Path.Combine(_workingDirectory, "docfx.json");
|
|
||||||
var config = CreateDocFxConfig(assemblies);
|
|
||||||
File.WriteAllText(configPath, config);
|
|
||||||
|
|
||||||
// Run DocFX metadata
|
|
||||||
var result = await RunDocFxMetadataAsync(configPath);
|
|
||||||
|
|
||||||
// Return path to the generated metadata
|
|
||||||
var apiPath = Path.Combine(_workingDirectory, "obj", "api");
|
|
||||||
return apiPath;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Error al generar metadatos con DocFX: {ex.Message}", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string CreateDocFxConfig(IEnumerable<AssemblyModel> assemblies)
|
|
||||||
{
|
|
||||||
var assemblyPaths = new List<string>();
|
|
||||||
var xmlPaths = new List<string>();
|
|
||||||
|
|
||||||
foreach (var assembly in assemblies)
|
|
||||||
{
|
|
||||||
assemblyPaths.Add(assembly.FilePath);
|
|
||||||
if (assembly.HasXmlDocumentation)
|
|
||||||
{
|
|
||||||
xmlPaths.Add(assembly.XmlDocPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $@"
|
|
||||||
{{
|
|
||||||
""metadata"": [
|
|
||||||
{{
|
|
||||||
""src"": [
|
|
||||||
{{
|
|
||||||
""files"": [
|
|
||||||
""{string.Join("\",\n \"", assemblyPaths.Select(p => p.Replace("\\", "\\\\")))}""
|
|
||||||
],
|
|
||||||
""src"": "".""
|
|
||||||
}}
|
|
||||||
],
|
|
||||||
""dest"": ""obj/api"",
|
|
||||||
""properties"": {{
|
|
||||||
""TargetFramework"": ""net6.0""
|
|
||||||
}},
|
|
||||||
""disableGitFeatures"": true,
|
|
||||||
""disableDefaultFilter"": false
|
|
||||||
}}
|
|
||||||
],
|
|
||||||
""build"": {{
|
|
||||||
""content"": [
|
|
||||||
{{
|
|
||||||
""files"": [""*.yml""],
|
|
||||||
""src"": ""obj/api"",
|
|
||||||
""dest"": ""api""
|
|
||||||
}}
|
|
||||||
],
|
|
||||||
""resource"": [
|
|
||||||
{{
|
|
||||||
""files"": [""images/**""],
|
|
||||||
""exclude"": [""obj/**"", ""_site/**""]
|
|
||||||
}}
|
|
||||||
],
|
|
||||||
""dest"": ""_site"",
|
|
||||||
""globalMetadataFiles"": [],
|
|
||||||
""fileMetadataFiles"": [],
|
|
||||||
""template"": [""default""],
|
|
||||||
""postProcessors"": [],
|
|
||||||
""markdownEngineName"": ""markdig"",
|
|
||||||
""noLangKeyword"": false,
|
|
||||||
""keepFileLink"": false,
|
|
||||||
""cleanupCacheHistory"": false,
|
|
||||||
""disableGitFeatures"": false
|
|
||||||
}}
|
|
||||||
}}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> RunDocFxMetadataAsync(string configPath)
|
|
||||||
{
|
|
||||||
var startInfo = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = _docfxPath,
|
|
||||||
Arguments = $"metadata \"{configPath}\"",
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
UseShellExecute = false,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
WorkingDirectory = _workingDirectory
|
|
||||||
};
|
|
||||||
|
|
||||||
using var process = new Process { StartInfo = startInfo };
|
|
||||||
var outputBuilder = new System.Text.StringBuilder();
|
|
||||||
var errorBuilder = new System.Text.StringBuilder();
|
|
||||||
|
|
||||||
process.OutputDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
|
||||||
outputBuilder.AppendLine(e.Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
process.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(e.Data))
|
|
||||||
errorBuilder.AppendLine(e.Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
process.BeginOutputReadLine();
|
|
||||||
process.BeginErrorReadLine();
|
|
||||||
|
|
||||||
await process.WaitForExitAsync();
|
|
||||||
|
|
||||||
if (process.ExitCode != 0)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
$"DocFX metadata falló con código de salida {process.ExitCode}. Error: {errorBuilder}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputBuilder.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,9 @@
|
||||||
using NetDocsForLLM.Models;
|
using NetDocsForLLM.Models;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
@ -16,29 +17,32 @@ namespace NetDocsForLLM.Services
|
||||||
|
|
||||||
public class DocumentationGenerator : IDocumentationGenerator
|
public class DocumentationGenerator : IDocumentationGenerator
|
||||||
{
|
{
|
||||||
private readonly IDocFxService _docFxService;
|
private readonly IDocFxService _metadataService;
|
||||||
|
|
||||||
public DocumentationGenerator(IDocFxService docFxService)
|
public DocumentationGenerator(IDocFxService metadataService)
|
||||||
{
|
{
|
||||||
_docFxService = docFxService ?? throw new ArgumentNullException(nameof(docFxService));
|
_metadataService = metadataService ?? throw new ArgumentNullException(nameof(metadataService));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<DocumentationModel> GenerateDocumentation(IEnumerable<AssemblyModel> assemblies, ExportSettings settings)
|
public async Task<DocumentationModel> GenerateDocumentation(IEnumerable<AssemblyModel> assemblies, ExportSettings settings)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Generate metadata with DocFX
|
// Generate metadata using reflection service
|
||||||
var metadataPath = await _docFxService.GenerateMetadataAsync(assemblies);
|
var metadataPath = await _metadataService.GenerateMetadataAsync(assemblies);
|
||||||
|
|
||||||
// Process metadata files
|
// Process metadata files
|
||||||
var documentation = new DocumentationModel();
|
var documentation = new DocumentationModel();
|
||||||
var namespaces = new Dictionary<string, NamespaceDocumentation>();
|
var namespaces = new Dictionary<string, NamespaceDocumentation>();
|
||||||
|
|
||||||
// Read YAML files produced by DocFX
|
// Read JSON files produced by our reflection service
|
||||||
var ymlFiles = Directory.GetFiles(metadataPath, "*.yml", SearchOption.AllDirectories);
|
var jsonFiles = Directory.GetFiles(metadataPath, "*.json", SearchOption.AllDirectories);
|
||||||
foreach (var ymlFile in ymlFiles)
|
foreach (var jsonFile in jsonFiles)
|
||||||
{
|
{
|
||||||
ProcessYamlMetadata(ymlFile, documentation, namespaces, settings);
|
if (Path.GetFileName(jsonFile).StartsWith("error_"))
|
||||||
|
continue; // Skip error files
|
||||||
|
|
||||||
|
ProcessJsonMetadata(jsonFile, documentation, namespaces, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
return documentation;
|
return documentation;
|
||||||
|
@ -49,63 +53,212 @@ namespace NetDocsForLLM.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessYamlMetadata(string ymlFile, DocumentationModel documentation,
|
private void ProcessJsonMetadata(string jsonFile, DocumentationModel documentation,
|
||||||
Dictionary<string, NamespaceDocumentation> namespaces,
|
Dictionary<string, NamespaceDocumentation> namespaces,
|
||||||
ExportSettings settings)
|
ExportSettings settings)
|
||||||
{
|
{
|
||||||
// This is a simplified implementation. In a real application,
|
try
|
||||||
// you would need to use a YAML parser to read DocFX output
|
|
||||||
|
|
||||||
// For this example, we'll create sample documentation data
|
|
||||||
var typeDoc = new TypeDocumentation
|
|
||||||
{
|
{
|
||||||
Name = Path.GetFileNameWithoutExtension(ymlFile),
|
// Leer el archivo JSON
|
||||||
FullName = $"ExampleNamespace.{Path.GetFileNameWithoutExtension(ymlFile)}",
|
var jsonContent = File.ReadAllText(jsonFile);
|
||||||
Description = "Descripción del tipo extraída de comentarios XML",
|
var typeData = JsonConvert.DeserializeObject<dynamic>(jsonContent);
|
||||||
TypeKind = "Class"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add some members
|
if (typeData == null)
|
||||||
typeDoc.Members.Add(new MemberDocumentation
|
return;
|
||||||
{
|
|
||||||
Name = "ExampleMethod",
|
|
||||||
Description = "Un método de ejemplo con documentación",
|
|
||||||
MemberType = "Method",
|
|
||||||
Signature = "public void ExampleMethod(string parameter1, int parameter2)",
|
|
||||||
ReturnType = "void",
|
|
||||||
ReturnDescription = "Este método no devuelve ningún valor"
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add parameters to the method
|
// Obtener namespace
|
||||||
typeDoc.Members[0].Parameters.Add(new ParameterDocumentation
|
string namespaceName = typeData.Namespace?.ToString() ?? "Global";
|
||||||
{
|
|
||||||
Name = "parameter1",
|
|
||||||
Type = "string",
|
|
||||||
Description = "Descripción del primer parámetro"
|
|
||||||
});
|
|
||||||
|
|
||||||
typeDoc.Members[0].Parameters.Add(new ParameterDocumentation
|
// Buscar o crear el namespace en nuestra documentación
|
||||||
{
|
|
||||||
Name = "parameter2",
|
|
||||||
Type = "int",
|
|
||||||
Description = "Descripción del segundo parámetro"
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add to namespace
|
|
||||||
var namespaceName = "ExampleNamespace";
|
|
||||||
if (!namespaces.TryGetValue(namespaceName, out var namespaceDoc))
|
if (!namespaces.TryGetValue(namespaceName, out var namespaceDoc))
|
||||||
{
|
{
|
||||||
namespaceDoc = new NamespaceDocumentation
|
namespaceDoc = new NamespaceDocumentation
|
||||||
{
|
{
|
||||||
Name = namespaceName,
|
Name = namespaceName,
|
||||||
Description = "Descripción del namespace"
|
Description = $"Contiene tipos del ensamblado"
|
||||||
};
|
};
|
||||||
namespaces[namespaceName] = namespaceDoc;
|
namespaces[namespaceName] = namespaceDoc;
|
||||||
documentation.Namespaces.Add(namespaceDoc);
|
documentation.Namespaces.Add(namespaceDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Crear documentación de tipo
|
||||||
|
var typeDoc = new TypeDocumentation
|
||||||
|
{
|
||||||
|
Name = typeData.Name,
|
||||||
|
FullName = typeData.FullName,
|
||||||
|
Description = typeData.XmlDocumentation?.Summary ?? "Sin documentación disponible",
|
||||||
|
TypeKind = GetTypeKind(typeData)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Agregar base types e interfaces si están disponibles
|
||||||
|
if (typeData.BaseType != null && typeData.BaseType.ToString() != "System.Object")
|
||||||
|
{
|
||||||
|
typeDoc.BaseTypes.Add(typeData.BaseType.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar interfaces
|
||||||
|
if (typeData.Interfaces != null)
|
||||||
|
{
|
||||||
|
foreach (var interfaceType in typeData.Interfaces)
|
||||||
|
{
|
||||||
|
typeDoc.Interfaces.Add(interfaceType.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Procesar miembros
|
||||||
|
if (typeData.Members != null)
|
||||||
|
{
|
||||||
|
foreach (var member in typeData.Members)
|
||||||
|
{
|
||||||
|
// Filtrar miembros privados si la configuración lo indica
|
||||||
|
if (!settings.IncludePrivateMembers &&
|
||||||
|
member.IsPublic != null && !(bool)member.IsPublic)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var memberDoc = new MemberDocumentation
|
||||||
|
{
|
||||||
|
Name = member.Name,
|
||||||
|
Description = member.XmlDocumentation?.Summary ?? "Sin documentación disponible",
|
||||||
|
MemberType = member.MemberType,
|
||||||
|
Signature = member.Signature ?? GenerateSignature(member),
|
||||||
|
ReturnType = GetReturnType(member),
|
||||||
|
ReturnDescription = member.XmlDocumentation?.Returns ?? ""
|
||||||
|
};
|
||||||
|
|
||||||
|
// Agregar parámetros si es un método
|
||||||
|
if (member.MemberType?.ToString() == "Method" && member.Parameters != null)
|
||||||
|
{
|
||||||
|
foreach (var param in member.Parameters)
|
||||||
|
{
|
||||||
|
var paramDoc = new ParameterDocumentation
|
||||||
|
{
|
||||||
|
Name = param.Name,
|
||||||
|
Type = param.Type,
|
||||||
|
IsOptional = param.IsOptional != null && (bool)param.IsOptional,
|
||||||
|
DefaultValue = param.DefaultValue?.ToString() ?? "",
|
||||||
|
Description = GetParameterDescription(member.XmlDocumentation, param.Name?.ToString())
|
||||||
|
};
|
||||||
|
|
||||||
|
memberDoc.Parameters.Add(paramDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregar ejemplos si están disponibles y configurados
|
||||||
|
if (settings.IncludeExamples &&
|
||||||
|
member.XmlDocumentation?.Examples != null)
|
||||||
|
{
|
||||||
|
foreach (var example in member.XmlDocumentation.Examples)
|
||||||
|
{
|
||||||
|
if (example != null && !string.IsNullOrWhiteSpace(example.ToString()))
|
||||||
|
memberDoc.Examples.Add(example.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typeDoc.Members.Add(memberDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespaceDoc.Types.Add(typeDoc);
|
namespaceDoc.Types.Add(typeDoc);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Si hay error al procesar, lo registramos pero continuamos
|
||||||
|
Console.WriteLine($"Error al procesar {jsonFile}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetTypeKind(dynamic typeData)
|
||||||
|
{
|
||||||
|
if (typeData.IsClass != null && (bool)typeData.IsClass)
|
||||||
|
return "Class";
|
||||||
|
if (typeData.IsInterface != null && (bool)typeData.IsInterface)
|
||||||
|
return "Interface";
|
||||||
|
if (typeData.IsEnum != null && (bool)typeData.IsEnum)
|
||||||
|
return "Enum";
|
||||||
|
return "Type";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateSignature(dynamic member)
|
||||||
|
{
|
||||||
|
// Generar una firma simple basada en el tipo de miembro
|
||||||
|
string memberType = member.MemberType?.ToString();
|
||||||
|
string name = member.Name?.ToString() ?? "Unknown";
|
||||||
|
|
||||||
|
if (memberType == "Method")
|
||||||
|
{
|
||||||
|
string returnType = member.ReturnType?.ToString() ?? "void";
|
||||||
|
string parameters = "";
|
||||||
|
|
||||||
|
if (member.Parameters != null)
|
||||||
|
{
|
||||||
|
var paramList = new List<string>();
|
||||||
|
foreach (var param in member.Parameters)
|
||||||
|
{
|
||||||
|
string paramType = param.Type?.ToString() ?? "object";
|
||||||
|
string paramName = param.Name?.ToString() ?? "param";
|
||||||
|
paramList.Add($"{paramType} {paramName}");
|
||||||
|
}
|
||||||
|
parameters = string.Join(", ", paramList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{returnType} {name}({parameters})";
|
||||||
|
}
|
||||||
|
else if (memberType == "Property")
|
||||||
|
{
|
||||||
|
string propType = member.Type?.ToString() ?? "object";
|
||||||
|
string accessors = "";
|
||||||
|
|
||||||
|
bool canRead = member.CanRead != null && (bool)member.CanRead;
|
||||||
|
bool canWrite = member.CanWrite != null && (bool)member.CanWrite;
|
||||||
|
|
||||||
|
if (canRead && canWrite)
|
||||||
|
accessors = " { get; set; }";
|
||||||
|
else if (canRead)
|
||||||
|
accessors = " { get; }";
|
||||||
|
else if (canWrite)
|
||||||
|
accessors = " { set; }";
|
||||||
|
|
||||||
|
return $"{propType} {name}{accessors}";
|
||||||
|
}
|
||||||
|
else if (memberType == "Field")
|
||||||
|
{
|
||||||
|
string fieldType = member.Type?.ToString() ?? "object";
|
||||||
|
return $"{fieldType} {name}";
|
||||||
|
}
|
||||||
|
else if (memberType == "Event")
|
||||||
|
{
|
||||||
|
string eventType = member.EventHandlerType?.ToString() ?? "EventHandler";
|
||||||
|
return $"event {eventType} {name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetReturnType(dynamic member)
|
||||||
|
{
|
||||||
|
string memberType = member.MemberType?.ToString();
|
||||||
|
|
||||||
|
if (memberType == "Method")
|
||||||
|
return member.ReturnType?.ToString() ?? "void";
|
||||||
|
else if (memberType == "Property")
|
||||||
|
return member.Type?.ToString() ?? "object";
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetParameterDescription(dynamic xmlDocumentation, string paramName)
|
||||||
|
{
|
||||||
|
if (xmlDocumentation?.Parameters == null || paramName == null)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
foreach (var param in xmlDocumentation.Parameters)
|
||||||
|
{
|
||||||
|
if (param.Name?.ToString() == paramName)
|
||||||
|
return param.Description?.ToString() ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
public string GenerateDocumentationPreview(DocumentationModel documentation, ExportSettings settings)
|
public string GenerateDocumentationPreview(DocumentationModel documentation, ExportSettings settings)
|
||||||
{
|
{
|
||||||
|
@ -116,21 +269,21 @@ namespace NetDocsForLLM.Services
|
||||||
return JsonConvert.SerializeObject(documentation, Formatting.Indented,
|
return JsonConvert.SerializeObject(documentation, Formatting.Indented,
|
||||||
new JsonSerializerSettings
|
new JsonSerializerSettings
|
||||||
{
|
{
|
||||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||||
|
NullValueHandling = NullValueHandling.Ignore
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else // YAML
|
else // YAML
|
||||||
{
|
{
|
||||||
// Convert to JSON first, then to YAML (simplified)
|
// En un escenario real, usaríamos YamlDotNet
|
||||||
var json = JsonConvert.SerializeObject(documentation, Formatting.None,
|
// Para esta implementación, usaremos una conversión manual simplificada
|
||||||
|
return ConvertJsonToSimpleYaml(
|
||||||
|
JsonConvert.SerializeObject(documentation, Formatting.None,
|
||||||
new JsonSerializerSettings
|
new JsonSerializerSettings
|
||||||
{
|
{
|
||||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||||
});
|
NullValueHandling = NullValueHandling.Ignore
|
||||||
|
}));
|
||||||
// In a real application, you would use a YAML serializer
|
|
||||||
// For this example, we'll return a simple YAML representation
|
|
||||||
return ConvertJsonToSimpleYaml(json);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -141,9 +294,6 @@ namespace NetDocsForLLM.Services
|
||||||
|
|
||||||
private string ConvertJsonToSimpleYaml(string json)
|
private string ConvertJsonToSimpleYaml(string json)
|
||||||
{
|
{
|
||||||
// This is a simplified conversion for demonstration purposes
|
|
||||||
// In a real application, you would use a YAML serializer library
|
|
||||||
|
|
||||||
// Deserialize JSON
|
// Deserialize JSON
|
||||||
var obj = JsonConvert.DeserializeObject<dynamic>(json);
|
var obj = JsonConvert.DeserializeObject<dynamic>(json);
|
||||||
|
|
||||||
|
@ -169,24 +319,37 @@ namespace NetDocsForLLM.Services
|
||||||
{
|
{
|
||||||
yaml.AppendLine($" - name: {member.Name}");
|
yaml.AppendLine($" - name: {member.Name}");
|
||||||
yaml.AppendLine($" memberType: {member.MemberType}");
|
yaml.AppendLine($" memberType: {member.MemberType}");
|
||||||
yaml.AppendLine($" signature: {member.Signature}");
|
yaml.AppendLine($" signature: \"{EscapeYamlString(member.Signature)}\"");
|
||||||
yaml.AppendLine($" description: {member.Description}");
|
yaml.AppendLine($" description: \"{EscapeYamlString(member.Description)}\"");
|
||||||
|
|
||||||
if (member.Parameters.Count > 0)
|
if (member.Parameters != null && member.Parameters.Count > 0)
|
||||||
{
|
{
|
||||||
yaml.AppendLine(" parameters:");
|
yaml.AppendLine(" parameters:");
|
||||||
foreach (var param in member.Parameters)
|
foreach (var param in member.Parameters)
|
||||||
{
|
{
|
||||||
yaml.AppendLine($" - name: {param.Name}");
|
yaml.AppendLine($" - name: {param.Name}");
|
||||||
yaml.AppendLine($" type: {param.Type}");
|
yaml.AppendLine($" type: {param.Type}");
|
||||||
yaml.AppendLine($" description: {param.Description}");
|
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))
|
if (!string.IsNullOrEmpty(member.ReturnType))
|
||||||
{
|
{
|
||||||
yaml.AppendLine($" returnType: {member.ReturnType}");
|
yaml.AppendLine($" returnType: {member.ReturnType}");
|
||||||
yaml.AppendLine($" returnDescription: {member.ReturnDescription}");
|
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 ")}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,5 +357,18 @@ namespace NetDocsForLLM.Services
|
||||||
|
|
||||||
return yaml.ToString();
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using NetDocsForLLM.Models;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NetDocsForLLM.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interfaz para servicios de extracción de metadatos de ensamblados.
|
||||||
|
/// El nombre se mantiene por compatibilidad, aunque ya no usemos DocFx.
|
||||||
|
/// </summary>
|
||||||
|
public interface IDocFxService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Genera metadatos de los ensamblados proporcionados
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="assemblies">Ensamblados para analizar</param>
|
||||||
|
/// <returns>Ruta al directorio con los metadatos generados</returns>
|
||||||
|
Task<string> GenerateMetadataAsync(IEnumerable<AssemblyModel> assemblies);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using NetDocsForLLM.Models;
|
using NetDocsForLLM.Models;
|
||||||
using NetDocsForLLM.Services;
|
using NetDocsForLLM.Services;
|
||||||
|
|
Loading…
Reference in New Issue