@scion-scxml/core
Version:
StateCharts Interpretation and Optimization eNgine (SCION) CORE is an implementation of Statecharts in JavaScript.
1,222 lines (1,064 loc) • 167 kB
JavaScript
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(["module", "exports"], factory);
} else if (typeof exports !== "undefined") {
factory(module, exports);
} else {
var mod = {
exports: {}
};
factory(mod, mod.exports);
global.scion = global.scion || {}; global.scion.core = mod.exports;
}
})(this, function (module, exports) {
"use strict";
var _typeof2 = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
(function (f) {
if ((typeof exports === "undefined" ? "undefined" : _typeof2(exports)) === "object" && typeof module !== "undefined") {
module.exports = f();
} else if (typeof define === "function" && define.amd) {
define([], f);
} else {
var g;if (typeof window !== "undefined") {
g = window;
} else if (typeof global !== "undefined") {
g = global;
} else if (typeof self !== "undefined") {
g = self;
} else {
g = this;
}g.core = f();
}
})(function () {
var define, module, exports;return function () {
function r(e, n, t) {
function o(i, f) {
if (!n[i]) {
if (!e[i]) {
var c = "function" == typeof require && require;if (!f && c) return c(i, !0);if (u) return u(i, !0);var a = new Error("Cannot find module '" + i + "'");throw a.code = "MODULE_NOT_FOUND", a;
}var p = n[i] = { exports: {} };e[i][0].call(p.exports, function (r) {
var n = e[i][1][r];return o(n || r);
}, p, p.exports, r, e, n, t);
}return n[i].exports;
}for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) {
o(t[i]);
}return o;
}return r;
}()({ 1: [function (require, module, exports) {
(function (setImmediate) {
'use strict';
var _createClass = 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);
}
}return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
};
}();
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
arr2[i] = arr[i];
}return arr2;
} else {
return Array.from(arr);
}
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}return call && ((typeof call === "undefined" ? "undefined" : _typeof2(call)) === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : _typeof2(superClass)));
}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
var base = require('@scion-scxml/core-base'),
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 = function (_base$BaseInterpreter) {
_inherits(Statechart, _base$BaseInterpreter);
function Statechart(modelOrModelFactory, opts) {
_classCallCheck(this, Statechart);
opts = opts || {};
opts.legacySemantics = false;
return _possibleConstructorReturn(this, (Statechart.__proto__ || Object.getPrototypeOf(Statechart)).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 _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = atomicStates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var state = _step.value;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
loop: for (var _iterator2 = [state].concat(query.getAncestors(state))[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var s = _step2.value;
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = s.transitions[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var t = _step3.value;
if (transitionSelector(t, currentEvent, e, selectEventlessTransitions)) {
enabledTransitions.add(t);
break loop;
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var priorityEnabledTransitions = this._removeConflictingTransition(enabledTransitions);
this._log("priorityEnabledTransitions", priorityEnabledTransitions);
return priorityEnabledTransitions;
}
/** @private */
}, {
key: '_removeConflictingTransition',
value: function _removeConflictingTransition(enabledTransitions) {
var _this2 = this;
var filteredTransitions = new this.opts.Set();
//toList sorts the transitions in the order of the states that selected them
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = enabledTransitions.iter()[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var t1 = _step4.value;
var t1Preempted = false;
var transitionsToRemove = new Set();
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
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 = _this2._computeExitSet([t1]);
var t2ExitSet = _this2._computeExitSet([t2]);
var hasIntersection = [].concat(_toConsumableArray(t1ExitSet)).some(function (s) {
return t2ExitSet.has(s);
}) || [].concat(_toConsumableArray(t2ExitSet)).some(function (s) {
return t1ExitSet.has(s);
});
_this2._log('t1ExitSet', t1.source.id, [].concat(_toConsumableArray(t1ExitSet)).map(function (s) {
return s.id;
}));
_this2._log('t2ExitSet', t2.source.id, [].concat(_toConsumableArray(t2ExitSet)).map(function (s) {
return s.id;
}));
_this2._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 (var _iterator5 = filteredTransitions.iter()[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var _ret = _loop();
if (_ret === 'break') break;
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
if (!t1Preempted) {
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = transitionsToRemove[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var t3 = _step6.value;
filteredTransitions.remove(t3);
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
filteredTransitions.add(t1);
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
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 = void 0,
arg = void 0;
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 = void 0;
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;
}).call(this, require("timers").setImmediate);
}, { "@scion-scxml/core-base": 6, "timers": 9 }], 2: [function (require, module, exports) {
'use strict';
/* 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 _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = l.o[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var v = _step.value;
this.o.add(v);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return this;
},
difference: function difference(l) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = l.o[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var v = _step2.value;
this.o.delete(v);
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
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 _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = this.o[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var v = _step3.value;
if (!s2.contains(v)) {
return false;
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
return true;
},
toString: function toString() {
return this.o.size === 0 ? '<empty>' : Array.from(this.o).join(',\n');
}
};
module.exports = ArraySet;
}, {}], 3: [function (require, module, exports) {
'use strict';
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
};
}, {}], 4: [function (require, module, exports) {
'use strict';
var _typeof = typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol" ? function (obj) {
return typeof obj === "undefined" ? "undefined" : _typeof2(obj);
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof2(obj);
};
var constants = require('./constants'),
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],
modelFnName: state.modelFnName
};
}
var statesWithInitialAttributes = [];
/**
@this {SCTransition}
*/
function transitionToString(sourceState) {
return sourceState + ' -- ' + (this.events ? '(' + this.events.join(',') + ')' : null) + (this.cond ? '[' + this.cond.name + ']' : '') + ' --> ' + (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) {
var model = modelFn.call(interpreter, opts._x, opts._x._sessionid, opts._x._ioprocessors, interpreter.isIn.bind(interpreter));
model.modelFnName = modelFn.name;
return model;
}
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;
}
}, { "./constants": 3 }], 5: [function (require, module, exports) {
'use strict';
var constants = require('./constants');
//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;
}, { "./constants": 3 }], 6: [function (require, module, exports) {
(function (process, setImmediate) {
// 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
*/
"use strict";
var _slicedToArray = function () {
function sliceIterator(arr, i) {
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"]) _i["return"]();
} finally {
if (_d) throw _e;
}
}return _arr;
}return function (arr, i) {
if (Array.isArray(arr)) {
return arr;
} else if (Symbol.iterator in Object(arr)) {
return sliceIterator(arr, i);
} else {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
};
}();
var _typeof = typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol" ? function (obj) {
return typeof obj === "undefined" ? "undefined" : _typeof2(obj);
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof2(obj);
};
var _createClass = 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);
}
}return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
};
}();
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
arr2[i] = arr[i];
}return arr2;
} else {
return Array.from(arr);
}
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}return call && ((typeof call === "undefined" ? "undefined" : _typeof2(call)) === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : _typeof2(superClass)));
}subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
var EventEmitter = require('tiny-events').EventEmitter,
util = require('util'),
ArraySet = require('./ArraySet'),
constants = require('./constants'),
helpers = require('./helpers'),
query = require('./query'),
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]