/xstate-builder

Use A Fluent Builder To Generate Your X-State Configuration

Primary LanguageTypeScriptMIT LicenseMIT

Under Developement

The package works fine, as seen on the tests. But the API is not stable yet and will change in the future.

Don't use it yet 🙏

Why this package?

The Builder Pattern decouples the creation of the object from the object itself. The main idea behind is that an object does not have to be responsible for its own creation. The correct and valid assembly of a complex object may be a complicated task in itself, so this task can be delegated to another class.

Configuring a state machine using the Object Configuration Pattern is straightfoward. But there is some flaws to it:

  • it lacks to provide meaning to the code, therefore, regression can and will happen.
  • it's long to read, reading JSON is very different from code reading.
  • composition is hard to achieve
  • techincal debt is hight.

What can this do for me?

  • Autocomplete, Dynamic Typing and improved API discovery 👌.
  • Easy to compose with any JS code to help you configure your machine.
  • Ability to quickly have a clear view of all the different states of the machine.
  • Write the same machine with fewer lines of code.
  • Increase Maintainability: Easier to read and understand ( because of the fluent API ).
  • Ability to organize the code in a way that makes the more sense to you, and not to the machine.
  • Integrates with all the js/ts tools you already have

Examples

Example: Sequence Pattern:

const machineConfig = Machine.Builder(machine => {
  const nodes = ['node-1', 'node-2', 'node-3', 'node-4'];
  
  machine.states(nodes).forEach((state, index, nodes) => {
   const nextTarget = nodes[index + 1] || nodes[0];
   const prevTarget = nodes[index - 1] || nodes[nodes.length - 1];
   
   state.on('NEXT').target(nextTarget)
    .on('PREVIOUS').target(prevTarget);
   
  })
})

// SAME AS:

const machineConfig = {
  initial: 'node-1',
  states: {
    'node-1': {
      type: 'atomic',
      on: {
        NEXT: 'node-2',
        PREVIOUS: 'node-4',
      },
    },
    'node-2': {
      type: 'atomic',
      on: {
        NEXT: 'node-3',
        PREVIOUS: 'node-1',
      },
    },
    'node-3': {
      type: 'atomic',
      on: {
        NEXT: 'node-4',
        PREVIOUS: 'node-2',
      },
    },
    'node-4': {
      type: 'atomic',
      on: {
        NEXT: 'node-1',
        PREVIOUS: 'node-3',
      },
    },
  },
}

Example 2: Simple State With Event Handler

const machineConfig = Machine.Builder(state => {
  state.atomic('initialState')
    .onEach(['TAP', 'CLICK', 'LONGPRESS'])
      .if('IS_ACTIVE').do('SET_INACTIVE')
      .if('IS_INACTIVE').do('SET_ACTIVE')
})

// SAME AS:

const machineConfig = {
  initial: 'initialState',
  states: {
    'initialState': {
      type: 'atomic',
      on: {
        TAP: [{
          cond: 'IS_ACTIVE',
          action: 'SET_INACTIVE',
        }, {
          cond: 'IS_INACTIVE',
          action: 'SET_ACTIVE',
        }],
        CLICK: [{
          cond: 'IS_ACTIVE',
          action: 'SET_INACTIVE',
        }, {
          cond: 'IS_INACTIVE',
          action: 'SET_ACTIVE',
        }],
        LONGPRESS: [{
          cond: 'IS_ACTIVE',
          action: 'SET_INACTIVE',
        }, {
          cond: 'IS_INACTIVE',
          action: 'SET_ACTIVE',
        }],
      },
    },
  },
}

Example 3: Transiant State

const machineConfig = Machine.Builder(state => {
  state.switch('transiant-example')
    .case('GUARD1').target('TARGET1')
    .case('GUARD1').target('TARGET2')
    .default('TARGET3')
})

const machineConfig = {
  initial: 'transiant-example',
  states: {
    'transiant-example': {
      type: 'atomic',
      on: {
        '': [
          {
            cond: 'GUARD1',
            target: 'TARGET1',
          },
          {
            cond: 'GUARD1',
            target: 'TARGET2',
          },
          {
            target: 'TARGET3',
          },
        ],
      },
    },
  },
}

What has been Done ✅

  • support for custom actions
  • support for activities
  • automatic intial state definition
  • support for compound states
  • support for parallel state
  • ability to use xstate object
  • add remove functions
  • ... a lot of other things