UNPKG

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
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