Repository navigation
feat(LLMsDocsGenerator): support Extensions components - #1269
Conversation
Reviewer's GuideExtends the LLM documentation generator to discover and document configured BootstrapBlazor.Extensions components and services from solution-listed projects, while adding Razor-only analysis, package-specific DI registration output, safer validation and nonzero failures, stale-file cleanup, and updated usage documentation. Sequence diagram for extension documentation generationsequenceDiagram
participant CLI
participant DocsGenerator
participant CategoryProvider
participant ComponentAnalyzer
participant ExtensionSources
participant MarkdownBuilder
CLI->>DocsGenerator: GenerateAllAsync(rootFolder, outputFolder)
DocsGenerator->>CategoryProvider: ParseExtensions()
DocsGenerator->>ExtensionSources: ReadExtensionProjects(repositoryRoot)
ExtensionSources-->>DocsGenerator: solution-listed projects
DocsGenerator->>ComponentAnalyzer: AnalyzeTypesByNameAsync(typeNames, resolveRegistration, registrationPackages)
ComponentAnalyzer->>ExtensionSources: EnsureCompilationAsync()
ExtensionSources-->>ComponentAnalyzer: core and extension syntax trees
ComponentAnalyzer-->>DocsGenerator: extension components and services
DocsGenerator->>MarkdownBuilder: BuildComponentSection(component)
MarkdownBuilder-->>DocsGenerator: package-specific registration markdown
DocsGenerator->>DocsGenerator: RemoveStaleDocuments(directory, types)
Flow diagram for extension documentation generationflowchart LR
A["docs.json extension packages"] --> B["Read BootstrapBlazor.Extensions.slnx"]
B --> C["Filter solution-listed projects"]
C --> D["Compile core and extension sources"]
D --> E["Analyze Razor-only components and services"]
E --> F["Resolve package-specific registrations"]
F --> G["Generate extensions documentation"]
G --> H["Remove stale generated files"]
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 6 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs" line_range="127" />
<code_context>
}
+ RemoveStaleDocuments(componentsOutputPath, components.Concat(services));
+ RemoveStaleDocuments(Path.Combine(_outputPath, "extensions"), extComponents.Concat(extServices));
+
Logger("Documentation generation complete!");
</code_context>
<issue_to_address>
**Previously generated docs are deleted**
When `docs.json` contains an `extensions` entry with a malformed package or component/service array, `RemoveStaleDocuments` treats the empty parsed package list as authoritative and deletes marked extension documents, so a malformed package entry can silently remove previously generated documentation.
Reject malformed extension configuration before generation or stale-file cleanup.
</issue_to_address>
### Comment 2
<location path="tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs" line_range="126-127" />
<code_context>
Logger($"Generated {extComponents.Count + extServices.Count} extension files in {extOutputPath}");
}
+ RemoveStaleDocuments(componentsOutputPath, components.Concat(services));
+ RemoveStaleDocuments(Path.Combine(_outputPath, "extensions"), extComponents.Concat(extServices));
+
Logger("Documentation generation complete!");
</code_context>
<issue_to_address>
**Newer documentation files disappear**
When two generator processes target the same output directory using different source or configuration snapshots, `RemoveStaleDocuments` compares the shared output against each run’s own expected-name set, so one run deletes files generated by the other and the surviving index links to missing documentation.
Serialize generation and stale-document cleanup per output directory, or publish each run’s output atomically from an isolated staging directory.
</issue_to_address>
### Comment 3
<location path="tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs" line_range="161" />
<code_context>
/// must include both the extension sources and the core library (for base types).
/// </summary>
- public async Task<List<ComponentInfo>> AnalyzeTypesByNameAsync(IEnumerable<string> typeNames, bool resolveRegistration = false)
+ public async Task<List<ComponentInfo>> AnalyzeTypesByNameAsync(IEnumerable<string> typeNames,
+ bool resolveRegistration = false, IReadOnlyList<ExtensionPackage>? registrationPackages = null)
{
</code_context>
<issue_to_address>
**Extension docs describe the wrong type**
When a configured extension type shares a short name with a core or another extension type, or two configured packages use the same short type name, `Distinct()` collapses duplicate configured names and `AnalyzeTypesByNameAsync` resolves names with `GetSymbolsWithName(...).FirstOrDefault()` across the combined compilation, so the generator documents the wrong declaration, can overwrite another package’s document, and produces incorrect or missing registration guidance.
Keep each configured name associated with its package and resolve it within the owning extension project instead of selecting the first symbol from the combined compilation.
Also at `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:162`, `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:333`, `tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs:69`.
</issue_to_address>
### Comment 4
<location path="tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs" line_range="79-80" />
<code_context>
+ // Razor-only components use the synthesized @inherits declaration.
var entryFiles = Directory.GetFiles(_componentsPath, "*.razor.cs", SearchOption.AllDirectories)
.Concat(Directory.GetFiles(_componentsPath, "*Base.cs", SearchOption.AllDirectories))
+ .Concat(Directory.GetFiles(_componentsPath, "*.razor", SearchOption.AllDirectories)
+ .Where(file => !File.Exists(file + ".cs") && _treeByPath.ContainsKey(Path.GetFullPath(file))))
.Distinct(StringComparer.OrdinalIgnoreCase);
</code_context>
<issue_to_address>
**Inherited component details disappear**
When a Razor-only component uses an unqualified `@inherits` base type supplied by `_Imports.razor` or project-level usings, `BuildInheritsShimAsync` parses the synthesized class without those imports, so Roslyn cannot resolve the base type and the analyzer omits inherited parameters and methods or excludes the component from the generated docs.
Include the applicable Razor imports and project-level usings when building the synthesized shim.
Also at `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:381`.
</issue_to_address>
### Comment 5
<location path="tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs" line_range="286" />
<code_context>
+ // First writer wins within each package so the most direct registration method sticks.
+ if (!registrations.Any(reg => reg.PackageName == packageName))
+ {
+ registrations.Add(new ServiceRegistration
{
+ PackageName = packageName,
</code_context>
<issue_to_address>
**Registration guidance is omitted**
When a configured extension service uses a non-generic registration overload such as `AddScoped(typeof(IDataService<>), ...)`, `BuildRegistrationIndex` only recognizes generic registration calls and their type arguments, so `ResolveRegistrations` finds no registration and the generated extension documentation omits the package’s registration instructions.
Teach `BuildRegistrationIndex` to extract service types from non-generic registration overloads that use `typeof`.
Also at `tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs:72-73`.
</issue_to_address>
### Comment 6
<location path="tools/BootstrapBlazor.LLMsDocsGenerator/README.md" line_range="146" />
<code_context>
+Run the integration checks with PowerShell:
+
+```powershell
+.\tools\BootstrapBlazor.LLMsDocsGenerator\tests\Verify-Generation.ps1
+```
</code_context>
<issue_to_address>
**Documented verification command fails**
When a user follows the README’s PowerShell verification instructions, the command targets `tests/Verify-Generation.ps1`, which is absent from the repository, so it fails before any integration checks run.
Add the referenced script or change the README command to point to an existing verification script.
Also at `tools/BootstrapBlazor.LLMsDocsGenerator/README.zh-CN.md:146`.
</issue_to_address>| } | ||
|
|
||
| RemoveStaleDocuments(componentsOutputPath, components.Concat(services)); | ||
| RemoveStaleDocuments(Path.Combine(_outputPath, "extensions"), extComponents.Concat(extServices)); |
There was a problem hiding this comment.
🟡 Medium · Previously generated docs are deleted
When docs.json contains an extensions entry with a malformed package or component/service array, RemoveStaleDocuments treats the empty parsed package list as authoritative and deletes marked extension documents, so a malformed package entry can silently remove previously generated documentation.
Reject malformed extension configuration before generation or stale-file cleanup.
Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs` at line 127:
**Previously generated docs are deleted**
When `docs.json` contains an `extensions` entry with a malformed package or component/service array, `RemoveStaleDocuments` treats the empty parsed package list as authoritative and deletes marked extension documents, so a malformed package entry can silently remove previously generated documentation.
Reject malformed extension configuration before generation or stale-file cleanup.| RemoveStaleDocuments(componentsOutputPath, components.Concat(services)); | ||
| RemoveStaleDocuments(Path.Combine(_outputPath, "extensions"), extComponents.Concat(extServices)); |
There was a problem hiding this comment.
🟡 Medium · Newer documentation files disappear
When two generator processes target the same output directory using different source or configuration snapshots, RemoveStaleDocuments compares the shared output against each run’s own expected-name set, so one run deletes files generated by the other and the surviving index links to missing documentation.
Serialize generation and stale-document cleanup per output directory, or publish each run’s output atomically from an isolated staging directory.
Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs` at lines 126-127:
**Newer documentation files disappear**
When two generator processes target the same output directory using different source or configuration snapshots, `RemoveStaleDocuments` compares the shared output against each run’s own expected-name set, so one run deletes files generated by the other and the surviving index links to missing documentation.
Serialize generation and stale-document cleanup per output directory, or publish each run’s output atomically from an isolated staging directory.| /// must include both the extension sources and the core library (for base types). | ||
| /// </summary> | ||
| public async Task<List<ComponentInfo>> AnalyzeTypesByNameAsync(IEnumerable<string> typeNames, bool resolveRegistration = false) | ||
| public async Task<List<ComponentInfo>> AnalyzeTypesByNameAsync(IEnumerable<string> typeNames, |
There was a problem hiding this comment.
🟡 Medium · Extension docs describe the wrong type
When a configured extension type shares a short name with a core or another extension type, or two configured packages use the same short type name, Distinct() collapses duplicate configured names and AnalyzeTypesByNameAsync resolves names with GetSymbolsWithName(...).FirstOrDefault() across the combined compilation, so the generator documents the wrong declaration, can overwrite another package’s document, and produces incorrect or missing registration guidance.
Keep each configured name associated with its package and resolve it within the owning extension project instead of selecting the first symbol from the combined compilation.
Also at tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:162, tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:333, tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs:69.
Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs` at line 161:
**Extension docs describe the wrong type**
When a configured extension type shares a short name with a core or another extension type, or two configured packages use the same short type name, `Distinct()` collapses duplicate configured names and `AnalyzeTypesByNameAsync` resolves names with `GetSymbolsWithName(...).FirstOrDefault()` across the combined compilation, so the generator documents the wrong declaration, can overwrite another package’s document, and produces incorrect or missing registration guidance.
Keep each configured name associated with its package and resolve it within the owning extension project instead of selecting the first symbol from the combined compilation.
Also at `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:162`, `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:333`, `tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs:69`.| .Concat(Directory.GetFiles(_componentsPath, "*.razor", SearchOption.AllDirectories) | ||
| .Where(file => !File.Exists(file + ".cs") && _treeByPath.ContainsKey(Path.GetFullPath(file)))) |
There was a problem hiding this comment.
🟡 Medium · Inherited component details disappear
When a Razor-only component uses an unqualified @inherits base type supplied by _Imports.razor or project-level usings, BuildInheritsShimAsync parses the synthesized class without those imports, so Roslyn cannot resolve the base type and the analyzer omits inherited parameters and methods or excludes the component from the generated docs.
Include the applicable Razor imports and project-level usings when building the synthesized shim.
Also at tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:381.
Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs` at lines 79-80:
**Inherited component details disappear**
When a Razor-only component uses an unqualified `@inherits` base type supplied by `_Imports.razor` or project-level usings, `BuildInheritsShimAsync` parses the synthesized class without those imports, so Roslyn cannot resolve the base type and the analyzer omits inherited parameters and methods or excludes the component from the generated docs.
Include the applicable Razor imports and project-level usings when building the synthesized shim.
Also at `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs:381`.| // First writer wins within each package so the most direct registration method sticks. | ||
| if (!registrations.Any(reg => reg.PackageName == packageName)) | ||
| { | ||
| registrations.Add(new ServiceRegistration |
There was a problem hiding this comment.
🟡 Medium · Registration guidance is omitted
When a configured extension service uses a non-generic registration overload such as AddScoped(typeof(IDataService<>), ...), BuildRegistrationIndex only recognizes generic registration calls and their type arguments, so ResolveRegistrations finds no registration and the generated extension documentation omits the package’s registration instructions.
Teach BuildRegistrationIndex to extract service types from non-generic registration overloads that use typeof.
Also at tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs:72-73.
Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocsGenerator/ComponentAnalyzer.cs` at line 286:
**Registration guidance is omitted**
When a configured extension service uses a non-generic registration overload such as `AddScoped(typeof(IDataService<>), ...)`, `BuildRegistrationIndex` only recognizes generic registration calls and their type arguments, so `ResolveRegistrations` finds no registration and the generated extension documentation omits the package’s registration instructions.
Teach `BuildRegistrationIndex` to extract service types from non-generic registration overloads that use `typeof`.
Also at `tools/BootstrapBlazor.LLMsDocsGenerator/DocsGenerator.cs:72-73`.| Run the integration checks with PowerShell: | ||
|
|
||
| ```powershell | ||
| .\tools\BootstrapBlazor.LLMsDocsGenerator\tests\Verify-Generation.ps1 |
There was a problem hiding this comment.
🟡 Medium · Documented verification command fails
When a user follows the README’s PowerShell verification instructions, the command targets tests/Verify-Generation.ps1, which is absent from the repository, so it fails before any integration checks run.
Add the referenced script or change the README command to point to an existing verification script.
Also at tools/BootstrapBlazor.LLMsDocsGenerator/README.zh-CN.md:146.
Prompt for AI agents
In `tools/BootstrapBlazor.LLMsDocsGenerator/README.md` at line 146:
**Documented verification command fails**
When a user follows the README’s PowerShell verification instructions, the command targets `tests/Verify-Generation.ps1`, which is absent from the repository, so it fails before any integration checks run.
Add the referenced script or change the README command to point to an existing verification script.
Also at `tools/BootstrapBlazor.LLMsDocsGenerator/README.zh-CN.md:146`.
Link issues
fixes #1268
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Extend the LLM documentation generator to analyze BootstrapBlazor.Extensions sources and produce validated, package-aware documentation alongside core component docs.
New Features:
Bug Fixes:
Enhancements:
CI:
Documentation:
Tests:
Chores: