Repository navigation
fix(core): map whole calls and parenthesized expressions so their diagnostics report (#231) - #262
Merged
Merged
Conversation
…gnostics report (#231) TypeScript reports TS2488 on a spread argument, TS2349 on a callee, TS1345 on a `void` condition and TS1355 on an `as const` operand over the whole expression. The mapping walker covered neither a call nor a parenthesized expression end to end, so Volar dropped these diagnostics. The walker now adds a verification-only whole-span mapping on each call and parenthesized expression the author wrote: one whose type and span match a node of the source AST, with the same callee or wrapped expression. Calls and parentheses the compiler generates with copied locations (Vue's defineVaporComponent wrapper, the parentheses around a compiled @if) get none. The superclass case from #222 now only covers array literals, since calls and parentheses map themselves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
) Record the author's calls and parenthesized expressions in visit_source_ast instead of a second walk over the source AST. That walk's JSXAttribute visitor never called next(), so it skipped attribute values. It now descends, which keeps the whole-call mapping for a call inside an attribute value (the compiler reprints an arrow body there over several lines, so the attribute's own mapping reported TS1345 two columns late) and also gives style blocks, script bodies and scoped class names inside attribute values their editor regions and CSS hovers, matching the compiled output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
1 task done
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #231
Problem
tsrx-tscexited 0 for this file, which TypeScript rejects with five errors:TypeScript reports each of these on a whole expression: the spread argument, the callee, the
ifcondition, the operand ofas const. Volar drops a diagnostic unless a mapping covers its end. The walker insegments.jsmapped neither aCallExpressionnor aParenthesizedExpressionend to end (the latter only withmetadata.forceMapping, which nothing in this repository sets), so nothing reached the closing).Fix
The walker now adds a verification-only whole-span mapping on each call and parenthesized expression, guarded on both ends having a source-map entry, as #222 does.
A mapping on every call is not safe. The transformed AST also contains calls and parentheses the compiler generates with source locations copied onto them. Errors in those would be reported over the author's code. Trying that version on the target test suites turned up:
defineVaporComponent(function App() { ... })wrapper, which carries the component's location. That was 144 of the 490 mappings the trial added, and it failsmaps Vue function components to the generated function in Volar TSX.(@if (props.on) { <b>on</b> }), which keeps its source parentheses around a generatedprops.on ? App__static1 : null(or<Show when={props.on}>on Solid).So the mapping only goes on a node the author wrote.
visit_source_ast, the existing walk over the source AST that collects CSS and script regions, now also records each call and parenthesized expression by type and span, along with the span of its callee or wrapped expression. The mapping walker gives a transformed node the mapping only when both match. With that check, every mapping the fix adds across the target,tsrx-utils,typescript-pluginandlanguage-servertest suites prints the same text as its source (ignoring whitespace), with one exception: an authoredprops.rows.map(...)whose callback the compiler rewrites into an IIFE (spread-ref normalization). That call is the author's, and the{...}around it already mapped over the same generated callback, so the new mapping only narrows where an error there lands.The superclass case from #222 now only handles array literals, because call and parenthesized superclasses get this mapping from their own walker case. Without that change they would be mapped twice.
Attribute values
The
JSXAttributevisitor invisit_source_astnever calledcontext.next(), apparently since it was renamed fromAttribute, so the walk skipped attribute values. It now descends. That keeps the mapping for a call in an attribute value. In<div onClick={() => { if (createVoid()) {} }} />, the compiler prints the arrow body over several lines, so onmainthe attribute's own mapping reports TS1345 two columns late.Descending also changes what the editor gets inside attribute values. Style blocks now get their CSS region,
<script>bodies their TypeScript region, and scoped class names their CSS hover, as they already do elsewhere in a template. This matches the compiled output, because the compiler already scopes those elements:icon={<span class="a" />}printsclass="a tsrx-…". The changeset covers this too.esrap
This doesn't depend on esrap. I linked in esrap 2.3.2 (the lockfile version), upstream
main(e924445), sveltejs/esrap#213, sveltejs/esrap#214, and #212 through #215 merged together, and ran 27 call and parenthesis shapes against each. Every build gave the same result: 21 of 27 diagnostics dropped without a walker change, all 27 reported on the author's expression with it. The issue description has the details. The esrap-dependent superclass case is #230, which needs sveltejs/esrap#214.Tests
(plain)and(plain)(), avoidifcondition, anas constoperand, a multi-line call with a trailing comma, an optional-chain callee, a logical expression in parentheses, nested parentheses, a call in a component body, and a call in an attribute value. No mapping over(@if (...) { ... }). A style block, a<script>body and scoped class names inside attribute values get their CSS region, script region and CSS hovers.tsc.test.js:tsrx-tscreports the five errors from the issue at the columnstscreports them.origin/main'ssegments.js, 85 of the 91 new cases fail, including the CLI test. The 6 that pass are the@ifcase, which guards against a mapping on every call and parenthesis.voidtests inside arrows, nested JSX, component props, a spread withref) all report attsc's position. Onmain, the TS1345 case above is two columns late.tsrx-tscagainsttscon 27 shapes: 6/27 onmain, 27/27 with the fix on Preact, React and Vue (three template-body cases differ fromtsconly because the.tscomparison source isn't the same text). Another 14 shapes (binary, logical, conditional,await, unary,satisfies, array, object, template andnewcallees) already matched and still do.pnpm test(118 files, 5372 tests), everypnpm typecheckstep (the Honotypecheck:testsstep run throughnode ../typescript-plugin/src/tsc.js, because a fresh worktree has notsrx-tscbin),pnpm format:checkandpnpm changeset:checkpass.🤖 Generated with Claude Code
Note
Medium Risk
Changes core source-map-to-Volar mapping logic that drives editor and CLI diagnostic positions; behavior is scoped with authored-node guards and covered by broad tests.
Overview
Fixes missing
.tsrxdiagnostics when TypeScript flags an entire call or parenthesized expression (e.g. TS2488 on[...createBase()], TS2349 oncreateBase()()/(plain)(), TS1345 onif (createVoid()), TS1355 oncreateBase() as const). Volar drops errors unless a source map covers the diagnostic end, and the mapping walker previously left those closing spans unmapped.The Volar mapping walker in
segments.jsnow adds verification-only, whole-span mappings forCallExpressionandParenthesizedExpression, but only for author-written nodes:collect_authored_span_nodesrecords calls/parens from the source AST (type, span, and callee/inner expression), andpush_authored_span_mappingapplies the mapping on the transformed tree only when that fingerprint matches—avoiding false positives on compiler-generated wrappers (e.g.defineVaporComponent, parentheses around compiled@if).Superclass handling is adjusted so call/parenthesized
extendsexpressions rely on the new path; the extra whole-span push remains only forArrayExpressionsuperclasses to prevent duplicate mappings.Shared source-mapping tests and a
tsrx-tscintegration test assert one correct mapping per shape and CLI output at the expected columns; the changeset documents the patch for@tsrx/core.Reviewed by Cursor Bugbot for commit 26acd38. Bugbot is set up for automated code reviews on this repo. Configure here.