npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@scxml/parser

v0.1.0

Published

A comprehensive TypeScript SCXML parsing and manipulation library

Readme

SCXML TypeScript Parser

CI Documentation npm version Coverage Status

A comprehensive TypeScript library for parsing, creating, modifying, validating, and serializing SCXML (State Chart XML) documents with full W3C specification support.

📖 View Full Documentation

Features

  • 🚀 Full SCXML Support: Complete implementation of W3C SCXML specification
  • 🏗️ Builder API: Fluent, type-safe API for creating SCXML documents
  • 🔧 Modification API: Programmatically modify existing SCXML documents
  • Validation: Comprehensive validation with detailed error reporting
  • 📝 XML Serialization: Convert SCXML documents back to XML
  • 🎯 TypeScript: Full TypeScript support with complete type definitions
  • Performance: Efficient parsing and manipulation of large state machines
  • 🧪 Well Tested: Comprehensive test suite with edge case coverage

Installation

npm install @scxml/parser

Quick Start

Creating SCXML Documents

import { SCXML } from '@scxml/parser';

// Create a simple state machine
const document = SCXML.create()
  .name('traffic-light')
  .initial('red')
  .addState(SCXML.state('red')
    .addTransition(SCXML.transition()
      .event('timer')
      .target('green')
      .build())
    .build())
  .addState(SCXML.state('green')
    .addTransition(SCXML.transition()
      .event('timer')
      .target('yellow')
      .build())
    .build())
  .addState(SCXML.state('yellow')
    .addTransition(SCXML.transition()
      .event('timer')
      .target('red')
      .build())
    .build())
  .build();

Parsing Existing SCXML

import { SCXML } from '@scxml/parser';

const xmlString = `
<scxml initial="idle" xmlns="http://www.w3.org/2005/07/scxml">
  <state id="idle">
    <transition event="start" target="active"/>
  </state>
  <state id="active">
    <transition event="stop" target="idle"/>
  </state>
</scxml>`;

const document = SCXML.parse(xmlString);

Serializing to XML

import { SCXML } from '@scxml/parser';

// Convert document back to XML
const xml = SCXML.serialize(document, { spaces: 2 });
console.log(xml);

Modifying Documents

import { SCXML } from '@scxml/parser';

const modifier = SCXML.modify(document)
  .addState(SCXML.state('error')
    .addOnEntry(SCXML.onEntry()
      .addLog({ label: 'Error occurred' })
      .build())
    .build())
  .addTransitionToState('active', SCXML.transition()
    .event('error')
    .target('error')
    .build());

const modifiedDocument = modifier.getDocument();

Complex Example: Chatbot State Machine

Here's a more complex example showing a chatbot conversation flow:

import { SCXML } from '@scxml/parser';

