JSPM

@germankuber/xstate-builders

1.0.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 2
  • Score
    100M100P100Q30807F
  • License MIT

Fluent builder pattern library for XState v5+ machines with full TypeScript support

Package Exports

  • @germankuber/xstate-builders

Readme

๐ŸŽฏ XState Builders

A complete fluent builder pattern library for creating XState v5+ state machines with full TypeScript support. Build complex state machines using an intuitive, type-safe API that makes XState more approachable and maintainable.

Build Status TypeScript XState License

โœจ Features

  • ๐Ÿ—๏ธ Fluent Builder Pattern: Intuitive, chainable API for constructing state machines
  • ๐ŸŽฏ Full TypeScript Support: Complete type safety with intelligent autocompletion
  • ๐Ÿท๏ธ Advanced State Features: Tags, meta, descriptions, outputs, and more
  • โฐ Delayed Transitions: Built-in support for time-based transitions
  • ๐Ÿ”„ Always Transitions: Automatic state transitions with guards
  • ๐Ÿ“ฆ Multi-Format Builds: CommonJS, ES Modules, and UMD distributions
  • ๐Ÿงช Comprehensive Tests: 400+ tests with 79% branch coverage
  • ๐Ÿ“š Live Examples: Interactive React examples included

๐Ÿš€ Quick Start

Installation

npm install @xstate/builders xstate

Basic Usage

import { 
  GenericMachineBuilder,
  GenericStateBuilder,
  GenericStatesBuilder,
  GenericActionsBuilder
} from '@xstate/builders';

// Create actions
const actions = GenericActionsBuilder.create()
  .withAssignAction('startLoading', { isLoading: true })
  .withAssignAction('completeLoading', { isLoading: false, result: 'success' })
  .build();

// Create states with advanced features
const idleState = GenericStateBuilder.create()
  .withTag('ready')
  .withDescription('Waiting for user action')
  .withTransition('START', 'loading', ['startLoading'])
  .build();

const loadingState = GenericStateBuilder.create()
  .withTags('loading', 'visible')
  .withAfter(
    GenericDelayedTransitionsBuilder.create()
      .afterWithActions(2000, ['completeLoading'], 'success')
      .build()
  )
  .build();

const successState = GenericStateBuilder.create()
  .asFinalStateWithOutput({ status: 'completed', timestamp: Date.now() })
  .withTag('success')
  .build();

// Build the complete machine
const machine = GenericMachineBuilder.create()
  .withId('dataProcessor')
  .withInitial('idle')
  .withContext({ isLoading: false, result: null })
  .withStates(
    GenericStatesBuilder.create()
      .withState('idle', idleState)
      .withState('loading', loadingState)
      .withState('success', successState)
      .build()
  )
  .withActions(actions)
  .build();

React Integration

import { useMachine } from '@xstate/react';

function MyComponent() {
  const [state, send] = useMachine(machine);
  
  return (
    <div>
      <p>Current state: {state.value}</p>
      <p>Tags: {Array.from(state.tags).join(', ')}</p>
      
      {state.context.isLoading && <div>Loading...</div>}
      
      <button 
        onClick={() => send({ type: 'START' })}
        disabled={!state.can({ type: 'START' })}
      >
        Start Process
      </button>
    </div>
  );
}

๐Ÿ“š Advanced Features

State Tags & Meta

const state = GenericStateBuilder.create()
  .withTags('loading', 'visible', 'critical')
  .withMeta(
    GenericMetaBuilder.create()
      .withComponent('LoadingSpinner')
      .withTimeout(5000)
      .build()
  )
  .withDescription('Shows loading indicator while processing')
  .build();

Delayed Transitions

const state = GenericStateBuilder.create()
  .withAfter(
    GenericDelayedTransitionsBuilder.create()
      .after(3000, 'timeout')  // Simple timeout
      .afterWithActions(1000, ['showWarning'], 'warning')  // With actions
      .afterWithGuard(5000, 'isStillWaiting', 'giveUp')   // With guard
      .build()
  )
  .build();

Final States with Output

const finalState = GenericStateBuilder.create()
  .asFinalStateWithOutput(
    GenericOutputBuilder.create()
      .withStatus('completed')
      .withResult('Processing finished successfully')
      .withTimestamp()
      .build()
  )
  .build();

Always Transitions

const state = GenericStateBuilder.create()
  .withAlways('processing', 'hasDataReady')  // Conditional auto-transition
  .build();

๐Ÿ› ๏ธ Development

Development Scripts

# Development with hot reload
npm run dev                    # Build library in watch mode
npm run example:dev            # Start example app (port 3001)

