mmir-lib
Version:
MMIR (Mobile Multimodal Interaction and Relay) library
3,015 lines • 109 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["scionCoreLib"] = factory();
else
root["scionCoreLib"] = factory();
})(self, function() {
return /******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./index.js":
/*!******************!*\
!*** ./index.js ***!
\******************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
module.exports = __webpack_require__(/*! @scion-scxml/core */ "./node_modules/@scion-scxml/core/lib/Statechart.js");
/***/ }),
/***/ "./node_modules/@scion-scxml/core-base/lib/ArraySet.js":
/*!*************************************************************!*\
!*** ./node_modules/@scion-scxml/core-base/lib/ArraySet.js ***!
\*************************************************************/
/***/ ((module) => {
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
/* begin ArraySet */
/** @constructor */
function ArraySet(l) {
l = l || [];
this.o = new Set(l);
}
ArraySet.prototype = {
add: function add(x) {
this.o.add(x);
},
remove: function remove(x) {
return this.o["delete"](x);
},
union: function union(l) {
var _iterator = _createForOfIteratorHelper(l.o),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var v = _step.value;
this.o.add(v);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return this;
},
difference: function difference(l) {
var _iterator2 = _createForOfIteratorHelper(l.o),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var v = _step2.value;
this.o["delete"](v);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return this;
},
contains: function contains(x) {
return this.o.has(x);
},
iter: function iter() {
return Array.from(this.o);
},
isEmpty: function isEmpty() {
return !this.o.size;
},
size: function size() {
return this.o.size;
},
equals: function equals(s2) {
if (this.o.size !== s2.size()) {
return false;
}
var _iterator3 = _createForOfIteratorHelper(this.o),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var v = _step3.value;
if (!s2.contains(v)) {
return false;
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
return true;
},
toString: function toString() {
return this.o.size === 0 ? '<empty>' : Array.from(this.o).join(',\n');
}
};
module.exports = ArraySet;
/***/ }),
/***/ "./node_modules/@scion-scxml/core-base/lib/constants.js":
/*!**************************************************************!*\
!*** ./node_modules/@scion-scxml/core-base/lib/constants.js ***!
\**************************************************************/
/***/ ((module) => {
var STATE_TYPES = {
BASIC: 0,
COMPOSITE: 1,
PARALLEL: 2,
HISTORY: 3,
INITIAL: 4,
FINAL: 5
};
var SCXML_IOPROCESSOR_TYPE = 'http://www.w3.org/TR/scxml/#SCXMLEventProcessor';
var HTTP_IOPROCESSOR_TYPE = 'http://www.w3.org/TR/scxml/#BasicHTTPEventProcessor';
var RX_TRAILING_WILDCARD = /\.\*$/;
module.exports = {
STATE_TYPES: STATE_TYPES,
SCXML_IOPROCESSOR_TYPE: SCXML_IOPROCESSOR_TYPE,
HTTP_IOPROCESSOR_TYPE: HTTP_IOPROCESSOR_TYPE,
RX_TRAILING_WILDCARD: RX_TRAILING_WILDCARD
};
/***/ }),
/***/ "./node_modules/@scion-scxml/core-base/lib/helpers.js":
/*!************************************************************!*\
!*** ./node_modules/@scion-scxml/core-base/lib/helpers.js ***!
\************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
var constants = __webpack_require__(/*! ./constants */ "./node_modules/@scion-scxml/core-base/lib/constants.js"),
STATE_TYPES = constants.STATE_TYPES,
RX_TRAILING_WILDCARD = constants.RX_TRAILING_WILDCARD;
var printTrace = false;
module.exports = {
extend: extend,
transitionWithTargets: transitionWithTargets,
transitionComparator: transitionComparator,
initializeModel: initializeModel,
isEventPrefixMatch: isEventPrefixMatch,
isTransitionMatch: isTransitionMatch,
scxmlPrefixTransitionSelector: scxmlPrefixTransitionSelector,
eventlessTransitionSelector: eventlessTransitionSelector,
getTransitionWithHigherSourceChildPriority: getTransitionWithHigherSourceChildPriority,
sortInEntryOrder: sortInEntryOrder,
getStateWithHigherSourceChildPriority: getStateWithHigherSourceChildPriority,
initializeModelGeneratorFn: initializeModelGeneratorFn,
deserializeSerializedConfiguration: deserializeSerializedConfiguration,
deserializeHistory: deserializeHistory
};
function extend(to, from) {
Object.keys(from).forEach(function (k) {
to[k] = from[k];
});
return to;
}
;
function transitionWithTargets(t) {
return t.targets;
}
function transitionComparator(t1, t2) {
return t1.documentOrder - t2.documentOrder;
}
function initializeModel(rootState, opts) {
var transitions = [],
idToStateMap = new Map(),
documentOrder = 0; //TODO: need to add fake ids to anyone that doesn't have them
//FIXME: make this safer - break into multiple passes
var idCount = {};
function generateId(type) {
if (idCount[type] === undefined) idCount[type] = 0;
do {
var count = idCount[type]++;
var id = '$generated-' + type + '-' + count;
} while (idToStateMap.has(id));
return id;
}
function wrapInFakeRootState(state) {
return {
$deserializeDatamodel: state.$deserializeDatamodel || function () {},
$serializeDatamodel: state.$serializeDatamodel || function () {
return null;
},
$idToStateMap: idToStateMap,
//keep this for handy deserialization of serialized configuration
docUrl: state.docUrl,
name: state.name,
states: [{
$type: 'initial',
transitions: [{
target: state
}]
}, state]
};
}
var statesWithInitialAttributes = [];
/**
@this {SCTransition}
*/
function transitionToString(sourceState) {
return "".concat(sourceState, " -- ").concat(this.events ? '(' + this.events.join(',') + ')' : null).concat(this.cond ? '[' + this.cond.name + ']' : '', " --> ").concat(this.targets ? this.targets.join(',') : null);
}
/**
@this {SCState}
*/
function stateToString() {
return this.id;
}
function populateStateIdMap(state) {
//populate state id map
if (state.id) {
idToStateMap.set(state.id, state);
}
if (state.states) {
for (var j = 0, len = state.states.length; j < len; j++) {
populateStateIdMap(state.states[j]);
}
}
}
function traverse(ancestors, state) {
if (printTrace) state.toString = stateToString; //add to global transition and state id caches
if (state.transitions) transitions.push.apply(transitions, state.transitions); //create a default type, just to normalize things
//this way we can check for unsupported types below
state.$type = state.$type || 'state'; //add ancestors and depth properties
state.ancestors = ancestors;
state.depth = ancestors.length;
state.parent = ancestors[0];
state.documentOrder = documentOrder++; //add some information to transitions
state.transitions = state.transitions || [];
for (var j = 0, len = state.transitions.length; j < len; j++) {
var transition = state.transitions[j];
transition.documentOrder = documentOrder++;
transition.source = state;
if (printTrace) transition.toString = transitionToString.bind(transition, state);
}
; //recursive step
if (state.states) {
var ancs = [state].concat(ancestors);
for (var j = 0, len = state.states.length; j < len; j++) {
traverse(ancs, state.states[j]);
}
} //setup fast state type
switch (state.$type) {
case 'parallel':
state.typeEnum = STATE_TYPES.PARALLEL;
state.isAtomic = false;
break;
case 'initial':
state.typeEnum = STATE_TYPES.INITIAL;
state.isAtomic = true;
break;
case 'history':
state.typeEnum = STATE_TYPES.HISTORY;
state.isAtomic = true;
break;
case 'final':
state.typeEnum = STATE_TYPES.FINAL;
state.isAtomic = true;
break;
case 'state':
case 'scxml':
if (state.states && state.states.length) {
state.typeEnum = STATE_TYPES.COMPOSITE;
state.isAtomic = false;
} else {
state.typeEnum = STATE_TYPES.BASIC;
state.isAtomic = true;
}
break;
default:
throw new Error('Unknown state type: ' + state.$type);
} //descendants property on states will now be populated. add descendants to this state
if (state.states) {
state.descendants = state.states.concat(state.states.map(function (s) {
return s.descendants;
}).reduce(function (a, b) {
return a.concat(b);
}, []));
} else {
state.descendants = [];
}
var initialChildren;
if (state.typeEnum === STATE_TYPES.COMPOSITE) {
//set up initial state
if (Array.isArray(state.initial) || typeof state.initial === 'string') {
statesWithInitialAttributes.push(state);
} else {
//take the first child that has initial type, or first child
initialChildren = state.states.filter(function (child) {
return child.$type === 'initial';
});
state.initialRef = [initialChildren.length ? initialChildren[0] : state.states[0]];
checkInitialRef(state);
}
} //hook up history
if (state.typeEnum === STATE_TYPES.COMPOSITE || state.typeEnum === STATE_TYPES.PARALLEL) {
var historyChildren = state.states.filter(function (s) {
return s.$type === 'history';
});
state.historyRef = historyChildren;
} //now it's safe to fill in fake state ids
if (!state.id) {
state.id = generateId(state.$type);
idToStateMap.set(state.id, state);
} //normalize onEntry/onExit, which can be single fn or array, or array of arrays (blocks)
['onEntry', 'onExit'].forEach(function (prop) {
if (state[prop]) {
if (!Array.isArray(state[prop])) {
state[prop] = [state[prop]];
}
if (!state[prop].every(function (handler) {
return Array.isArray(handler);
})) {
state[prop] = [state[prop]];
}
}
});
if (state.invokes && !Array.isArray(state.invokes)) {
state.invokes = [state.invokes];
state.invokes.forEach(function (invoke) {
if (invoke.finalize && !Array.isArray(invoke.finalize)) {
invoke.finalize = [invoke.finalize];
}
});
}
} //TODO: convert events to regular expressions in advance
function checkInitialRef(state) {
if (!state.initialRef) throw new Error('Unable to locate initial state for composite state: ' + state.id);
}
function connectIntialAttributes() {
for (var j = 0, len = statesWithInitialAttributes.length; j < len; j++) {
var s = statesWithInitialAttributes[j];
var initialStates = Array.isArray(s.initial) ? s.initial : [s.initial];
s.initialRef = initialStates.map(function (initialState) {
return idToStateMap.get(initialState);
});
checkInitialRef(s);
}
}
var RX_WHITESPACE = /\s+/;
function connectTransitionGraph() {
//normalize as with onEntry/onExit
for (var i = 0, len = transitions.length; i < len; i++) {
var t = transitions[i];
if (t.onTransition && !Array.isArray(t.onTransition)) {
t.onTransition = [t.onTransition];
} //normalize "event" attribute into "events" attribute
if (typeof t.event === 'string') {
t.events = t.event.trim().split(RX_WHITESPACE);
}
delete t.event;
if (t.targets || typeof t.target === 'undefined') {
//targets have already been set up
continue;
}
if (typeof t.target === 'string') {
var target = idToStateMap.get(t.target);
if (!target) throw new Error('Unable to find target state with id ' + t.target);
t.target = target;
t.targets = [t.target];
} else if (Array.isArray(t.target)) {
t.targets = t.target.map(function (target) {
if (typeof target === 'string') {
target = idToStateMap.get(target);
if (!target) throw new Error('Unable to find target state with id ' + t.target);
return target;
} else {
return target;
}
});
} else if (_typeof(t.target) === 'object') {
t.targets = [t.target];
} else {
throw new Error('Transition target has unknown type: ' + t.target);
}
} //hook up LCA - optimization
for (var i = 0, len = transitions.length; i < len; i++) {
var t = transitions[i];
if (t.targets) t.lcca = getLCCA(t.source, t.targets[0]); //FIXME: we technically do not need to hang onto the lcca. only the scope is used by the algorithm
t.scope = getScope(t);
}
}
function getScope(transition) {
//Transition scope is normally the least common compound ancestor (lcca).
//Internal transitions have a scope equal to the source state.
var transitionIsReallyInternal = transition.type === 'internal' && transition.source.typeEnum === STATE_TYPES.COMPOSITE && //is transition source a composite state
transition.source.parent && //root state won't have parent
transition.targets && //does it target its descendants
transition.targets.every(function (target) {
return transition.source.descendants.indexOf(target) > -1;
});
if (!transition.targets) {
return null;
} else if (transitionIsReallyInternal) {
return transition.source;
} else {
return transition.lcca;
}
}
function getLCCA(s1, s2) {
var commonAncestors = [];
for (var j = 0, len = s1.ancestors.length; j < len; j++) {
var anc = s1.ancestors[j];
if ((opts && opts.legacySemantics ? anc.typeEnum === STATE_TYPES.COMPOSITE : anc.typeEnum === STATE_TYPES.COMPOSITE || anc.typeEnum === STATE_TYPES.PARALLEL) && anc.descendants.indexOf(s2) > -1) {
commonAncestors.push(anc);
}
}
;
if (!commonAncestors.length) throw new Error("Could not find LCA for states.");
return commonAncestors[0];
} //main execution starts here
//FIXME: only wrap in root state if it's not a compound state
populateStateIdMap(rootState);
var fakeRootState = wrapInFakeRootState(rootState); //I wish we had pointer semantics and could make this a C-style "out argument". Instead we return him
traverse([], fakeRootState);
connectTransitionGraph();
connectIntialAttributes();
return fakeRootState;
}
function isEventPrefixMatch(prefix, fullName) {
prefix = prefix.replace(RX_TRAILING_WILDCARD, '');
if (prefix === fullName) {
return true;
}
if (prefix.length > fullName.length) {
return false;
}
if (fullName.charAt(prefix.length) !== '.') {
return false;
}
return fullName.indexOf(prefix) === 0;
}
function isTransitionMatch(t, eventName) {
return t.events.some(function (tEvent) {
return tEvent === '*' || isEventPrefixMatch(tEvent, eventName);
});
}
function scxmlPrefixTransitionSelector(t, event, evaluator, selectEventlessTransitions) {
return (selectEventlessTransitions ? !t.events : t.events && event && event.name && isTransitionMatch(t, event.name)) && (!t.cond || evaluator(t.cond));
}
function eventlessTransitionSelector(state) {
return state.transitions.filter(function (transition) {
return !transition.events || transition.events && transition.events.length === 0;
});
} //priority comparison functions
function getTransitionWithHigherSourceChildPriority(_args) {
var t1 = _args[0],
t2 = _args[1];
var r = getStateWithHigherSourceChildPriority(t1.source, t2.source); //compare transitions based first on depth, then based on document order
if (t1.source.depth < t2.source.depth) {
return t2;
} else if (t2.source.depth < t1.source.depth) {
return t1;
} else {
if (t1.documentOrder < t2.documentOrder) {
return t1;
} else {
return t2;
}
}
}
function sortInEntryOrder(s1, s2) {
return getStateWithHigherSourceChildPriority(s1, s2) * -1;
}
function getStateWithHigherSourceChildPriority(s1, s2) {
//compare states based first on depth, then based on document order
if (s1.depth > s2.depth) {
return -1;
} else if (s1.depth < s2.depth) {
return 1;
} else {
//Equality
if (s1.documentOrder < s2.documentOrder) {
return 1;
} else if (s1.documentOrder > s2.documentOrder) {
return -1;
} else {
return 0;
}
}
}
function initializeModelGeneratorFn(modelFn, opts, interpreter) {
return modelFn.call(interpreter, opts._x, opts._x._sessionid, opts._x._ioprocessors, interpreter.isIn.bind(interpreter));
}
function deserializeSerializedConfiguration(serializedConfiguration, idToStateMap) {
return serializedConfiguration.map(function (id) {
var state = idToStateMap.get(id);
if (!state) throw new Error('Error loading serialized configuration. Unable to locate state with id ' + id);
return state;
});
}
function deserializeHistory(serializedHistory, idToStateMap) {
var o = {};
Object.keys(serializedHistory).forEach(function (sid) {
o[sid] = serializedHistory[sid].map(function (id) {
var state = idToStateMap.get(id);
if (!state) throw new Error('Error loading serialized history. Unable to locate state with id ' + id);
return state;
});
});
return o;
}
/***/ }),
/***/ "./node_modules/@scion-scxml/core-base/lib/query.js":
/*!**********************************************************!*\
!*** ./node_modules/@scion-scxml/core-base/lib/query.js ***!
\**********************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
var constants = __webpack_require__(/*! ./constants */ "./node_modules/@scion-scxml/core-base/lib/constants.js"); //model accessor functions
var query = {
isDescendant: function isDescendant(s1, s2) {
//Returns 'true' if state1 is a descendant of state2 (a child, or a child of a child, or a child of a child of a child, etc.) Otherwise returns 'false'.
return s2.descendants.indexOf(s1) > -1;
},
getAncestors: function getAncestors(s, root) {
var ancestors, index, state;
index = s.ancestors.indexOf(root);
if (index > -1) {
return s.ancestors.slice(0, index);
} else {
return s.ancestors;
}
},
isOrthogonalTo: function isOrthogonalTo(s1, s2) {
//Two control states are orthogonal if they are not ancestrally
//related, and their smallest, mutual parent is a Concurrent-state.
return !this.isAncestrallyRelatedTo(s1, s2) && this.getLCA(s1, s2).typeEnum === constants.STATE_TYPES.PARALLEL;
},
isAncestrallyRelatedTo: function isAncestrallyRelatedTo(s1, s2) {
//Two control states are ancestrally related if one is child/grandchild of another.
return this.getAncestorsOrSelf(s2).indexOf(s1) > -1 || this.getAncestorsOrSelf(s1).indexOf(s2) > -1;
},
getAncestorsOrSelf: function getAncestorsOrSelf(s, root) {
return [s].concat(query.getAncestors(s, root));
},
getDescendantsOrSelf: function getDescendantsOrSelf(s) {
return [s].concat(s.descendants);
},
getLCA: function getLCA(s1, s2) {
var commonAncestors = this.getAncestors(s1).filter(function (a) {
return a.descendants.indexOf(s2) > -1;
}, this);
return commonAncestors[0];
}
};
module.exports = query;
/***/ }),
/***/ "./node_modules/@scion-scxml/core-base/lib/scion-core-base.js":
/*!********************************************************************!*\
!*** ./node_modules/@scion-scxml/core-base/lib/scion-core-base.js ***!
\********************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
// Copyright 2012-2012 Jacob Beard, INFICON, and other SCION contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* SCION-CORE global object
* @namespace scion
*/
/**
* An Array of strings representing the ids all of the basic states the
* interpreter is in after a big-step completes.
* @typedef {Array<string>} Configuration
*/
/**
* A set of basic and composite state ids.
* @typedef {Array<string>} FullConfiguration
*/
/**
* A set of basic and composite state ids.
* @typedef {Array<string>} FullConfiguration
*/
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
var EventEmitter = __webpack_require__(/*! tiny-events */ "./node_modules/tiny-events/lib/index.js").EventEmitter,
util = __webpack_require__(/*! util */ "./util-inspect-stub.js"),
ArraySet = __webpack_require__(/*! ./ArraySet */ "./node_modules/@scion-scxml/core-base/lib/ArraySet.js"),
constants = __webpack_require__(/*! ./constants */ "./node_modules/@scion-scxml/core-base/lib/constants.js"),
helpers = __webpack_require__(/*! ./helpers */ "./node_modules/@scion-scxml/core-base/lib/helpers.js"),
query = __webpack_require__(/*! ./query */ "./node_modules/@scion-scxml/core-base/lib/query.js"),
extend = helpers.extend,
transitionWithTargets = helpers.transitionWithTargets,
transitionComparator = helpers.transitionComparator,
initializeModel = helpers.initializeModel,
isEventPrefixMatch = helpers.isEventPrefixMatch,
isTransitionMatch = helpers.isTransitionMatch,
scxmlPrefixTransitionSelector = helpers.scxmlPrefixTransitionSelector,
eventlessTransitionSelector = helpers.eventlessTransitionSelector,
getTransitionWithHigherSourceChildPriority = helpers.getTransitionWithHigherSourceChildPriority,
sortInEntryOrder = helpers.sortInEntryOrder,
getStateWithHigherSourceChildPriority = helpers.getStateWithHigherSourceChildPriority,
initializeModelGeneratorFn = helpers.initializeModelGeneratorFn,
deserializeSerializedConfiguration = helpers.deserializeSerializedConfiguration,
deserializeHistory = helpers.deserializeHistory,
BASIC = constants.STATE_TYPES.BASIC,
COMPOSITE = constants.STATE_TYPES.COMPOSITE,
PARALLEL = constants.STATE_TYPES.PARALLEL,
HISTORY = constants.STATE_TYPES.HISTORY,
INITIAL = constants.STATE_TYPES.INITIAL,
FINAL = constants.STATE_TYPES.FINAL,
SCXML_IOPROCESSOR_TYPE = constants.SCXML_IOPROCESSOR_TYPE;
var printTrace = typeof process !== 'undefined' && !!process.env.DEBUG;
/**
* @interface EventEmitter
*/
/**
* @event scion.BaseInterpreter#onError
* @property {string} tagname The name of the element that produced the error.
* @property {number} line The line in the source file in which the error occurred.
* @property {number} column The column in the source file in which the error occurred.
* @property {string} reason An informative error message. The text is platform-specific and subject to change.
*/
/**
* @function
* @name EventEmitter.prototype#on
* @param {string} type
* @param {callback} listener
*/
/**
* @function
* @name EventEmitter.prototype#once
* @param {string} type
* @param {callback} listener
*/
/**
* @function
* @name EventEmitter.prototype#off
* @param {string} type
* @param {callback} listener
*/
/**
* @function
* @name EventEmitter.prototype#emit
* @param {string} type
* @param {any} args
*/
/**
* @description The SCXML constructor creates an interpreter instance from a model object.
* @abstract
* @class BaseInterpreter
* @memberof scion
* @extends EventEmitter
* @param {SCJSON | scxml.ModelFactory} modelOrModelFactory Either an SCJSON root state; or an scxml.ModelFactory, which is a function which returns an SCJSON object.
* @param opts
* @param {string} [opts.sessionid] Used to populate SCXML _sessionid.
* @param {function} [opts.generateSessionid] Factory used to generate sessionid if sessionid keyword is not specified
* @param {Map<string, BaseInterpreter>} [opts.sessionRegistry] Map used to map sessionid strings to Statechart instances.
* @param [opts.Set] Class to use as an ArraySet. Defaults to ES6 Set.
* @param {object} [opts.params] Used to pass params from invoke. Sets the datamodel when interpreter is instantiated.
* @param {Snapshot} [opts.snapshot] State machine snapshot. Used to restore a serialized state machine.
* @param {Statechart} [opts.parentSession] Used to pass parent session during invoke.
* @param {string }[opts.invokeid] Support for id of invoke element at runtime.
* @param {boolean} [opts.legacySemantics]
* @param [opts.console]
* @param [opts.transitionSelector]
* @param [opts.customCancel]
* @param [opts.customSend]
* @param [opts.sendAsync]
* @param [opts.doSend]
* @param [opts.invokers]
* @param [opts.xmlParser]
* @param [opts.interpreterScriptingContext]
* @param [opts.invokerExecutionContext]
*/
var BaseInterpreter = /*#__PURE__*/function (_EventEmitter) {
_inherits(BaseInterpreter, _EventEmitter);
var _super = _createSuper(BaseInterpreter);
function BaseInterpreter(modelOrModelFactory, opts) {
var _this;
_classCallCheck(this, BaseInterpreter);
_this = _super.call(this);
_this.opts = opts;
_this.opts.InterpreterScriptingContext = _this.opts.InterpreterScriptingContext || InterpreterScriptingContext;
_this._isStepping = false;
_this._scriptingContext = _this.opts.interpreterScriptingContext || (_this.opts.InterpreterScriptingContext ? new _this.opts.InterpreterScriptingContext(_assertThisInitialized(_this)) : {});
_this.opts.generateSessionid = _this.opts.generateSessionid || BaseInterpreter.generateSessionid;
_this.opts.sessionid = _this.opts.sessionid || _this.opts.generateSessionid();
_this.opts.sessionRegistry = _this.opts.sessionRegistry || BaseInterpreter.sessionRegistry; //TODO: define a better interface. For now, assume a Map<sessionid, session>
_this.opts.invokerExecutionContext = opts.invokerExecutionContext || modelOrModelFactory._executionContext;
var _ioprocessors = {};
_ioprocessors[SCXML_IOPROCESSOR_TYPE] = {
location: "#_scxml_".concat(_this.opts.sessionid)
};
_ioprocessors.scxml = _ioprocessors[SCXML_IOPROCESSOR_TYPE]; //alias
//SCXML system variables:
_this.opts._x = {
_sessionid: _this.opts.sessionid,
_ioprocessors: _ioprocessors
};
var model;
if (typeof modelOrModelFactory === 'function') {
model = initializeModelGeneratorFn(modelOrModelFactory, _this.opts, _assertThisInitialized(_this));
} else if (_typeof(modelOrModelFactory) === 'object') {
model = JSON.parse(JSON.stringify(modelOrModelFactory)); //assume object
} else {
throw new Error('Unexpected model type. Expected model factory function, or scjson object.');
}
_this._model = initializeModel(model, _this.opts);
_this.opts.console = _this.opts.console || (typeof console === 'undefined' ? {
log: function log() {}
} : console); //rely on global console if this console is undefined
_this.opts.Set = _this.opts.Set || ArraySet;
_this.opts.priorityComparisonFn = _this.opts.priorityComparisonFn || getTransitionWithHigherSourceChildPriority;
_this.opts.transitionSelector = _this.opts.transitionSelector || scxmlPrefixTransitionSelector;
_this.opts.sessionRegistry.set(String(_this.opts.sessionid), _assertThisInitialized(_this));
_this._scriptingContext.log = _this._scriptingContext.log || function log() {
if (this.opts.console.log.apply) {
this.opts.console.log.apply(this.opts.console, arguments);
} else {
//console.log on older IE does not support Function.apply, so just pass him the first argument. Best we can do for now.
this.opts.console.log(Array.prototype.slice.apply(arguments).join(','));
}
}.bind(_assertThisInitialized(_this)); //set up default scripting context log function
_this._externalEventQueue = [];
_this._internalEventQueue = [];
if (_this.opts.params) {
_this._model.$deserializeDatamodel(_this.opts.params); //load up the datamodel
} //check if we're loading from a previous snapshot
if (_this.opts.snapshot) {
_this._configuration = new _this.opts.Set(deserializeSerializedConfiguration(_this.opts.snapshot[0], _this._model.$idToStateMap));
_this._historyValue = deserializeHistory(_this.opts.snapshot[1], _this._model.$idToStateMap);
_this._isInFinalState = _this.opts.snapshot[2];
_this._model.$deserializeDatamodel(_this.opts.snapshot[3]); //load up the datamodel
_this._internalEventQueue = _this.opts.snapshot[4];
} else {
_this._configuration = new _this.opts.Set();
_this._historyValue = {};
_this._isInFinalState = false;
} //add debug logging
BaseInterpreter.EVENTS.forEach(function (event) {
this.on(event, this._log.bind(this, event));
}, _assertThisInitialized(_this));
module.exports.emit('new', _assertThisInitialized(_this));
return _this;
}
/**
* Cancels the session. This clears all timers; puts the interpreter in a
* final state; and runs all exit actions on current states.
* @memberof BaseInterpreter.prototype
*/
_createClass(BaseInterpreter, [{
key: "cancel",
value: function cancel() {
delete this.opts.parentSession;
if (this._isInFinalState) return;
this._isInFinalState = true;
this._log("session cancelled ".concat(this.opts.invokeid));
this._exitInterpreter(null);
}
}, {
key: "_exitInterpreter",
value: function _exitInterpreter(event) {
var _this2 = this;
//TODO: cancel invoked sessions
//cancel all delayed sends when we enter into a final state.
this._cancelAllDelayedSends();
var statesToExit = this._getFullConfiguration().sort(getStateWithHigherSourceChildPriority);
for (var j = 0, len = statesToExit.length; j < len; j++) {
var stateExited = statesToExit[j];
if (stateExited.onExit !== undefined) {
for (var exitIdx = 0, exitLen = stateExited.onExit.length; exitIdx < exitLen; exitIdx++) {
var block = stateExited.onExit[exitIdx];
for (var blockIdx = 0, blockLen = block.length; blockIdx < blockLen; blockIdx++) {
var actionRef = block[blockIdx];
try {
actionRef.call(this._scriptingContext, null);
} catch (e) {
this._handleError(e, actionRef);
break;
}
}
}
} //cancel invoked session
if (stateExited.invokes) stateExited.invokes.forEach(function (invoke) {
_this2._scriptingContext.cancelInvoke(invoke.id);
}); //if he is a top-level <final> state, then return the done event
if (stateExited.$type === 'final' && stateExited.parent.$type === 'scxml') {
if (this.opts.parentSession) {
this._scriptingContext.send({
target: '#_parent',
name: 'done.invoke.' + this.opts.invokeid,
data: stateExited.donedata && stateExited.donedata.call(this._scriptingContext, event)
});
}
this.opts.sessionRegistry["delete"](this.opts.sessionid);
this.emit('onExitInterpreter', event);
}
}
}
/**
* Starts the interpreter. Should only be called once, and should be called
* before BaseInterpreter.prototype#gen is called for the first time. Returns a
* Configuration.
* @return {Configuration}
* @memberof BaseInterpreter.prototype
* @emits scion.BaseInterpreter#onEntry
* @emits scion.BaseInterpreter#onExit
* @emits scion.BaseInterpreter#onTransition
* @emits scion.BaseInterpreter#onDefaultEntry
* @emits scion.BaseInterpreter#onError
* @emits scion.BaseInterpreter#onBigStepBegin
* @emits scion.BaseInterpreter#onBigStepEnd
* @emits scion.BaseInterpreter#onBigStepSuspend
* @emits scion.BaseInterpreter#onBigStepResume
* @emits scion.BaseInterpreter#onSmallStepBegin
* @emits scion.BaseInterpreter#onSmallStepEnd
* @emits scion.BaseInterpreter#onBigStepEnd
* @emits scion.BaseInterpreter#onExitInterpreter
*/
}, {
key: "start",
value: function start() {
this._initStart();
this._performBigStep();
return this.getConfiguration();
}
/**
* This callback is displayed as a global member.
* @callback genCallback
* @param {Error} err
* @param {Configuration} configuration
*/
/**
* Starts the interpreter asynchronously
* @param {genCallback} cb Callback invoked with an error or the interpreter's stable configuration
* @memberof BaseInterpreter.prototype
* @emits scion.BaseInterpreter#onEntry
* @emits scion.BaseInterpreter#onExit
* @emits scion.BaseInterpreter#onTransition
* @emits scion.BaseInterpreter#onDefaultEntry
* @emits scion.BaseInterpreter#onError
* @emits scion.BaseInterpreter#onBigStepBegin
* @emits scion.BaseInterpreter#onBigStepEnd
* @emits scion.BaseInterpreter#onBigStepSuspend
* @emits scion.BaseInterpreter#onBigStepResume
* @emits scion.BaseInterpreter#onSmallStepBegin
* @emits scion.BaseInterpreter#onSmallStepEnd
* @emits scion.BaseInterpreter#onBigStepEnd
* @emits scion.BaseInterpreter#onExitInterpreter
*/
}, {
key: "startAsync",
value: function startAsync(cb) {
cb = this._initStart(cb);
this.genAsync(null, cb);
}
}, {
key: "_initStart",
value: function _initStart(cb) {
var _this3 = this;
if (typeof cb !== 'function') {
cb = nop;
}
this._log("performing initial big step"); //We effectively need to figure out states to enter here to populate initial config. assuming root is compound state makes this simple.
//but if we want it to be parallel, then this becomes more complex. so when initializing the model, we add a 'fake' root state, which
//makes the following operation safe.
this._model.initialRef.forEach(function (s) {
return _this3._configuration.add(s);
});
return cb;
}
/**
* Returns state machine {@link Configuration}.
* @return {Configuration}
* @memberof BaseInterpreter.prototype
*/
}, {
key: "getConfiguration",
value: function getConfiguration() {
return this._configuration.iter().map(function (s) {
return s.id;
});
}
}, {
key: "_getFullConfiguration",
value: function _getFullConfiguration() {
return this._configuration.iter().map(function (s) {
return [s].concat(query.getAncestors(s));
}, this).reduce(function (a, b) {
return a.concat(b);
}, []). //flatten
reduce(function (a, b) {
return a.indexOf(b) > -1 ? a : a.concat(b);
}, []); //uniq
}
/**
* @return {FullConfiguration}
* @memberof BaseInterpreter.prototype
*/
}, {
key: "getFullConfiguration",
value: function getFullConfiguration() {
return this._getFullConfiguration().map(function (s) {
return s.id;
});
}
/**
* @return {boolean}
* @memberof BaseInterpreter.prototype
* @param {string} stateName
*/
}, {
key: "isIn",
value: function isIn(stateName) {
return this.getFullConfiguration().indexOf(stateName) > -1;
}
/**
* Is the state machine in a final state?
* @return {boolean}
* @memberof BaseInterpreter.prototype
*/
}, {
key: "isFinal",
value: function isFinal() {
return this._isInFinalState;
}
/** @private */
}, {
key: "_performBigStep",
value: function _performBigStep(e) {
var currentEvent, keepGoing, allStatesExited, allStatesEntered;
var _this$_startBigStep = this._startBigStep(e);
var _this$_startBigStep2 = _slicedToArray(_this$_startBigStep, 4);
allStatesExited = _this$_startBigStep2[0];
allStatesEntered = _this$_startBigStep2[1];
keepGoing = _this$_startBigStep2[2];
currentEvent = _this$_startBigStep2[3];
while (keepGoing) {
var _this$_selectTransiti = this._selectTransitionsAndPerformSmallStep(currentEvent, allStatesEntered, allStatesExited);
var _this$_selectTransiti2 = _slicedToArray(_this$_selectTransiti, 2);
currentEvent = _this$_selectTransiti2[0];
keepGoing = _this$_selectTransiti2[1];
}
this._finishBigStep(currentEvent, allStatesEntered, allStatesExited);
}
}, {
key: "_selectTransitionsAndPerformSmallStep",
value: function _selectTransitionsAndPerformSmallStep(currentEvent, allStatesEntered, allStatesExited) {
//first select with null event
var selectedTransitions = this._selectTransitions(currentEvent, true);
if (selectedTransitions.isEmpty()) {
var ev = this._internalEventQueue.shift();
if (ev) {
currentEvent = ev;
selectedTransitions = this._selectTransitions(currentEvent, false);
}
}
if (!selectedTransitions.isEmpty()) {
this.emit('onSmallStepBegin', currentEvent);
var statesExited, statesEntered;
var _this$_performSmallSt = this._performSmallStep(currentEvent, selectedTransitions);
var _this$_performSmallSt2 = _slicedToArray(_this$_performSmallSt, 2);
statesExited = _this$_performSmallSt2[0];
statesEntered = _this$_performSmallSt2[1];
if (statesExited) statesExited.forEach(function (s) {
return allStatesExited.add(s);
});
if (statesEntered) statesEntered.forEach(function (s) {
return allStatesEntered.add(s);
});
this.emit('onSmallStepEnd', currentEvent);
}
var keepGoing = !selectedTransitions.isEmpty() || this._internalEventQueue.length;
return [currentEvent, keepGoing];
}
}, {
key: "_startBigStep",
value: function _startBigStep(e) {
var _this4 = this;
this.emit('onBigStepBegin', e); //do applyFinalize and autoforward
this._configuration.iter().forEach(function (state) {
if (state.invokes) state.invokes.forEach(function (invoke) {
if (invoke.autoforward) {
//autoforward
_this4._scriptingContext.send({
target: "#_".concat(invoke.id),
name: e.name,
data: e.data
});
}
if (invoke.id === e.invokeid) {
//applyFinalize
if (invoke.finalize) invoke.finalize.forEach(function (action) {
return _this4._evaluateAction(e, action);
});
}
});
});
if (e) this._internalEventQueue.push(e);
var allStatesExited = new Set(),
allStatesEntered = new Set();
var keepGoing = true;
var currentEvent = e;
return [allStatesEntered, allStatesExited, keepGoing, currentEvent];
}
}, {
key: "_finishBigStep",
value: function _finishBigStep(e, allStatesEntered, allStatesExited, cb) {
var _this5 = this;
var statesToInvoke = Array.from(new Set(_toConsumableArray(allStatesEntered).filter(function (s) {
return s.invokes && !allStatesExited.has(s);
}))).sort(sortInEntryOrder); // Here we invoke whatever needs to be invoked. The implementation of 'invoke' is platform-specific
statesToInvoke.forEach(function (s) {
s.invokes.forEach(function (f) {
return _this5._evaluateAction(e, f);
});
}); // cancel invoke for allStatesExited
allStatesExited.forEach(function (s) {
if (s.invokes) s.invokes.forEach(function (invoke) {
_this5._scriptingContext.cancelInvoke(invoke.id);
});
}); // TODO: Invoking may have raised internal error events and we iterate to handle them
//if not internalQueue.isEmpty():
// continue
this._isInFinalState = this._configuration.iter().every(function (s) {
return s.typeEnum === FINAL;
});
if (this._isInFinalState) {
this._exitInterpreter(e);
}
this.emit('onBigStepEnd', e);
if (cb) cb(undefined, this.getConfiguration());
}
}, {
key: "_cancelAllDelayedSends",
value: function _cancelAllDelayedSends() {
var _iterator = _createForOfIteratorHelper(this._scriptingContext._timeouts),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var timeoutOptions = _step.value;
if (!timeoutOptions.sendOptions.delay) continue;
this._log('cancelling delayed send', timeoutOptions);
clearTimeout(timeoutOptions.timeoutHandle);
this._scriptingContext._timeouts["delete"](timeoutOptions);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
Object.keys(this._scriptingContext._timeoutMap).forEach(function (key) {
delete this._scriptingContext._timeoutMap[key];
}, this);
}
}, {
key: "_performBigStepAsync",
value: function _performBigStepAsync(e, cb) {
var currentEvent, keepGoing, allStatesExited, allStatesEntered;
var _this$_startBigStep3 = this._startBigStep(e);
var _this$_startBigStep4 = _slicedToArray(_this$_startBigStep3, 4);
allStatesExited = _this$_startBigStep4[0];
allStatesEntered = _this$_startBigStep4[1];
keepGoing = _this$_startBigStep4[2];
currentEvent = _this$_startBigStep4[3];
function nextStep(emit) {
this.emit(emit);
var _this$_selectTransiti3 = this._selectTransitionsAndPerformSmallStep(currentEvent, allStatesEntered, allStatesExited);
var _this$_selectTransiti4 = _slicedToArray(_this$_selectTransiti3, 2);
currentEvent = _this$_selectTransiti4[0];
keepGoing = _this$_selectTransiti4[1];
if (keepGoing) {
this.emit('onBigStepSuspend');
setImmediate(nextStep.bind(this, 'onBigStepResume'));
} else {
this._finishBigStep(currentEvent, allStatesEntered, allStatesExited, cb);
}
}
nextStep.call(this, 'onBigStepBegin');
}
/** @private */
}, {
key: "_performSmallStep",
value: function _performSmallStep(currentEvent, selectedTransitions) {
this._log("selecting transitions with currentEvent", currentEvent);
this._log("selected transitions", selectedTransitions);
var statesExited, statesEntered;
if (!selectedTransitions.isEmpty()) {
//we only want to enter and exit states from transitions with targets
//filter out targetless transitions here - we will only use these to execute transition actions
var selectedTransitionsWithTargets = new this.opts.Set(selectedTransitions.iter().filter(transitionWithTargets));
statesExited = this._exitStates(currentEvent, selectedTransitionsWithTargets);
this._executeTransitions(currentEvent, selectedTransitions);
statesEntered = this._enterStates(currentEvent, selectedTransitionsWithTargets);
this._log("new configuration ", this._configuration);
}
return [statesExited, statesEntered];
}
}, {
key: "_exitStates",
value: function _exitStates(currentEvent, selectedTransitionsWithTargets) {
var basicStatesExited, statesExited;
var _this$_getStatesExite = this._getStatesExited(selectedTransitionsWithTargets);
var _this$_getStatesExite2 = _slicedToArray(_this$_getStatesExite, 2);
basicStatesExited = _this$_getStatesExite2[0];
statesExited = _this$_getStatesExite2[1];
this._log('exiting states');
for (var j = 0, len = statesExited.length; j < len; j++) {
var stateExited = statesExited[j];
if (stateExited.isAtomic) this._configuration.remove(stateExited);
this._log("exiting ", stateExited.id); //invoke listeners
this.emit('onExit', stateExited.id);
if (stateExited.onExit !== undefined) {
for (var exitIdx = 0, exitLen = stateExited.onExit.length; exitIdx < exitLen; exitIdx++) {
var block = stateExited.onExit[exitIdx];
for (var blockIdx = 0, blockLen = block.length; blockIdx < blockLen; blockIdx++) {
var actionRef = block[blockIdx];
try {
actionRef.call(this._scriptingContext, currentEvent);
} catch (e) {
this._handleError(e, actionRef);
break;
}
}
}
}
var f;
if (stateExited.historyRef) {
var _iterator2 = _createForOfIteratorHelper(stateExited.historyRef),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var historyRef = _step2.value;
if (historyRef.isDeep) {
f = function f(s0) {
return s0.typeEnum === BASIC && stateExited.descendants.indexOf(s0) > -1;
};
} else {
f = function f(s0) {
return s0.parent === stateExited;
};
} //update history
this._historyValue[historyRef.id] = statesExited.filter(f);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
}
return statesExited;
}
/** @private */
}, {
key: "_getStatesExited",
value: function _getStatesExited(transitions) {
var statesExited = new this.opts.Set();
var basicStatesExited = new this.opts.Set(); //States exited are defined to be active states that are
//descendants of the scope of each priority-enabled transition.
//Here, we iterate through the transitions, and collect states
//that match this condition.
var transitionList = transitions.iter();
for (var txIdx = 0, txLen = transitionList.length; txIdx < txLen; txIdx++) {
var transition = transitionList[txIdx];
var scope = transition.scope,
desc = scope.descendants; //For each state in the configuration
//is that state a descendant of the transition scope?
//Store ancestors of that state up to but not including the scope.
var configList = this._configuration.iter();
for (var cfgIdx = 0, cfgLen = configList.length; cfgIdx < cfgLen; cfgIdx++) {
var state = configList[cfgIdx];
if (desc.indexOf(state) > -1) {
basicStatesExited.add(state);
statesExited.add(state);
var ancestors = query.getAncestors(state, scope);
for (var ancIdx = 0, ancLen = ancestors.length; ancIdx < ancLen; ancIdx++) {
statesExited.add(ancestors[ancIdx]);
}
}
}
}
var sortedStatesExited = statesExited.iter().sort(getStateWithHigherSourceChildPriority);
return [basicStatesExited, sortedStatesExited];
}
}, {
key: "_executeTransitions",
value: function _executeTransitions(currentEvent, selectedTransitions) {
var sortedTransitions = selectedTransitions.iter().sort(transitionComparator);
this._log("executing transitition actions");
for (var stxIdx = 0, len = sortedTransitions.length; stxIdx < len; stxIdx++) {
var transition = sortedTransitions[stxIdx];
var targetIds = transition.targets && transition.targets.map(function (target) {
return target.id;
});
this.emit('onTransition', transition.source.id, targetIds, transition.source.transitions.indexOf(transition));
if (transition.onTransition !== undefined) {
for (var txIdx = 0, txLen = transition.onTransition.length; txIdx < txLen; txIdx++) {
var actionRef = transition.onTransition[txIdx];
try {
actionRef.call(this._scriptingContext, currentEvent);
} catch (e) {
this._handleError(e, actionRef);
break;
}
}
}
}
}
}, {
key: "_enterStates",
value: function _enterStates(currentEvent, selectedTransitionsWithTargets) {
var _this6 = this;
this._log("entering states");
var statesEntered = new Set();
var statesForDefaultEntry = new Set(); // initialize the temporary table for default content in history states
var defaultHistoryContent = {};
this._computeEntrySet(selectedTransitionsWithTargets, statesEntered, statesForDefaultEntry, defaultHistoryContent);
statesEntered = Array.from(statesEntered).sort(sortInEntryOrder);
this._log("statesEntered ", statesEntered);
for (var enterIdx = 0, enterLen = statesEntered.length; enterIdx < enterLen; enterIdx++) {
var stateEntered = statesEntered[enterIdx];
if (stateEntered.isAtomic) this._configuration.add(stateEntered);
this._log("entering", stateEntered.id);
this.emit('onEntry', stateEntered.id);
if (stateEntered.onEntry !== undefined) {
for (var entryIdx = 0, entryLen = stateEntered.onEntry.length; entryIdx < entryLen; entryIdx++) {
var block = stateEntered.onEntry[entryIdx];
for (var blockIdx = 0, blockLen = block.length; blockIdx < blockLen; blockIdx++) {
var actionRef = block[blockIdx];
try {
actionRef.call(this._scriptingContext, currentEvent);
} catch (e) {
this._handleError(e, actionRef);
break;
}
}
}
}
if (statesForDefaultEntry.has(stateEntered)) {
var _iterator3 = _createForOfIteratorHelper(stateEntered.initialRef),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var initialState = _step3.value;
this.emit('onDefaultEntry', initialState.id);
if (initialState.typeEnum === INITIAL) {
var transition = initialState.transitions[0];
if (transition.onTransition !== undefined) {
this._log('executing initial transition content for initial state of parent state', stateEntered.id);
for (var txIdx = 0, txLen = transition.onTransition.length; txIdx < txLen; txIdx++) {
var _actionRef = transition.onTransition[txIdx];
try {
_actionRef.call(this._scriptingContext, currentEvent);
} catch (e) {
this._handleError(e, _actionRef);
break;
}
}
}
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
if (defaultHistoryContent[stateEntered.id]) {
var _transition = defaultHistoryContent[stateEntered.id];
if (_transition.onTransition !== undefined) {
this._log('executing history transition content for history state of parent state', stateEntered.id);
for (var txIdx = 0, txLen = _transition.onTransition.length; txIdx < txLen; txIdx++) {
var _actionRef2 = _transition.onTransition[txIdx];
try {
_actionRef2.call(this._scriptingContext, currentEvent);
} catch (e) {
this._handleError(e, _actionRef2);
break;
}
}
}
}
}
for (var enterIdx = 0, enterLen = statesEntered.length; enterIdx < enterLen; enterIdx++) {
var stateEntered = statesEntered[enterIdx];
if (stateEntered.typeEnum === FINAL) {
var parent = stateEntered.parent;
var grandparent = parent.parent;
this._internalEventQueue.push({
name: "done.state." + parent.id,
data: stateEntered.donedata && stateEntered.donedata.call(this._scriptingContext, currentEvent)
});
if (grandparent && grandparent.typeEnum === PARALLEL) {
if (grandparent.states.every(function (s) {
return _this6.isInFinalState(s);
})) {
this._internalEventQueue.push({
name: "done.state." + grandparent.id
});
}
}
}
}
return statesEntered;
}
}, {
key: "_getEffectiveTargetStates",
value: function _getEffectiveTargetStates(transition) {
var targets = new Set();
var _iterator4 = _createForOfIteratorHelper(transition.targets),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var s = _step4.value;
if (s.typeEnum === HISTORY) {
if (s.id in this._historyValue) this._historyValue[s.id].forEach(function (state) {
return targets.add(state);
});else _toConsumableArray(this._getEffectiveTargetStates(s.transitions[0])).forEach(function (state) {
return targets.add(state);
});
} else {
targets.add(s);
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
return targets;
}
}, {
key: "_computeEntrySet",
value: function _computeEntrySet(transitions, statesToEnter, statesForDefaultEntry, defaultHistoryContent) {
var _iterator5 = _createForOfIteratorHelper(transitions.iter()),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var t = _step5.value;
var _iterator6 = _createForOfIteratorHelper(t.targets),
_step6;
try {
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
var s = _step6.value;
this._addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
var ancestor = t.scope;
var _iterator7 = _createForOfIteratorHelper(this._getEffectiveTargetStates(t)),
_step7;
try {
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
var _s2 = _step7.value;
this._addAncestorStatesToEnter(_s2, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
} catch (err) {
_iterator7.e(err);
} finally {
_iterator7.f();
}
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
}
}, {
key: "_computeExitSet",
value: function _computeExitSet(transitions) {
var statesToExit = new Set();
var _iterator8 = _createForOfIteratorHelper(transitions),
_step8;
try {
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
var t = _step8.value;
if (t.targets) {
var scope = t.scope;
var _iterator9 = _createForOfIteratorHelper(this._getFullConfiguration()),
_step9;
try {
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
var s = _step9.value;
if (query.isDescendant(s, scope)) statesToExit.add(s);
}
} catch (err) {
_iterator9.e(err);
} finally {
_iterator9.f();
}
}
}
} catch (err) {
_iterator8.e(err);
} finally {
_iterator8.f();
}
return statesToExit;
}
}, {
key: "_addAncestorStatesToEnter",
value: function _addAncestorStatesToEnter(state, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent) {
var _this7 = this;
var traverse = function traverse(anc) {
if (anc.typeEnum === PARALLEL) {
var _iterator10 = _createForOfIteratorHelper(anc.states),
_step10;
try {
var _loop = function _loop() {
var child = _step10.value;
if (child.typeEnum !== HISTORY && !_toConsumableArray(statesToEnter).some(function (s) {
return query.isDescendant(s, child);
})) {
_this7._addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
};
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
_loop();
}
} catch (err) {
_iterator10.e(err);
} finally {
_iterator10.f();
}
}
};
var _iterator11 = _createForOfIteratorHelper(query.getAncestors(state, ancestor)),
_step11;
try {
for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
var anc = _step11.value;
statesToEnter.add(anc);
traverse(anc);
}
} catch (err) {
_iterator11.e(err);
} finally {
_iterator11.f();
}
traverse(ancestor);
}
}, {
key: "_addDescendantStatesToEnter",
value: function _addDescendantStatesToEnter(state, statesToEnter, statesForDefaultEntry, defaultHistoryContent) {
var _this8 = this;
if (state.typeEnum === HISTORY) {
if (this._historyValue[state.id]) {
var _iterator12 = _createForOfIteratorHelper(this._historyValue[state.id]),
_step12;
try {
for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
var s = _step12.value;
this._addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
} catch (err) {
_iterator12.e(err);
} finally {
_iterator12.f();
}
var _iterator13 = _createForOfIteratorHelper(this._historyValue[state.id]),
_step13;
try {
for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
var _s3 = _step13.value;
this._addAncestorStatesToEnter(_s3, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
} catch (err) {
_iterator13.e(err);
} finally {
_iterator13.f();
}
} else {
defaultHistoryContent[state.parent.id] = state.transitions[0];
var _iterator14 = _createForOfIteratorHelper(state.transitions[0].targets),
_step14;
try {
for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
var _s4 = _step14.value;
this._addDescendantStatesToEnter(_s4, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
} catch (err) {
_iterator14.e(err);
} finally {
_iterator14.f();
}
var _iterator15 = _createForOfIteratorHelper(state.transitions[0].targets),
_step15;
try {
for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) {
var _s5 = _step15.value;
this._addAncestorStatesToEnter(_s5, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
} catch (err) {
_iterator15.e(err);
} finally {
_iterator15.f();
}
}
} else {
statesToEnter.add(state);
if (state.typeEnum === COMPOSITE) {
statesForDefaultEntry.add(state); //for each state in initialRef, if it is an initial state, then add ancestors and descendants.
var _iterator16 = _createForOfIteratorHelper(state.initialRef),
_step16;
try {
for (_iterator16.s(); !(_step16 = _iterator16.n()).done;) {
var _s6 = _step16.value;
var targets = _s6.typeEnum === INITIAL ? _s6.transitions[0].targets : [_s6];
var _iterator18 = _createForOfIteratorHelper(targets),
_step18;
try {
for (_iterator18.s(); !(_step18 = _iterator18.n()).done;) {
var targetState = _step18.value;
this._addDescendantStatesToEnter(targetState, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
} catch (err) {
_iterator18.e(err);
} finally {
_iterator18.f();
}
}
} catch (err) {
_iterator16.e(err);
} finally {
_iterator16.f();
}
var _iterator17 = _createForOfIteratorHelper(state.initialRef),
_step17;
try {
for (_iterator17.s(); !(_step17 = _iterator17.n()).done;) {
var _s7 = _step17.value;
var _targets = _s7.typeEnum === INITIAL ? _s7.transitions[0].targets : [_s7];
var _iterator19 = _createForOfIteratorHelper(_targets),
_step19;
try {
for (_iterator19.s(); !(_step19 = _iterator19.n()).done;) {
var _targetState = _step19.value;
this._addAncestorStatesToEnter(_targetState, state, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
} catch (err) {
_iterator19.e(err);
} finally {
_iterator19.f();
}
}
} catch (err) {
_iterator17.e(err);
} finally {
_iterator17.f();
}
} else {
if (state.typeEnum === PARALLEL) {
var _iterator20 = _createForOfIteratorHelper(state.states),
_step20;
try {
var _loop2 = function _loop2() {
var child = _step20.value;
if (child.typeEnum !== HISTORY && !_toConsumableArray(statesToEnter).some(function (s) {
return query.isDescendant(s, child);
})) {
_this8._addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry, defaultHistoryContent);
}
};
for (_iterator20.s(); !(_step20 = _iterator20.n()).done;) {
_loop2();
}
} catch (err) {
_iterator20.e(err);
} finally {
_iterator20.f();
}
}
}
}
}
}, {
key: "isInFinalState",
value: function isInFinalState(s) {
var _this9 = this;
if (s.typeEnum === COMPOSITE) {
return s.states.some(function (s) {
return s.typeEnum === FINAL && _this9._configuration.contains(s);
});
} else if (s.typeEnum === PARALLEL) {
return s.states.every(this.isInFinalState.bind(this));
} else {
return false;
}
}
/** @private */
}, {
key: "_evaluateAction",
value: function _evaluateAction(currentEvent, actionRef) {
try {
return actionRef.call(this._scriptingContext, currentEvent); //SCXML system variables
} catch (e) {
this._handleError(e, actionRef);
}
}
}, {
key: "_handleError",
value: function _handleError(e, actionRef) {
var event = e instanceof Error || typeof e.__proto__.name === 'string' && e.__proto__.name.match(/^.*Error$/) ? //we can't just do 'e instanceof Error', because the Error object in the sandbox is from a different context, and instanceof will return false
{
name: 'error.execution',
data: {
tagname: actionRef.tagname,
line: actionRef.line,
column: actionRef.column,
reason: e.message
},
type: 'platform'
} : e.name ? e : {
name: 'error.execution',
data: e,
type: 'platform'
};
this._internalEventQueue.push(event);
this.emit('onError', event);
}
}, {
key: "_log",
value: function _log() {
if (printTrace) {
var args = Array.from(arguments);
this.opts.console.log("".concat(args[0], ": ").concat(args.slice(1).map(function (arg) {
return arg === null ? 'null' : arg === undefined ? 'undefined' : typeof arg === 'string' ? arg : arg.toString() === '[object Object]' ? util.inspect(arg) : arg.toString();
}).join(', '), "\n"));
}
}
/**
* @interface Listener
*/
/**
* @function
* @name Listener#onEntry
* @param {string} stateId
*/
/**
* @function
* @name Listener#onExit
* @param {string} stateId
*/
/**
* @function
* @name Listener#onTransition
* @param {string} sourceStateId Id of the source state
* @param {Array<string>} targetStatesIds Ids of the target states
* @param {number} transitionIndex Index of the transition relative to other transitions originating from source state.
*/
/**
* @function
* @name Listener#onError
* @param {Error} errorInfo
*/
/**
* @function
* @name Listener#onBigStepBegin
*/
/**
* @function
* @name Listener#onBigStepResume
*/
/**
* @function
* @name Listener#onBigStepSuspend
*/
/**
* @function
* @name Listener#onBigStepEnd
*/
/**
* @function
* @name Listener#onSmallStepBegin
* @param {string} event
*/
/**
* @function
* @name Listener#onSmallStepEnd
*/
/**
* Provides a generic mechanism to subscribe to state change and runtime
* error notifications. Can be used for logging and debugging. For example,
* can attach a logger that simply logs the state changes. Or can attach a
* network debugging client that sends state change notifications to a
* debugging server.
* This is an alternative interface to {@link EventEmitter.prototype#on}.
* @memberof BaseInterpreter.prototype
* @param {Listener} listener
*/
}, {
key: "registerListener",
value: function registerListener(listener) {
BaseInterpreter.EVENTS.forEach(function (event) {
if (listener[event]) this.on(event, listener[event]);
}, this);
}
/**
* Unregister a Listener
* @memberof BaseInterpreter.prototype
* @param {Listener} listener
*/
}, {
key: "unregisterListener",
value: function unregisterListener(listener) {
BaseInterpreter.EVENTS.forEach(function (event) {
if (listener[event]) this.off(event, listener[event]);
}, this);
}
/**
* Query the model to get all transition events.
* @return {Array<string>} Transition events.
* @memberof BaseInterpreter.prototype
*/
}, {
key: "getAllTransitionEvents",
value: function getAllTransitionEvents() {
var events = {};
function getEvents(state) {
if (state.transitions) {
for (var txIdx = 0, txLen = state.transitions.length; txIdx < txLen; txIdx++) {
events[state.transitions[txIdx].event] = true;
}
}
if (state.states) {
for (var stateIdx = 0, stateLen = state.states.length; stateIdx < stateLen; stateIdx++) {
getEvents(state.states[stateIdx]);
}
}
}
getEvents(this._model);
return Object.keys(events);
}
/**
* Three things capture the current snapshot of a running SCION interpreter:
*
* <ul>
* <li> basic configuration (the set of basic states the state machine is in)</li>
* <li> history state values (the states the state machine was in last time it was in the parent of a history state)</li>
* <li> the datamodel</li>
* </ul>
*
* The snapshot object can be serialized as JSON and saved to a database. It can
* later be passed to the SCXML constructor to restore the state machine
* using the snapshot argument.
*
* @return {Snapshot}
* @memberof BaseInterpreter.prototype
*/
}, {
key: "getSnapshot",
value: function getSnapshot() {
return [this.getConfiguration(), this._serializeHistory(), this._isInFinalState, this._model.$serializeDatamodel(), this._internalEventQueue.slice()];
}
}, {
key: "_serializeHistory",
value: function _serializeHistory() {
var o = {};
Object.keys(this._historyValue).forEach(function (sid) {
o[sid] = this._historyValue[sid].map(function (state) {
return state.id;
});
}, this);
return o;
}
/**
* @interface Event
*/
/**
* @member name
* @memberof Event.prototype
* @type string
* @description The name of the event
*/
/**
* @member data
* @memberof Event.prototype
* @type any
* @description The event data
*/
/**
* An SCXML interpreter takes SCXML events as input, where an SCXML event is an
* object with "name" and "data" properties. These can be passed to method `gen`
* as two positional arguments, or as a single object.
* @param {string|Event} evtObjOrName
* @param {any=} optionalData
* @emits scion.BaseInterpreter#onEntry
* @emits scion.BaseInterpreter#onExit
* @emits scion.BaseInterpreter#onTransition
* @emits scion.BaseInterpreter#onDefaultEntry
* @emits scion.BaseInterpreter#onError
* @emits scion.BaseInterpreter#onBigStepBegin
* @emits scion.BaseInterpreter#onBigStepEnd
* @emits scion.BaseInterpreter#onBigStepSuspend
* @emits scion.BaseInterpreter#onBigStepResume
* @emits scion.BaseInterpreter#onSmallStepBegin
* @emits scion.BaseInterpreter#onSmallStepEnd
* @emits scion.BaseInterpreter#onBigStepEnd
* @emits scion.BaseInterpreter#onExitInterpreter
*/
}, {
key: "gen",
value: function gen(evtObjOrName, optionalData) {
var currentEvent;
switch (_typeof(evtObjOrName)) {
case 'string':
currentEvent = {
name: evtObjOrName,
data: optionalData
};
break;
case 'object':
if (typeof evtObjOrName.name === 'string') {
currentEvent = evtObjOrName;
} else {
throw new Error('Event object must have "name" property of type string.');
}
break;
default:
throw new Error('First argument to gen must be a string or object.');
}
if (this._isStepping) throw new Error('Cannot call gen during a big-step'); //otherwise, kick him off
this._isStepping = true;
this._performBigStep(currentEvent);
this._isStepping = false;
return this.getConfiguration();
}
/**
* Injects an external event into the interpreter asynchronously
* @param {Event} currentEvent The event to inject
* @param {genCallback} cb Callback invoked with an error or the interpreter's stable configuration
* @emits scion.BaseInterpreter#onEntry
* @emits scion.BaseInterpreter#onExit
* @emits scion.BaseInterpreter#onTransition
* @emits scion.BaseInterpreter#onDefaultEntry
* @emits scion.BaseInterpreter#onError
* @emits scion.BaseInterpreter#onBigStepBegin
* @emits scion.BaseInterpreter#onBigStepEnd
* @emits scion.BaseInterpreter#onBigStepSuspend
* @emits scion.BaseInterpreter#onBigStepResume
* @emits scion.BaseInterpreter#onSmallStepBegin
* @emits scion.BaseInterpreter#onSmallStepEnd
* @emits scion.BaseInterpreter#onBigStepEnd
* @emits scion.BaseInterpreter#onExitInterpreter
*/
}, {
key: "genAsync",
value: function genAsync(currentEvent, cb) {
if (currentEvent !== null && (_typeof(currentEvent) !== 'object' || !currentEvent || typeof currentEvent.name !== 'string')) {
throw new Error('Expected currentEvent to be null or an Object with a name');
}
if (typeof cb !== 'function') {
cb = nop;
}
this._externalEventQueue.push([currentEvent, cb]); //the semantics we want are to return to the cb the results of processing that particular event.
function nextStep(e, c) {
this._performBigStepAsync(e, function (err, config) {
c(err, config);
if (this._externalEventQueue.length) {
nextStep.apply(this, this._externalEventQueue.shift());
} else {
this._isStepping = false;
}
}.bind(this));
}
if (!this._isStepping) {
this._isStepping = true;
nextStep.apply(this, this._externalEventQueue.shift());
}
}
}]);
return BaseInterpreter;
}(EventEmitter);
BaseInterpreter.EVENTS = ['onEntry', 'onExit', 'onTransition', 'onDefaultEntry', 'onError', 'onBigStepBegin', 'onBigStepSuspend', 'onBigStepResume', 'onSmallStepBegin', 'onSmallStepEnd', 'onBigStepEnd', 'onExitInterpreter']; //some global singletons to use to generate in-memory session ids, in case the user does not specify these data structures
BaseInterpreter.sessionIdCounter = 1;
BaseInterpreter.generateSessionid = function () {
return BaseInterpreter.sessionIdCounter++;
};
BaseInterpreter.sessionRegistry = new Map(); // Do nothing
function nop() {}
var InterpreterScriptingContext = /*#__PURE__*/function () {
function InterpreterScriptingContext(interpreter) {
_classCallCheck(this, InterpreterScriptingContext);
this._interpreter = interpreter;
this._timeoutMap = {};
this._invokeMap = {};
this._timeouts = new Set(); //Regex from:
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
// http://stackoverflow.com/a/6927878
this.validateUriRegex = /(#_.*)|\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i;
this.invokeSendTargetRegex = /^#_(.*)$/;
this.scxmlSendTargetRegex = /^#_scxml_(.*)$/;
}
_createClass(InterpreterScriptingContext, [{
key: "raise",
value: function raise(event) {
this._installDefaultPropsOnEvent(event, true);
this._interpreter._internalEventQueue.push(event);
}
}, {
key: "parseXmlStringAsDOM",
value: function parseXmlStringAsDOM(xmlString) {
return (this._interpreter.opts.xmlParser || InterpreterScriptingContext.xmlParser).parse(xmlString);
}
}, {
key: "invoke",
value: function invoke(invokeObj) {
var _this10 = this;
//look up invoker by type. assume invokers are passed in as an option to constructor
this._invokeMap[invokeObj.id] = new Promise(function (resolve, reject) {
(_this10._interpreter.opts.invokers || InterpreterScriptingContext.invokers)[invokeObj.type](_this10._interpreter, invokeObj, _this10._interpreter.opts.invokerExecutionContext, function (err, session) {
if (err) return reject(err);
_this10._interpreter.emit('onInvokedSessionInitialized', session);
resolve(session);
});
});
}
}, {
key: "cancelInvoke",
value: function cancelInvoke(invokeid) {
var _this11 = this;
//TODO: on cancel invoke clean up this._invokeMap
var sessionPromise = this._invokeMap[invokeid];
this._interpreter._log("cancelling session with invokeid ".concat(invokeid));
if (sessionPromise) {
this._interpreter._log("sessionPromise found");
sessionPromise.then(function (session) {
_this11._interpreter._log("resolved session ".concat(invokeid, ". cancelling... "));
session.cancel(); //clean up
delete _this11._invokeMap[invokeid];
}, function (err) {//TODO: dispatch error back into the state machine as error.communication
});
}
}
}, {
key: "_installDefaultPropsOnEvent",
value: function _installDefaultPropsOnEvent(event, isInternal) {
if (!isInternal) {
event.origin = this._interpreter.opts._x._ioprocessors.scxml.location; //TODO: preserve original origin when we autoforward?
event.origintype = event.type || SCXML_IOPROCESSOR_TYPE;
}
if (typeof event.type === 'undefined') {
event.type = isInternal ? 'internal' : 'external';
}
['name', 'sendid', 'invokeid', 'data', 'origin', 'origintype'].forEach(function (prop) {
if (typeof event[prop] === 'undefined') {
event[prop] = undefined;
}
});
}
}, {
key: "send",
value: function send(event, options) {
this._interpreter._log('send event', event, options);
options = options || {};
var sendType = options.type || SCXML_IOPROCESSOR_TYPE; //TODO: move these out
function validateSend(event, options, sendAction) {
if (event.target) {
var targetIsValidUri = this.validateUriRegex.test(event.target);
if (!targetIsValidUri) {
throw {
name: "error.execution",
data: 'Target is not valid URI',
sendid: event.sendid,
type: 'platform'
};
}
}
if (sendType !== SCXML_IOPROCESSOR_TYPE) {
//TODO: extend this to support HTTP, and other IO processors
throw {
name: "error.execution",
data: 'Unsupported event processor type',
sendid: event.sendid,
type: 'platform'
};
}
sendAction.call(this, event, options);
}
function defaultSendAction(event, options) {
var _this12 = this;
if (typeof setTimeout === 'undefined') throw new Error('Default implementation of BaseInterpreter.prototype.send will not work unless setTimeout is defined globally.');
var match;
if (event.target === '#_internal') {
this.raise(event);
} else {
this._installDefaultPropsOnEvent(event, false);
event.origintype = SCXML_IOPROCESSOR_TYPE; //TODO: extend this to support HTTP, and other IO processors
//TODO : paramterize this based on send/@type?
if (!event.target) {
doSend.call(this, this._interpreter);
} else if (event.target === '#_parent') {
if (this._interpreter.opts.parentSession) {
event.invokeid = this._interpreter.opts.invokeid;
doSend.call(this, this._interpreter.opts.parentSession);
} else {
throw {
name: "error.communication",
data: 'Parent session not specified',
sendid: event.sendid,
type: 'platform'
};
}
} else if (match = event.target.match(this.scxmlSendTargetRegex)) {
var targetSessionId = match[1];
var session = this._interpreter.opts.sessionRegistry.get(targetSessionId);
if (session) {
doSend.call(this, session);
} else {
throw {
name: 'error.communication',
sendid: event.sendid,
type: 'platform'
};
}
} else if (match = event.target.match(this.invokeSendTargetRegex)) {
//TODO: test this code path.
var invokeId = match[1];
this._invokeMap[invokeId].then(function (session) {
doSend.call(_this12, session);
});
} else {
throw new Error('Unrecognized send target.'); //TODO: dispatch error back into the state machine
}
}
function doSend(session) {
//TODO: we probably now need to refactor data structures:
// this._timeouts
// this._timeoutMap
var timeoutHandle = setTimeout(function () {
if (event.sendid) delete this._timeoutMap[event.sendid];
this._timeouts["delete"](timeoutOptions);
if (this._interpreter.opts.doSend) {
this._interpreter.opts.doSend(session, event);
} else {
session[this._interpreter.opts.sendAsync ? 'genAsync' : 'gen'](event);
}
}.bind(this), options.delay || 0);
var timeoutOptions = {
sendOptions: options,
timeoutHandle: timeoutHandle
};
if (event.sendid) this._timeoutMap[event.sendid] = timeoutHandle;
this._timeouts.add(timeoutOptions);
}
}
function publish() {
this._interpreter.emit(event.name, event.data);
} //choose send function
//TODO: rethink how this custom send works
var sendFn;
if (event.type === 'https://github.com/jbeard4/SCION#publish') {
sendFn = publish;
} else if (this._interpreter.opts.customSend) {
sendFn = this._interpreter.opts.customSend;
} else {
sendFn = defaultSendAction;
}
options = options || {};
this._interpreter._log("sending event", event.name, "with content", event.data, "after delay", options.delay);
validateSend.call(this, event, options, sendFn);
}
}, {
key: "cancel",
value: function cancel(sendid) {
if (this._interpreter.opts.customCancel) {
return this._interpreter.opts.customCancel.apply(this, [sendid]);
}
if (typeof clearTimeout === 'undefined') throw new Error('Default implementation of BaseInterpreter.prototype.cancel will not work unless setTimeout is defined globally.');
if (sendid in this._timeoutMap) {
this._interpreter._log("cancelling ", sendid, " with timeout id ", this._timeoutMap[sendid]);
clearTimeout(this._timeoutMap[sendid]);
}
}
}]);
return InterpreterScriptingContext;
}();
module.exports = extend(new EventEmitter(), {
BaseInterpreter: BaseInterpreter,
ArraySet: ArraySet,
STATE_TYPES: constants.STATE_TYPES,
initializeModel: initializeModel,
InterpreterScriptingContext: InterpreterScriptingContext,
helpers: helpers,
query: query
});
/***/ }),
/***/ "./node_modules/@scion-scxml/core/lib/Statechart.js":
/*!**********************************************************!*\
!*** ./node_modules/@scion-scxml/core/lib/Statechart.js ***!
\**********************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
var base = __webpack_require__(/*! @scion-scxml/core-base */ "./node_modules/@scion-scxml/core-base/lib/scion-core-base.js"),
helpers = base.helpers,
query = base.query,
transitionComparator = base.helpers.transitionComparator;
/**
* @description Implements semantics described in Algorithm D of the SCXML specification.
* See {@link scion.BaseInterpreter} for information on the constructor arguments.
* @class SCInterpreter
* @extends BaseInterpreter
*/
var Statechart = /*#__PURE__*/function (_base$BaseInterpreter) {
_inherits(Statechart, _base$BaseInterpreter);
var _super = _createSuper(Statechart);
function Statechart(modelOrModelFactory, opts) {
_classCallCheck(this, Statechart);
opts = opts || {};
opts.legacySemantics = false;
return _super.call(this, modelOrModelFactory, opts);
}
/** @private */
_createClass(Statechart, [{
key: "_selectTransitions",
value: function _selectTransitions(currentEvent, selectEventlessTransitions) {
var transitionSelector = this.opts.transitionSelector;
var enabledTransitions = new this.opts.Set();
var e = this._evaluateAction.bind(this, currentEvent);
var atomicStates = this._configuration.iter().sort(transitionComparator);
var _iterator = _createForOfIteratorHelper(atomicStates),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var state = _step.value;
var _iterator2 = _createForOfIteratorHelper([state].concat(query.getAncestors(state))),
_step2;
try {
loop: for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var s = _step2.value;
var _iterator3 = _createForOfIteratorHelper(s.transitions),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var t = _step3.value;
if (transitionSelector(t, currentEvent, e, selectEventlessTransitions)) {
enabledTransitions.add(t);
break loop;
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
var priorityEnabledTransitions = this._removeConflictingTransition(enabledTransitions);
this._log("priorityEnabledTransitions", priorityEnabledTransitions);
return priorityEnabledTransitions;
}
/** @private */
}, {
key: "_removeConflictingTransition",
value: function _removeConflictingTransition(enabledTransitions) {
var _this = this;
var filteredTransitions = new this.opts.Set(); //toList sorts the transitions in the order of the states that selected them
var _iterator4 = _createForOfIteratorHelper(enabledTransitions.iter()),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var t1 = _step4.value;
var t1Preempted = false;
var transitionsToRemove = new Set();
var _iterator5 = _createForOfIteratorHelper(filteredTransitions.iter()),
_step5;
try {
var _loop = function _loop() {
var t2 = _step5.value;
//TODO: can we compute this statically? for example, by checking if the transition scopes are arena orthogonal?
var t1ExitSet = _this._computeExitSet([t1]);
var t2ExitSet = _this._computeExitSet([t2]);
var hasIntersection = _toConsumableArray(t1ExitSet).some(function (s) {
return t2ExitSet.has(s);
}) || _toConsumableArray(t2ExitSet).some(function (s) {
return t1ExitSet.has(s);
});
_this._log('t1ExitSet', t1.source.id, _toConsumableArray(t1ExitSet).map(function (s) {
return s.id;
}));
_this._log('t2ExitSet', t2.source.id, _toConsumableArray(t2ExitSet).map(function (s) {
return s.id;
}));
_this._log('hasIntersection', hasIntersection);
if (hasIntersection) {
if (t2.source.descendants.indexOf(t1.source) > -1) {
//is this the same as being ancestrally related?
transitionsToRemove.add(t2);
} else {
t1Preempted = true;
return "break";
}
}
};
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var _ret = _loop();
if (_ret === "break") break;
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
if (!t1Preempted) {
var _iterator6 = _createForOfIteratorHelper(transitionsToRemove),
_step6;
try {
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
var t3 = _step6.value;
filteredTransitions.remove(t3);
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
filteredTransitions.add(t1);
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
return filteredTransitions;
}
}]);
return Statechart;
}(base.BaseInterpreter);
base.Statechart = Statechart; //simple default invoker
base.InterpreterScriptingContext.invokers = {
"http://www.w3.org/TR/scxml/": function httpWwwW3OrgTRScxml(invokingSession, invokeObj, invokerExecutionContext, cb) {
//put invoke logic here:
var method, arg;
if (invokeObj.constructorFunction) {
var fnModel = invokeObj.constructorFunction;
var options = {
invokeid: invokeObj.id,
params: invokeObj.params,
parentSession: invokingSession,
docUrl: invokeObj.docUrl //sessionid : //TODO: construct or generate a sessionid for invoked session
};
var model = invokerExecutionContext;
var interpreter;
if (options.parentSession instanceof Statechart) {
interpreter = new Statechart(fnModel, options);
}
cb(null, interpreter, fnModel, model); //we introduce a delay here before starting the interpreter to give clients that are subscribed to onInvokedSessionInitialized event a chance to subscribe to events on the newly instantiated interpreter
setImmediate(function () {
return interpreter.start();
});
} else {
throw new Error('Invoke object needs a constructorFunction property');
}
}
};
base.InterpreterScriptingContext.invokers[undefined] = base.InterpreterScriptingContext.invokers[null] = base.InterpreterScriptingContext.invokers['scxml'] = base.InterpreterScriptingContext.invokers["http://www.w3.org/TR/scxml/"];
module.exports = base;
/***/ }),
/***/ "./node_modules/tiny-events/lib/index.js":
/*!***********************************************!*\
!*** ./node_modules/tiny-events/lib/index.js ***!
\***********************************************/
/***/ ((module) => {
function EventEmitter() {
this._listeners = {};
}
EventEmitter.prototype.on = function _on(type, listener) {
if (!Array.isArray(this._listeners[type])) {
this._listeners[type] = [];
}
if (this._listeners[type].indexOf(listener) === -1) {
this._listeners[type].push(listener);
}
return this;
};
EventEmitter.prototype.once = function _once(type, listener) {
var self = this;
function __once() {
for (var args = [], i = 0; i < arguments.length; i += 1) {
args[i] = arguments[i];
}
self.off(type, __once);
listener.apply(self, args);
}
__once.listener = listener;
return this.on(type, __once);
};
EventEmitter.prototype.off = function _off(type, listener) {
if (!Array.isArray(this._listeners[type])) {
return this;
}
if (typeof listener === 'undefined') {
this._listeners[type] = [];
return this;
}
var index = this._listeners[type].indexOf(listener);
if (index === -1) {
for (var i = 0; i < this._listeners[type].length; i += 1) {
if (this._listeners[type][i].listener === listener) {
index = i;
break;
}
}
}
this._listeners[type].splice(index, 1);
return this;
};
EventEmitter.prototype.emit = function _emit(type) {
if (!Array.isArray(this._listeners[type])) {
return this;
}
for (var args = [], i = 1; i < arguments.length; i += 1) {
args[i - 1] = arguments[i];
}
this._listeners[type].forEach(function __emit(listener) {
listener.apply(this, args);
}, this);
return this;
};
module.exports.EventEmitter = EventEmitter;
/***/ }),
/***/ "./util-inspect-stub.js":
/*!******************************!*\
!*** ./util-inspect-stub.js ***!
\******************************/
/***/ ((__unused_webpack_module, exports) => {
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
/* "minimal" replacement for node's util.inspect() */
function inspect(obj, _opts) {
try {
return JSON.stringify(obj, dedupe(), 2);
} catch (_err) {
return '' + obj;
}
}
exports.inspect = inspect; // adapted from https://careerkarma.com/blog/converting-circular-structure-to-json/
function dedupe() {
var visited = createWeakSet();
return function (_key, value) {
if (_typeof(value) === 'object' && value !== null) {
if (visited.has(value)) {
return '[Circular Reference]';
}
visited.add(value);
}
return value;
};
}
; // try to create WeakSet(), fall back to Set()
function createWeakSet() {
if (typeof WeakSet !== 'undefined') {
return new WeakSet();
}
return new Set();
}
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module used 'module' so it can't be inlined
/******/ var __webpack_exports__ = __webpack_require__("./index.js");
/******/
/******/ return __webpack_exports__;
/******/ })()
;
});