// Create a chatbot conversation state machine
const chatbotModel = SCXML.create()
  .name('chatbot-dialogue')
  .initial('greeting')
  .datamodel('ecmascript')
  .addDataModel(SCXML.dataModel()
    .addData(SCXML.data('userName').expr('null').build())
    .addData(SCXML.data('conversationContext').content('{}').build())
    .addData(SCXML.data('confidenceScore').expr('0.8').build())
    .build())
  .addState(SCXML.state('greeting')
    .addOnEntry(SCXML.onEntry()
      .addLog({ label: 'Bot: Hello! How can I help you today?' })
      .addSend({ event: 'bot.message', target: 'ui' })
      .build())
    .addTransition(SCXML.transition()
      .event('user.message')
      .target('understanding')
      .addAssign({ location: 'conversationContext.lastUserMessage', expr: '_event.data.text' })
      .build())
    .build())
  .addState(SCXML.state('understanding')
    .addInvoke(SCXML.invoke()
      .id('nlp-service')
      .type('http')
      .src('/api/nlp/understand')
      .addParam({ name: 'text', expr: 'conversationContext.lastUserMessage' })
      .build())
    .addTransition(SCXML.transition()
      .event('nlp.understood')
      .target('responding')
      .addAssign({ location: 'conversationContext.intent', expr: '_event.data.intent' })
      .build())
    .addTransition(SCXML.transition()
      .event('nlp.error')
      .target('fallback')
      .build())
    .build())
  .addState(SCXML.state('responding')
    .addTransition(SCXML.transition()
      .event('confidence.high')
      .cond('confidenceScore > 0.7')
      .target('generating-response')
      .build())
    .addTransition(SCXML.transition()
      .event('confidence.low')
      .cond('confidenceScore <= 0.3')
      .target('fallback')
      .build())
    .build())
  .addState(SCXML.state('generating-response')
    .addOnEntry(SCXML.onEntry()
      .addLog({ label: 'Generating response' })
      .build())
    .addTransition(SCXML.transition()
      .event('response.ready')
      .target('delivering')
      .build())
    .build())
  .addState(SCXML.state('delivering')
    .addOnEntry(SCXML.onEntry()
      .addSend({ event: 'bot.message', target: 'ui' })
      .build())
    .addTransition(SCXML.transition()
      .event('message.delivered')
      .target('waiting')
      .build())
    .build())
  .addState(SCXML.state('waiting')
    .addTransition(SCXML.transition()
      .event('user.message')
      .target('understanding')
      .build())
    .addTransition(SCXML.transition()
      .event('conversation.end')
      .target('goodbye')
      .build())
    .build())
  .addState(SCXML.state('fallback')
    .addOnEntry(SCXML.onEntry()
      .addLog({ label: 'Using fallback response' })
      .build())
    .addTransition(SCXML.transition()
      .event('user.message')
      .target('understanding')
      .build())
    .build())
  .addFinal({ id: 'goodbye' })
  .build();

// Validate the state machine
const errors = SCXML.validate(chatbotModel);
if (errors.length > 0) {
  console.log('Validation errors:', errors);
}

// Serialize to XML for storage or transmission
const xml = SCXML.serialize(chatbotModel, { spaces: 2 });

API Reference

Core Functions

SCXML.create()

Creates a new SCXML document builder.

SCXML.parse(xmlString: string)

Parses an SCXML XML string into a document object.

SCXML.validate(document: SCXMLDocument)

Validates an SCXML document and returns validation errors.

SCXML.serialize(document: SCXMLDocument, options?: SerializationOptions)

Serializes an SCXML document to XML string.

SCXML.modify(document: SCXMLDocument)

Creates a modifier for programmatically changing SCXML documents.

Builders

State Builder

SCXML.state('my-state')
  .initial('child-state')
  .addTransition(transition)
  .addOnEntry(onEntryAction)
  .addOnExit(onExitAction)
  .addInvoke(invokeElement)
  .addState(childState)
  .build();

Transition Builder

SCXML.transition()
  .event('my-event')
  .cond('x > 0')
  .target('target-state')
  .type('external')
  .addLog({ label: 'Transitioning' })
  .addAssign({ location: 'x', expr: 'x + 1' })
  .addSend({ event: 'notification', target: 'parent' })
  .build();

Data Model Builder

SCXML.dataModel()
  .addData(SCXML.data('counter').expr('0').build())
  .addData(SCXML.data('config').content('{"enabled": true}').build())
  .build();

Action Builders

// Entry/Exit Actions
SCXML.onEntry()
  .addLog({ label: 'Entering state' })
  .addAssign({ location: 'count', expr: 'count + 1' })
  .addRaise({ event: 'internal.entered' })
  .addSend({ event: 'notify', target: 'parent' })
  .build();

// Parallel States
SCXML.parallel('concurrent-region')
  .addState(branch1)
  .addState(branch2)
  .build();

// Invocations
SCXML.invoke()
  .type('http')
  .src('/api/service')
  .id('my-service')
  .autoforward(true)
  .build();

Modification API

const modifier = SCXML.modify(document);

// State management
modifier.addState(newState);
modifier.removeState('state-id');
modifier.updateState('state-id', state => {
  state.initial = 'new-initial';
  return state;
});
modifier.renameState('old-id', 'new-id');

