Skip to content

Svelte: every .svelte file reports a syntax error at line 1; functions inside <script> are never extracted (extract_svelte feeds the whole file to the JS grammar) #3928

Description

@chrisltq97

Summary

extract_svelte calls _extract_generic(path, _JS_CONFIG) on the raw .svelte file. The HTML template is not JavaScript, so tree-sitter hits a top-level ERROR at line 1 and never reaches function_declaration nodes inside <script>. Only imports survive, via the regex rescue pass. On a SvelteKit app with 394 components, every single one was flagged "syntax errors and may be partially extracted".

This is the same failure mode as #2788 / PR #3902 for Astro. Vue already avoids it via _vue_mask_non_script.

Reproduce (graphify 0.9.71, macOS, Python 3.13)

mkdir t && cd t
printf '<script>\n  import { foo } from "./x";\n  let n = 1;\n  function bump() { n++; }\n</script>\n<button onclick={bump}>{n}</button>\n' > A.svelte
graphify extract . --code-only --no-cluster

Output:

warning: 1 file(s) had syntax errors and may be partially extracted: A.svelte (first error at line 1, 1 symbol(s) extracted)
wrote graphify-out/graph.json — 2 nodes, 1 edges

bump() is missing. Same result with <script lang="ts"> and with Svelte 5 runes ($state, $props).

Fix that works locally

Mirror extract_vue: mask non-script regions with _vue_mask_non_script (regex is generic <script …>…</script>), pick _JS_CONFIG when lang is js/jsx else _TS_CONFIG, run _normalize_ts_import_types, and pass source_override= to _extract_generic. The existing regex import-rescue stays as-is.

src = path.read_text(encoding="utf-8", errors="replace")
masked, lang = _vue_mask_non_script(src)
cfg = _JS_CONFIG if lang in ("js", "jsx") else _TS_CONFIG
mb = masked.encode("utf-8")
if cfg is _TS_CONFIG:
    mb = _normalize_ts_import_types(mb) or mb
result = _extract_generic(path, cfg, source_override=mb)

Results on a real SvelteKit repo (658 code files, 394 .svelte):

files with parse errors nodes edges
before 394 1829 3816
after 0 3377 5921

Minimal repro above: 2 nodes / 1 edge -> 3 nodes / 3 edges (bump() present). Line numbers stay correct because the mask preserves \n.

Happy to open a PR if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions