Repository navigation
Bug: Vue lang="tsx" scripts use the JavaScript parser; warnings depend on surviving symbols #2570
Description
Summary
Vue SFC <script lang="tsx"> blocks are classified as JavaScript rather than TSX. Valid TypeScript inside them is therefore parsed with the JavaScript grammar.
The visible symptom depends on whether any script symbols survive: a macro-only withDefaults(defineProps<T>()) script emits parse produced no symbols, while adding an unrelated const suppresses that warning even though the underlying JavaScript parse still has errors.
Environment
- CodeGraph reports
1.6.2, built frommainat8f1f842b5b828175992d2ce2cdf673b955b2cce9(not just the v1.6.2 release tag). - Windows x64, bundled Node
v24.16.0. - Vue compiler used for independent validation:
@vue/compiler-sfc3.4.27.
Minimal reproduction
Create an otherwise empty directory containing Title.vue:
<template><h1>{{ title }}</h1></template>
<script setup lang="tsx">
withDefaults(defineProps<{ title?: string }>(), { title: 'Hello' });
</script>Run:
codegraph init --yes .
codegraph files --json --path .Observed warning:
Title.vue: parse produced no symbols (tree has errors) — the file is indexed but contributes nothing to the graph
The file record has nodeCount: 2 and a parse_error warning. The two retained nodes are the file and component, so the diagnostic should not be read as the entire SFC being absent from the graph.
Controls verified in separate fresh indexes
- Original
lang="tsx": 2 nodes, 1 edge, oneparse_errorwarning. - Change only the attribute to
lang="ts": 2 nodes, 1 edge, no warning. - Keep
lang="tsx"and addconst marker = 1;inside the script: 3 nodes, 2 edges, no warning.
Using CodeGraph's own parsers directly on the original script content, the JavaScript tree has hasError: true, while the TSX tree has hasError: false. Adding the constant leaves the JavaScript tree erroneous; it only changes the warning gate. These checks were run against the installed build, not inferred solely from the source.
The same behavior was reproduced on nine existing SFCs. All nine passed the Vue compiler's SFC parsing, compileScript, and template compilation. Three other existing Vue TSX components also produced erroneous JavaScript trees without a warning because symbols survived extraction.
Likely cause
vue-extractor.ts:212 recognizes only ts / typescript:
const isTypeScript = /lang\s*=\s*["'](ts|typescript)["']/.test(attrs);processScriptBlock consequently selects javascript for tsx. The warning gate in tree-sitter.ts:741 explains why only the zero-symbol script reports it.
Expected behavior
Preserve the script block's declared language and select the TSX grammar for lang="tsx", including blocks containing actual JSX. Valid macro-only scripts should not produce a parser warning. A regression test should also cover a TSX script with another declaration, since a missing warning alone does not prove the right grammar was used.
Related: #1858 rewrites Vue API extraction, but its current diff still checks only ts / typescript when selecting the delegated script parser. #2336 concerns index-health reporting rather than this language selection bug.
Activity
fix(extraction): match a Vue script's lang case-insensitively (colbym…
yanhongwang1017 commentedon Oct 16, 2026
Fixed in #1858 (the Vue component-contract PR, which rewrites this extractor).
Your diagnosis was exactly right —
lang="tsx"fell through to the JavaScriptgrammar. The fix carries the declared lang through instead of an is-TS flag:
tsx → the TSX grammar, jsx → JSX, and ts stays TypeScript. Two things your
report surfaced that a single-line change would have missed:
collectComponentApi's delegated parse needed BOTH babel plugins(typescript + jsx) for tsx, not just jsx;
expandGrammarLanguagespreloaded only typescript/javascript for Vueprojects, so even with the right grammar name the parser was absent — and a
parser_errormakes the whole file store nothing, which is why the symptomwas "the file contributes nothing" rather than a partial parse.
Both of your suggested tests are in: the macro-only script (no warning) and a
tsx script with real JSX, since — as you noted — a surviving declaration
suppresses the warning even under the wrong grammar. Thanks for the detailed
repro; the controls you ran made this quick to confirm.
fix(extraction): parse Vue <script lang="tsx"> with the TSX grammar (c…
fix(extraction): match a Vue script's lang case-insensitively (colbym…
fix(vue): a <script lang="tsx"> block is read with the TSX grammar
fix(vue): a <script lang="tsx"> block is read with the TSX grammar (#…
colbymchenry commentedon Oct 23, 2026
Thanks for the careful report and the controls; they made this quick to pin down.
#2824 is merged to
main. It reads<script lang="tsx">with the TSX grammar. It also makes Vue projects load that grammar when they have no.tsxor.jsfile of their own; without that, those components would have dropped out of the index entirely.A macro-only script like your
Title.vueno longer warns, and the interfaces and types a TSX script declares now show up in the graph. It ships in the next release; re-index Vue projects that uselang="tsx"after upgrading.fix(rust): a Vue <script lang="tsx"> block is read with the TSX gramm…