# Building
npm run build                  # Build library (CJS, ESM, UMD)
npm run example:build          # Build example app

# Testing
npm test                       # Run tests in watch mode
npm run test:ci               # Run tests with coverage
npm run type-check            # TypeScript type checking

Project Structure

@xstate/builders/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ lib/                  # Library entry point
โ”‚   โ”‚   โ””โ”€โ”€ index.ts
โ”‚   โ”œโ”€โ”€ xstate-builders/      # Builder implementations  
โ”‚   โ”‚   โ”œโ”€โ”€ MachineBuilder.ts
โ”‚   โ”‚   โ”œโ”€โ”€ StateBuilder.ts
โ”‚   โ”‚   โ”œโ”€โ”€ ActionsBuilder.ts
โ”‚   โ”‚   โ””โ”€โ”€ ...
โ”‚   โ””โ”€โ”€ __tests__/           # Test files
โ”œโ”€โ”€ examples/                # Example React app
โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ””โ”€โ”€ App.tsx         # Live examples
โ”‚   โ””โ”€โ”€ package.json        # References parent via file:..
โ”œโ”€โ”€ dist/                    # Built library files
โ”‚   โ”œโ”€โ”€ index.js            # CommonJS
โ”‚   โ”œโ”€โ”€ index.esm.js        # ES Modules
โ”‚   โ”œโ”€โ”€ index.umd.js        # UMD
โ”‚   โ””โ”€โ”€ index.d.ts          # TypeScript definitions
โ””โ”€โ”€ package.json            # Main package configuration

Builder Classes Available

Builder Purpose Key Methods
GenericMachineBuilder Complete state machines withId(), withStates(), withActions()
GenericStateBuilder Individual states withTag(), withMeta(), withAfter(), withAlways()
GenericStatesBuilder State collections withState(), build()
GenericActionsBuilder Actions withAssignAction(), withSendAction(), withSpawnChildAction()
GenericDelayedTransitionsBuilder Time-based transitions after(), afterWithActions(), afterWithGuard()
GenericOutputBuilder Final state outputs withStatus(), withResult(), withTimestamp()
GenericMetaBuilder State metadata withComponent(), withTimeout(), withLevel()

๐Ÿ“ฆ Multi-Format Distribution

The library is distributed in multiple formats for maximum compatibility:

  • CommonJS (dist/index.js): For Node.js and older bundlers
  • ES Modules (dist/index.esm.js): For modern bundlers and browsers
  • UMD (dist/index.umd.js): For direct browser usage
  • TypeScript (dist/index.d.ts): Complete type definitions

๐ŸŽฏ Why Use XState Builders?

Before (Raw XState):

const machine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  states: {
    inactive: {
      tags: ['off'],
      meta: { color: 'red' },
      on: {
        TOGGLE: {
          target: 'active',
          actions: ['setActive']
        }
      }
    },
    active: {
      tags: ['on'],
      meta: { color: 'green' },
      after: {
        5000: 'inactive'
      },
      on: {
        TOGGLE: {
          target: 'inactive', 
          actions: ['setInactive']
        }
      }
    }
  }
});

After (XState Builders):

const machine = GenericMachineBuilder.create()
  .withId('toggle')
  .withInitial('inactive')
  .withStates(
    GenericStatesBuilder.create()
      .withState('inactive', 
        GenericStateBuilder.create()
          .withTag('off')
          .withMeta({ color: 'red' })
          .withTransition('TOGGLE', 'active', ['setActive'])
          .build()
      )
      .withState('active',
        GenericStateBuilder.create()
          .withTag('on') 
          .withMeta({ color: 'green' })
          .withAfter(
            GenericDelayedTransitionsBuilder.create()
              .after(5000, 'inactive')
              .build()
          )
          .withTransition('TOGGLE', 'inactive', ['setInactive'])
          .build()
      )
      .build()
  )
  .build();

Benefits:

  • ๐Ÿ”ง More Readable: Self-documenting, fluent API
  • ๐ŸŽฏ Type Safe: Catch errors at compile time
  • ๐Ÿ“ฆ Reusable: Share builder configurations
  • ๐Ÿงฉ Composable: Mix and match builders
  • ๐Ÿ›ก๏ธ Reliable: Comprehensive test coverage

๐Ÿ“Š Test Coverage

The library maintains high test coverage across all builders:

Test Suites: 16 passed
Tests:       425 passed
Coverage:    79% branches, 55% statements

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

๐Ÿ“„ License

MIT License - see the LICENSE file for details.


Built with โค๏ธ for the XState community