From 2114766c91067aef963acd706e5044f53ee5b399 Mon Sep 17 00:00:00 2001 From: ayushcodes10 Date: Thu, 17 Sep 2026 15:34:49 +0530 Subject: [PATCH] Index JavaScript in inline script blocks of a PHP file The PHP tree sitter grammar treats a span that is not PHP, such as an inline script block, as opaque markup, so any JavaScript declared there was entirely absent from the graph: functions, calls, and everything else in that region. extract_php now runs a second pass after the PHP extraction. Every part of the source that is not a script body is blanked to spaces, preserving newlines so line numbers stay accurate, and the masked source is parsed with the JS grammar the same way the Vue extractor already masks everything outside its own script block. The two node sets are merged onto the one file node, so a symbol declared in the script block looks like any other symbol in the file. A script tag with only a src attribute and no body masks to an empty region and contributes nothing, and a file with no script tag at all skips the second pass entirely. Co-Authored-By: Claude Sonnet 5 --- graphify/extract.py | 67 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/graphify/extract.py b/graphify/extract.py index d54b841d9..29692e9ed 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -2546,9 +2546,72 @@ def extract_scala(path: Path) -> dict: return _extract_generic(path, _SCALA_CONFIG) +_PHP_SCRIPT_RE = re.compile( + r"\"'])*>([\s\S]*?)", + re.IGNORECASE, +) + + +def _php_mask_to_script_blocks(src: str) -> tuple[str, bool]: + """Blank everything outside inline ```` with no body masks to an empty region, + which parses as empty JS and contributes nothing — no special-casing needed. + Returns ``(masked_source, had_script)``; the caller skips the JS pass + entirely when ``had_script`` is False. + """ + def _blank(s: str) -> str: + return re.sub(r"[^\r\n]", " ", s) + + out: list[str] = [] + pos = 0 + had_script = False + for m in _PHP_SCRIPT_RE.finditer(src): + had_script = True + out.append(_blank(src[pos:m.start(1)])) # everything up to and including and any trailing part of the match + pos = m.end() + if not had_script: + return src, False + out.append(_blank(src[pos:])) + return "".join(out), True + + def extract_php(path: Path) -> dict: - """Extract classes, functions, methods, namespace uses, and calls from a .php file.""" - return _extract_generic(path, _PHP_CONFIG) + """Extract classes, functions, methods, namespace uses, and calls from a .php file. + + Also parses any inline ``