// Transition management
modifier.addTransitionToState('state-id', transition);
modifier.removeTransitionFromState('state-id', t => t.event === 'remove-me');
modifier.updateTransitionInState('state-id',
  t => t.event === 'update-me',
  t => { t.target = 'new-target'; return t; }
);

// Data management
modifier.addDataToModel(dataElement);
modifier.updateDataInModel('data-id', d => {
  d.expr = 'newValue';
  return d;
});
modifier.removeDataFromModel('data-id');

// Utility methods
modifier.getAllStateIds();
modifier.findState('state-id');
modifier.clone();

const modifiedDocument = modifier.getDocument();

Validation

import { SCXML, ValidationError } from 'scxml-parser';

const errors: ValidationError[] = SCXML.validate(document);

errors.forEach(error => {
  console.log(`${error.severity}: ${error.message} at ${error.path}`);
});

Advanced XState Integration

import { SCXML, XStateConverter } from 'scxml-parser';

const converter = new XStateConverter({
  customActions: {
    myCustomAction: (context, event) => {
      console.log('Custom action executed');
    }
  },
  customGuards: {
    isEnabled: (context, event) => context.enabled === true
  },
  customServices: {
    myService: (context, event) => {
      return fetch('/api/my-service');
    }
  }
});

const machine = converter.createMachine(document);

SCXML Feature Support

This library supports all major SCXML features:

  • Basic States: Simple and compound states
  • Parallel States: Concurrent state regions
  • Final States: Terminal states with done data
  • Transitions: Event-driven, conditional, and targetless transitions
  • Actions: Entry, exit, and transition actions
  • Data Model: ECMAScript and other data models
  • Executable Content: Raise, log, assign, send, cancel, script, if, foreach
  • Invocations: External service invocations
  • History States: Shallow and deep history
  • Validation: Comprehensive structural validation

MCP Integration for AI Agents

This library is designed to work seamlessly with Model Context Protocol (MCP) systems, allowing AI agents to:

  1. Create State Models: Define their own behavioral state machines
  2. Update Models: Dynamically modify state machines based on learning
  3. Execute Models: Use XState for actual state machine execution
  4. Persist Models: Serialize state machines for storage and transmission
  5. Validate Models: Ensure state machine correctness before execution

Example MCP Tool Integration

// MCP tool for AI agents to manage their state models
export async function updateAgentWorldModel(
  currentModelXml: string,
  updates: StateUpdate[]
): Promise<string> {
  const document = SCXML.parse(currentModelXml);
  const modifier = SCXML.modify(document);

  updates.forEach(update => {
    switch (update.type) {
      case 'add-state':
        modifier.addState(SCXML.state(update.stateId)
          .addOnEntry(SCXML.onEntry()
            .addLog({ label: `Entering ${update.stateId}` })
            .build())
          .build());
        break;
      case 'add-transition':
        modifier.addTransitionToState(update.fromState,
          SCXML.transition()
            .event(update.event)
            .target(update.toState)
            .build());
        break;
    }
  });

  const updatedDocument = modifier.getDocument();

  // Validate before returning
  const errors = SCXML.validate(updatedDocument);
  if (errors.length > 0) {
    throw new Error(`Invalid state model: ${errors.map(e => e.message).join(', ')}`);
  }

  return SCXML.serialize(updatedDocument);
}

Testing

Run the test suite:

npm test

The library includes comprehensive tests covering:

  • Parser functionality with various SCXML documents
  • Builder API for all SCXML elements
  • Modification operations
  • Validation rules
  • XState conversion accuracy
  • Serialization round-trips
  • Integration scenarios
  • Performance with large state machines

Contributing

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

License

MIT License - see LICENSE file for details.

Acknowledgments

  • Built on the W3C SCXML specification
  • Integrates with XState for execution
  • Designed for AI agent world modeling use cases
  • Supports Model Context Protocol (MCP) integration