-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
77 lines (64 loc) · 1.77 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
const EventEmitter = require('events').EventEmitter
const assert = require('assert')
const fsm = require('fsm')
module.exports = fsmEvent
// create an fsmEvent instance
// obj -> fn
function fsmEvent (start, events) {
if (typeof start === 'object') {
events = start
start = 'START'
}
assert.equal(typeof start, 'string')
assert.equal(typeof events, 'object')
assert.ok(events[start], 'invalid starting state ' + start)
assert.ok(fsm.validate(events))
const emitter = new EventEmitter()
emit._graph = fsm.reachable(events)
emit._emitter = emitter
emit._events = events
emit._state = start
emit.emit = emit
emit.on = on
return emit
// set a state listener
// str, fn -> null
function on (event, cb) {
emitter.on(event, cb)
}
// change the state
// str -> null
function emit (str) {
const nwState = emit._events[emit._state][str]
if (!reach(emit._state, nwState, emit._graph)) {
const err = 'invalid transition: ' + emit._state + ' -> ' + str
return emitter.emit('error', err)
}
const leaveEv = emit._state + ':leave'
const enterEv = nwState + ':enter'
if (!emit._state) return enter()
return leave()
function leave () {
if (!emitter._events[leaveEv]) enter()
else emitter.emit(leaveEv, enter)
}
function enter () {
if (!emitter._events[enterEv]) done()
else emitter.emit(enterEv, done)
}
function done () {
emit._state = nwState
emitter.emit(nwState)
emitter.emit('done')
}
}
}
// check if state can reach in reach
// str, str, obj -> bool
function reach (curr, next, reachable) {
if (!next) return false
if (!curr) return true
const here = reachable[curr]
if (!here || !here[next]) return false
return here[next].length === 1
}