feat(extract): discover Blazor .razor components and emit Route nodes for @page - #1824
Open
The1nk wants to merge 2 commits into
Open
feat(extract): discover Blazor .razor components and emit Route nodes for @page#1824The1nk wants to merge 2 commits into
The1nk wants to merge 2 commits into
Conversation
A .razor file had no entry in EXT_TABLE, so discovery skipped it entirely and a Blazor application produced no graph nodes for any of its components. The only way in was an undocumented extra_extensions entry in a per-project .codebase-memory.json. Map .razor to CBM_LANG_CSHARP. This is best-effort by design: the C# grammar recovers the @code block, while the surrounding markup lands in ERROR regions and is reported through parse_partial. That is strictly more than the Module-and-imports the other markup-hosted languages (Vue, Svelte, Astro) extract today, and it needs no new grammar. Covered by tests/test_language.c:lang_ext_razor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: The1nk <23087600+The1nk@users.noreply.github.com>
get_architecture's routes aspect returned nothing for a Blazor application: the entry surface of the app was invisible in the graph even though every @page directive names one. @page lives in markup above the @code block, which tree-sitter's C# grammar never parses, so there is no AST node to read it from. Scan the raw source for it instead. The match is deliberately strict — the directive must be the first token on its line, followed by whitespace and a double-quoted path beginning with '/' — so @pageSize and prose mentions cannot match. The route is attached to the file's module def. A .razor component's class is implicit, so there is no class node to carry it, and the module QN already is the component's identity. insert_def_into_gbuf is label-agnostic and creates Route + HANDLES from route_path. pass_route_nodes.c's ensure_decorator_routes gains "Module" for the same reason. Extraction covers the full-index path on its own; this backstop is what runs on an incremental re-index, so without it a component's Route would appear on a full index and vanish the next time that one file changed. Its loop bound now derives from the labels array rather than borrowing the unrelated RN_STRIP_PASSES, so adding a label cannot silently skip it. Verified no double-creation when both paths can fire. Measured on a real Blazor application (36 .razor files): routes went from 0 to 11, with 11 matching HANDLES edges, and no change to the 363 Class / 1775 Method / 3805 CALLS already extracted from its C#. Covered by two new tests in tests/test_extraction.c. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: The1nk <23087600+The1nk@users.noreply.github.com>
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Makes Blazor
.razorcomponents visible to the indexer, and turns their@pagedirectives intoRoutenodes.Two changes, in dependency order:
1.
feat(discover): map .razor to C#—.razorhad no entry inEXT_TABLE, so discovery skipped it and a Blazor application produced nograph nodes for any component. The only way in was an undocumented
extra_extensionsentry in a per-project.codebase-memory.json. This maps.razortoCBM_LANG_CSHARP.It is best-effort by design: the C# grammar recovers the
@codeblock, whilethe surrounding markup lands in ERROR regions and is reported through
parse_partial. That is still strictly more than the Module-and-imports theother markup-hosted languages extract today, and it needs no new grammar.
2.
feat(extract): emit Route nodes for Blazor @page directives—get_architecture'sroutesaspect returned nothing for a Blazorapplication: the entry surface of the app was invisible even though every
@pagenames one.@pagelives in markup above the@codeblock, which tree-sitter's C#grammar never parses, so there is no AST node to read it from. This scans the
raw source instead. The match is deliberately strict — the directive must be
the first token on its line, followed by whitespace and a double-quoted path
beginning with
/— so@pageSizeand prose mentions cannot match.The route is attached to the file's module def. A
.razorcomponent'sclass is implicit, so there is no class node to carry it, and the module QN
already is the component's identity.
insert_def_into_gbufis label-agnosticand creates
Route+HANDLESfromroute_path.pass_route_nodes.c'sensure_decorator_routesgains"Module"for thesame reason. Extraction covers the full-index path on its own; this backstop
is what runs on an incremental re-index, so without it a component's
Routewould appear on a full index and vanish the next time that one filechanged. Its loop bound now derives from the labels array rather than
borrowing the unrelated
RN_STRIP_PASSES, so adding a label cannot silentlyskip it. Verified there is no double-creation when both paths can fire (60
files: 60 Routes and 60 HANDLES either way).
Measured
Paired control on a real Blazor application (36
.razorfiles, 261.cs),same source, same day, isolated caches:
+11nodes is exactly the 11Routenodes.get_architecture(routes)wentfrom the aspect being absent to 11 entries. No regression in what was already
extracted from that project's C#: 363 Class, 1775 Method, 3805 CALLS
unchanged, no store schema change.
End-to-end on a dedicated fixture, with a negative control:
Stable across a re-index.
What this does not claim
@codemethods are not reliably extracted from.razor. Real markup(
class=,role=attributes) defeats recovery and the file comes backparse_partialas a whole. Bare@codefields remain a separate gap.they reproduce on the unmodified binary too: routes report
handler:""although the
HANDLESedge exists, and the language census counts.razoras C# rather than as its own surface.
@pageon a component is taken, becauseCBMDefinitioncarries a single
route_path.Checklist
git commit -s) — required, CI rejectsunsigned commits (DCO, see CONTRIBUTING.md)
make -f Makefile.cbm test)make -f Makefile.cbm lint-ci)Full suite on this branch, rebased onto
010569fa(currentmainat the timeof writing): 7415 passed / 0 failed / 8 skipped, 139 suites, via
scripts/test.sh. The branch itself adds 3 of those tests —extract_blazor_page_directive_routes_component,extract_blazor_component_without_page_has_no_routeandlang_ext_razor, themiddle one being the negative control.
An earlier draft of this description quoted 7335/138 against base
49d928be.That base is now 129 commits behind, so the branch was rebased and re-measured
rather than shipped with stale numbers; the difference is upstream's, not this
change's.
On lint, stated plainly
make -f Makefile.cbm lint-ci— the gate this checklist names — passes: exit0, "CI linters passed", run in a clean container against this branch rebased
onto
010569fa.scripts/lint.shin full mode does not pass, and I do not believe any ofit is mine. Full mode adds clang-tidy, which fails repo-wide on rules like
readability-magic-numbers,readability-braces-around-statementsandmisc-no-recursion, in files this branch never touches —src/ui/httpd.h,src/pipeline/lsp_resolve.h,src/pipeline/pass_lsp_cross.h,src/foundation/*.hamong others.internal/cbm/extract_defs.cdoes appear in that output, but not at thischange's lines: the diagnostics sit at lines 281-1245 (including
cbm_resolve_func_name's cognitive complexity of 396), while this branch'shunks are at 7524-7613 and 7626-7643. Happy to be corrected if you read it
differently.
One scope question I would rather raise than assume
CONTRIBUTING.md asks for prior design discussion on "new pipeline passes or
indexing algorithms — anything that changes what gets extracted or how", and
this does change what gets extracted. What I took as the go-ahead was #1667
being open for eight days and labelled
bug/language-request/priority/high, plus the standing exception for focused bug fixes. If youwould rather this went through a design discussion first, say so and I will
close it and move the conversation back to the issue — no hard feelings.
Fixes #1667
Built and measured with Claude Code; all numbers above are from real runs on
a real application, not generated.