statelyai / xstate-tools

Public monorepo for XState tooling

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

v5 migration codemod

with-heart opened this issue · comments

This issue is for building a codemod that migrates a codebase from v4 to v5. The codemod would analyze the abstract syntax tree (AST) of the codebase in order to identify syntax changes that need to be made and apply those changes.

We'd also need to create a cli to apply the codemod. I can't remember if there's an xstate cli out there already or not, but if so we can reuse it. I'm thinking xstate codemod v4-to-v5 or something like that.

You can find the current (as of 4/14) migration guide here: https://docs-git-davidkpiano-v5-outline-statelyai.vercel.app/xstate-v5/migration

Here's a table of changes to target:

v4 v5 Changes to make Comments/Questions
Machine createMachine
  • replace Machine identifier with createMachine
  • replace Machine import with createMachine
cond guard
  • replace cond keys with guard
cond and actions objects can have any key objects can only have type and params
  • move any non-type properties into new params property object
(context, event) ({context, event})
  • wrap arguments in object syntax
if the arguments aren't named context and event, we'll need to make sure that the object's keys use the correct names (example: (ctx) becomes ({context: ctx}))
actor.onTransition actor.subscribe ? do they have the same interface?
send raise/sendTo ? is there a way to tell from send usage which new fn should be used instead?
internal: false reenter: true
  • if internal: true, remove property
  • if internal: false, remove and replace with new reenter: true property
interpret(machine).start(state) interpret(machine, {state}).start()
  • remove state argument from start call
  • create/update 2nd interpret argument object with state property
actor.send('event') actor.send({type: 'event'})
  • remove string argument
  • create object argument with type: 'event' property
null event ('') always
  • replace '' key with always
createMachine(config, options) createMachine(config).provide(options)
  • remove 2nd argument from createMachine
  • append call to .provide with options as its argument
machine.withConfig(options, context) machine.provide({…options, context})
  • remove .withConfig call
  • add .provide call
  • if context is passed
    • add empty object argument to provide call
    • spread options in object argument
    • add context property to object argument
  • if context is not passed, add options as argument to provide
need to handle cases where both .withConfig and .withContext were called
machine.withContext(context) machine.provide({context})
  • remove .withContext call
  • add .provide call
  • add object with context property as argument to provide
need to handle cases where both .withConfig and .withContext were called
predictableActionArguments: true -
  • remove predictableActionArguments property
strict: true -
  • remove strict property
state.history -
  • remove state.history property
is there anything else we could do here? maybe notify the user that state.history no longer exists and where it's being used so they can adjust their code?
actor.batch([...]) removed
  • remove actor.batch call
  • create an individual actor.send call for each event in the array
is this an appropriate solution?
config.schema config.types
  • rename schema key to types
need to make sure this works together with config.tsTypes change
config.tsTypes config.types.typegen
  • create types property with empty object value
  • move tsTypes property to types object
  • rename tsTypes key to typegen
need to make sure this works together with config.schema change