Dev changes #5
+10
-1
@@ -2,4 +2,13 @@ bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
/_ReSharper.Caches/
|
||||
/.vs
|
||||
<<<<<<< Updated upstream
|
||||
/OmegaLeo.HelperLib.Web
|
||||
=======
|
||||
/OmegaLeo.HelperLib.Web/.config
|
||||
/OmegaLeo.HelperLib.Web/Properties/PublishProfiles
|
||||
/OmegaLeo.HelperLib.Web/publish
|
||||
>>>>>>> Stashed changes
|
||||
/OmegaLeo.HelperLib.Web/OmegaLeo.HelperLib.Web.csproj.user
|
||||
|
||||
@@ -13,9 +13,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath="\"/>
|
||||
<None Include="CHANGELOG.md" Pack="true" PackagePath="\"/>
|
||||
<None Include="LICENSE.md" Pack="true" PackagePath="\"/>
|
||||
<None Include="README.md" Pack="true" PackagePath="\" />
|
||||
<None Include="CHANGELOG.md" Pack="true" PackagePath="\" />
|
||||
<None Include="LICENSE.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,7 +9,12 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OmegaLeo.HelperLib.Changelog\OmegaLeo.HelperLib.Changelog.csproj" />
|
||||
<ProjectReference Include="..\OmegaLeo.HelperLib.Game\OmegaLeo.HelperLib.Game.csproj" />
|
||||
<ProjectReference Include="..\OmegaLeo.HelperLib\OmegaLeo.HelperLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -14,6 +14,7 @@ var changelogs = new Dictionary<string, Assembly>()
|
||||
{
|
||||
{Path.Join(root, "OmegaLeo.HelperLib.Changelog", "CHANGELOG.md"), typeof(Changelog).Assembly},
|
||||
{Path.Join(root, "OmegaLeo.HelperLib", "CHANGELOG.md"), typeof(BenchmarkUtility).Assembly},
|
||||
{Path.Join(root, "OmegaLeo.HelperLib.Game", "CHANGELOG.md"), typeof(OmegaLeo.HelperLib.Game.Models.ConsoleCommand).Assembly},
|
||||
};
|
||||
|
||||
foreach (var changelog in changelogs)
|
||||
|
||||
@@ -13,4 +13,8 @@
|
||||
<ProjectReference Include="..\OmegaLeo.HelperLib\OmegaLeo.HelperLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using NetFlow.DocumentationHelper.Library.Attributes;
|
||||
using OmegaLeo.HelperLib.Game.Models;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Game.Extensions
|
||||
{
|
||||
public static class ListExtensions
|
||||
{
|
||||
[Documentation(nameof(Shuffle),
|
||||
"Shuffles the elements of the list in place using the provided RandomNumberGenerator.",
|
||||
null,
|
||||
@"```csharp
|
||||
var list = new List<int> { 1, 2, 3, 4};
|
||||
var rng = new RandomNumberGenerator();
|
||||
// List before: [1, 2, 3, 4]
|
||||
list.Shuffle(rng);
|
||||
// List after: [3, 1, 4, 2] (example output)
|
||||
```")]
|
||||
public static void Shuffle<T>(this IList<T> list, RandomNumberGenerator rng)
|
||||
{
|
||||
for (int i = list.Count - 1; i > 0; i--)
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
using NetFlow.DocumentationHelper.Library.Attributes;
|
||||
using OmegaLeo.HelperLib.Game.Models;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Game.Handlers
|
||||
{
|
||||
[Documentation(nameof(DelayedActionHandler), "Handler for managing delayed actions, allowing cancellation and status checking.", null, @"```csharp
|
||||
var action = new DelayedAction(...);
|
||||
var handler = new DelayedActionHandler(action);
|
||||
```")]
|
||||
public class DelayedActionHandler
|
||||
{
|
||||
private readonly DelayedAction _action;
|
||||
@@ -11,6 +16,9 @@ namespace OmegaLeo.HelperLib.Game.Handlers
|
||||
_action = action;
|
||||
}
|
||||
|
||||
[Documentation(nameof(Cancel), "Cancels the delayed action if it has not yet executed.", null, @"```csharp
|
||||
handler.Cancel();
|
||||
```")]
|
||||
public void Cancel()
|
||||
{
|
||||
if (_action != null)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LibGit2Sharp" Version="0.30.0"/>
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.2"/>
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// File: `OmegaLeo.HelperLib.Web/Controllers/HomeController.cs`
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using GameDevLibrary.Helpers;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NetFlow.DocumentationHelper.Library.Helpers;
|
||||
using NetFlow.DocumentationHelper.Library.Models;
|
||||
using OmegaLeo.HelperLib.Changelog.Tools;
|
||||
using OmegaLeo.HelperLib.Web.Models;
|
||||
|
||||
@@ -25,31 +28,34 @@ public class HomeController : Controller
|
||||
if (_libraryCache != null) return;
|
||||
|
||||
var root = GetSolutionRoot();
|
||||
_logger.LogInformation("Initializing libraries from base directory: {Root}", root);
|
||||
|
||||
_libraryCache = new Dictionary<string, LibraryDocumentationViewModel>
|
||||
{
|
||||
["core"] = GenerateLibraryDocs(
|
||||
typeof(BenchmarkUtility).Assembly,
|
||||
Path.Join(root, "OmegaLeo.HelperLib", "CHANGELOG.md"),
|
||||
Path.Combine(root, "changelogs", "OmegaLeo.HelperLib.CHANGELOG.md"),
|
||||
"Core Library",
|
||||
"Core utilities and helper functions for general C# development",
|
||||
"OmegaLeo.HelperLib"
|
||||
),
|
||||
["changelog"] = GenerateLibraryDocs(
|
||||
typeof(Changelog.Models.Changelog).Assembly,
|
||||
Path.Join(root, "OmegaLeo.HelperLib.Changelog", "CHANGELOG.md"),
|
||||
Path.Combine(root, "changelogs", "OmegaLeo.HelperLib.Changelog.CHANGELOG.md"),
|
||||
"Changelog Library",
|
||||
"Tools for managing and generating changelogs",
|
||||
|
|
||||
"OmegaLeo.HelperLib.Changelog"
|
||||
),
|
||||
["game"] = GenerateLibraryDocs(
|
||||
typeof(OmegaLeo.HelperLib.Game.Models.ConsoleCommand).Assembly,
|
||||
Path.Join(root, "OmegaLeo.HelperLib.Game", "CHANGELOG.md"),
|
||||
Path.Combine(root, "changelogs", "OmegaLeo.HelperLib.Game.CHANGELOG.md"),
|
||||
"Game Development Library",
|
||||
"Game development utilities for Unity and Godot",
|
||||
"OmegaLeo.HelperLib.Game"
|
||||
)
|
||||
};
|
||||
|
||||
_logger.LogInformation("Initialized {Count} libraries", _libraryCache.Count);
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
@@ -62,7 +68,18 @@ public class HomeController : Controller
|
||||
if (string.IsNullOrEmpty(id) || !_libraryCache.ContainsKey(id))
|
||||
return NotFound();
|
||||
|
||||
return View(_libraryCache[id]);
|
||||
var cache = _libraryCache[id];
|
||||
|
||||
if (cache.Documentation.Any())
|
||||
{
|
||||
_logger.LogInformation($"Found cache for {id}: {cache.Documentation.Count} entries");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"Cache for {id} is empty!");
|
||||
}
|
||||
|
||||
return View(cache);
|
||||
}
|
||||
|
||||
public IActionResult Privacy()
|
||||
@@ -76,55 +93,258 @@ public class HomeController : Controller
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
|
This assignment to allDocumentation is useless, since its value is never read. This assignment to [allDocumentation](1) is useless, since its value is never read.
```suggestion
IEnumerable<DocumentationStructure> allDocumentation;
```
This assignment to changelog is useless, since its value is never read. This assignment to [changelog](1) is useless, since its value is never read.
```suggestion
var changelogMarkdown = string.Empty;
if (System.IO.File.Exists(changelogPath))
{
try
{
ChangelogTool.ExtractChangelog(assembly);
changelogMarkdown = ChangelogTool.GetMarkdown(assembly);
_logger.LogInformation("Parsed changelog for {Assembly}", assembly.GetName().Name);
```
|
||||
}
|
||||
|
||||
private LibraryDocumentationViewModel GenerateLibraryDocs(Assembly assembly, string changelogPath, string displayName, string description, string nugetPackageId)
|
||||
private void LogDocumentationHelperInfo()
|
||||
{
|
||||
var allDocumentation = DocumentationHelperTool.GenerateDocumentation();
|
||||
var assemblyName = assembly.GetName().Name;
|
||||
try
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var target = assemblies.FirstOrDefault(a =>
|
||||
a.GetName().Name.Equals("NetFlow.DocumentationHelper.Library", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var filteredDocumentation = allDocumentation
|
||||
.Where(d => d.AssemblyName.Equals(assemblyName, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(d => d.ClassName)
|
||||
.ToList();
|
||||
if (target == null)
|
||||
{
|
||||
_logger.LogWarning("NetFlow.DocumentationHelper.Library not loaded. Loaded assemblies ({Count}):",
|
||||
assemblies.Length);
|
||||
foreach (var a in assemblies.OrderBy(a => a.GetName().Name))
|
||||
{
|
||||
_logger.LogInformation(" {Name} {Version} => {Location}", a.GetName().Name, a.GetName().Version,
|
||||
SafeLocation(a));
|
||||
}
|
||||
|
||||
string changelogMarkdown = "";
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Found {Name} {Version} at {Location}", target.GetName().Name,
|
||||
target.GetName().Version, SafeLocation(target));
|
||||
|
||||
|
Inefficient use of 'ContainsKey' and indexer. Inefficient use of 'ContainsKey' and [indexer](1).
|
||||
Type attrType = null;
|
||||
try
|
||||
{
|
||||
attrType = target.GetType("NetFlow.DocumentationHelper.Library.Attributes.DocumentationAttribute",
|
||||
false, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to GetType for DocumentationAttribute in {Assembly}",
|
||||
target.GetName().Name);
|
||||
}
|
||||
|
||||
if (attrType == null)
|
||||
{
|
||||
_logger.LogWarning("Type 'DocumentationAttribute' not found in {Assembly}.", target.GetName().Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ctors = attrType.GetConstructors(BindingFlags.Public | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic);
|
||||
if (!ctors.Any())
|
||||
_logger.LogWarning("No constructors found on DocumentationAttribute in {Assembly}.",
|
||||
target.GetName().Name);
|
||||
foreach (var ctor in ctors)
|
||||
{
|
||||
var sig = string.Join(", ", ctor.GetParameters().Select(p => p.ParameterType.Name + " " + p.Name));
|
||||
_logger.LogInformation("DocumentationAttribute ctor: ({Signature})", sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to log DocumentationHelper assembly info.");
|
||||
}
|
||||
|
||||
static string SafeLocation(Assembly a)
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.IsNullOrEmpty(a.Location) ? "<in-memory>" : a.Location;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InspectDocumentationHelperMethod()
|
||||
{
|
||||
try
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
Type helperType = null;
|
||||
foreach (var asm in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
var t = asm.GetTypes().FirstOrDefault(tt =>
|
||||
tt.Name.Equals("DocumentationHelperTool", StringComparison.OrdinalIgnoreCase)
|
||||
|| tt.FullName?.EndsWith(".DocumentationHelperTool") == true);
|
||||
if (t != null)
|
||||
{
|
||||
helperType = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (ReflectionTypeLoadException rtlex)
|
||||
{
|
||||
_logger.LogDebug(rtlex, "Could not enumerate types in {Assembly}", asm.GetName().Name);
|
||||
foreach (var loaderEx in rtlex.LoaderExceptions ?? Array.Empty<Exception>())
|
||||
_logger.LogDebug(loaderEx, "Loader exception for {Assembly}", asm.GetName().Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug(ex, "Failed enumerating types in {Assembly}", asm.GetName().Name);
|
||||
}
|
||||
}
|
||||
|
||||
if (helperType == null)
|
||||
{
|
||||
_logger.LogWarning("DocumentationHelperTool type not found in loaded assemblies.");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("DocumentationHelperTool found: {Type} in {Assembly} ({Location})",
|
||||
helperType.FullName, helperType.Assembly.GetName().Name, SafeLocation(helperType.Assembly));
|
||||
|
||||
var method = helperType.GetMethod("GenerateDocumentation",
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
|
||||
if (method == null)
|
||||
{
|
||||
_logger.LogWarning("GenerateDocumentation method not found on {Type}.", helperType.FullName);
|
||||
}
|
||||
else
|
||||
{
|
||||
var parameters = string.Join(", ",
|
||||
method.GetParameters().Select(p => p.ParameterType.Name + " " + p.Name));
|
||||
_logger.LogInformation("Method: {Name} ({Parameters}) -> {ReturnType}", method.Name, parameters,
|
||||
method.ReturnType.FullName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to inspect DocumentationHelperTool type/method.");
|
||||
}
|
||||
|
||||
static string SafeLocation(Assembly a)
|
||||
{
|
||||
try
|
||||
{
|
||||
return string.IsNullOrEmpty(a.Location) ? "<in-memory>" : a.Location;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LibraryDocumentationViewModel GenerateLibraryDocs(Assembly assembly, string changelogPath,
|
||||
string displayName, string description, string nugetPackageId)
|
||||
{
|
||||
_logger.LogInformation("=== Starting GenerateLibraryDocs for {Assembly} ===", assembly.GetName().Name);
|
||||
_logger.LogInformation("Assembly location: {Location}", assembly.Location ?? "<in-memory>");
|
||||
_logger.LogInformation("Changelog path: {Path}", changelogPath);
|
||||
_logger.LogInformation("Changelog exists: {Exists}", System.IO.File.Exists(changelogPath));
|
||||
|
||||
// Log types in assembly and their attributes
|
||||
try
|
||||
{
|
||||
var types = assembly.GetTypes();
|
||||
_logger.LogInformation("Assembly {Name} contains {Count} types", assembly.GetName().Name, types.Length);
|
||||
|
||||
var typesWithDocAttr = types.Where(t =>
|
||||
t.GetCustomAttributes().Any(a =>
|
||||
a.GetType().Name.Contains("Documentation", StringComparison.OrdinalIgnoreCase)))
|
||||
.ToList();
|
||||
|
||||
_logger.LogInformation("Found {Count} types with DocumentationAttribute-like attributes",
|
||||
typesWithDocAttr.Count);
|
||||
|
||||
if (typesWithDocAttr.Any())
|
||||
{
|
||||
foreach (var type in typesWithDocAttr.Take(5))
|
||||
{
|
||||
_logger.LogInformation(" Type with doc attr: {TypeName}", type.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to inspect assembly types");
|
||||
}
|
||||
|
||||
LogDocumentationHelperInfo();
|
||||
|
||||
IEnumerable<DocumentationStructure> allDocumentation = Enumerable.Empty<DocumentationStructure>();
|
||||
try
|
||||
{
|
||||
// Pass the specific assembly to only scan that assembly
|
||||
var result = DocumentationHelperTool.GenerateDocumentation();
|
||||
allDocumentation = result?
|
||||
.Where(d => d.AssemblyName?.Equals(assembly.GetName().Name ,StringComparison.OrdinalIgnoreCase) == true)
|
||||
.ToList() ?? Enumerable.Empty<DocumentationStructure>();
|
||||
|
||||
_logger.LogInformation("GenerateDocumentation returned {Count} items for {Assembly}",
|
||||
allDocumentation.Count(), assembly.GetName().Name);
|
||||
|
||||
if (!allDocumentation.Any())
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"No documentation items generated for {Assembly}. Check if types have [Documentation] attribute applied.",
|
||||
assembly.GetName().Name);
|
||||
}
|
||||
}
|
||||
catch (MissingMethodException mmex)
|
||||
{
|
||||
_logger.LogError(mmex,
|
||||
"Missing method when calling DocumentationHelperTool.GenerateDocumentation(). Possible assembly mismatch.");
|
||||
InspectDocumentationHelperMethod();
|
||||
ExceptionDispatchInfo.Capture(mmex).Throw();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "DocumentationHelperTool.GenerateDocumentation threw an exception.");
|
||||
InspectDocumentationHelperMethod();
|
||||
throw;
|
||||
}
|
||||
|
||||
var changelogMarkdown = string.Empty;
|
||||
if (System.IO.File.Exists(changelogPath))
|
||||
{
|
||||
changelogMarkdown = ChangelogTool.GetMarkdown(assembly);
|
||||
try
|
||||
{
|
||||
ChangelogTool.ExtractChangelog(assembly);
|
||||
changelogMarkdown = ChangelogTool.GetMarkdown(assembly);
|
||||
_logger.LogInformation("Parsed changelog for {Assembly}", assembly.GetName().Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to parse changelog at {Path}", changelogPath);
|
||||
}
|
||||
}
|
||||
|
||||
string version = assembly.GetCustomAttribute<System.Reflection.AssemblyInformationalVersionAttribute>()?.InformationalVersion
|
||||
?? assembly.GetName().Version?.ToString()
|
||||
?? "1.0.0";
|
||||
|
||||
if (version.Contains('+'))
|
||||
else
|
||||
{
|
||||
version = version.Substring(0, version.IndexOf('+'));
|
||||
_logger.LogWarning("Changelog file not found at {Path}", changelogPath);
|
||||
}
|
||||
|
||||
return new LibraryDocumentationViewModel
|
||||
var viewModel = new LibraryDocumentationViewModel
|
||||
{
|
||||
LibraryName = displayName,
|
||||
Description = description,
|
||||
Version = version,
|
||||
NuGetPackageId = nugetPackageId,
|
||||
Documentation = filteredDocumentation,
|
||||
ChangelogMarkdown = changelogMarkdown
|
||||
ChangelogMarkdown = changelogMarkdown,
|
||||
Documentation = allDocumentation.ToList()
|
||||
};
|
||||
|
||||
_logger.LogInformation(
|
||||
"=== Completed GenerateLibraryDocs for {Assembly}. Total documentation items: {Count} ===",
|
||||
assembly.GetName().Name, viewModel.Documentation.Count);
|
||||
|
||||
return viewModel;
|
||||
}
|
||||
|
||||
|
||||
static string GetSolutionRoot()
|
||||
{
|
||||
string dir = AppContext.BaseDirectory;
|
||||
|
||||
while (!string.IsNullOrEmpty(dir))
|
||||
{
|
||||
if (Directory.GetFiles(dir, "*.sln").Length > 0)
|
||||
return dir;
|
||||
|
||||
dir = Directory.GetParent(dir)?.FullName;
|
||||
}
|
||||
|
||||
throw new Exception("Solution root not found.");
|
||||
return AppContext.BaseDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdig" Version="0.40.0" />
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.2" />
|
||||
<PackageReference Include="MarkdigExtensions.SyntaxHighlighting" Version="1.0.3" />
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.3" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
using Serilog;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddControllersWithViews();
|
||||
|
||||
// Configure logging
|
||||
// Configure Serilog
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Information()
|
||||
.WriteTo.Console()
|
||||
.WriteTo.File(
|
||||
path: Path.Combine(AppContext.BaseDirectory, "logs", "documentation-.txt"),
|
||||
rollingInterval: RollingInterval.Day,
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
|
||||
.CreateLogger();
|
||||
|
||||
builder.Host.UseSerilog();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
@* File: `OmegaLeo.HelperLib.Web/Views/Home/Library.cshtml` *@
|
||||
@using ColorCode.Styling
|
||||
@using GameDevLibrary.Extensions
|
||||
@using Markdig
|
||||
@model OmegaLeo.HelperLib.Web.Models.LibraryDocumentationViewModel
|
||||
@{
|
||||
ViewData["Title"] = Model.LibraryName;
|
||||
var groupedByNamespace = Model.Documentation.GroupBy(d => d.AssemblyName).OrderBy(g => g.Key);
|
||||
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UseAdvancedExtensions()
|
||||
.UseSyntaxHighlighting(StyleDictionary.DefaultDark)
|
||||
.Build();
|
||||
}
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
@@ -75,7 +83,14 @@
|
||||
{
|
||||
<tr>
|
||||
<td><code>@desc.Title</code></td>
|
||||
<td>@Html.Raw(desc.Description)</td>
|
||||
<td>@Html.Raw(desc.Description)<br/>
|
||||
@if (desc.CodeExample.IsNotNullOrEmpty())
|
||||
{
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
@Html.Raw(Markdig.Markdown.ToHtml(desc.CodeExample, pipeline))
|
||||
</div>
|
||||
}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
|
||||
@@ -34,6 +34,14 @@
|
||||
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="Library" asp-route-id="game">Game Dev</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/omegaleo/HelperLib" target="_blank" rel="noopener noreferrer" aria-label="GitHub repository">
|
||||
<i class="bi bi-github" style="font-size:1.25rem;"></i> View on Github
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -42,12 +50,6 @@
|
||||
@RenderBody()
|
||||
</main>
|
||||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container">
|
||||
© @DateTime.Now.Year - OmegaLeo Helper Libraries
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
|
||||
@@ -5,5 +5,6 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
"AllowedHosts": "*",
|
||||
"https_port": 443
|
||||
}
|
||||
|
||||
@@ -19,4 +19,22 @@ html {
|
||||
|
||||
body {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 1rem;
|
||||
background-color: #495057;
|
||||
position: relative;
|
||||
|
||||
color: #f2f2f2;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.example-code > div {
|
||||
border-radius: 0.5rem !important;
|
||||
background-color: #495057 !important;
|
||||
}
|
||||
@@ -14,6 +14,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmegaLeo.HelperLib.Web", "O
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OmegaLeo.HelperLib.Game", "OmegaLeo.HelperLib.Game\OmegaLeo.HelperLib.Game.csproj", "{488BC3EA-9B7A-4251-B802-22EB098D6494}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionFiles", "SolutionFiles", "{00CF0543-37F3-41DE-B78F-8ADA6DE796ED}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
|
||||
CONTRIBUTING.md = CONTRIBUTING.md
|
||||
LICENSE = LICENSE
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADocumentationDescription_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fomegaleo_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe7ce68ea4d3540e4bc8ef1bd962ca30b3a00_003F46_003F1f9d3ace_003FDocumentationDescription_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADocumentationHelperTool_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fomegaleo_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F165936b93b8c4f33b6ee955456d3fd6a3c00_003F08_003F718f7e37_003FDocumentationHelperTool_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fomegaleo_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fbf9021a960b74107a7e141aa06bc9d8a0a53c929178c2fb95b1597be8af8dc_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMonitor_002ECoreCLR_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fomegaleo_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F9ee76fb4aded5e9da6e66cc2dcb127fac08d3ec5ac84fc6db9d4ee1d2e38_003FMonitor_002ECoreCLR_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARuntimeHandles_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fomegaleo_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003F42d5e9d0d54843a23887036cb9c33c9ce48bbc6f7c35ed3759154a95456c796_003FRuntimeHandles_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASafeFileHandle_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fomegaleo_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc21672d0d37542808f219d7d1f059dc1b2e000_003Faf_003Fbed3a9b4_003FSafeFileHandle_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fomegaleo_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc61cc76f205b4535a5b4f40700c07900b2d200_003Fe5_003F6b3ec67e_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATreeChanges_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fomegaleo_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F7478b0ce6362feb345e793626f5c504bd9d7ffeb748226521658c85fc4e29_003FTreeChanges_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using NetFlow.DocumentationHelper.Library.Attributes;
|
||||
|
||||
namespace GameDevLibrary.Helpers
|
||||
{
|
||||
[Documentation(nameof(BenchmarkUtility), "Utility class for benchmarking code execution time.", null, @"```csharp
|
||||
BenchmarkUtility.Start(""MyBenchmark"");
|
||||
// Code to benchmark
|
||||
BenchmarkUtility.Stop(""MyBenchmark"");
|
||||
var results = BenchmarkUtility.GetResults(""MyBenchmark"");
|
||||
```")]
|
||||
public class BenchmarkUtility
|
||||
{
|
||||
private static Dictionary<string, List<long>> _benchmarks = new Dictionary<string, List<long>>();
|
||||
private static Dictionary<string, Stopwatch> _stopwatches = new Dictionary<string, Stopwatch>();
|
||||
|
||||
[Documentation("GetStopwatch", "Retrieves or creates a Stopwatch instance for the given key.", null, null)]
|
||||
private static Stopwatch GetStopwatch(string key)
|
||||
{
|
||||
Stopwatch stopwatch;
|
||||
@@ -22,6 +30,14 @@ namespace GameDevLibrary.Helpers
|
||||
return stopwatch;
|
||||
}
|
||||
|
||||
[Documentation("Record", "Records the execution time of the provided action and returns the elapsed time in milliseconds.", null, @"```csharp
|
||||
var time = BenchmarkUtility.Record(() =>
|
||||
{
|
||||
// Code to benchmark
|
||||
});
|
||||
|
||||
Console.WriteLine($""Elapsed time: {time} ms"");
|
||||
```")]
|
||||
public static long Record(Action actionToRecord)
|
||||
{
|
||||
var stopwatch = new Stopwatch();
|
||||
@@ -33,6 +49,19 @@ namespace GameDevLibrary.Helpers
|
||||
return stopwatch.ElapsedMilliseconds;
|
||||
}
|
||||
|
||||
[Documentation("RecordAndSaveToResults", "Records the execution time of the provided action, saves it under the given key, and returns the elapsed time in milliseconds.", null, @"```csharp
|
||||
var time = BenchmarkUtility.RecordAndSaveToResults(""MyBenchmark"", () =>
|
||||
{
|
||||
// Code to benchmark
|
||||
});
|
||||
|
||||
Console.WriteLine($""Elapsed time: {time} ms"");
|
||||
|
||||
var results = BenchmarkUtility.GetResults(""MyBenchmark"");
|
||||
|
||||
var averageTime = results.Average();
|
||||
Console.WriteLine($""Average time: {averageTime} ms"");
|
||||
```")]
|
||||
public static long RecordAndSaveToResults(string key, Action actionToRecord)
|
||||
{
|
||||
var stopwatch = new Stopwatch();
|
||||
@@ -52,11 +81,13 @@ namespace GameDevLibrary.Helpers
|
||||
return stopwatch.ElapsedMilliseconds;
|
||||
}
|
||||
|
||||
[Documentation("Start", "Starts or restarts the stopwatch for the given key.", null, null)]
|
||||
public static void Start(string key)
|
||||
{
|
||||
GetStopwatch(key).Restart();
|
||||
}
|
||||
|
||||
[Documentation("Stop", "Stops the stopwatch for the given key and records the elapsed time.", null, null)]
|
||||
public static void Stop(string key)
|
||||
{
|
||||
if (!_benchmarks.ContainsKey(key))
|
||||
@@ -68,16 +99,19 @@ namespace GameDevLibrary.Helpers
|
||||
_benchmarks[key].Add(GetStopwatch(key).ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
[Documentation("GetResults", "Retrieves the list of recorded times for the given key.", null, null)]
|
||||
public static List<long> GetResults(string key)
|
||||
{
|
||||
return _benchmarks.ContainsKey(key) ? _benchmarks[key] : new List<long>();
|
||||
}
|
||||
|
||||
[Documentation("ClearResults", "Clears all recorded benchmark results.", null, null)]
|
||||
public static void ClearResults()
|
||||
{
|
||||
_benchmarks.Clear();
|
||||
}
|
||||
|
||||
[Documentation("GetAllResults", "Retrieves all recorded benchmark results.", null, null)]
|
||||
public static Dictionary<string, List<long>> GetAllResults()
|
||||
{
|
||||
return new Dictionary<string, List<long>>(_benchmarks);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.2" />
|
||||
<PackageReference Include="NetFlow.DocumentationHelper.Library" Version="1.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,50 @@
|
||||
# HelperLib
|
||||
|
Missing period at the end of the sentence. The sentence should end with "details." to maintain consistency with documentation standards. Missing period at the end of the sentence. The sentence should end with "details." to maintain consistency with documentation standards.
```suggestion
This project is licensed under the AGPL v3 License. See the [LICENSE](LICENSE) file for details.
```
|
||||
Library to help with C# projects and with game development using C#
|
||||
|
||||
Lightweight utility library for C\# projects and game development helpers.
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Features](#features)
|
||||
- [Install](#install)
|
||||
- [Documentation](#documentation)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
- [Socials](#socials)
|
||||
|
||||
## Overview
|
||||
|
||||
`HelperLib` contains small helpers and abstractions commonly useful in application and game development (helpers for collections, math, and utilities to keep game and engine code concise).
|
||||
|
||||
## Features
|
||||
|
||||
- Small, focused utilities for C\#
|
||||
- Helpers that favor clarity and testability
|
||||
- Game development specific helpers in the `OmegaLeo.HelperLib.Game` package
|
||||
- Changelog generation utilities in the `OmegaLeo.HelperLib.Changelog` package
|
||||
- Lightweight and easy to integrate into existing projects
|
||||
- Well-documented and maintained
|
||||
- Open source under the AGPL v3 License
|
||||
|
||||
## Install
|
||||
|
||||
Add the library to your project via NuGet:
|
||||
|
||||
```bash
|
||||
dotnet add package OmegaLeo.HelperLib
|
||||
dotnet add package OmegaLeo.HelperLib.Game
|
||||
dotnet add package OmegaLeo.HelperLib.Changelog
|
||||
```
|
||||
|
||||
## Documentation
|
||||
The documentation for this project can be found at [https://library.omegaleo.dev](https://library.omegaleo.dev).
|
||||
This documentation is automatically generated from the code using the [NetFlow.DocumentationHelper.Library](https://github.com/omegaleo/Netflow.DocumentationHelper).
|
||||
|
||||
## Contributing
|
||||
Contributions are welcome! Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for guidelines.
|
||||
|
||||
## License
|
||||
This project is licensed under the AGPL v3 License. See the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## Socials
|
||||
[![Youtube](https://img.shields.io/youtube/channel/subscribers/UCsdYKC7EK4Z_cpgWt0YiO9Q?style=plastic&label=Youtube&color=red
|
||||
|
||||
Reference in New Issue
Block a user
Write to static field from instance method, property, or constructor.
@copilot open a new pull request to apply changes based on this feedback