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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sasha-z/fsm_js

v0.1.2

Published

fsm - Finite-state machine

Downloads

2

Readme

fsm - Finite-state machine

You can create simple FSM:

var machine = Machine([
  State('solid', ['liquid'], {initial: true}),
  State('liquid', ['solid', 'gas']),
  State('gas', ['liquid']),
]);

machine.go('liquid');
machine.go('gas');
machine.go('liquid');

Or more complicate:

var machine = Machine(
  [
    State('solid', [Transition({to: 'liquid'})], {initial: true}),
    State('liquid', [
      Transition({name: 'freeze', to: 'solid'}),
      'gas'
    ]),
    State(entity => entity == 'gas', [
      Transition({
        canTransite: function (entity) {
          return entity == 'liquid';
        },
        generateEntity: function () {
          return 'liquid';
        },
      })
    ]),
  ],
  {
    initResult: '',
    calculateResult: function (memo, entity) {
      return memo + entity[0];
    }
  }
);

machine.go('liquid');
machine.run('freeze');
machine.go('liquid');
machine.history() == ['liquid', 'solid', 'liquid'];
machine.result() == 'lsl';

Machine

You can create machine by calling Machine function

var machine = Machine(statesList, options);

where statesList must be array of State's. "options" is optional

Machine options

var machine = Machine(statesList, {
  onTransition(from, to) {
    // this function will be called whenever any transition happens
  },
  onUnhandledTransition(from, to) {
    // this function will be called only if corresponding Transition don't have `onTransition` handler
  },
  onUnsupportedTransition(from, to) {
    // this function will be called if `go` or `run` called but no supported transition found
  },
  initResult: '', // init value for result
  calculateResult: function (memo, entity) {
    // this function will be called whenever any transition happens. First argument is old result, and second is entity what must be combined with old result. Function must return combined result.
  }
});

Machine methods

Method go run transition to the state what identified by the entity, and return true if transition possible or false if not

machine.go(ace);

Method run run transition by the name, and return true if transition possible or false if not

m.run('transition');

Also:

// returns true if there are no transitions from current state, or false in other case
m.isFinished()
// returns last entity what runs transition
m.last()
// check if transition posible
m.canTransite(entity)
// returns all entities from runed transition
m.history()
// returns gathered result
m.result()
// reset state
m.restart()

State

State(identifier, transitionsList, options);

where transitionsList must be array of Transition's, and it's optional. "options" is optional. If some Transition in transitionsList have only to field it can be simplified this way:

State(identifier, [Transition({to: 'test'})]);
State(identifier, ['test']);

Both State are equal.

State identifier

State identifier can be object or function If it is object fsm will compere it with candidat object with operator "==", if comparision returns true thats mean the State is fit and it's be next State.

var machine = Machine([
  State(null, ['test'], {initial: true}),
  State('test'),
]);
machine.go('test');

If more complex logic needed you can use function. It must return true if entity is fit to this State

var testEntity = {id: "test"};
var machine = Machine([
  State(null, [testEntity], {initial: true}),
  State(function(entity) {
    return entity.id == "test";
  }),
]);
machine.go(testEntity);

State options

Option can have field "initial" if machine must be initialized with this State. If few States have this option machine will be initialized with first of them. The State what will be initial will not be in a history or result.

State(identifier, transitionsList, { initial: true });

Transition

Transition(parameters);
Transition({
  name: 'testing',
  to: 'test',
  canTransite: function (entity) {
  },
  generateEntity: function () {
  },
  onTransition: function (from) {
  }
});

Transitions parameters

name parameter used if you call run function on machine. It must be string and uniquly identify the transition. If transition runs using run function it must have generateEntity or to parameter, what will be used to identify State.

var machine = Machine([
  State(null, [
    Transition({
      name: 'testing',
      to: 'test'
    })
  ], {initial: true}),
  State('test'),
], options);
machine.run('testing');

canTransite parameter used if you call go function on machine. It must return true if trunsition to given entity is possible. If canTransiteused parameters can have generateEntity or to field to identify State, if them absent original(what passed to go function) entity used.

var machine = Machine([
  State(null, [
    Transition({
      canTransite: function (entity) {
        return entity == 'test'
      }
    })
  ], {initial: true}),
  State('test'),
], options);
machine.go('test');

to parameter is a minimum to create valid Transition. If there is no canTransite it used to deside if transition possible. If there is no generateEntity it used to identify State.

var machine = Machine([
  State(null, [
    Transition({
      to: 'test'
    })
  ], {initial: true}),
  State('test'),
], options);
machine.go('test');

generateEntity is used to identify suitable State.

var machine = Machine([
  State(null, [
    Transition({
      to: 'forward',
      generateEntity: function () {
        return 'test';
      }
    })
  ], {initial: true}),
  State('test'),
], options);
machine.go('forward');

onTransition calls when transition happens.

var machine = Machine([
  State(null, [
    Transition({
      to: 'test',
      onTransition: function (from) {
        console.log('it transite');
      }
    })
  ], {initial: true}),
  State('test'),
], options);
machine.go('test'); // it transite