UNPKG

@rotorsoft/flow

Version:

A minimalistic state machine

58 lines (48 loc) 1.78 kB
/*! * @rotorsoft/flow * Copyright(c) 2020 rotorsoft@outlook.com * MIT Licensed */ module.exports = ({ actions, params = {}, reducer, invoked, shifted }) => { if (typeof actions !== 'object') throw Error('actions must be an object') if (typeof reducer !== 'function') throw Error('reducer must be a function') const $ = { state: {}, scope: { level: -1 }, yielding: null, stack: [] } const invoke = (callback, root) => { const name = root || callback.name if (!name && callback !== $.yielding) { $.yielding = callback return $ } delete $.yielding if (name) { const recur = $.scope.name === name ? $.scope.recur + 1 : 0 $.scope = { name, recur, parent: { ...$.scope }, level: $.scope.level + 1, depth: $.stack.length } $.stack.unshift(name) } const any = callback($.state, $.scope, { params, actions }) if (invoked) invoked(name, any, $.scope) Array.isArray(any) ? $.stack.unshift(...any) : any ? $.stack.unshift(any) : null return shift() } const shift = () => { const any = $.stack.shift() if (shifted) shifted(any, $.scope) $.done = !$.stack.length if (!any) return $ if (typeof any === 'string') $.scope = $.scope.parent return next(any) } const next = any => { if (typeof any === 'function') return invoke(any) if (typeof any === 'object') $.state = reducer($.state, $.scope, any) return shift() } return any => { if (typeof any === 'function' && !$.stack.length) return invoke(any, any.name || '$root') if (typeof any === 'object') { $.state = reducer($.state, $.scope, any) return $.yielding ? invoke($.yielding) : shift() } throw 'invalid operation' } }