feat(parser): parse plain HTML — inline <script> blocks + DocSection anchors (#521) - #818
feat(parser): parse plain HTML — inline <script> blocks + DocSection anchors (#521)#818joseedson18jc wants to merge 1 commit into
Conversation
…anchors (tirth8205#521) Reuses the Vue/Svelte SFC delegation machinery for .html/.htm, per the maintainer's guidance on tirth8205#521: - Inline <script> blocks: walk the tree-sitter html AST iteratively (script elements sit at arbitrary depth, and deep documents must not hit the recursion limit), skip <script src=…> references and non-JS payloads (application/json, importmap, text/x-template, …), parse each body with the JavaScript grammar, and offset line numbers back to the containing .html file. Unquoted (type=module) and case-varied attributes are handled. Relative imports inside type="module" blocks resolve from the HTML file's directory. - DocSection anchors: id-anchored div/section/article elements become DocSection nodes (extra.html_id, full element line range) with a CONTAINS edge from the File node, so children_of and structural traversal reach them. Anchor lookup only — no prose-content claims. On duplicate ids the first occurrence wins (getElementById semantics). Style blocks and heading anchors stay out of scope. Closes the blind spot where single-file HTML apps produced only a bare File node: a 246 KB dashboard index.html now yields 169 functions with accurate line ranges. 15 new tests in tests/test_multilang.py::TestHtmlEmbeddedScripts cover multiple and nested scripts, external/empty scripts, malformed HTML, duplicate ids, unquoted and case-varied attributes, .htm detection, line offsets, import/call edges, and CONTAINS reachability. Closes tirth8205#521 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Original reporter of #521 here. Thanks for picking this up, and for rebasing rather than trying to salvage my branch — that was the right call. Some field validation, since I've been running an out-of-tree variant of this design against a real repo since June (currently CRG 2.3.7, 2,065 files, 64,747 nodes):
On your requirement #1 ( Your requirement #2 is also right to insist on. Anchor- One gap, purely as a follow-up and explicitly not a request to widen this PR: this covers |
Linked issue
Closes #521
What & why
Implements plain-HTML parsing per the maintainer's guidance on #521 (credit to @dannymn for the proposal and reference design — this is a fresh implementation rebased on current main, since the reference branch was noted as 341 commits behind).
Inline
<script>blocks — same delegation pattern as_parse_vue/_parse_svelte:<script src=…>references and non-JS payloads (application/json,importmap,text/x-template, …) are skipped; an absent/emptytypeandmodule/text/javascript-family types parse as JavaScripttype=module) and case-varied attributes handled.htmlfiletype="module"blocks resolve from the HTML file's directory (source-side gate only;.htmlis deliberately not added as an import target, which would not be valid ES semantics)DocSectionanchors — per your integration requirements on the issue:div/section/articlewith anid→DocSectionnode (extra.html_id, full element line range)CONTAINSedge from the File node to eachDocSection, sochildren_ofand structural traversal reach themgetElementByIdsemantics)Field validation on a real codebase: a 246 KB single-file dashboard (
index.html, previously a bareFilenode) now yields 169 functions with accurate line ranges; semantic queries like "save the api key to browser storage" resolve to the correct function at rank 1.How it was tested
15 new tests in
tests/test_multilang.py::TestHtmlEmbeddedScriptscover the regression list from the issue discussion: multiple and nested scripts, external (src=) and empty scripts, malformed HTML (unclosed element), duplicate ids, unquoted and case-varied attributes,.htmdetection, line-number offsets, import/call edges across blocks, andCONTAINSreachability of everyDocSection.Checklist
uv run pytest tests/ --tb=short -quv run ruff check code_review_graph/uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional🤖 Generated with Claude Code