From 971e5343977c55a241026534f65f330921b75474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Leng=C3=A1l?= Date: Wed, 4 Mar 2026 20:44:53 +0100 Subject: [PATCH 1/8] done --- .github/instructions/default.instructions.md | 152 +++++++++++++++++++ .gitignore | 5 +- 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 .github/instructions/default.instructions.md diff --git a/.github/instructions/default.instructions.md b/.github/instructions/default.instructions.md new file mode 100644 index 00000000..53f0d258 --- /dev/null +++ b/.github/instructions/default.instructions.md @@ -0,0 +1,152 @@ +# RefDocGen - Coding Instructions + +## Project Overview + +RefDocGen is a **reference documentation generator for .NET**, installed as a .NET global tool (`refdocgen`). It extracts XML documentation comments from .NET assemblies and generates static HTML reference documentation using server-side Razor rendering. + +## Tech Stack + +- **.NET 8** (target framework: `net8.0`) +- **C#** with nullable reference types enabled and implicit usings +- **Razor SDK** (`Microsoft.NET.Sdk.Razor`) — used for server-side HTML rendering via `HtmlRenderer`, not as a web app +- **Key libraries**: AngleSharp (HTML parsing), CommandLineParser (CLI), Markdig (Markdown), YamlDotNet (YAML config), Serilog (logging), Microsoft.Build (MSBuild integration) +- **Testing**: xUnit + Shouldly (assertions) + NSubstitute (mocking) + AngleSharp (integration test HTML assertions) +- **E2E tests**: Playwright (Node.js, separate from .NET test projects) + +## Solution Structure + +| Project | Path | Purpose | +|---------|------|---------| +| `RefDocGen` | `src/RefDocGen/` | Main application (console tool) | +| `RefDocGen.UnitTests` | `tests/RefDocGen.UnitTests/` | Unit tests | +| `RefDocGen.IntegrationTests` | `tests/RefDocGen.IntegrationTests/` | Integration tests (generates HTML, asserts on DOM) | +| `RefDocGen.ExampleLibrary` | `tests/RefDocGen.ExampleLibrary/` | C# example library used as test input | +| `RefDocGen.ExampleFSharpLibrary` | `tests/RefDocGen.ExampleFSharpLibrary/` | F# example library used as test input | +| `RefDocGen.ExampleVbLibrary` | `tests/RefDocGen.ExampleVbLibrary/` | VB.NET example library used as test input | +| `RefDocGen.EndToEndTests` | `tests/RefDocGen.EndToEndTests/` | Playwright E2E tests (Node.js) | + +## Key Namespaces + +| Namespace | Purpose | +|-----------|---------| +| `RefDocGen` | Entry point (`Program`, `DocGenerator`) | +| `RefDocGen.AssemblyAnalysis` | Assembly loading, type/member extraction | +| `RefDocGen.CodeElements` | Core data model: types, members, enums, access modifiers | +| `RefDocGen.CodeElements.Members.Abstract` | Member interfaces (`IMemberData`, `IMethodData`, etc.) | +| `RefDocGen.CodeElements.Members.Concrete` | Member implementations | +| `RefDocGen.CodeElements.Types.Abstract` | Type interfaces (`IObjectTypeData`, `ITypeDeclaration`, etc.) | +| `RefDocGen.CodeElements.Types.Concrete` | Type implementations | +| `RefDocGen.CodeElements.TypeRegistry` | Central type storage (`ITypeRegistry`) | +| `RefDocGen.Config` | CLI and YAML configuration | +| `RefDocGen.DocExtraction` | XML doc comment extraction and `inheritdoc` resolution | +| `RefDocGen.TemplateProcessors` | Template processing abstraction and implementations | +| `RefDocGen.TemplateProcessors.Shared` | Shared template infrastructure, model creators, template models | +| `RefDocGen.Tools` | Extension methods, exceptions, XML utilities | + +## Architecture Patterns + +- **Abstract/Concrete split**: Interfaces live in `Abstract/` folders, implementations in `Concrete/` folders (applies to both `Members/` and `Types/`) +- **Public interfaces, internal implementations**: Public API is exposed via interfaces; concrete classes are `internal` +- **`InternalsVisibleTo`**: Unit tests and integration tests can access internal members +- **Record types** for simple data carriers (e.g., `AssemblyData`, `NamespaceData`, `AssemblyDataConfiguration`) +- **Template architecture**: `ITemplateProcessor` → `RazorTemplateProcessor` (generic base) → `DefaultTemplateProcessor` (concrete) +- **Template model creators** follow `*TMCreator` naming (e.g., `ObjectTypeTMCreator`, `EnumTMCreator`) +- **Extension point markers** in code: `#ADD_TEMPLATE`, `#ADD_TEMPLATE_PROCESSOR`, `#ADD_LANGUAGE` +- **Immutable collections**: Heavy use of `IReadOnlyDictionary`, `IReadOnlyList`, `IEnumerable` + +## Coding Conventions + +### Naming + +- **Types** (class, struct, interface, enum, delegate): `PascalCase` +- **Interfaces**: Prefix with `I` (e.g., `IMemberData`, `ITemplateProcessor`) +- **Properties, methods, events**: `PascalCase` +- **Local variables, parameters**: `camelCase` +- **Private/protected fields**: `camelCase` without underscore prefix (e.g., `private readonly ILogger logger;`) +- **Private constants**: `camelCase` (e.g., `private const string delegateMethodName = "Invoke";`) + +### Style + +- **File-scoped namespaces** — always use `namespace Foo;` not `namespace Foo { }` +- **No top-level statements** — `Program.cs` uses explicit `Main` method pattern +- **No primary constructors** — use traditional constructor syntax +- **`var` usage**: Do not use `var` for built-in types; use `var` when the type is apparent or elsewhere +- **Indentation**: 4 spaces (2 spaces for YAML/YML files) +- **Line endings**: CRLF +- **Final newline**: Yes +- **Trim trailing whitespace**: Yes +- **`internal` access modifier**: Used extensively for concrete implementations +- **Discard pattern**: Use `_ =` for unused return values (e.g., `_ = services.AddLogging(…);`) +- **Collection expressions** (C# 12): Use `[.. collection]` syntax where applicable +- **`required` modifier**: Used on properties in configuration classes + +### XML Documentation + +- Write comprehensive XML doc comments on **all public and internal members** +- Use standard tags: ``, ``, ``, ``, `` +- Use `/// ` to inherit documentation from interfaces/base classes in implementations +- The project itself generates documentation (`GenerateDocumentationFile=true`) + +### Error Handling + +- Custom exception hierarchy rooted at `RefDocGenFatalException` (internal) +- Use `string.Format(CultureInfo.InvariantCulture, …)` for exception message formatting +- `ExceptionDispatchInfo` used to capture and rethrow with original stack trace + +## Testing Conventions + +### Unit Tests (`RefDocGen.UnitTests`) + +- **Framework**: xUnit with `[Fact]` and `[Theory]`/`[InlineData]` +- **Assertions**: Shouldly (`.ShouldBe()`, `Should.Throw<>()`) +- **Mocking**: NSubstitute (`Substitute.For()`, `.Returns()`) +- **Test class naming**: `{ClassName}Tests` (e.g., `StringExtensionsTests`) +- **Test method naming**: `MethodName_ExpectedBehavior_Condition` (e.g., `TryGetIndex_ReturnsExpectedIndex_IfTheValueIsFound`) +- **Shared mocks**: `MockHelper` class with static factory methods + +### Integration Tests (`RefDocGen.IntegrationTests`) + +- Use **xUnit Collection Fixtures** (`[Collection(...)]`, `ICollectionFixture`) to share expensive doc generation setup +- Generate actual HTML output, then parse with **AngleSharp** to assert on DOM structure +- Helper tools in `Tools/` folder (e.g., `DocumentationTools.GetApiPage()`, `TypePageTools.GetAttributes()`) + +## Build & CI + +### Building + +```bash +dotnet build --no-restore -warnaserror +``` + +### Running Tests + +```bash +dotnet test ./tests/RefDocGen.UnitTests +dotnet test ./tests/RefDocGen.IntegrationTests +``` + +### Format Check + +```bash +dotnet format style --verify-no-changes +``` + +### CI Pipeline (`.github/workflows/dotnet.yml`) + +Triggered on push/PR to `master`: +1. `dotnet restore` +2. `dotnet build --no-restore -warnaserror` +3. Unit tests → Integration tests → Format check +4. Generate reference docs and upload as artifact +5. E2E tests (Playwright) +6. Deploy to GitHub Pages (master only) + +## Suppressed Warnings + +- `IDE0058` — expression value unused (in tests) +- `CA1707` — underscores in identifiers (allowed in test method names) +- `IDE0072` — switch expression exhaustiveness +- `CA1822` — mark members as static +- `CA1852` — seal internal types +- `IDE0046` — convert to conditional expression +- `CA1848` — logging message template performance diff --git a/.gitignore b/.gitignore index 4b9b9e19..683848a1 100644 --- a/.gitignore +++ b/.gitignore @@ -48,8 +48,11 @@ bld/ [Ll]ogs/ out/ -# Visual Studio 2015/2017 cache/options directory +# IDEs .vs/ +.vscode/ +.idea/ + # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ From 1f417a92ed943eafddae75e059c159ca142c0c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Leng=C3=A1l?= Date: Wed, 4 Mar 2026 20:50:25 +0100 Subject: [PATCH 2/8] done --- .github/instructions/default.instructions.md | 2 +- .github/workflows/dotnet.yml | 2 +- README.md | 2 +- docs/index.md | 2 +- src/RefDocGen/RefDocGen.csproj | 4 ++-- .../RefDocGen.ExampleFSharpLibrary.fsproj | 2 +- .../RefDocGen.ExampleLibrary.csproj | 2 +- .../RefDocGen.ExampleVbLibrary.vbproj | 2 +- .../Fixtures/DocumentationFixture.cs | 6 +++--- .../Fixtures/VersionedDocumentationFixture.cs | 2 +- .../RefDocGen.IntegrationTests.csproj | 2 +- tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj | 2 +- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/instructions/default.instructions.md b/.github/instructions/default.instructions.md index 53f0d258..a7170412 100644 --- a/.github/instructions/default.instructions.md +++ b/.github/instructions/default.instructions.md @@ -6,7 +6,7 @@ RefDocGen is a **reference documentation generator for .NET**, installed as a .N ## Tech Stack -- **.NET 8** (target framework: `net8.0`) +- **.NET 10** (target framework: `net10.0`) - **C#** with nullable reference types enabled and implicit usings - **Razor SDK** (`Microsoft.NET.Sdk.Razor`) — used for server-side HTML rendering via `HtmlRenderer`, not as a web app - **Key libraries**: AngleSharp (HTML parsing), CommandLineParser (CLI), Markdig (Markdown), YamlDotNet (YAML config), Serilog (logging), Microsoft.Build (MSBuild integration) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index e7a65683..f4205a4e 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -31,7 +31,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3 with: - dotnet-version: 8.0.x + dotnet-version: 10.0.x - name: Restore dependencies run: dotnet restore diff --git a/README.md b/README.md index eead485b..f5624127 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Default UI: ## Installation Prerequisites: -- .NET 8 (or higher) +- .NET 10 (or higher) Install as a .NET global tool from [NuGet](https://www.nuget.org/packages/RefDocGen): diff --git a/docs/index.md b/docs/index.md index 3f3e4563..7a14a9de 100644 --- a/docs/index.md +++ b/docs/index.md @@ -22,7 +22,7 @@ RefDocGen is a reference documentation generator for .NET. ## Installation Prerequisites: -- .NET 8 (or higher) +- .NET 10 (or higher) Install as a .NET global tool from [NuGet](https://www.nuget.org/packages/RefDocGen): diff --git a/src/RefDocGen/RefDocGen.csproj b/src/RefDocGen/RefDocGen.csproj index 5c98caa0..5deaa66a 100644 --- a/src/RefDocGen/RefDocGen.csproj +++ b/src/RefDocGen/RefDocGen.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 enable enable recommended @@ -26,7 +26,7 @@ - + diff --git a/tests/RefDocGen.ExampleFSharpLibrary/RefDocGen.ExampleFSharpLibrary.fsproj b/tests/RefDocGen.ExampleFSharpLibrary/RefDocGen.ExampleFSharpLibrary.fsproj index c48d9a7d..12b8f151 100644 --- a/tests/RefDocGen.ExampleFSharpLibrary/RefDocGen.ExampleFSharpLibrary.fsproj +++ b/tests/RefDocGen.ExampleFSharpLibrary/RefDocGen.ExampleFSharpLibrary.fsproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 true true diff --git a/tests/RefDocGen.ExampleLibrary/RefDocGen.ExampleLibrary.csproj b/tests/RefDocGen.ExampleLibrary/RefDocGen.ExampleLibrary.csproj index 774dd38e..522c33db 100644 --- a/tests/RefDocGen.ExampleLibrary/RefDocGen.ExampleLibrary.csproj +++ b/tests/RefDocGen.ExampleLibrary/RefDocGen.ExampleLibrary.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable true diff --git a/tests/RefDocGen.ExampleVbLibrary/RefDocGen.ExampleVbLibrary.vbproj b/tests/RefDocGen.ExampleVbLibrary/RefDocGen.ExampleVbLibrary.vbproj index 9442cbad..554a171e 100644 --- a/tests/RefDocGen.ExampleVbLibrary/RefDocGen.ExampleVbLibrary.vbproj +++ b/tests/RefDocGen.ExampleVbLibrary/RefDocGen.ExampleVbLibrary.vbproj @@ -2,7 +2,7 @@ RefDocGen.ExampleVbLibrary - net8.0 + net10.0 true true diff --git a/tests/RefDocGen.IntegrationTests/Fixtures/DocumentationFixture.cs b/tests/RefDocGen.IntegrationTests/Fixtures/DocumentationFixture.cs index 9a5c8481..521a5838 100644 --- a/tests/RefDocGen.IntegrationTests/Fixtures/DocumentationFixture.cs +++ b/tests/RefDocGen.IntegrationTests/Fixtures/DocumentationFixture.cs @@ -69,9 +69,9 @@ public void GenerateDoc() var generator = new DocGenerator( [ - "../../../../RefDocGen.ExampleLibrary/bin/Debug/net8.0/RefDocGen.ExampleLibrary.dll", // ExampleLibrary - "../../../../RefDocGen.ExampleFSharpLibrary/bin/Debug/net8.0/RefDocGen.ExampleFSharpLibrary.dll", // ExampleFSharpLibrary - "../../../../RefDocGen.ExampleVbLibrary/bin/Debug/net8.0/RefDocGen.ExampleVbLibrary.dll", // ExampleVbLibrary + "../../../../RefDocGen.ExampleLibrary/bin/Debug/net10.0/RefDocGen.ExampleLibrary.dll", // ExampleLibrary + "../../../../RefDocGen.ExampleFSharpLibrary/bin/Debug/net10.0/RefDocGen.ExampleFSharpLibrary.dll", // ExampleFSharpLibrary + "../../../../RefDocGen.ExampleVbLibrary/bin/Debug/net10.0/RefDocGen.ExampleVbLibrary.dll", // ExampleVbLibrary ], templateProcessor, assemblyDataConfig, diff --git a/tests/RefDocGen.IntegrationTests/Fixtures/VersionedDocumentationFixture.cs b/tests/RefDocGen.IntegrationTests/Fixtures/VersionedDocumentationFixture.cs index 465697bc..c38b8d86 100644 --- a/tests/RefDocGen.IntegrationTests/Fixtures/VersionedDocumentationFixture.cs +++ b/tests/RefDocGen.IntegrationTests/Fixtures/VersionedDocumentationFixture.cs @@ -68,7 +68,7 @@ public void GenerateDoc() var logger = Substitute.For(); var generator = new DocGenerator( - ["../../../../RefDocGen.ExampleLibrary/bin/Debug/net8.0/RefDocGen.ExampleLibrary.dll"], // use only the ExampleLibrary + ["../../../../RefDocGen.ExampleLibrary/bin/Debug/net10.0/RefDocGen.ExampleLibrary.dll"], // use only the ExampleLibrary templateProcessor, assemblyDataConfig, outputDir, diff --git a/tests/RefDocGen.IntegrationTests/RefDocGen.IntegrationTests.csproj b/tests/RefDocGen.IntegrationTests/RefDocGen.IntegrationTests.csproj index 35a0a285..d5ebdfbf 100644 --- a/tests/RefDocGen.IntegrationTests/RefDocGen.IntegrationTests.csproj +++ b/tests/RefDocGen.IntegrationTests/RefDocGen.IntegrationTests.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable recommended diff --git a/tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj b/tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj index 5cfd65ee..d9b94658 100644 --- a/tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj +++ b/tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable recommended From 85995e12d56d176fbff15be184eb14f861d188f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Leng=C3=A1l?= Date: Wed, 4 Mar 2026 20:54:49 +0100 Subject: [PATCH 3/8] fixes --- .../Shared/DocComments/Html/DocCommentTransformer.cs | 7 ++----- .../Shared/DocVersioning/DocVersionManager.cs | 5 +---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/RefDocGen/TemplateProcessors/Shared/DocComments/Html/DocCommentTransformer.cs b/src/RefDocGen/TemplateProcessors/Shared/DocComments/Html/DocCommentTransformer.cs index c57dbeeb..e1b9c3c3 100644 --- a/src/RefDocGen/TemplateProcessors/Shared/DocComments/Html/DocCommentTransformer.cs +++ b/src/RefDocGen/TemplateProcessors/Shared/DocComments/Html/DocCommentTransformer.cs @@ -32,9 +32,6 @@ internal class DocCommentTransformer : IDocCommentTransformer /// private readonly IDocCommentHtmlConfiguration htmlConfiguration; - /// - private TypeUrlResolver? typeUrlResolver; - /// private ITypeRegistry? typeRegistry; @@ -89,8 +86,8 @@ public ITypeRegistry TypeRegistry /// private TypeUrlResolver TypeUrlResolver { - get => typeUrlResolver ?? throw new InvalidOperationException("Type registry not provided"); - set => typeUrlResolver = value; + get => field ?? throw new InvalidOperationException("Type registry not provided"); + set; } /// diff --git a/src/RefDocGen/TemplateProcessors/Shared/DocVersioning/DocVersionManager.cs b/src/RefDocGen/TemplateProcessors/Shared/DocVersioning/DocVersionManager.cs index 6ee1620a..6be3d2fd 100644 --- a/src/RefDocGen/TemplateProcessors/Shared/DocVersioning/DocVersionManager.cs +++ b/src/RefDocGen/TemplateProcessors/Shared/DocVersioning/DocVersionManager.cs @@ -135,10 +135,7 @@ private void UpdateOlderPageVersions(string pagePath) var versionList = document.GetElementById(versionListElementId); - if (versionList is not null) - { - versionList.InnerHtml = JsonSerializer.Serialize(versions); // add the current version to the 'Version list' element - } + versionList?.InnerHtml = JsonSerializer.Serialize(versions); // add the current version to the 'Version list' element File.WriteAllText(olderVersionFile, document.ToHtml()); // Write the updated HTML } From e04451bd083162639e02dd946d92cdaeab019f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Leng=C3=A1l?= Date: Wed, 4 Mar 2026 21:03:56 +0100 Subject: [PATCH 4/8] upgrade packages --- src/RefDocGen/RefDocGen.csproj | 22 +++++++++---------- .../RefDocGen.IntegrationTests.csproj | 10 ++++----- .../RefDocGen.UnitTests.csproj | 8 +++---- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/RefDocGen/RefDocGen.csproj b/src/RefDocGen/RefDocGen.csproj index 5deaa66a..7c960cbc 100644 --- a/src/RefDocGen/RefDocGen.csproj +++ b/src/RefDocGen/RefDocGen.csproj @@ -12,7 +12,7 @@ true refdocgen ./nupkg - 1.0.6 + 1.1.0 Vojtěch Lengál RefDocGen Reference Documentation Generator for .NET @@ -24,22 +24,22 @@ - + - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + - - - + + + diff --git a/tests/RefDocGen.IntegrationTests/RefDocGen.IntegrationTests.csproj b/tests/RefDocGen.IntegrationTests/RefDocGen.IntegrationTests.csproj index d5ebdfbf..ef8a100e 100644 --- a/tests/RefDocGen.IntegrationTests/RefDocGen.IntegrationTests.csproj +++ b/tests/RefDocGen.IntegrationTests/RefDocGen.IntegrationTests.csproj @@ -11,12 +11,12 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -24,11 +24,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj b/tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj index d9b94658..356d6d5d 100644 --- a/tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj +++ b/tests/RefDocGen.UnitTests/RefDocGen.UnitTests.csproj @@ -11,11 +11,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -23,11 +23,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 0254e6f9ad9293d320360dd7e06543a9d9049adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Leng=C3=A1l?= Date: Wed, 4 Mar 2026 21:20:29 +0100 Subject: [PATCH 5/8] done --- .../AssemblyAnalysis/AssemblyTypeExtractor.cs | 5 ++- .../Members/Concrete/MethodData.cs | 2 +- .../Members/Concrete/ParameterData.cs | 2 +- .../DocExtraction/DocCommentExtractor.cs | 3 +- src/RefDocGen/Program.cs | 3 +- .../Shared/RazorTemplateProcessor.cs | 27 ++++++++++--- .../Shared/StaticPages/StaticPageProcessor.cs | 6 ++- .../Tools/Logging/RefDocGenLogMessages.cs | 39 +++++++++++++++++++ 8 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs diff --git a/src/RefDocGen/AssemblyAnalysis/AssemblyTypeExtractor.cs b/src/RefDocGen/AssemblyAnalysis/AssemblyTypeExtractor.cs index 763bb57c..1493e5f7 100644 --- a/src/RefDocGen/AssemblyAnalysis/AssemblyTypeExtractor.cs +++ b/src/RefDocGen/AssemblyAnalysis/AssemblyTypeExtractor.cs @@ -8,6 +8,7 @@ using RefDocGen.CodeElements.Types.Concrete; using RefDocGen.CodeElements.Types.Concrete.Delegate; using RefDocGen.CodeElements.Types.Concrete.Enum; +using RefDocGen.Tools.Logging; using RefDocGen.Tools.Exceptions; using System.Reflection; @@ -135,11 +136,11 @@ internal TypeRegistry GetDeclaredTypes() types.AddRange(assembly.GetTypes()); includedAssemblies.Add(assemblyPath); - logger.LogInformation("Assembly {Name} loaded", assemblyPath); + RefDocGenLogMessages.LogAssemblyLoaded(logger, assemblyPath); } else { - logger.LogInformation("Assembly {Name} excluded", assemblyPath); + RefDocGenLogMessages.LogAssemblyExcluded(logger, assemblyPath); } } diff --git a/src/RefDocGen/CodeElements/Members/Concrete/MethodData.cs b/src/RefDocGen/CodeElements/Members/Concrete/MethodData.cs index 2cdaa3e8..63260ee3 100644 --- a/src/RefDocGen/CodeElements/Members/Concrete/MethodData.cs +++ b/src/RefDocGen/CodeElements/Members/Concrete/MethodData.cs @@ -92,7 +92,7 @@ internal MethodData( public bool IsFinal => MethodInfo.IsFinal; /// - public bool IsAsync => MethodInfo.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null; + public bool IsAsync => MethodInfo.GetCustomAttribute() != null; /// public bool IsSealed => OverridesAnotherMember && IsFinal; diff --git a/src/RefDocGen/CodeElements/Members/Concrete/ParameterData.cs b/src/RefDocGen/CodeElements/Members/Concrete/ParameterData.cs index d05bea3b..ef0d0166 100644 --- a/src/RefDocGen/CodeElements/Members/Concrete/ParameterData.cs +++ b/src/RefDocGen/CodeElements/Members/Concrete/ParameterData.cs @@ -46,7 +46,7 @@ public ParameterData( public ITypeNameData Type { get; } /// - public bool IsParamsCollection => ParameterInfo.GetCustomAttribute(typeof(ParamArrayAttribute)) != null; + public bool IsParamsCollection => ParameterInfo.GetCustomAttribute() != null; /// public bool IsInput => ParameterInfo.IsIn; diff --git a/src/RefDocGen/DocExtraction/DocCommentExtractor.cs b/src/RefDocGen/DocExtraction/DocCommentExtractor.cs index ce5dfa9e..1f9873a8 100644 --- a/src/RefDocGen/DocExtraction/DocCommentExtractor.cs +++ b/src/RefDocGen/DocExtraction/DocCommentExtractor.cs @@ -7,6 +7,7 @@ using RefDocGen.DocExtraction.Handlers.Types; using RefDocGen.DocExtraction.InheritDoc; using RefDocGen.DocExtraction.Tools; +using RefDocGen.Tools.Logging; using RefDocGen.Tools.Xml; using System.Xml.Linq; @@ -133,7 +134,7 @@ internal void AddComments() { // load the document (preserve the whitespace, as the documentation is to be converted into HTML) xmlDocument = XDocument.Load(xmlPath, LoadOptions.PreserveWhitespace); - logger.LogInformation("XML documentation file {Name} loaded", xmlPath); + RefDocGenLogMessages.LogXmlDocFileLoaded(logger, xmlPath); } catch (FileNotFoundException) { diff --git a/src/RefDocGen/Program.cs b/src/RefDocGen/Program.cs index 90577de9..f3a61b71 100644 --- a/src/RefDocGen/Program.cs +++ b/src/RefDocGen/Program.cs @@ -10,6 +10,7 @@ using RefDocGen.TemplateProcessors.Default; using RefDocGen.TemplateProcessors.Shared.Languages; using RefDocGen.Tools.Exceptions; +using RefDocGen.Tools.Logging; using Serilog; using Serilog.Events; using System.Globalization; @@ -143,7 +144,7 @@ private static async Task Run(IProgramConfiguration config) if (config.SaveConfig) // save the configuration { YamlFileConfiguration.SaveToFile(config); - logger.LogInformation("Configuration saved into {File} file", YamlFileConfiguration.FileName); + RefDocGenLogMessages.LogConfigurationSaved(logger, YamlFileConfiguration.FileName); } Console.WriteLine($"Documentation generated in the '{config.OutputDir}' folder"); diff --git a/src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs b/src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs index bf01a515..204ec0b8 100644 --- a/src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs +++ b/src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs @@ -19,6 +19,7 @@ using RefDocGen.TemplateProcessors.Shared.Tools; using RefDocGen.Tools; using RefDocGen.Tools.Exceptions; +using RefDocGen.Tools.Logging; namespace RefDocGen.TemplateProcessors.Shared; @@ -200,7 +201,10 @@ public void ProcessTemplates(ITypeRegistry typeRegistry, string outputDirectory, _ = Directory.CreateDirectory(this.outputDirectory); } - this.logger?.LogInformation("Generating documentation in {Folder} folder", this.outputDirectory); + if (this.logger is not null) + { + RefDocGenLogMessages.LogGeneratingDocumentation(this.logger, this.outputDirectory); + } CopyStaticPages(); @@ -357,11 +361,17 @@ private void CopyStaticTemplateFilesDirectory() if (staticFilesDir.Exists) { staticFilesDir.CopyTo(outputDirPath, true); - logger?.LogInformation("A directory containing static template data copied to {Directory}", outputDirPath); + if (logger is not null) + { + RefDocGenLogMessages.LogStaticTemplateDataCopied(logger, outputDirPath); + } } else { - logger?.LogInformation("No directory containing static template data found at path {Directory}", staticFilesDir); + if (logger is not null) + { + RefDocGenLogMessages.LogNoStaticTemplateDataFound(logger, staticFilesDir.FullName); + } } } @@ -430,7 +440,11 @@ private void CopyStaticPages() foreach (var page in pages) // wrap each page in the static page template, process it, and copy it into the output directory { - logger?.LogInformation("Static page {Path} found", Path.Combine(staticPagesDirectory, page.FullName)); + if (logger is not null && logger.IsEnabled(LogLevel.Information)) + { + RefDocGenLogMessages.LogStaticPageFound(logger, staticPagesDirectory, page.FullName); + } + string outputPath = Path.Combine(outputDirectory, page.PageDirectory); var paramDictionary = new Dictionary() @@ -486,7 +500,10 @@ private void ProcessTemplate(Dictionary customTempla File.WriteAllText(outputFileName, html); _ = pagesGenerated.Add(pagePath); - logger?.LogInformation("Page {Name} created", outputFileName); + if (logger is not null) + { + RefDocGenLogMessages.LogPageCreated(logger, outputFileName); + } } catch (Exception ex) // Template compilation failed -> delete the directory & throw an exception { diff --git a/src/RefDocGen/TemplateProcessors/Shared/StaticPages/StaticPageProcessor.cs b/src/RefDocGen/TemplateProcessors/Shared/StaticPages/StaticPageProcessor.cs index 52016f2e..b9d101fd 100644 --- a/src/RefDocGen/TemplateProcessors/Shared/StaticPages/StaticPageProcessor.cs +++ b/src/RefDocGen/TemplateProcessors/Shared/StaticPages/StaticPageProcessor.cs @@ -3,6 +3,7 @@ using AngleSharp.Html.Dom; using Markdig; using Microsoft.Extensions.Logging; +using RefDocGen.Tools.Logging; using RefDocGen.Tools.Exceptions; namespace RefDocGen.TemplateProcessors.Shared.StaticPages; @@ -120,7 +121,10 @@ internal void CopyNonPageFiles(string outputDirectory) } File.Copy(file.FullName, outputPath, true); - logger?.LogInformation("Static file {FilePath} copied to {OutputPath}", filePath, outputPath); + if (logger is not null) + { + RefDocGenLogMessages.LogStaticFileCopied(logger, filePath, outputPath); + } } } } diff --git a/src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs b/src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs new file mode 100644 index 00000000..e189f532 --- /dev/null +++ b/src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs @@ -0,0 +1,39 @@ +using Microsoft.Extensions.Logging; + +namespace RefDocGen.Tools.Logging; + +/// +/// Source-generated logging methods used across the application. +/// +internal static partial class RefDocGenLogMessages +{ + [LoggerMessage(Level = LogLevel.Information, Message = "Assembly {Name} loaded")] + internal static partial void LogAssemblyLoaded(ILogger logger, string name); + + [LoggerMessage(Level = LogLevel.Information, Message = "Assembly {Name} excluded")] + internal static partial void LogAssemblyExcluded(ILogger logger, string name); + + [LoggerMessage(Level = LogLevel.Information, Message = "XML documentation file {Name} loaded")] + internal static partial void LogXmlDocFileLoaded(ILogger logger, string name); + + [LoggerMessage(Level = LogLevel.Information, Message = "Configuration saved into {File} file")] + internal static partial void LogConfigurationSaved(ILogger logger, string file); + + [LoggerMessage(Level = LogLevel.Information, Message = "Generating documentation in {Folder} folder")] + internal static partial void LogGeneratingDocumentation(ILogger logger, string folder); + + [LoggerMessage(Level = LogLevel.Information, Message = "A directory containing static template data copied to {Directory}")] + internal static partial void LogStaticTemplateDataCopied(ILogger logger, string directory); + + [LoggerMessage(Level = LogLevel.Information, Message = "No directory containing static template data found at path {Directory}")] + internal static partial void LogNoStaticTemplateDataFound(ILogger logger, string directory); + + [LoggerMessage(Level = LogLevel.Information, Message = "Static page {Directory}/{Page} found")] + internal static partial void LogStaticPageFound(ILogger logger, string directory, string page); + + [LoggerMessage(Level = LogLevel.Information, Message = "Page {Name} created")] + internal static partial void LogPageCreated(ILogger logger, string name); + + [LoggerMessage(Level = LogLevel.Information, Message = "Static file {FilePath} copied to {OutputPath}")] + internal static partial void LogStaticFileCopied(ILogger logger, string filePath, string outputPath); +} \ No newline at end of file From 8b5365e6e6c995923eeba434b0a2c64c147f6137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Leng=C3=A1l?= Date: Wed, 4 Mar 2026 21:21:03 +0100 Subject: [PATCH 6/8] done --- src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs b/src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs index e189f532..6f1506f6 100644 --- a/src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs +++ b/src/RefDocGen/Tools/Logging/RefDocGenLogMessages.cs @@ -36,4 +36,4 @@ internal static partial class RefDocGenLogMessages [LoggerMessage(Level = LogLevel.Information, Message = "Static file {FilePath} copied to {OutputPath}")] internal static partial void LogStaticFileCopied(ILogger logger, string filePath, string outputPath); -} \ No newline at end of file +} From c0a4598dd6227ed4210fa45001dbef2fd089c69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Leng=C3=A1l?= Date: Wed, 4 Mar 2026 21:22:39 +0100 Subject: [PATCH 7/8] format --- .../Shared/DocVersioning/DocVersionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RefDocGen/TemplateProcessors/Shared/DocVersioning/DocVersionManager.cs b/src/RefDocGen/TemplateProcessors/Shared/DocVersioning/DocVersionManager.cs index 6be3d2fd..ef42eaee 100644 --- a/src/RefDocGen/TemplateProcessors/Shared/DocVersioning/DocVersionManager.cs +++ b/src/RefDocGen/TemplateProcessors/Shared/DocVersioning/DocVersionManager.cs @@ -135,7 +135,7 @@ private void UpdateOlderPageVersions(string pagePath) var versionList = document.GetElementById(versionListElementId); - versionList?.InnerHtml = JsonSerializer.Serialize(versions); // add the current version to the 'Version list' element + _ = (versionList?.InnerHtml = JsonSerializer.Serialize(versions)); // add the current version to the 'Version list' element File.WriteAllText(olderVersionFile, document.ToHtml()); // Write the updated HTML } From d95c5b3571aae42bdfa9fae750d749a50e48e420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Leng=C3=A1l?= Date: Wed, 4 Mar 2026 21:29:55 +0100 Subject: [PATCH 8/8] Update src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../TemplateProcessors/Shared/RazorTemplateProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs b/src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs index 204ec0b8..dd70f398 100644 --- a/src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs +++ b/src/RefDocGen/TemplateProcessors/Shared/RazorTemplateProcessor.cs @@ -440,7 +440,7 @@ private void CopyStaticPages() foreach (var page in pages) // wrap each page in the static page template, process it, and copy it into the output directory { - if (logger is not null && logger.IsEnabled(LogLevel.Information)) + if (logger is not null) { RefDocGenLogMessages.LogStaticPageFound(logger, staticPagesDirectory, page.FullName); }