Skip to content

fix(core): treat {@const} and {let}/{const} declaration tags as shadowing bindings - #301

Merged
oekazuma merged 4 commits into
mainfrom
fix/const-tag-scope
Jul 24, 2026
Merged

oekazuma merged 4 commits into
mainfrom
fix/const-tag-scope

Conversation

@oekazuma

@oekazuma oekazuma commented Jul 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

Follow-up flagged by the final review of #285: scopeIntroducedNames did not treat template declaration tags as scope-introducing, so a write to a template-local alias was misattributed to a same-named top-level $state binding. Covers {@const ...} (ConstTag) and the newer {let ...} / {const ...} declaration tags (DeclarationTag, svelte.dev/docs/svelte/declaration-tags — AST shape verified against svelte 5.56). Verified false positive before this fix:

<script>
  let tags = $state(new Set());
</script>
{#each groups as g}
  {@const tags = g.tags}  <!-- same for {let tags = g.tags} / {const tags = g.tags} -->
  <button onclick={() => tags.add('x')}>x</button>
{/each}

correctness/nonreactive-builtin-state flagged the outer tags, and the same misattribution suppressed correctness/unmutated-state's constableStates.

Change

One addition to the shared scopeIntroducedNames helper: a Fragment's own ConstTag/DeclarationTag declarations now shadow the whole fragment (same over-conservative whole-scope model as a block's let; both node types carry the same declaration.declarations shape, so one branch covers all three tags). A write to one of these template-locals — possible for {let} — is still not a write to the outer binding, so the fix is strictly precision-improving for every consumer of the helper (all component-analysis collectors) at once.

Testing

  • Four regression tests (nonreactive-builtin-state facts for {@const}/{let}/{const} + constableStates for {@const} mutation and {let} reassignment), each verified to fail without the fix and pass with it
  • core 668 and cli 703 tests green; tsc, oxlint, oxfmt clean
  • Changeset: patch × core / cli / vite / mcp

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Fragment-level {@const} declarations are now included in scope shadowing, preventing writes through same-named aliases from being attributed to outer $state variables. Parser tests cover constableStates and nonreactiveBuiltinStates, with patch releases recorded.

Changes

Fragment const shadowing

Layer / File(s) Summary
Recognize fragment const bindings
packages/core/src/component-parse.ts
scopeIntroducedNames now records identifiers declared by fragment-level {@const} tags as shadowed names.
Validate shadowed mutation analysis
packages/core/test/*parse.test.ts, .changeset/const-tag-scope-shadow.md
Tests verify that mutations through {@const} aliases do not affect outer state analysis, and patch releases are recorded for the affected packages.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the core change around shadowing bindings, though it is broader than the patch and mentions tags not clearly changed here.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@oekazuma oekazuma changed the title fix(core): treat {@const} declarations as shadowing bindings in scope resolution fix(core): treat {@const} and {let}/{const} declaration tags as shadowing bindings Jul 24, 2026
@oekazuma
oekazuma merged commit ad2eab5 into main Jul 24, 2026
7 checks passed
@oekazuma
oekazuma deleted the fix/const-tag-scope branch July 24, 2026 01:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant