finestate
Version:
Powerful and easy to use Finite State Machine with hierarchy, orthogonal states and 100% tests coverage.
272 lines (271 loc) • 8.41 kB
JavaScript
var T = Object.defineProperty;
var S = (i, t, e) => t in i ? T(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
var a = (i, t, e) => S(i, typeof t != "symbol" ? t + "" : t, e);
const p = "Destroyed state used";
function O(i, ...t) {
return [i, ...t];
}
class Q {
}
function u(i) {
return i[0];
}
function _(i) {
return i.length - 1;
}
function d(i, t) {
return i[1 + t];
}
var D = /* @__PURE__ */ ((i) => (i[i.Ascending = 0] = "Ascending", i[i.Descending = 1] = "Descending", i))(D || {}), g = /* @__PURE__ */ ((i) => (i[i.StopOnProcessed = 0] = "StopOnProcessed", i[i.DontStopOnProcessed = 1] = "DontStopOnProcessed", i))(g || {});
class F {
constructor(t, e, r, s) {
a(this, "dispatchOrder", 0);
a(this, "dispatchOrthoPolicy", 0);
a(this, "_fsm");
a(this, "_parent");
a(this, "_orthoIndex");
a(this, "_children");
this._fsm = t, this._parent = e, this._orthoIndex = r, this._children = new Array(s);
for (let n = 0; n < s; ++n)
this._children[n] = null;
this._parent && (this._parent._children[r] = this);
}
context(t) {
return this._parent ? this._parent instanceof t ? this._parent : this._parent.context(t) : null;
}
get fsm() {
if (!this._fsm)
throw new Error(p);
return this._fsm;
}
get parent() {
return this._parent;
}
get children() {
return this._children;
}
get orthoIndex() {
return this._orthoIndex;
}
get destroyed() {
return this._fsm === null;
}
_init(t) {
this.initParams(t);
}
dispatchToChildren(t) {
let e = !1;
const r = (s) => {
if (s)
return !!(s.dispatch(t) && (e = !0, this.dispatchOrthoPolicy == 0));
};
switch (this.dispatchOrder) {
case 0: {
for (let s = 0; s < this.children.length && !r(this.children[s]); ++s)
;
break;
}
case 1: {
for (let s = this.children.length; s-- && !r(this.children[s]); )
;
break;
}
}
return e;
}
dispatch(t) {
if (this.dispatchToChildren(t))
return !0;
const e = this.processEvent(t);
return !(!e || e instanceof Promise);
}
processEvent(t) {
return !1;
}
_destroy() {
for (let t = this._children.length; t--; ) {
let e = this._children[t];
e && (e._destroy(), e = null);
}
this.destroy(), this._parent && (this._parent._children[this._orthoIndex] = null, this._parent = null), this._fsm = null;
}
transit(t, e) {
if (!this._fsm)
throw p;
return this._fsm.transit(this, t, e), !0;
}
initParams(t) {
this.init();
}
init() {
}
destroy() {
}
}
const w = "The same class is used twice in FSM description: ", m = "The state is not registered in FSM: ", y = "Transition from transition or init is not allowed.", I = "Transition from one ortho area to another is not allowed.";
class M {
constructor(t) {
a(this, "_descs");
a(this, "_rootState");
a(this, "_stateTypeToDesc", /* @__PURE__ */ new Map());
a(this, "_stateDescParent", /* @__PURE__ */ new Map());
a(this, "_stateOrthoIndex", /* @__PURE__ */ new Map());
a(this, "_dispatchDeferred", !1);
a(this, "_dispatchQueue", []);
a(this, "_dispatchQueueIndex", 0);
a(this, "_inTransition", !1);
this._descs = t, this._rootState = null, t.forEach((e) => {
this._fillStateTypeToDescMap(e, 0), this._fillStateDescParent(null, e);
});
}
init(t) {
t || (t = {});
try {
this._dispatchDeferred = !0, this._inTransition = !0, this._createDefaultStateTree(null, this._descs[0], 0, t), this._inTransition = !1, this._dispatchDeferred = !1;
} catch (e) {
throw this._inTransition = !1, this._dispatchDeferred = !1, e;
}
this._dispatchQueue.length > 0 && this._dispatchDeferredQueue();
}
get rootState() {
return this._rootState;
}
transit(t, e, r) {
if (this._inTransition)
throw new Error(y);
const s = this._stateTypeToDesc.get(e);
if (!s)
throw m + e.name;
const n = s;
{
const h = this._stateDescParent.get(n), o = this._stateOrthoIndex.get(e);
if (t.parent && h && t.parent.constructor === u(h) && t.orthoIndex != o)
throw new Error(I);
}
r || (r = {});
try {
this._dispatchDeferred = !0, this._inTransition = !0;
const h = t.parent;
t._destroy();
let o;
if (h) {
const c = this._destroyTillFirstCommonAncestor(h, n);
o = this._createSpecificState(c, n, r);
} else
o = this._createSpecificState(null, n, r);
const l = _(n);
for (let c = 0; c < l; ++c) {
const f = d(n, c);
f && f.length > 0 && this._createDefaultStateTree(o, f[0], c, r);
}
this._inTransition = !1, this._dispatchDeferred = !1;
} catch (h) {
throw this._inTransition = !1, this._dispatchDeferred = !1, h;
}
return this._dispatchQueue.length > 0 && this._dispatchDeferredQueue(), !0;
}
dispatch(t) {
if (this._dispatchDeferred)
return this._dispatchQueue.push(t), !1;
let e;
try {
this._dispatchDeferred = !0, e = this._rootState.dispatch(t), this._dispatchDeferred = !1, this._dispatchQueue.length > 0 && this._dispatchDeferredQueue();
} catch (r) {
throw this._dispatchDeferred = !1, r;
}
return e;
}
_dispatchDeferredQueue() {
try {
for (; this._dispatchQueueIndex < this._dispatchQueue.length; ) {
const t = this._dispatchQueue[this._dispatchQueueIndex++];
this._dispatchDeferred = !0, this._rootState.dispatch(t), this._dispatchDeferred = !1;
}
this._dispatchQueue = [], this._dispatchQueueIndex = 0;
} catch (t) {
throw this._dispatchQueue = [], this._dispatchQueueIndex = 0, this._dispatchDeferred = !1, t;
}
}
_createDefaultStateTree(t, e, r, s) {
const n = _(e), h = u(e), o = new h(this, t, r, n);
o._init(s), t || (this._rootState = o);
for (let l = 0; l < n; ++l) {
const c = d(e, l);
c && c.length > 0 && this._createDefaultStateTree(o, c[0], l, s);
}
return o;
}
_destroyTillFirstCommonAncestor(t, e) {
const r = this._stateTypeToDesc.get(t.constructor);
if (this._areFromTheSameStateTree(r, e))
return t;
const s = t.parent;
return t._destroy(), s ? this._destroyTillFirstCommonAncestor(s, e) : null;
}
_createSpecificState(t, e, r) {
const s = this._stateDescParent.get(e);
if (t === null && s === null || t !== null && u(s) === t.constructor)
return this._createSpecificStateWithOrthoSiblings(t, e, r);
const n = this._createSpecificState(t, s, r);
return this._createSpecificStateWithOrthoSiblings(
n,
e,
r
);
}
_createSpecificStateWithOrthoSiblings(t, e, r) {
const s = u(e), n = this._stateOrthoIndex.get(s), h = _(e);
let o = null;
return t === null ? (o = new s(this, null, 0, h), this._rootState = o, o._init(r)) : (o = new s(this, t, n, h), o._init(r)), o;
}
_fillStateTypeToDescMap(t, e) {
const r = u(t);
if (this._stateTypeToDesc.has(r))
throw w + r.name;
this._stateTypeToDesc.set(r, t), this._stateOrthoIndex.set(r, e);
const s = _(t);
for (let n = 0; n < s; ++n) {
const h = d(t, n);
h == null || h.forEach((o) => this._fillStateTypeToDescMap(o, n));
}
}
_fillStateDescParent(t, e) {
this._stateDescParent.set(e, t);
const r = _(e);
for (let s = 0; s < r; ++s) {
const n = d(e, s);
n == null || n.forEach((h) => {
this._fillStateDescParent(e, h);
});
}
}
_areFromTheSameStateTree(t, e) {
if (t === e)
return !1;
const r = _(t);
for (let s = 0; s < r; ++s) {
const n = d(t, s);
for (const h of n)
if (h === e || this._areFromTheSameStateTree(h, e))
return !0;
}
return !1;
}
}
export {
D as DispatchOrder,
g as DispatchOrthoPolicy,
Q as Event,
M as Fsm,
F as State,
p as ThrowMsg_DestroyedStateUsed,
w as ThrowMsg_TheSameClassUsedTwiceInTheFSMDescription,
m as ThrowMsg_TheStateIsNotRegistered,
I as ThrowMsg_TransitionFromOneOrthoAreaToAnotherIsNotAllowed,
y as ThrowMsg_TransitionFromTransitionOrInitIsNotAllowed,
_ as numOrthoChildrenFromStateDesc,
d as orthoChildrenFromStateDesc,
O as stateDesc,
u as stateTypeFromStateDesc
};
//# sourceMappingURL=finestate.es.js.map