@@ -3924,6 +3924,75 @@ TEST(extract_java_jaxrs_path_composition_issue1005) {
39243924 PASS ();
39253925}
39263926
3927+ /* Return the file's Module definition (extraction pushes it first), or NULL. */
3928+ static const CBMDefinition * find_module_def (CBMFileResult * r ) {
3929+ for (int i = 0 ; i < r -> defs .count ; i ++ ) {
3930+ if (r -> defs .items [i ].label && strcmp (r -> defs .items [i ].label , "Module" ) == 0 ) {
3931+ return & r -> defs .items [i ];
3932+ }
3933+ }
3934+ return NULL ;
3935+ }
3936+
3937+ /* Blazor: a routable component declares its route with a `@page` directive in
3938+ * MARKUP, above the `@code` block. The C# grammar recovers `@code` (that is why
3939+ * .razor already yields methods via extra_extensions) but never sees the
3940+ * directive, so a routable page contributes no Route node and
3941+ * get_architecture(routes) is empty for a whole Blazor app.
3942+ *
3943+ * The route hangs off the file's Module definition, not off a class: a .razor
3944+ * component's class is implicit — it is never written in the source — so there
3945+ * is no class node to carry it. The Module's qualified name already IS the
3946+ * component's identity (t.Pages.Counter), and insert_def_into_gbuf creates
3947+ * Route+HANDLES for any definition carrying route_path, whatever its label. */
3948+ TEST (extract_blazor_page_directive_routes_component ) {
3949+ CBMFileResult * r = extract ("@page \"/counter\"\n"
3950+ "@inject NavigationManager Nav\n"
3951+ "\n"
3952+ "<h1>Counter</h1>\n"
3953+ "<button @onclick=\"Increment\">Click</button>\n"
3954+ "\n"
3955+ "@code {\n"
3956+ " private int count;\n"
3957+ " private void Increment() { count++; }\n"
3958+ "}\n" ,
3959+ CBM_LANG_CSHARP , "t" , "Pages/Counter.razor" );
3960+ ASSERT_NOT_NULL (r );
3961+ ASSERT_FALSE (r -> has_error );
3962+ /* The markup must not cost us the @code block we already extract today. */
3963+ ASSERT_NOT_NULL (find_def_by_name (r , "Increment" ));
3964+ const CBMDefinition * mod = find_module_def (r );
3965+ ASSERT_NOT_NULL (mod );
3966+ ASSERT_NOT_NULL (mod -> route_path );
3967+ ASSERT_STR_EQ (mod -> route_path , "/counter" );
3968+ /* A routable Blazor page is reached by navigation, i.e. GET. */
3969+ ASSERT_NOT_NULL (mod -> route_method );
3970+ ASSERT_STR_EQ (mod -> route_method , "GET" );
3971+ cbm_free_result (r );
3972+ PASS ();
3973+ }
3974+
3975+ /* The directive scan must not fire on every .razor file. A non-routable
3976+ * component (no @page) has to stay route-free, or every shared component in the
3977+ * tree becomes a bogus Route node. */
3978+ TEST (extract_blazor_component_without_page_has_no_route ) {
3979+ CBMFileResult * r = extract ("@inject IJSRuntime JS\n"
3980+ "\n"
3981+ "<div class=\"card\">@Title</div>\n"
3982+ "\n"
3983+ "@code {\n"
3984+ " private void Refresh() { }\n"
3985+ "}\n" ,
3986+ CBM_LANG_CSHARP , "t" , "Shared/Card.razor" );
3987+ ASSERT_NOT_NULL (r );
3988+ ASSERT_FALSE (r -> has_error );
3989+ const CBMDefinition * mod = find_module_def (r );
3990+ ASSERT_NOT_NULL (mod );
3991+ ASSERT_NULL (mod -> route_path );
3992+ cbm_free_result (r );
3993+ PASS ();
3994+ }
3995+
39273996/* A comment between decorators must not drop the decorators above it.
39283997 * Comments are NAMED tree-sitter nodes, so the prev-sibling walk used to stop
39293998 * at one — a documented route (@Post + @HttpCode above an explanatory comment)
@@ -6309,16 +6378,6 @@ TEST(iris_export_xml_multi_class) {
63096378 * question asked in words could not reach either. Both now carry the prose in
63106379 * `docstring`, which is what nodes_fts indexes into its `body` column. */
63116380
6312- /* First Module-labelled definition, or NULL. */
6313- static const CBMDefinition * find_module_def (CBMFileResult * r ) {
6314- for (int i = 0 ; i < r -> defs .count ; i ++ ) {
6315- if (strcmp (r -> defs .items [i ].label , "Module" ) == 0 ) {
6316- return & r -> defs .items [i ];
6317- }
6318- }
6319- return NULL ;
6320- }
6321-
63226381TEST (markdown_section_body_becomes_docstring_issue518 ) {
63236382 CBMFileResult * r = extract ("# Installation\n"
63246383 "Run the bootstrap script to provision a workstation.\n"
@@ -6827,6 +6886,8 @@ SUITE(extraction) {
68276886 RUN_TEST (arkts_lazy_import );
68286887 RUN_TEST (arkts_ts_compat );
68296888 RUN_TEST (extract_java_jaxrs_path_composition_issue1005 );
6889+ RUN_TEST (extract_blazor_page_directive_routes_component );
6890+ RUN_TEST (extract_blazor_component_without_page_has_no_route );
68306891 RUN_TEST (extract_ts_template_string_url_issue1006 );
68316892 RUN_TEST (extract_go_binary_concat_url_issue1249 );
68326893 RUN_TEST (extract_go_binary_concat_url_no_literal_suffix_issue1249 );
0 commit comments