UNPKG

uml-state-machine

Version:
242 lines (194 loc) 7.37 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.traverseState = traverseState; exports.buildStateMap = buildStateMap; exports.isAncestor = isAncestor; exports.walkOnEntry = walkOnEntry; exports.walkOnExit = walkOnExit; exports.findInitialState = findInitialState; exports.State = State; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _lodash = _interopRequireDefault(require("lodash")); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function traverseState(currentState, parent) { var callback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _lodash["default"].noop; callback(currentState, parent); _lodash["default"].map(currentState.states, function (state, name) { state.name = name; traverseState(state, currentState, callback); }); } function buildStateMap(smDef) { var stateMap = new Map(); if (!smDef.state) { throw { name: "Parser", message: "Root state is missing: " + smDef, details: smDef }; } smDef.state.name = "Root"; var callback = function callback(state, parent) { var parentModel = parent ? stateMap.get(parent.name) : undefined; var stateModel = State(smDef, state, parentModel); stateMap.set(state.name, stateModel); }; traverseState(smDef.state, null, callback); return stateMap; } function isEqualState(s1, s2) { return s1.name() === s2.name(); } function isAncestor(ancestorState, childState) { if (isEqualState(ancestorState, childState)) { return true; } var parent = childState.parent(); if (!parent) { return false; } if (isEqualState(ancestorState, parent)) { return true; } else { return isAncestor(ancestorState, parent); } } function processTransactionPre(context, stateNext) { var statePrevious = context.setStatePreviousFromCurrent(); context.setStateNext(stateNext); context.observers.onTransitionBegin(context, statePrevious.name(), stateNext.name()); walkOnExit(context, statePrevious, stateNext); } function processTransactionPost(context, stateNext) { var statePrevious = context.getStatePrevious(); walkOnEntry(context, statePrevious, stateNext); context.setStatePrevious(null); context.setStateNext(null); var stateCurrent = stateNext ? stateNext : statePrevious; context.setStateCurrent(stateCurrent.name()); context.observers.onTransitionEnd(context, statePrevious.name(), stateNext.name()); } function walkOnEntry(context, previousState, nextState) { if (!nextState) { return; } function onEntry(nextState) { context.observers.onEntry(context, nextState.name()); nextState.onEntry(context.actioner); } if (isEqualState(previousState, nextState)) { onEntry(nextState); } else if (!isAncestor(nextState, previousState)) { var parent = nextState.parent(); if (parent) { walkOnEntry(context, previousState, parent); onEntry(nextState); } } } function walkOnExit(context, previousState, nextState) { if (!nextState) { return; } //console.log("walkOnExit ", previousState.name(), nextState.name()) function onExit(state) { context.observers.onExit(context, state.name()); state.onExit(context.actioner); } if (isEqualState(previousState, nextState)) { onExit(nextState); } else if (!isAncestor(previousState, nextState)) { onExit(previousState); var parent = previousState.parent(); if (parent) { //console.log("walkOnExit parent ", parent.name()) walkOnExit(context, parent, nextState); } } } function findInitialState(stateInfo) { var states = stateInfo.states; var firstChildName = _lodash["default"].keys(states)[0]; if (firstChildName) { var firstChild = stateInfo.states[firstChildName]; firstChild.name = firstChildName; return findInitialState(firstChild); } else { return stateInfo.name; } } function createAllEvents(state, events) { return _lodash["default"].reduce(events, function (state, event) { //console.log("createAllEvents event ", state.name(), event) state[event] = function (context) {//console.log("unhandle event ", event, ", state: ", context.getStateCurrent().name()) }; return state; }, state); } function createEvents(state, transitions) { if (!transitions) { return state; } var events = _lodash["default"].groupBy(transitions, "event"); //console.log("event ", events) return _lodash["default"].reduce(events, function (state, transitions, key) { //console.log("adding event key ", key, " to state ", state.name()), //console.log("transitions ", transitions) state[key] = function (context, payload) { transitions.some(function (transition) { if (transition.condition && !transition.condition(context, payload)) { return false; } var nextStateName = transition.nextState; if (nextStateName) { var nextState = context.stateMap().get(nextStateName); processTransactionPre(context, nextState); if (transition.actions) { //console.log("transition.actions ", transition.actions.length) transition.actions.forEach(function (action) { return action(context.actioner); }); } processTransactionPost(context, nextState); } return true; }); }; return state; }, state); } function State(smDef) { var stateInfo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var stateParent = arguments.length > 2 ? arguments[2] : undefined; //console.log("State ", stateInfo.name); var state = _objectSpread({}, stateParent, {}, { isRoot: function isRoot() { return !stateParent; }, isLeaf: function isLeaf() { return !stateInfo.states; }, name: function name() { return stateInfo.name; }, parent: function parent() { return stateParent; }, info: function info() { return stateInfo; }, onEntry: function onEntry(context) { if (stateInfo.onEntry) stateInfo.onEntry(context); }, onExit: function onExit(context) { if (stateInfo.onExit) stateInfo.onExit(context); } }); if (!stateParent) { state = createAllEvents(state, smDef.events); } state = createEvents(state, stateInfo.transitions); return state; }