diff --git a/graphify/extractors/razor.py b/graphify/extractors/razor.py index b2b75a508..303bfcc73 100644 --- a/graphify/extractors/razor.py +++ b/graphify/extractors/razor.py @@ -9,7 +9,7 @@ from graphify.security import sanitize_metadata def extract_razor(path: Path) -> dict: - """Extract directives, component refs, and @code methods from .razor/.cshtml.""" + """Extract directives, component refs, and @code/@functions methods from .razor/.cshtml.""" try: src = path.read_text(encoding="utf-8", errors="replace") except OSError: @@ -158,7 +158,11 @@ def extract_razor(path: Path) -> dict: line_num = src[:m.start()].count("\n") + 1 _add_ref(comp_name, "calls", line_num) - _CODE_BLOCK_RE = re.compile(r'@code\s*\{', re.MULTILINE) + # @code is the Blazor (.razor) spelling; @functions is the equivalent + # Razor-Pages / MVC (.cshtml) spelling. Both compile to class members, and + # this extractor serves both file types, so a .cshtml that declares its + # methods in an @functions block lost every one of them. + _CODE_BLOCK_RE = re.compile(r'@(?:code|functions)\s*\{', re.MULTILINE) for m in _CODE_BLOCK_RE.finditer(src): block_start = m.end() depth = 1 diff --git a/tests/test_languages.py b/tests/test_languages.py index 7ab32a7f7..1684e9a8f 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -3719,6 +3719,23 @@ def test_razor_finds_code_block_methods(): assert any("IncrementCount" in l for l in labels) assert any("LoadData" in l for l in labels) +def test_razor_finds_functions_block_methods(tmp_path): + # @functions is the Razor Pages / MVC (.cshtml) spelling of the Blazor + # @code block. Both compile to class members and this extractor serves both + # file types, but only @code was recognised, so .cshtml methods vanished. + page = tmp_path / "Page.cshtml" + page.write_text( + "@functions {\n" + " public int Square(int x) { return x * x; }\n" + " public string Greet() { return \"hi\"; }\n" + "}\n", + encoding="utf-8", + ) + r = extract_razor(page) + labels = _labels(r) + assert "Square" in labels + assert "Greet" in labels + def test_razor_no_dangling_edges(): r = extract_razor(FIXTURES / "sample.razor") node_ids = {n["id"] for n in r["nodes"]}