Skip to content

fix(extract): extract structure from Svelte/HTML/Astro inline scripts - #2056

Open
bmcnaboe wants to merge 2 commits into
DeusData:mainfrom
bmcnaboe:fix/svelte-html-astro-embedded-structure
Open

fix(extract): extract structure from Svelte/HTML/Astro inline scripts#2056
bmcnaboe wants to merge 2 commits into
DeusData:mainfrom
bmcnaboe:fix/svelte-html-astro-embedded-structure

Conversation

@bmcnaboe

@bmcnaboe bmcnaboe commented Sep 4, 2026

Copy link
Copy Markdown

Fixes #1807. Follow-up to #1852, carrying the generalization agreed on #1410.

What it does

#1852 built the shared embedded-script seam (included-ranges parse over the original buffer, lang=/src= resolution) and gated structural extraction to Vue. This widens it: Svelte, HTML and Astro <script> blocks — and Astro's frontmatter fence — now yield Function definitions and CALLS edges in host-file coordinates, exactly as a standalone .ts/.js file does.

Concretely, in internal/cbm/extract_imports.c and internal/cbm/lang_specs.c:

  • The extract_structure boolean is gone; every embedded block extracts definitions, imports and calls.
  • vue_embedded_language() is now script_embedded_language() and runs for all four markup hosts. It starts from the spec row's language rather than hard-coding JavaScript, so an attribute-free block keeps its declared grammar. It also learns HTML's type=: absent/empty, module, text/javascript and application/javascript pass; application/json, importmap, text/x-template, application/ld+json and anything else bail, so data blocks cannot leak garbage definitions. src= and unsupported lang= bail as before.
  • CFML's <cfscript> carries no attributes and keeps its spec-fixed language (the resolver is not consulted for it).
  • Astro's frontmatter fence and <script> bodies default to TypeScript, deliberately: Astro type-checks both as TS with no lang= attribute to say so, and the fence cannot carry one. The TypeScript grammar parses untyped JavaScript unchanged.

Tests

  • The fix(extract): extract structure from Vue inline scripts #1852 control pinning Svelte/HTML/Astro at zero functions and zero calls is flipped to assert the real symbols (embedded_structure_sibling_hosts_issue1807).
  • Stay-at-zero controls: <script type="application/json"> and <script src> in every host, plus importmap and text/x-template for HTML (embedded_structure_inert_blocks_issue1807). HTML's own tag walker still records the src= reference as an import edge; that names the external file and is asserted explicitly.
  • Both Svelte blocks contribute — <script context="module"> and Svelte 5's bare module — with per-block lang= and host-file line numbers (svelte_embedded_structure_both_blocks_issue1807).
  • HTML's accepted type= forms with line numbers, and a data block on the same page ignored (html_embedded_structure_issue1807).
  • Astro: TS frontmatter (interface + typed signatures) and a <script> body, both in host-file coordinates (astro_embedded_structure_issue1807).
  • End-to-end CALLS edge inside a .svelte file, the exact shape Svelte <script> function/call symbols never extracted — component call-graph is empty (imports work per #223, calls don't; Svelte analog of #1410) #1807 reports missing (es_calls_svelte_embedded_issue1807).
  • The per-grammar label goldens for Svelte and Astro gain the Variable their fixtures always declared (test_grammar_labels.c).

Validation

Indexed a 213-component Vue corpus (~26k nodes, ~75k edges) with main and with this branch, isolated caches: node counts per label, per host extension (.vue, .html, .ts), CALLS/IMPORTS counts per extension, and trace_path output for Vue-defined functions are identical. Vue behaviour is unchanged.

scripts/test.sh and scripts/lint.sh are green locally. DCO signed.

The Vue change (DeusData#1852) built the shared embedded-script seam — the
included-ranges parse over the original buffer and the lang=/src=
resolver — but gated structural extraction on the host being Vue. A
Svelte component, an HTML page or an Astro file therefore still yielded
only File + Module nodes and IMPORTS edges from its <script> blocks: no
Function definitions, no CALLS, and a false dead-code verdict for
anything used only from a component.

Widen the seam to every host that declares an embedded spec:

- Structural extraction (definitions + calls) runs for every embedded
  block; the per-host boolean is gone.
- The Vue attribute resolver becomes script_embedded_language() and
  runs for all four markup hosts. It starts from the spec row's language
  instead of hard-coding JavaScript, and learns HTML's type= attribute:
  absent or empty, module, text/javascript and application/javascript
  pass; application/json, importmap, text/x-template and the like bail,
  so data blocks cannot leak garbage definitions into the graph. src=
  and unsupported lang= values bail as before. CFML's <cfscript> carries
  no attributes and keeps its spec-fixed language.
- Astro's frontmatter fence and <script> bodies default to TypeScript:
  Astro type-checks both as TS with no lang= attribute to say so, and
  the fence cannot carry one. The TypeScript grammar parses untyped
  JavaScript unchanged.

Tests: the DeusData#1852 control that pinned Svelte/HTML/Astro at zero functions
and zero calls now asserts the real symbols; stay-at-zero controls cover
type="application/json" and <script src> in every host; both Svelte
blocks (context="module", and Svelte 5's bare module) contribute in
host-file coordinates; HTML's accepted type= forms and Astro's TS
frontmatter are covered; an end-to-end CALLS edge inside a .svelte file
is asserted. The Svelte and Astro label goldens gain the Variable their
fixtures always declared.

Verified on a 213-component Vue corpus: node counts per label and per
host language, edge counts and trace_path output are identical before
and after.

Fixes DeusData#1807

Signed-off-by: Brian McNaboe <bmcnaboe@gmail.com>
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

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. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

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.

@DeusData DeusData added bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. labels Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Svelte <script> function/call symbols never extracted — component call-graph is empty (imports work per #223, calls don't; Svelte analog of #1410)

2 participants