UNPKG

finestate

Version:

Powerful and easy to use Finite State Machine with hierarchy, orthogonal states and 100% tests coverage.

3 lines (2 loc) 6.47 kB
"use strict";var y=Object.defineProperty;var I=(i,t,e)=>t in i?y(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var a=(i,t,e)=>I(i,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p="Destroyed state used";function O(i,...t){return[i,...t]}class F{}function u(i){return i[0]}function l(i){return i.length-1}function d(i,t){return i[1+t]}var T=(i=>(i[i.Ascending=0]="Ascending",i[i.Descending=1]="Descending",i))(T||{}),S=(i=>(i[i.StopOnProcessed=0]="StopOnProcessed",i[i.DontStopOnProcessed=1]="DontStopOnProcessed",i))(S||{});class M{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 D="The same class is used twice in FSM description: ",g="The state is not registered in FSM: ",w="Transition from transition or init is not allowed.",m="Transition from one ortho area to another is not allowed.";class x{constructor(t){a(this,"_descs");a(this,"_rootState");a(this,"_stateTypeToDesc",new Map);a(this,"_stateDescParent",new Map);a(this,"_stateOrthoIndex",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(w);const s=this._stateTypeToDesc.get(e);if(!s)throw g+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(m)}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<_;++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=l(e),h=u(e),o=new h(this,t,r,n);o._init(s),t||(this._rootState=o);for(let _=0;_<n;++_){const c=d(e,_);c&&c.length>0&&this._createDefaultStateTree(o,c[0],_,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=l(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 D+r.name;this._stateTypeToDesc.set(r,t),this._stateOrthoIndex.set(r,e);const s=l(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=l(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=l(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}}exports.DispatchOrder=T;exports.DispatchOrthoPolicy=S;exports.Event=F;exports.Fsm=x;exports.State=M;exports.ThrowMsg_DestroyedStateUsed=p;exports.ThrowMsg_TheSameClassUsedTwiceInTheFSMDescription=D;exports.ThrowMsg_TheStateIsNotRegistered=g;exports.ThrowMsg_TransitionFromOneOrthoAreaToAnotherIsNotAllowed=m;exports.ThrowMsg_TransitionFromTransitionOrInitIsNotAllowed=w;exports.numOrthoChildrenFromStateDesc=l;exports.orthoChildrenFromStateDesc=d;exports.stateDesc=O;exports.stateTypeFromStateDesc=u; //# sourceMappingURL=finestate.cjs.js.map