Skip to content

Resolve # targets by exact id only - #5814

Merged
davidkpiano merged 2 commits into
nextfrom
fix/exact-id-targets
Oct 18, 2026
Merged

davidkpiano merged 2 commits into
nextfrom
fix/exact-id-targets

Conversation

@davidkpiano

@davidkpiano davidkpiano commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Rule

#x is an exact id lookup. The text after # is matched against state ids as a whole and is never split into a path. It matches a state's explicit id or its implicit id (path from the root joined by ., prefixed by the machine id when set; escaped key segments keep \.). Explicit ids are opaque strings: dots need no escaping. Applies to transition targets, initial: { target: '#…' }, snapshot.matches('#…'), @xstate.stateIn and getStateNodeById. Combining an id with a relative path (#someId.foo.bar) is no longer supported. Prior art: CSS #id, SCXML id-only targets.

Before / after

// machine id: 'shop'; `wizard` has id: 'flow'
// Before (v5 / earlier alphas)
browsing: { on: { review: { target: '#flow.review' } } }
// After
browsing: { on: { review: { target: '#shop.wizard.review' } } }
// or give `review` its own id and target '#review'

Error suggestion

No state has id "flow.review". Use "#shop.wizard.review", or give that state an id.

When a prefix of the id is a state id and the rest resolves beneath it as a relative path, the error names the target's actual id (Use "#bee". when the target has an explicit id). Otherwise: No state has id "…". Duplicate ids still throw.

Changes

  • Runtime: getStateNodeById does one idMap lookup; removed the first-segment+path resolution, the implicit-id fallback, the \. unescaping for ids, and the # branches in getStateNodeByPath/getStateNode. @xstate/test coverage target resolution no longer falls back to path parsing for # strings.
  • Types: createMachine # targets and setup() id targets accept only whole ids (explicit ids unescaped; implicit ids for createMachine). Removed #id.path composition types.
  • Codemod: new report-only report-id-path-targets transform; flags #a.b targets (target, initial, bare on/after values, arrays) and matches/stateIn arguments (string or static template literals) that are not whole state ids of the enclosing createMachine/createStateConfig config; references outside a config are always reported. Included in the manual-migration section.
  • Docs: transitions (new "Target by id"), guards, configuration, history states, migration guide (+ codemod table).
  • Checked: machineFromJSON and @xstate/test propertyTest already did exact lookups; @xstate/scxml emits #id with . sanitized to $ (unaffected); graph utilities do not parse # targets.

Verification

pnpm install --frozen-lockfile, pnpm build, pnpm test (264 files, 4448 passed / 32 skipped / 3 todo), pnpm typecheck, pnpm typecheck:examples, pnpm lint, pnpm format:check, pnpm check:exports, pnpm check:packed, pnpm knip, pnpm bench:type-errors --check (snapshot unchanged) all pass. Lockfile unchanged.

@changeset-bot

changeset-bot Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cff1d05

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@xstate/codemod Minor
xstate Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: edfdb2c2-43c9-493f-9819-61c64d051efe

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

Devin Review

Comment thread packages/xstate-codemod/src/transforms/report-id-path-targets.ts Outdated
Comment thread packages/xstate-codemod/src/transforms/report-id-path-targets.ts Outdated
Comment thread docs/transitions.md Outdated
@davidkpiano
davidkpiano merged commit 39d3b5c into next Oct 18, 2026
3 checks passed
@davidkpiano
davidkpiano deleted the fix/exact-id-targets branch October 18, 2026 09:00
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