Skip to content

fix(core): parse components with argument-less $state() instead of silently skipping them - #429

Merged
oekazuma merged 1 commit into
mainfrom
fix/424-state-noarg-crash
Aug 9, 2026
Merged

oekazuma merged 1 commit into
mainfrom
fix/424-state-noarg-crash

Conversation

@oekazuma

@oekazuma oekazuma commented Aug 9, 2026 •

Copy link
Copy Markdown
Owner

Fixes #424.

Problem

let el = $state(); — the idiomatic bind:this declaration — crashed fact extraction: two scans in component-parse.ts (the $state.raw candidates scan and the builtin-state candidates scan) call unwrapTs(init.arguments?.[0]), and unwrapTs dereferenced .type on the undefined argument. The resulting TypeError was swallowed by collectComponentFacts's deliberate never-throw fallback, so the whole file silently contributed emptyComponentFacts — invisible to every rule, with a clean Health 100/100 to show for it.

Verified blast radius: only bare $state() in .svelte components. $state.raw() / $state.frozen() with no argument and argument-less $state() in .svelte.ts runes modules never reached the crashing scans (pinned by a regression test so that stays true).

Fix

unwrapTs now tolerates undefined via an overload pair — one guard in the shared helper covers both current call sites and any future caller, while keeping the non-undefined callers' return type narrow. No call sites changed; the never-throw fallback in component-collect.ts is untouched (it remains the safety net for genuinely malformed files).

Tests

  • The issue's exact repro ($state() alongside count/doubled/$effect) yields normal facts — loc, effects, constableStates, plus rawableStates/nonreactiveBuiltinStates to exercise both formerly-crashing scans.
  • The typed $state<HTMLDialogElement>() variant from the issue's trigger table.
  • .svelte.ts runes module with argument-less $state() (already worked; pinned against regression).
  • collectComponentFacts no longer falls back to empty facts for such a file (the user-visible symptom).

Mutation-checked: with the unwrapTs guard reverted, the three .svelte tests fail with the original TypeError; the .svelte.ts pin passes, as expected.

Release note

Changeset (@svelte-vitals/core patch) states the gate movement explicitly: files previously skipped by this crash are now analyzed, so projects using this pattern may see new findings — including critical ones — and a previously green run can fail the default --fail-on critical gate. That is the fix working.

Follow-up (out of scope)

The issue's secondary point — nothing surfaces when a file is skipped by the never-throw fallback — is a real observability gap but a separate design decision (skipped-file counter / stderr note). Filing it separately keeps this a pure crash fix.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed analysis for argument-less $state() declarations so affected components are processed normally instead of being skipped.
    • Restored detection of findings that were previously hidden when these declarations caused parsing errors.
    • Added support for typed argument-less $state<T>() declarations.
  • Tests

    • Added regression coverage for component and module-state analysis, including locations, effects, and state findings.

…lently skipping them (#424)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 52031383-9f2f-439c-b98d-4348bdc0e242

📥 Commits

Reviewing files that changed from the base of the PR and between 20d6f16 and a744568.

📒 Files selected for processing (4)
  • .changeset/state-noarg-parse-crash.md
  • packages/core/src/component-parse.ts
  • packages/core/test/component-collect.test.ts
  • packages/core/test/component-parse.test.ts

📝 Walkthrough

Walkthrough

The parser now handles argument-less $state() declarations without replacing component facts with empty results. Tests cover component, typed, and .svelte.ts module cases. A changeset documents the patch release.

Changes

Argument-less state parsing

Layer / File(s) Summary
Optional expression unwrapping
packages/core/src/component-parse.ts
unwrapTs now accepts an undefined expression and safely returns undefined when $state() has no argument.
Regression coverage and release note
packages/core/test/component-parse.test.ts, packages/core/test/component-collect.test.ts, .changeset/state-noarg-parse-crash.md
Tests cover component facts, typed calls, module state declarations, and collection results. The changeset documents the patch release.

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the fix for argument-less $state() component parsing.
Linked Issues check ✅ Passed The changes restore normal analysis for argument-less, typed, and generic $state() declarations as required by issue #424.
Out of Scope Changes check ✅ Passed The changeset, implementation, and regression tests directly support the parsing fix and contain no unrelated code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@oekazuma

oekazuma commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@oekazuma

oekazuma commented Aug 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@oekazuma
oekazuma merged commit 2d0bae3 into main Aug 9, 2026
8 checks passed
@oekazuma
oekazuma deleted the fix/424-state-noarg-crash branch August 9, 2026 06:25
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.

component parsing: an argument-less $state() makes a component invisible to every rule

1 participant