Migrate XState to v5 from v4 Has Fix
Description
XState is a state management/orchestration library based on state machines, statecharts, and the actor model. It allows you to model complex logic in event-driven ways, and orchestrate the behavior of many actors communicating with each other.
XState's v5 version introduced some breaking changes and new features compared to v4. While the migration should be a straightforward process, it is a tedious process and requires knowledge of the differences between v4 and v5.
ast-grep provides a way to automate the process and a way to encode valuable knowledge to executable rules.
The following example picks up some migration items and demonstrates the power of ast-grep's rule system.
YAML
The rules below correspond to XState v5's createMachine
, createActor
, and machine.provide
.
The example shows how ast-grep can use various features like utility rule, transformation and multiple rule in single file to automate the migration. Each rule has a clear and descriptive id
field that explains its purpose.
For more information, you can use @ast-grep-bot to provide more detailed explanation for each rule.
id: migrate-import-name
utils:
FROM_XS: {kind: import_statement, has: {kind: string, regex: xstate}}
XS_EXPORT:
kind: identifier
inside: { has: { matches: FROM_XS }, stopBy: end }
rule: { regex: ^Machine|interpret$, pattern: $IMPT, matches: XS_EXPORT }
transform:
STEP1:
replace: {by: create$1, replace: (Machine), source: $IMPT }
FINAL:
replace: { by: createActor, replace: interpret, source: $STEP1 }
fix: $FINAL
---
id: migrate-to-provide
rule: { pattern: $MACHINE.withConfig }
fix: $MACHINE.provide
---
id: migrate-to-actors
rule:
kind: property_identifier
regex: ^services$
inside: { pattern: $M.withConfig($$$ARGS), stopBy: end }
fix: actors
Example
import { Machine, interpret } from 'xstate';
const machine = Machine({ /*...*/});
const specificMachine = machine.withConfig({
actions: { /* ... */ },
guards: { /* ... */ },
services: { /* ... */ },
});
const actor = interpret(specificMachine, {
/* actor options */
});
Diff
import { Machine, interpret } from 'xstate';
import { createMachine, createActor } from 'xstate';
const machine = Machine({ /*...*/});
const machine = createMachine({ /*...*/});
const specificMachine = machine.withConfig({
const specificMachine = machine.provide({
actions: { /* ... */ },
guards: { /* ... */ },
services: { /* ... */ },
actors: { /* ... */ },
});
const actor = interpret(specificMachine, {
const actor = createActor(specificMachine, {
/* actor options */
});
Contributed by
Inspired by XState's blog.