{"id":26294612,"url":"https://github.com/afiore/statemachine.js","last_synced_at":"2025-10-30T19:06:13.195Z","repository":{"id":137468019,"uuid":"1787599","full_name":"afiore/stateMachine.js","owner":"afiore","description":"My own javascript reinterpretation of Ruby on Rails' plugin 'Acts as a State Machine' ","archived":false,"fork":false,"pushed_at":"2011-05-23T12:27:19.000Z","size":694,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-05-08T23:07:05.365Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/afiore.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-05-23T11:22:43.000Z","updated_at":"2017-03-05T22:42:03.000Z","dependencies_parsed_at":"2023-07-18T22:45:13.769Z","dependency_job_id":null,"html_url":"https://github.com/afiore/stateMachine.js","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/afiore/stateMachine.js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afiore%2FstateMachine.js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afiore%2FstateMachine.js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afiore%2FstateMachine.js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afiore%2FstateMachine.js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/afiore","download_url":"https://codeload.github.com/afiore/stateMachine.js/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afiore%2FstateMachine.js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281862935,"owners_count":26574735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-30T02:00:06.501Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-15T03:31:12.090Z","updated_at":"2025-10-30T19:06:13.173Z","avatar_url":"https://github.com/afiore.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# StateMachine.js\n\nMy own JavaScript re-interpretation of Ruby on Rails' pluging [Acts as a state machine](https://github.com/rubyist/aasm), designed to run on both node and the browser.\nProvides a convenient mechanism for defining a set of machine states and the possible transitions between them.\n\n## Usage\n\n\n    function VendingMachine () {\n      StateMachine.call(this);\n      ...\n      this.initialize(function () {\n        this.addState('off');\n        this.addState('on');\n        this.addState('money-loaded');\n        this.addState('product-selected');\n\n        this.addTransition('switchOn', {\n          from: 'off',\n          to: 'on'\n        });\n        this.addTransition('switchOff', {\n          from: 'on',\n          to: 'off'\n        });\n        this.addTransition('loadMoney', {\n            from: 'on',\n            to: 'money-loaded'\n          },\n          function () {\n            var self = this;\n            //reset timeout if one already has been set\n            if (this._timeout) {\n              clearTimeout(this._timeout);\n            }\n            this._timeout = setTimeout(function () {\n              self.endTransaction();\n            }, 120000);\n          }\n        );\n        this.addTransition('selectProduct', {\n          from: 'money-loaded',\n          to: 'product-selected'\n        });\n        this.addTransition('endTransaction', {\n             from: ['product-selected', 'money-loaded'],\n             to: 'on'\n           },\n           function () {\n             this._calculateChange();\n             this._selectedProduct = null;\n             this._moneyLoaded = 0;\n           }\n        );\n      });\n    }\n    _.extend(VendingMachine.prototype, StateMachine.prototype);\n\nSee [example/vending-machine.js](https://github.com/afiore/stateMachine.js/blob/master/example/vending-machine.js) for the complete snippet.\n\n## API\n\n### States\n\n    currentState()\n\nReturns the instance's current state.\n\n---\n\n    addState(state, onEnter, onExit)\n\nDefines a machine state.\n\nParameters:\n\n- _state_: the name of a machine state (String).\n- _onEnter:_ a callback to be executed when the object enters the state (Function, optional).\n- _onExit:_ a callback to be executed when the object leaves the state (Function, optional).\n\nEvents:\n\nWhen entering a state, the object will fire two events using the [EventEmitter](http://nodejs.org/docs/v0.4.7/api/events.html) API:\n\n- `state:\u003cstate-name\u003e`: an event suitable for handling a single specific state change (will also pass along a `data` argument if the `onEnter` callback returns a value).\n- `state-change`: a generic event suitable for handling several state changes through a single function.\n\nevent listener example:\n\n        vendingMachine.on('state-change', function onStateChange(enteringState, data) {\n          switch (enteringState) {\n            case 'money-loaded':\n              console.info('money has been loaded');\n              break;\n            case 'off':\n            ...\n          }\n        });\n\n### Transitions\n\n    addTransition(transitionName, fromTo, onTransition)\n\nDefines a valid transition between machine states and implements it as an executable instance method.\n\nParameters:\n\n- _transitionName:_ the name of the transition and of the method thereof (String).\n- _fromTo:_  An object mapping from what to what internal states the machine may transit (Object). \n  While the `from` key may be either a string or an array of multiple strings, the value of the `to` key must always be a single string.\n- _onTransition:_ a callback to be executed after the state change.\n\nA transition method will always throw an error if the instance's current state is not valid for that specific transition (that is, if the value returned by `#currentState()` is not one of those specified in the `from` value of `fromTo` parameter).\n\n---\n\nNotes:\n\n- The object's initial state is implicitly set to the one added first.\n- In both `addState` and `addTransition` callbacks, the value of `this` is automatically bound to the instance object.\n- If the `onEnter` or the `onTransition` callbacks return a value, this is passed along to event listeners as the `data` argument (see the `onStateChange` function in the example above).\n\n## Dependencies\n\nStateMachine.js requires the following third party libraries:\n\n* DocumentCloud's [underscore.js](http://documentcloud.github.com/underscore) (JavaScript functional programming utility belt).\n* Oliver Caldwell's cross-platform implementation of nodejs [EventEmitter](https://github.com/Wolfy87/EventEmitter/) API.\n* [Jasmine](https://github.com/pivotal/jasmine) and [Jasmine-node](https://github.com/pivotal/jasmine-nodejs) (Unit testing)\n\n\n## Running the test suite\n\nIn nodejs:\n\n    npm install -g underscore jasmine-node\n    cd \u003cproject_path\u003e/test \u0026\u0026 jasmine-node specs\n\nIn the browser, just open `test/index.html` (both the HTTP:// and the file:// protocols will work).\n\n## TODO\n\n- Allow to define custom conditions (elsewhere dubbed *guards*) whereby transitions may or may not be executed.\n- Write more examples.\n- Make the API more dry.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fafiore%2Fstatemachine.js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fafiore%2Fstatemachine.js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fafiore%2Fstatemachine.js/lists"}