diff --git a/CHANGELOG.md b/CHANGELOG.md index a192d8e28..70cfa4bb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### New Features -- ASP.NET Razor (`.cshtml`) and Blazor (`.razor`) markup are now parsed for code relationships. A `@model` / `@inherits` / `@inject` directive links the view to the C# view-model, base type, or service it names; a Blazor `` tag (plus `@typeof(...)` and generic `TItem="..."` arguments) links to the component class. So a view-model, component, or service referenced only from markup is no longer reported as having no dependents, and editing it surfaces the views that use it. (ASP.NET, Blazor) +- ASP.NET Razor (`.cshtml`) and Blazor (`.razor`) markup are now parsed for code relationships. A `@model` / `@inherits` / `@inject` directive links the view to the C# view-model, base type, or service it names; a Blazor `` tag (plus `@typeof(...)` and generic `TItem="..."` arguments) links to the component class; and the C# inside `@code { }` / `@functions { }` / `@{ }` blocks is analyzed too, so services and types used in component logic are linked. A view-model, component, or service referenced only from markup is no longer reported as having no dependents, and editing it surfaces the views that use it. (ASP.NET, Blazor) - `codegraph status --json` now also reports the running CLI `version`, the index directory (`indexPath`), and a `lastIndexed` timestamp (ISO-8601, or null when nothing's indexed yet), so CI and scripts can pin the CLI version and check index freshness from a single command. A matching `CodeGraph.getLastIndexedAt()` library method exposes the same freshness check without shelling out. Thanks @12122J and @eddieran. (#329) ### Fixes diff --git a/__tests__/extraction.test.ts b/__tests__/extraction.test.ts index 1636797d6..a80cf69d5 100644 --- a/__tests__/extraction.test.ts +++ b/__tests__/extraction.test.ts @@ -4005,6 +4005,26 @@ describe('Razor / Blazor markup extraction', () => { const htmlNodes = cg.getNodesByKind('class').filter((n) => n.name === 'div' || n.name === 'input'); expect(htmlNodes.length, 'no node for HTML elements').toBe(0); }); + + it('delegates Blazor @code block C# to cover types used in component logic', async () => { + fs.writeFileSync( + path.join(tempDir, 'CatalogService.cs'), + `namespace App { public class CatalogService { public void Load() { } } }` + ); + fs.writeFileSync( + path.join(tempDir, 'List.razor'), + `

Catalog

\n\n@code {\n private CatalogService _svc = new CatalogService();\n void Refresh() { _svc.Load(); }\n}\n` + ); + + cg = CodeGraph.initSync(tempDir); + await cg.indexAll(); + cg.resolveReferences(); + + const svc = cg.getNodesByKind('class').find((n) => n.name === 'CatalogService'); + expect(svc, 'CatalogService class').toBeDefined(); + const deps = [...cg.getImpactRadius(svc!.id, 2).nodes.values()].map((n) => n.filePath ?? ''); + expect(deps.some((p) => p.endsWith('List.razor')), '@code usage links the component to the service').toBe(true); + }); }); describe('Default import resolution (renamed default export)', () => { diff --git a/src/extraction/razor-extractor.ts b/src/extraction/razor-extractor.ts index ffa11f8b0..5f89b5ceb 100644 --- a/src/extraction/razor-extractor.ts +++ b/src/extraction/razor-extractor.ts @@ -1,5 +1,7 @@ -import { Node, ExtractionResult, ExtractionError, UnresolvedReference } from '../types'; +import { Node, Edge, ExtractionResult, ExtractionError, UnresolvedReference } from '../types'; import { generateNodeId } from './tree-sitter-helpers'; +import { TreeSitterExtractor } from './tree-sitter'; +import { isLanguageSupported } from './grammars'; /** * RazorExtractor — extracts code relationships from ASP.NET Razor (`.cshtml`) @@ -49,6 +51,7 @@ export class RazorExtractor { private filePath: string; private source: string; private nodes: Node[] = []; + private edges: Edge[] = []; private unresolvedReferences: UnresolvedReference[] = []; private errors: ExtractionError[] = []; @@ -67,6 +70,11 @@ export class RazorExtractor { if (this.filePath.toLowerCase().endsWith('.razor')) { this.extractComponentTags(componentId); } + // Delegate the C# in `@code { }` / `@functions { }` / `@{ }` blocks to the + // C# tree-sitter extractor (the Blazor analog of Svelte's