@peter.naydenov/fsm-hub 2.1.5 → 2.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,22 @@
1
1
  ## Release History
2
2
 
3
3
 
4
+
5
+ ### 2.1.7 ( 2026-07-25)
6
+ - [x] Dependency update. @peter.naydenov/stack - v.3.0.1;
7
+ - [x] Migrating the testing framework from mocha to vitest;
8
+ - [x] Migrating the coverage framework from c8 to vitest/coverage-v8;
9
+
10
+
11
+
12
+ ### 2.1.6 ( 2026-07-22)
13
+ - [x] Fix: `_callback.js` crashed when a callback rule fired with a `null` response (or a transformer returning `null`). Guarded the `.answer` access so the placeholder-clear no-ops and the callback still runs.
14
+ - [x] Fix: `MISSING_FSM` debugger call logged the whole subscribers array instead of the missing name. Now passes the specific missing entry.
15
+ - [x] Tests: 3 regression cases added (1 for the `MISSING_FSM` data, 2 for the null-response crashes). 14 → 17 passing;
16
+ - [x] Dev dependencies updates. @peter.naydenov/fsm - v.5.2.7;
17
+
18
+
19
+
4
20
  ### 2.1.5 ( 2026-07-21)
5
21
  - [x] Dependency update. ask-for-promise@3.2.0;
6
22
  - [x] Dev dependency update. @peter.naydenov/fsm - v.5.2.6;
package/dist/fsm-hub.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("ask-for-promise"),n=require("@peter.naydenov/stack");const r={_setTransitions:function(e,n){return function({reactivity:r,transformers:t},s={}){let a={},c={},o={},i={};return r.forEach((r,t)=>{if(!(r instanceof Array))return void e._debugger(n.WRONG_REACTIVITY_RECORD,t+1);const s=r.length,[a,u,l,f]=r;if(!(4==s||3==s))return void e._debugger(n.WRONG_REACTIVITY_RECORD,t+1);const h=`${a}/${u}`;if(4==s){c[h]||(c[h]=[]),c[h].push(l);o[`${h}/${l}`]=f}3==s&&(i[h]||(i[h]=[]),i[h].push(l))}),t&&Object.keys(t).forEach(e=>{const n=t[e],r=s[n];r&&(a[e]=r)}),{transformers:a,subscribers:c,callbacks:i,actions:o}}},_debugger:function(e){return function(n,r){e.debug&&console.log(n,r)}},_callback:function(n,r){return function(t,s,a,c){const o=`${s}/${a}`,i=n.subscribers[o]||!1,u=n.callbacks[o]||!1,l=n.fnCallbacks,f=n.actions,h=[];let d;if(i||u){if(i&&i.forEach(e=>{if(!n.fsm[e])return void n._debugger(r.MISSING_FSM,i);const t=f[`${o}/${e}`],u=`${s}/${e}`,l=n.transformers[u];d="function"==typeof l?l(a,c):c,d||(d={},d.___internalFlag=!0);const _=n.fsm[e].update(t,d);h.push(_)}),u){let t=e();h.push(t.promise),u.forEach(e=>{const t=l[e],o=`${s}/${e}`,i=n.transformers[o];d="function"==typeof i?i(a,c):c,d.answer&&d.answer.hasOwnProperty("___internalFlag")&&(d.answer=void 0),"function"==typeof t?t(d):n._debugger(r.MISSING_FN,e)}),t.done()}Promise.all(h).then(()=>t.done())}else t.done()}},addFsm:function(n,r){return function(t){Object.keys(t).forEach(s=>{function a(e){if(e&&(n.haveInternalRequest=!1),n.haveInternalRequest)return;let r=n.cacheInternal.isEmpty();if(n.cache.isEmpty()&&r)return void(n.lock=!1);let[t,s,a]=r?n.cache.pull():n.cacheInternal.pull();n.cache.isEmpty()&&(n.lock=!1),n.cacheInternal.isEmpty()&&(n.haveInternalRequest=!1),c(t,s,a)}function c(r,t,s){let c;if(!n.lock)return n.lock=!0,c=e(),c.onComplete(e=>a(!1)),void n._callback(c,r,t,s);if(s){if(n.haveInternalRequest)return void n.cacheInternal.push([[r,t,s]]);let c=e();return c.onComplete(e=>a(!0)),n.haveInternalRequest=!0,void n._callback(c,r,t,s)}n.cache.push([[r,t,s]])}n.fsm[s]?n._debugger(r.REGISTERED_FSM_NAME,s):(n.fsm[s]=t[s],n.fsm[s].on("update",(e,n)=>c(s,e,n)))})}},addFunctions:function(e,n){return function(r){Object.keys(r).forEach(t=>{e.fnCallbacks[t]?e._debugger(n.REGISTERED_FUNCTION_NAME,t):e.fnCallbacks[t]=r[t]})}}},t={WRONG_REACTIVITY_RECORD:"Error: Wrong reactivity record on row %s.",REGISTERED_FSM_NAME:'Warning: FSM "%s" is already registered.',REGISTERED_FUNCTION_NAME:'Warning: Function "%s" is already registered.',MISSING_FSM:'Warning: Fsm "%s" is not registered to the hub.',MISSING_FN:'Warning: Function "%s" is not registered to the hub.'};module.exports=function(s,a){const c=this,o=Object.keys(r);c.fsm={},c.fnCallbacks={},c.debug=s.debug||!1,c.cache=n({type:"FIFO"}),c.cacheInternal=n({type:"FIFO"}),c.wait=[],c.lock=!1,c.haveInternalRequest=!1,c.reactivityTask=!1,c.askForPromise=e,o.forEach(e=>{c[e]=r[e](c,t)});const{transformers:i,subscribers:u,actions:l,callbacks:f}=c._setTransitions(s,a);c.transformers=i,c.subscribers=u,c.actions=l,c.callbacks=f};
1
+ "use strict";var e=require("ask-for-promise"),n=require("@peter.naydenov/stack");const r={_setTransitions:function(e,n){return function({reactivity:r,transformers:t},s={}){let a={},c={},o={},i={};return r.forEach((r,t)=>{if(!(r instanceof Array))return void e._debugger(n.WRONG_REACTIVITY_RECORD,t+1);const s=r.length,[a,u,l,f]=r;if(!(4==s||3==s))return void e._debugger(n.WRONG_REACTIVITY_RECORD,t+1);const h=`${a}/${u}`;if(4==s){c[h]||(c[h]=[]),c[h].push(l);o[`${h}/${l}`]=f}3==s&&(i[h]||(i[h]=[]),i[h].push(l))}),t&&Object.keys(t).forEach(e=>{const n=t[e],r=s[n];r&&(a[e]=r)}),{transformers:a,subscribers:c,callbacks:i,actions:o}}},_debugger:function(e){return function(n,r){e.debug&&console.log(n,r)}},_callback:function(n,r){return function(t,s,a,c){const o=`${s}/${a}`,i=n.subscribers[o]||!1,u=n.callbacks[o]||!1,l=n.fnCallbacks,f=n.actions,h=[];let d;if(i||u){if(i&&i.forEach(e=>{if(!n.fsm[e])return void n._debugger(r.MISSING_FSM,e);const t=f[`${o}/${e}`],i=`${s}/${e}`,u=n.transformers[i];d="function"==typeof u?u(a,c):c,d||(d={},d.___internalFlag=!0);const l=n.fsm[e].update(t,d);h.push(l)}),u){let t=e();h.push(t.promise),u.forEach(e=>{const t=l[e],o=`${s}/${e}`,i=n.transformers[o];d="function"==typeof i?i(a,c):c,d&&d.answer&&d.answer.hasOwnProperty("___internalFlag")&&(d.answer=void 0),"function"==typeof t?t(d):n._debugger(r.MISSING_FN,e)}),t.done()}Promise.all(h).then(()=>t.done())}else t.done()}},addFsm:function(n,r){return function(t){Object.keys(t).forEach(s=>{function a(e){if(e&&(n.haveInternalRequest=!1),n.haveInternalRequest)return;let r=n.cacheInternal.isEmpty();if(n.cache.isEmpty()&&r)return void(n.lock=!1);let[t,s,a]=r?n.cache.pull():n.cacheInternal.pull();n.cache.isEmpty()&&(n.lock=!1),n.cacheInternal.isEmpty()&&(n.haveInternalRequest=!1),c(t,s,a)}function c(r,t,s){let c;if(!n.lock)return n.lock=!0,c=e(),c.onComplete(e=>a(!1)),void n._callback(c,r,t,s);if(s){if(n.haveInternalRequest)return void n.cacheInternal.push([[r,t,s]]);let c=e();return c.onComplete(e=>a(!0)),n.haveInternalRequest=!0,void n._callback(c,r,t,s)}n.cache.push([[r,t,s]])}n.fsm[s]?n._debugger(r.REGISTERED_FSM_NAME,s):(n.fsm[s]=t[s],n.fsm[s].on("update",(e,n)=>c(s,e,n)))})}},addFunctions:function(e,n){return function(r){Object.keys(r).forEach(t=>{e.fnCallbacks[t]?e._debugger(n.REGISTERED_FUNCTION_NAME,t):e.fnCallbacks[t]=r[t]})}}},t={WRONG_REACTIVITY_RECORD:"Error: Wrong reactivity record on row %s.",REGISTERED_FSM_NAME:'Warning: FSM "%s" is already registered.',REGISTERED_FUNCTION_NAME:'Warning: Function "%s" is already registered.',MISSING_FSM:'Warning: Fsm "%s" is not registered to the hub.',MISSING_FN:'Warning: Function "%s" is not registered to the hub.'};module.exports=function(s,a){const c=this,o=Object.keys(r);c.fsm={},c.fnCallbacks={},c.debug=s.debug||!1,c.cache=n({type:"FIFO"}),c.cacheInternal=n({type:"FIFO"}),c.wait=[],c.lock=!1,c.haveInternalRequest=!1,c.reactivityTask=!1,c.askForPromise=e,o.forEach(e=>{c[e]=r[e](c,t)});const{transformers:i,subscribers:u,actions:l,callbacks:f}=c._setTransitions(s,a);c.transformers=i,c.subscribers=u,c.actions=l,c.callbacks=f};
@@ -1 +1 @@
1
- import e from"ask-for-promise";import n from"@peter.naydenov/stack";const t={_setTransitions:function(e,n){return function({reactivity:t,transformers:r},s={}){let a={},c={},o={},i={};return t.forEach((t,r)=>{if(!(t instanceof Array))return void e._debugger(n.WRONG_REACTIVITY_RECORD,r+1);const s=t.length,[a,u,l,f]=t;if(!(4==s||3==s))return void e._debugger(n.WRONG_REACTIVITY_RECORD,r+1);const h=`${a}/${u}`;if(4==s){c[h]||(c[h]=[]),c[h].push(l);o[`${h}/${l}`]=f}3==s&&(i[h]||(i[h]=[]),i[h].push(l))}),r&&Object.keys(r).forEach(e=>{const n=r[e],t=s[n];t&&(a[e]=t)}),{transformers:a,subscribers:c,callbacks:i,actions:o}}},_debugger:function(e){return function(n,t){e.debug&&console.log(n,t)}},_callback:function(n,t){return function(r,s,a,c){const o=`${s}/${a}`,i=n.subscribers[o]||!1,u=n.callbacks[o]||!1,l=n.fnCallbacks,f=n.actions,h=[];let d;if(i||u){if(i&&i.forEach(e=>{if(!n.fsm[e])return void n._debugger(t.MISSING_FSM,i);const r=f[`${o}/${e}`],u=`${s}/${e}`,l=n.transformers[u];d="function"==typeof l?l(a,c):c,d||(d={},d.___internalFlag=!0);const _=n.fsm[e].update(r,d);h.push(_)}),u){let r=e();h.push(r.promise),u.forEach(e=>{const r=l[e],o=`${s}/${e}`,i=n.transformers[o];d="function"==typeof i?i(a,c):c,d.answer&&d.answer.hasOwnProperty("___internalFlag")&&(d.answer=void 0),"function"==typeof r?r(d):n._debugger(t.MISSING_FN,e)}),r.done()}Promise.all(h).then(()=>r.done())}else r.done()}},addFsm:function(n,t){return function(r){Object.keys(r).forEach(s=>{function a(e){if(e&&(n.haveInternalRequest=!1),n.haveInternalRequest)return;let t=n.cacheInternal.isEmpty();if(n.cache.isEmpty()&&t)return void(n.lock=!1);let[r,s,a]=t?n.cache.pull():n.cacheInternal.pull();n.cache.isEmpty()&&(n.lock=!1),n.cacheInternal.isEmpty()&&(n.haveInternalRequest=!1),c(r,s,a)}function c(t,r,s){let c;if(!n.lock)return n.lock=!0,c=e(),c.onComplete(e=>a(!1)),void n._callback(c,t,r,s);if(s){if(n.haveInternalRequest)return void n.cacheInternal.push([[t,r,s]]);let c=e();return c.onComplete(e=>a(!0)),n.haveInternalRequest=!0,void n._callback(c,t,r,s)}n.cache.push([[t,r,s]])}n.fsm[s]?n._debugger(t.REGISTERED_FSM_NAME,s):(n.fsm[s]=r[s],n.fsm[s].on("update",(e,n)=>c(s,e,n)))})}},addFunctions:function(e,n){return function(t){Object.keys(t).forEach(r=>{e.fnCallbacks[r]?e._debugger(n.REGISTERED_FUNCTION_NAME,r):e.fnCallbacks[r]=t[r]})}}},r={WRONG_REACTIVITY_RECORD:"Error: Wrong reactivity record on row %s.",REGISTERED_FSM_NAME:'Warning: FSM "%s" is already registered.',REGISTERED_FUNCTION_NAME:'Warning: Function "%s" is already registered.',MISSING_FSM:'Warning: Fsm "%s" is not registered to the hub.',MISSING_FN:'Warning: Function "%s" is not registered to the hub.'};function s(s,a){const c=this,o=Object.keys(t);c.fsm={},c.fnCallbacks={},c.debug=s.debug||!1,c.cache=n({type:"FIFO"}),c.cacheInternal=n({type:"FIFO"}),c.wait=[],c.lock=!1,c.haveInternalRequest=!1,c.reactivityTask=!1,c.askForPromise=e,o.forEach(e=>{c[e]=t[e](c,r)});const{transformers:i,subscribers:u,actions:l,callbacks:f}=c._setTransitions(s,a);c.transformers=i,c.subscribers=u,c.actions=l,c.callbacks=f}export{s as default};
1
+ import e from"ask-for-promise";import n from"@peter.naydenov/stack";const t={_setTransitions:function(e,n){return function({reactivity:t,transformers:r},s={}){let a={},c={},o={},i={};return t.forEach((t,r)=>{if(!(t instanceof Array))return void e._debugger(n.WRONG_REACTIVITY_RECORD,r+1);const s=t.length,[a,u,l,f]=t;if(!(4==s||3==s))return void e._debugger(n.WRONG_REACTIVITY_RECORD,r+1);const h=`${a}/${u}`;if(4==s){c[h]||(c[h]=[]),c[h].push(l);o[`${h}/${l}`]=f}3==s&&(i[h]||(i[h]=[]),i[h].push(l))}),r&&Object.keys(r).forEach(e=>{const n=r[e],t=s[n];t&&(a[e]=t)}),{transformers:a,subscribers:c,callbacks:i,actions:o}}},_debugger:function(e){return function(n,t){e.debug&&console.log(n,t)}},_callback:function(n,t){return function(r,s,a,c){const o=`${s}/${a}`,i=n.subscribers[o]||!1,u=n.callbacks[o]||!1,l=n.fnCallbacks,f=n.actions,h=[];let d;if(i||u){if(i&&i.forEach(e=>{if(!n.fsm[e])return void n._debugger(t.MISSING_FSM,e);const r=f[`${o}/${e}`],i=`${s}/${e}`,u=n.transformers[i];d="function"==typeof u?u(a,c):c,d||(d={},d.___internalFlag=!0);const l=n.fsm[e].update(r,d);h.push(l)}),u){let r=e();h.push(r.promise),u.forEach(e=>{const r=l[e],o=`${s}/${e}`,i=n.transformers[o];d="function"==typeof i?i(a,c):c,d&&d.answer&&d.answer.hasOwnProperty("___internalFlag")&&(d.answer=void 0),"function"==typeof r?r(d):n._debugger(t.MISSING_FN,e)}),r.done()}Promise.all(h).then(()=>r.done())}else r.done()}},addFsm:function(n,t){return function(r){Object.keys(r).forEach(s=>{function a(e){if(e&&(n.haveInternalRequest=!1),n.haveInternalRequest)return;let t=n.cacheInternal.isEmpty();if(n.cache.isEmpty()&&t)return void(n.lock=!1);let[r,s,a]=t?n.cache.pull():n.cacheInternal.pull();n.cache.isEmpty()&&(n.lock=!1),n.cacheInternal.isEmpty()&&(n.haveInternalRequest=!1),c(r,s,a)}function c(t,r,s){let c;if(!n.lock)return n.lock=!0,c=e(),c.onComplete(e=>a(!1)),void n._callback(c,t,r,s);if(s){if(n.haveInternalRequest)return void n.cacheInternal.push([[t,r,s]]);let c=e();return c.onComplete(e=>a(!0)),n.haveInternalRequest=!0,void n._callback(c,t,r,s)}n.cache.push([[t,r,s]])}n.fsm[s]?n._debugger(t.REGISTERED_FSM_NAME,s):(n.fsm[s]=r[s],n.fsm[s].on("update",(e,n)=>c(s,e,n)))})}},addFunctions:function(e,n){return function(t){Object.keys(t).forEach(r=>{e.fnCallbacks[r]?e._debugger(n.REGISTERED_FUNCTION_NAME,r):e.fnCallbacks[r]=t[r]})}}},r={WRONG_REACTIVITY_RECORD:"Error: Wrong reactivity record on row %s.",REGISTERED_FSM_NAME:'Warning: FSM "%s" is already registered.',REGISTERED_FUNCTION_NAME:'Warning: Function "%s" is already registered.',MISSING_FSM:'Warning: Fsm "%s" is not registered to the hub.',MISSING_FN:'Warning: Function "%s" is not registered to the hub.'};function s(s,a){const c=this,o=Object.keys(t);c.fsm={},c.fnCallbacks={},c.debug=s.debug||!1,c.cache=n({type:"FIFO"}),c.cacheInternal=n({type:"FIFO"}),c.wait=[],c.lock=!1,c.haveInternalRequest=!1,c.reactivityTask=!1,c.askForPromise=e,o.forEach(e=>{c[e]=t[e](c,r)});const{transformers:i,subscribers:u,actions:l,callbacks:f}=c._setTransitions(s,a);c.transformers=i,c.subscribers=u,c.actions=l,c.callbacks=f}export{s as default};
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).fsmHub=t()}(this,function(){"use strict";function e(e){return e?function(e){let i=e.map(e=>t()),o=i.map(e=>e.promise);i.promises=i;let c=n(Promise.all(o));const s={promise:Promise.all(o),promises:i,_list:e,_activeTimer:null,each:()=>{},onComplete:c,timeout:()=>{},done:function(e){null!==this._activeTimer&&(clearTimeout(this._activeTimer),this._activeTimer=null),this.promises.forEach(t=>t.done(e))},cancel:function(e){null!==this._activeTimer&&(clearTimeout(this._activeTimer),this._activeTimer=null),this.promises.forEach(t=>t.cancel(e))}};return s.each=function(e,...t){this.promises.forEach((n,r)=>e({value:this._list[r],done:n.done,cancel:n.cancel,timeout:n.timeout},r,...t))},s.timeout=r(!0),s}(e):t()}function t(){let e,t;const i=new Promise((n,r)=>{e=n,t=r}),o={promise:i,promises:null,_activeTimer:null,each:()=>{},onComplete:n(i),timeout:()=>{}},c=new WeakRef(o);return o.done=function(t){const n=c.deref();void 0!==n&&null!==n._activeTimer&&(clearTimeout(n._activeTimer),n._activeTimer=null),e(t)},o.cancel=function(e){const n=c.deref();void 0!==n&&null!==n._activeTimer&&(clearTimeout(n._activeTimer),n._activeTimer=null),t(e)},o.timeout=r(!1),o.each=function(e,...t){e({value:null,done:o.done,cancel:o.cancel,timeout:this.timeout},...t)},o}function n(e){return function(t,n=null){null===n?e.then(e=>t(e)):e.then(e=>t(e),e=>n(e))}}function r(e){return function(t,r){const i=new WeakRef(this);let o,c;o=e?Promise.all(this.promises.map(e=>e.promise)):this.promise;const s=new Promise((e,n)=>{c=setTimeout(()=>{const t=i.deref();void 0!==t&&t.done(r),e(r)},t)});return this._activeTimer=c,o.then(()=>clearTimeout(c)),this.onComplete=n(Promise.race([o,s])),this}}e.sequence=function(t,...n){const r=e(),i=[];const o=function*(e){for(const t of e)yield t}(t);try{!function e(t,...n){t.done?r.done(i):Promise.resolve().then(()=>t.value(...n)).then(t=>{i.push(t),e(o.next(),...n,t)},e=>{r.cancel(e)})}(o.next(),...n)}catch(e){r.cancel(e)}return r},e.all=function(t,...n){const r=e(),i=[];let o;try{o=t.map((e,t)=>Promise.resolve().then(()=>"function"==typeof e?e(...n):e).then(e=>i[t]=e,e=>{throw e}))}catch(e){return r.cancel(e),r}return Promise.all(o).then(()=>r.done(i),e=>r.cancel(e)),r};const i={_setTransitions:function(e,t){return function({reactivity:n,transformers:r},i={}){let o={},c={},s={},l={};return n.forEach((n,r)=>{if(!(n instanceof Array))return void e._debugger(t.WRONG_REACTIVITY_RECORD,r+1);const i=n.length,[o,a,u,f]=n;if(!(4==i||3==i))return void e._debugger(t.WRONG_REACTIVITY_RECORD,r+1);const m=`${o}/${a}`;if(4==i){c[m]||(c[m]=[]),c[m].push(u);s[`${m}/${u}`]=f}3==i&&(l[m]||(l[m]=[]),l[m].push(u))}),r&&Object.keys(r).forEach(e=>{const t=r[e],n=i[t];n&&(o[e]=n)}),{transformers:o,subscribers:c,callbacks:l,actions:s}}},_debugger:function(e){return function(t,n){e.debug&&console.log(t,n)}},_callback:function(t,n){return function(r,i,o,c){const s=`${i}/${o}`,l=t.subscribers[s]||!1,a=t.callbacks[s]||!1,u=t.fnCallbacks,f=t.actions,m=[];let h;if(l||a){if(l&&l.forEach(e=>{if(!t.fsm[e])return void t._debugger(n.MISSING_FSM,l);const r=f[`${s}/${e}`],a=`${i}/${e}`,u=t.transformers[a];h="function"==typeof u?u(o,c):c,h||(h={},h.___internalFlag=!0);const p=t.fsm[e].update(r,h);m.push(p)}),a){let r=e();m.push(r.promise),a.forEach(e=>{const r=u[e],s=`${i}/${e}`,l=t.transformers[s];h="function"==typeof l?l(o,c):c,h.answer&&h.answer.hasOwnProperty("___internalFlag")&&(h.answer=void 0),"function"==typeof r?r(h):t._debugger(n.MISSING_FN,e)}),r.done()}Promise.all(m).then(()=>r.done())}else r.done()}},addFsm:function(t,n){return function(r){Object.keys(r).forEach(i=>{function o(e){if(e&&(t.haveInternalRequest=!1),t.haveInternalRequest)return;let n=t.cacheInternal.isEmpty();if(t.cache.isEmpty()&&n)return void(t.lock=!1);let[r,i,o]=n?t.cache.pull():t.cacheInternal.pull();t.cache.isEmpty()&&(t.lock=!1),t.cacheInternal.isEmpty()&&(t.haveInternalRequest=!1),c(r,i,o)}function c(n,r,i){let c;if(!t.lock)return t.lock=!0,c=e(),c.onComplete(e=>o(!1)),void t._callback(c,n,r,i);if(i){if(t.haveInternalRequest)return void t.cacheInternal.push([[n,r,i]]);let c=e();return c.onComplete(e=>o(!0)),t.haveInternalRequest=!0,void t._callback(c,n,r,i)}t.cache.push([[n,r,i]])}t.fsm[i]?t._debugger(n.REGISTERED_FSM_NAME,i):(t.fsm[i]=r[i],t.fsm[i].on("update",(e,t)=>c(i,e,t)))})}},addFunctions:function(e,t){return function(n){Object.keys(n).forEach(r=>{e.fnCallbacks[r]?e._debugger(t.REGISTERED_FUNCTION_NAME,r):e.fnCallbacks[r]=n[r]})}}},o={WRONG_REACTIVITY_RECORD:"Error: Wrong reactivity record on row %s.",REGISTERED_FSM_NAME:'Warning: FSM "%s" is already registered.',REGISTERED_FUNCTION_NAME:'Warning: Function "%s" is already registered.',MISSING_FSM:'Warning: Fsm "%s" is not registered to the hub.',MISSING_FN:'Warning: Function "%s" is not registered to the hub.'};function c(e={}){let t=[],{type:n,limit:r,onLimit:i}=Object.assign({},{type:"FIFO",limit:!1,onLimit:"update"},e),o="LIFO"===n.toUpperCase(),c=!1;function s(e=1,n=0){let r=[];return n>0&&Array.from({length:n}).map(()=>t.pop()),1==e?t.pop():(Array.from({length:e}).map(()=>{let e=t.pop();null!=e&&r.push(e)}),r)}function l(e=1,n=0){let r=[],i=t.length-n;return e>1&&Array.from({length:e}).map(()=>{null!=t[i-1]&&r.push(t[i-1]),i--}),1==e?t[t.length-1]:r}function a(){}return a.prototype={pull:s,pullReverse:function(e=1,t=0){let n=s(e,t);return n instanceof Array?n.reverse():n},peek:l,peekReverse:function(e=1,t=0){const n=l(e,t);return n instanceof Array?n.reverse():n},getSize:()=>t.length,isEmpty:()=>0==t.length,reset:()=>(t=[],!0),debug:()=>[...t]},a.prototype.push=o?function(e){const n=e instanceof Array,o=n?e.length:1;let l=!1;if("full"!==i||!c){if(r&&n&&o>r&&(e=e.slice(0,-o+r)),r){const o=(n?e.length:1)+t.length;o>=r&&"full"===i&&(e=e.slice(0,-(o-r))),o>=r&&"update"===i&&(l=s(o-r))}return t=e instanceof Array?t.concat(e):t.concat([e]),c=!!r&&t.length===r,l||void 0}}:function(e){const n=e instanceof Array,o=n?e.length:1;let l=!1;if("full"!==i||!c){if(r&&n&&o>r&&(e=e.slice(o-r)),r){const o=(n?e.length:1)+t.length;o>=r&&"full"===i&&(e=e.slice(0,-(o-r))),o>=r&&"update"===i&&(l=s(o-r))}return t=n?e.reduce((e,t)=>[t,...e],t):[e].reduce((e,t)=>[t,...e],t),c=!!r&&t.length===r,l||void 0}},new a}return function(t,n){const r=this,s=Object.keys(i);r.fsm={},r.fnCallbacks={},r.debug=t.debug||!1,r.cache=c({type:"FIFO"}),r.cacheInternal=c({type:"FIFO"}),r.wait=[],r.lock=!1,r.haveInternalRequest=!1,r.reactivityTask=!1,r.askForPromise=e,s.forEach(e=>{r[e]=i[e](r,o)});const{transformers:l,subscribers:a,actions:u,callbacks:f}=r._setTransitions(t,n);r.transformers=l,r.subscribers=a,r.actions=u,r.callbacks=f}});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).fsmHub=t()}(this,function(){"use strict";function e(e){return e?function(e){let i=e.map(e=>t()),o=i.map(e=>e.promise);i.promises=i;let c=n(Promise.all(o));const s={promise:Promise.all(o),promises:i,_list:e,_activeTimer:null,each:()=>{},onComplete:c,timeout:()=>{},done:function(e){null!==this._activeTimer&&(clearTimeout(this._activeTimer),this._activeTimer=null),this.promises.forEach(t=>t.done(e))},cancel:function(e){null!==this._activeTimer&&(clearTimeout(this._activeTimer),this._activeTimer=null),this.promises.forEach(t=>t.cancel(e))}};return s.each=function(e,...t){this.promises.forEach((n,r)=>e({value:this._list[r],done:n.done,cancel:n.cancel,timeout:n.timeout},r,...t))},s.timeout=r(!0),s}(e):t()}function t(){let e,t;const i=new Promise((n,r)=>{e=n,t=r}),o={promise:i,promises:null,_activeTimer:null,each:()=>{},onComplete:n(i),timeout:()=>{}},c=new WeakRef(o);return o.done=function(t){const n=c.deref();void 0!==n&&null!==n._activeTimer&&(clearTimeout(n._activeTimer),n._activeTimer=null),e(t)},o.cancel=function(e){const n=c.deref();void 0!==n&&null!==n._activeTimer&&(clearTimeout(n._activeTimer),n._activeTimer=null),t(e)},o.timeout=r(!1),o.each=function(e,...t){e({value:null,done:o.done,cancel:o.cancel,timeout:this.timeout},...t)},o}function n(e){return function(t,n=null){null===n?e.then(e=>t(e)):e.then(e=>t(e),e=>n(e))}}function r(e){return function(t,r){const i=new WeakRef(this);let o,c;o=e?Promise.all(this.promises.map(e=>e.promise)):this.promise;const s=new Promise((e,n)=>{c=setTimeout(()=>{const t=i.deref();void 0!==t&&t.done(r),e(r)},t)});return this._activeTimer=c,o.then(()=>clearTimeout(c)),this.onComplete=n(Promise.race([o,s])),this}}e.sequence=function(t,...n){const r=e(),i=[];const o=function*(e){for(const t of e)yield t}(t);try{!function e(t,...n){t.done?r.done(i):Promise.resolve().then(()=>t.value(...n)).then(t=>{i.push(t),e(o.next(),...n,t)},e=>{r.cancel(e)})}(o.next(),...n)}catch(e){r.cancel(e)}return r},e.all=function(t,...n){const r=e(),i=[];let o;try{o=t.map((e,t)=>Promise.resolve().then(()=>"function"==typeof e?e(...n):e).then(e=>i[t]=e,e=>{throw e}))}catch(e){return r.cancel(e),r}return Promise.all(o).then(()=>r.done(i),e=>r.cancel(e)),r};const i={_setTransitions:function(e,t){return function({reactivity:n,transformers:r},i={}){let o={},c={},s={},l={};return n.forEach((n,r)=>{if(!(n instanceof Array))return void e._debugger(t.WRONG_REACTIVITY_RECORD,r+1);const i=n.length,[o,a,u,f]=n;if(!(4==i||3==i))return void e._debugger(t.WRONG_REACTIVITY_RECORD,r+1);const m=`${o}/${a}`;if(4==i){c[m]||(c[m]=[]),c[m].push(u);s[`${m}/${u}`]=f}3==i&&(l[m]||(l[m]=[]),l[m].push(u))}),r&&Object.keys(r).forEach(e=>{const t=r[e],n=i[t];n&&(o[e]=n)}),{transformers:o,subscribers:c,callbacks:l,actions:s}}},_debugger:function(e){return function(t,n){e.debug&&console.log(t,n)}},_callback:function(t,n){return function(r,i,o,c){const s=`${i}/${o}`,l=t.subscribers[s]||!1,a=t.callbacks[s]||!1,u=t.fnCallbacks,f=t.actions,m=[];let h;if(l||a){if(l&&l.forEach(e=>{if(!t.fsm[e])return void t._debugger(n.MISSING_FSM,e);const r=f[`${s}/${e}`],l=`${i}/${e}`,a=t.transformers[l];h="function"==typeof a?a(o,c):c,h||(h={},h.___internalFlag=!0);const u=t.fsm[e].update(r,h);m.push(u)}),a){let r=e();m.push(r.promise),a.forEach(e=>{const r=u[e],s=`${i}/${e}`,l=t.transformers[s];h="function"==typeof l?l(o,c):c,h&&h.answer&&h.answer.hasOwnProperty("___internalFlag")&&(h.answer=void 0),"function"==typeof r?r(h):t._debugger(n.MISSING_FN,e)}),r.done()}Promise.all(m).then(()=>r.done())}else r.done()}},addFsm:function(t,n){return function(r){Object.keys(r).forEach(i=>{function o(e){if(e&&(t.haveInternalRequest=!1),t.haveInternalRequest)return;let n=t.cacheInternal.isEmpty();if(t.cache.isEmpty()&&n)return void(t.lock=!1);let[r,i,o]=n?t.cache.pull():t.cacheInternal.pull();t.cache.isEmpty()&&(t.lock=!1),t.cacheInternal.isEmpty()&&(t.haveInternalRequest=!1),c(r,i,o)}function c(n,r,i){let c;if(!t.lock)return t.lock=!0,c=e(),c.onComplete(e=>o(!1)),void t._callback(c,n,r,i);if(i){if(t.haveInternalRequest)return void t.cacheInternal.push([[n,r,i]]);let c=e();return c.onComplete(e=>o(!0)),t.haveInternalRequest=!0,void t._callback(c,n,r,i)}t.cache.push([[n,r,i]])}t.fsm[i]?t._debugger(n.REGISTERED_FSM_NAME,i):(t.fsm[i]=r[i],t.fsm[i].on("update",(e,t)=>c(i,e,t)))})}},addFunctions:function(e,t){return function(n){Object.keys(n).forEach(r=>{e.fnCallbacks[r]?e._debugger(t.REGISTERED_FUNCTION_NAME,r):e.fnCallbacks[r]=n[r]})}}},o={WRONG_REACTIVITY_RECORD:"Error: Wrong reactivity record on row %s.",REGISTERED_FSM_NAME:'Warning: FSM "%s" is already registered.',REGISTERED_FUNCTION_NAME:'Warning: Function "%s" is already registered.',MISSING_FSM:'Warning: Fsm "%s" is not registered to the hub.',MISSING_FN:'Warning: Function "%s" is not registered to the hub.'};function c(e={}){let t=[],{type:n,limit:r,onLimit:i}=Object.assign({},{type:"FIFO",limit:!1,onLimit:"update"},e),o="LIFO"===n.toUpperCase(),c=!1;function s(e=1,n=0){let r=[];return n>0&&Array.from({length:n}).map(()=>t.pop()),1==e?t.pop():(Array.from({length:e}).map(()=>{let e=t.pop();null!=e&&r.push(e)}),r)}function l(e=1,n=0){let r=[],i=t.length-n;return e>1&&Array.from({length:e}).map(()=>{null!=t[i-1]&&r.push(t[i-1]),i--}),1==e?t[t.length-1-n]:r}function a(){}return a.prototype={pull:s,pullReverse:function(e=1,t=0){let n=s(e,t);return n instanceof Array?n.reverse():n},peek:l,peekReverse:function(e=1,t=0){const n=l(e,t);return n instanceof Array?n.reverse():n},getSize:()=>t.length,isEmpty:()=>0==t.length,reset:()=>(t=[],!0),debug:()=>[...t]},a.prototype.push=o?function(e){e instanceof Array||(e=[e]);const n=e.length;let o=!1;if("full"!==i||!c){if(r&&n>r&&(e=e.slice(0,-n+r)),r){const n=e.length+t.length;n>=r&&"full"===i&&(e=e.slice(0,-(n-r))),n>=r&&"update"===i&&(o=s(n-r))}return t=t.concat(e),c=!!r&&t.length===r,o||void 0}}:function(e){e instanceof Array||(e=[e]);const n=e.length;let o=!1;if("full"!==i||!c){if(r&&n>r&&(e=e.slice(n-r)),r){const n=e.length+t.length;n>=r&&"full"===i&&(e=e.slice(0,-(n-r))),n>=r&&"update"===i&&(o=s(n-r))}return t=e.reduce((e,t)=>[t,...e],t),c=!!r&&t.length===r,o||void 0}},new a}return function(t,n){const r=this,s=Object.keys(i);r.fsm={},r.fnCallbacks={},r.debug=t.debug||!1,r.cache=c({type:"FIFO"}),r.cacheInternal=c({type:"FIFO"}),r.wait=[],r.lock=!1,r.haveInternalRequest=!1,r.reactivityTask=!1,r.askForPromise=e,s.forEach(e=>{r[e]=i[e](r,o)});const{transformers:l,subscribers:a,actions:u,callbacks:f}=r._setTransitions(t,n);r.transformers=l,r.subscribers=a,r.actions=u,r.callbacks=f}});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@peter.naydenov/fsm-hub",
3
3
  "description": "FSM orchestration and state-managment tool",
4
- "version": "2.1.5",
4
+ "version": "2.1.7",
5
5
  "license": "MIT",
6
6
  "author": "Peter Naydenov",
7
7
  "main": "./dist/fsm-hub.umd.js",
@@ -17,45 +17,30 @@
17
17
  "./src/*": "./src/*"
18
18
  },
19
19
  "scripts": {
20
- "test": "mocha test",
21
- "cover": "c8 mocha test",
20
+ "test": "vitest run",
21
+ "cover": "vitest run --coverage",
22
22
  "build": "rollup -c"
23
23
  },
24
24
  "dependencies": {
25
- "@peter.naydenov/stack": "^3.0.0",
25
+ "@peter.naydenov/stack": "^3.0.1",
26
26
  "ask-for-promise": "^3.2.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@peter.naydenov/fsm": "5.2.6",
29
+ "@peter.naydenov/fsm": "5.2.7",
30
30
  "@rollup/plugin-commonjs": "^29.0.3",
31
31
  "@rollup/plugin-node-resolve": "^16.0.3",
32
32
  "@rollup/plugin-terser": "^1.0.0",
33
- "c8": "^12.0.0",
34
- "chai": "6.2.2",
35
- "mocha": "11.7.6",
36
- "rollup": "^4.62.2"
33
+ "@vitest/coverage-v8": "^4.1.10",
34
+ "rollup": "^4.62.2",
35
+ "vitest": "^4.1.10"
37
36
  },
38
37
  "overrides": {
39
- "diff": "^8.0.4",
40
38
  "serialize-javascript": "^7.0.5"
41
39
  },
42
40
  "repository": {
43
41
  "type": "git",
44
42
  "url": "https://github.com/PeterNaydenov/fsm-hub.git"
45
43
  },
46
- "c8": {
47
- "include": [
48
- "src/**/*.js"
49
- ],
50
- "exclude": [
51
- "node_modules",
52
- "test"
53
- ],
54
- "reporter": [
55
- "lcov",
56
- "text-summary"
57
- ]
58
- },
59
44
  "keywords": [
60
45
  "fsm",
61
46
  "state-managment",
@@ -17,10 +17,18 @@ return function _callback ( task, fsmName, state, response ) {
17
17
  return
18
18
  }
19
19
 
20
- if ( fsmSubscriber ) { // Execute fsm rules
20
+ if ( fsmSubscriber ) { // Execute fsm rules
21
21
  fsmSubscriber.forEach ( subscriberName => {
22
22
  if ( !hub.fsm[ subscriberName ] ) {
23
- hub._debugger ( msg.MISSING_FSM, fsmSubscriber )
23
+ // Log the missing subscriber's name, not the
24
+ // whole subscribers array. The debugger formats
25
+ // the warning as `Warning: Fsm "%s" is not
26
+ // registered to the hub.` and the array makes
27
+ // the message look like
28
+ // `... to the hub. [ 'two' ]`
29
+ // instead of the intended
30
+ // `... to the hub. two`
31
+ hub._debugger ( msg.MISSING_FSM, subscriberName )
24
32
  return
25
33
  }
26
34
  const
@@ -57,8 +65,16 @@ return function _callback ( task, fsmName, state, response ) {
57
65
  if ( typeof transformFn == 'function' ) data = transformFn (state, response )
58
66
  else data = response
59
67
 
60
- if ( data.answer && data.answer.hasOwnProperty ( '___internalFlag') ) data.answer = undefined
61
-
68
+ // `data` can be null/undefined if the response is
69
+ // null and no transformer is set, or if the
70
+ // transformer itself returns null. Guard the
71
+ // `.answer` access so we don't blow up — the
72
+ // placeholder-clear below is a no-op when
73
+ // `data` is falsy, and `fn(data)` will still
74
+ // receive whatever value the user/transformer
75
+ // produced (null included).
76
+ if ( data && data.answer && data.answer.hasOwnProperty ( '___internalFlag') ) data.answer = undefined
77
+
62
78
  if ( typeof fn == 'function' ) fn(data)
63
79
  else hub._debugger ( msg.MISSING_FN, cbName )
64
80
 
package/test/01-basics.js CHANGED
@@ -1,6 +1,6 @@
1
+ import { describe, it, expect } from 'vitest'
1
2
  import FsmHub from '../src/main.js'
2
3
  import Fsm from '@peter.naydenov/fsm'
3
- import { expect } from 'chai'
4
4
 
5
5
  const
6
6
  WRONG_REACTIVITY_RECORD = 'Error: Wrong reactivity record on row %s.'
@@ -14,7 +14,7 @@ describe ( 'Fsm Hub', () => {
14
14
 
15
15
 
16
16
  it ( 'Hub structure', () => {
17
- const
17
+ const
18
18
  hubDetails = {
19
19
  reactivity : [
20
20
  [ 'one', 'active', 'two', 'activate' ]
@@ -23,28 +23,29 @@ it ( 'Hub structure', () => {
23
23
 
24
24
  const hub = new FsmHub ( hubDetails )
25
25
 
26
- expect ( hub ).to.have.property ( 'fsm' )
27
- expect ( hub ).to.have.property ('fnCallbacks')
28
- expect ( hub ).to.have.property ( 'transformers' )
29
- expect ( hub ).to.have.property ( 'subscribers' )
30
- expect ( hub ).to.have.property ( 'actions' )
31
- expect ( hub ).to.have.property ( 'callbacks' )
26
+ expect ( hub ).toHaveProperty ( 'fsm' )
27
+ expect ( hub ).toHaveProperty ('fnCallbacks')
28
+ expect ( hub ).toHaveProperty ( 'transformers' )
29
+ expect ( hub ).toHaveProperty ( 'subscribers' )
30
+ expect ( hub ).toHaveProperty ( 'actions' )
31
+ expect ( hub ).toHaveProperty ( 'callbacks' )
32
32
 
33
- expect ( hub.subscribers ).to.have.property ( 'one/active' )
34
- expect ( hub.subscribers['one/active'] ).to.be.an ( 'array' )
35
- expect ( hub.subscribers['one/active'][0] ).to.be.equal ( 'two' )
33
+ expect ( hub.subscribers ).toHaveProperty ( 'one/active' )
34
+ expect ( Array.isArray ( hub.subscribers['one/active'] ) ).toBe ( true )
35
+ expect ( hub.subscribers['one/active'][0] ).toBe ( 'two' )
36
+
37
+ expect ( hub.actions ).toHaveProperty ( 'one/active/two' )
38
+ expect ( hub.actions['one/active/two']).toBe ( 'activate' )
36
39
 
37
- expect ( hub.actions ).to.have.property ( 'one/active/two' )
38
- expect ( hub.actions['one/active/two']).to.be.equal ( 'activate' )
39
-
40
40
  }) // it hub structure
41
41
 
42
42
 
43
43
 
44
44
 
45
45
 
46
+
46
47
  it ( 'Add a fsm', () => {
47
- const
48
+ const
48
49
  miniMachine = {
49
50
  init : 'none'
50
51
  , behavior : [
@@ -52,7 +53,7 @@ it ( 'Add a fsm', () => {
52
53
  ]
53
54
  };
54
55
  const machine = new Fsm ( miniMachine );
55
- const
56
+ const
56
57
  hubDescription = {
57
58
  reactivity : [
58
59
  [ 'one', 'active', 'two', 'activate' ]
@@ -61,18 +62,19 @@ it ( 'Add a fsm', () => {
61
62
  , transformers : {
62
63
  // "from/to" : functionName
63
64
  'two/showme' : 'simple'
64
- }
65
+ }
65
66
  }
66
67
  const hub = new FsmHub ( hubDescription );
67
68
  hub.addFsm ( { one:machine })
68
69
 
69
- expect ( hub.fsm ).to.have.property ( 'one' )
70
+ expect ( hub.fsm ).toHaveProperty ( 'one' )
70
71
  }) // register a fsm
71
72
 
72
73
 
73
74
 
74
75
 
75
76
 
77
+
76
78
  it ( 'Add a callback function', () => {
77
79
  function showme ( data ) {
78
80
  console.log ( data )
@@ -80,35 +82,36 @@ it ( 'Add a callback function', () => {
80
82
  function more ( data ) {
81
83
  console.log ( data )
82
84
  } // more func.
83
- const
85
+ const
84
86
  hubDescription = {
85
87
  reactivity : [
86
88
  [ 'one', 'active', 'two', 'activate' ]
87
89
  , [ 'two', 'active', 'showme' ]
88
- ]
90
+ ]
89
91
  }
90
92
  const hub = new FsmHub ( hubDescription );
91
93
  hub.addFunctions ( { showme, more })
92
94
 
93
- const activeCallbacks = Object.keys ( hub.callbacks );
94
- expect ( activeCallbacks.length ).to.be.equal ( 1 ) // function 'more' should be register only in fnCallbacks.
95
+ const activeCallbacks = Object.keys ( hub.callbacks );
96
+ expect ( activeCallbacks.length ).toBe ( 1 ) // function 'more' should be register only in fnCallbacks.
95
97
 
96
- expect ( hub.callbacks ).to.have.property ( 'two/active' )
97
- expect ( hub.callbacks['two/active']).to.be.an ( 'array' )
98
- expect ( hub.callbacks['two/active'][0]).to.be.equal ( 'showme' )
98
+ expect ( hub.callbacks ).toHaveProperty ( 'two/active' )
99
+ expect ( Array.isArray ( hub.callbacks['two/active'] ) ).toBe ( true )
100
+ expect ( hub.callbacks['two/active'][0]).toBe ( 'showme' )
99
101
 
100
- expect ( hub.fnCallbacks ).to.have.property ( 'showme' )
101
- expect ( hub.fnCallbacks ).to.have.property ( 'more' )
102
- expect ( typeof hub.fnCallbacks['showme']).to.be.equal ( 'function' )
103
- expect ( typeof hub.fnCallbacks['more']).to.be.equal ( 'function' )
102
+ expect ( hub.fnCallbacks ).toHaveProperty ( 'showme' )
103
+ expect ( hub.fnCallbacks ).toHaveProperty ( 'more' )
104
+ expect ( typeof hub.fnCallbacks['showme']).toBe ( 'function' )
105
+ expect ( typeof hub.fnCallbacks['more']).toBe ( 'function' )
104
106
  }) // register a fsm
105
107
 
106
108
 
107
109
 
108
110
 
109
111
 
112
+
110
113
  it ( 'Add a fsm', () => {
111
- const
114
+ const
112
115
  mini = {
113
116
  init : 'none'
114
117
  , behavior : [
@@ -116,7 +119,7 @@ it ( 'Add a fsm', () => {
116
119
  ]
117
120
  };
118
121
  const machine = new Fsm ( mini );
119
- const
122
+ const
120
123
  hubDescription = {
121
124
  reactivity : [
122
125
  [ 'one', 'active', 'two', 'activate' ]
@@ -125,21 +128,22 @@ it ( 'Add a fsm', () => {
125
128
  , transformers : {
126
129
  // "from/to" : functionName
127
130
  'two/showme' : 'simple'
128
- }
131
+ }
129
132
  }
130
133
  const hub = new FsmHub ( hubDescription );
131
134
  hub.addFsm ( { one:machine })
132
135
 
133
- expect ( hub.fsm ).to.have.property ( 'one' )
136
+ expect ( hub.fsm ).toHaveProperty ( 'one' )
134
137
  }) // register a fsm
135
138
 
136
139
 
137
140
 
138
141
 
139
142
 
140
- it ( 'Use hub-transformer', done => {
143
+
144
+ it ( 'Use hub-transformer', () => new Promise ( resolve => {
141
145
  // Define Fsm machines
142
- const
146
+ const
143
147
  miniOne = {
144
148
  init : 'none'
145
149
  , behavior : [
@@ -150,8 +154,8 @@ it ( 'Use hub-transformer', done => {
150
154
  // Setup fsm transition libraries
151
155
  const transitionOne = {
152
156
  switchOn ( {task}, data ) {
153
- task.done ({
154
- success : true
157
+ task.done ({
158
+ success : true
155
159
  , response : data
156
160
  })
157
161
  }
@@ -164,7 +168,7 @@ it ( 'Use hub-transformer', done => {
164
168
  ;
165
169
 
166
170
  // Define hub
167
- const
171
+ const
168
172
  hubMachine = {
169
173
  reactivity : [
170
174
  [ 'one', 'active', 'two', 'activate' ]
@@ -173,32 +177,32 @@ it ( 'Use hub-transformer', done => {
173
177
  , transformers : {
174
178
  // "from/to" : functionName
175
179
  'two/showme' : 'simple'
176
- }
180
+ }
177
181
  }
178
182
  , transformerLib = {
179
183
  simple : function ( state, resultResponseData ) {
180
184
  return {
181
185
  second : 'second'
182
- , state
186
+ , state
183
187
  , 'answer' : resultResponseData
184
188
  }
185
- }
189
+ }
186
190
  }
187
191
  ;
188
192
  // Initialize the hub
189
193
  const hub = new FsmHub ( hubMachine, transformerLib );
190
-
194
+
191
195
  function showme (transitionResult) {
192
196
  const {
193
197
  second
194
198
  , state
195
- , answer
199
+ , answer
196
200
  } = transitionResult;
197
201
  console.log ( second, state, answer )
198
- expect ( second ).to.be.equal ( 'second' )
199
- expect ( state ).to.be.equal ( 'active' )
200
- expect ( answer ).to.be.equal ( 'try' )
201
- done ()
202
+ expect ( second ).toBe ( 'second' )
203
+ expect ( state ).toBe ( 'active' )
204
+ expect ( answer ).toBe ( 'try' )
205
+ resolve ()
202
206
  } // showme func.
203
207
 
204
208
  hub.addFsm ({ one, two })
@@ -206,7 +210,8 @@ console.log ( second, state, answer )
206
210
 
207
211
  // Start!
208
212
  one.update ( 'activate', 'try' )
209
- }) // it use hub-transformer
213
+ })) // it use hub-transformer
214
+
210
215
 
211
216
 
212
217
 
@@ -214,7 +219,7 @@ console.log ( second, state, answer )
214
219
 
215
220
  it ( 'Wrong length of reactivity record', () => {
216
221
  // Define hub
217
- const
222
+ const
218
223
  hubDetails = {
219
224
  reactivity : [
220
225
  [ 'one', 'active', 'two', 'activate', 'aloha' ]
@@ -223,16 +228,16 @@ it ( 'Wrong length of reactivity record', () => {
223
228
  , transformers : {
224
229
  // "from/to" : functionName
225
230
  'two/showme' : 'simple'
226
- }
231
+ }
227
232
  };
228
233
  const originalDebugger = FsmHub.prototype._debugger;
229
234
  FsmHub.prototype._debugger = function ( str, data ) {
230
- expect ( str ).to.be.equal ( WRONG_REACTIVITY_RECORD )
235
+ expect ( str ).toBe ( WRONG_REACTIVITY_RECORD )
231
236
  }
232
237
  const hub = new FsmHub ( hubDetails );
233
238
 
234
- expect ( hub.callbacks ).to.have.property ( 'two/active' )
235
- expect ( hub.callbacks ['two/active'][0]).to.be.equal ( 'showme' )
239
+ expect ( hub.callbacks ).toHaveProperty ( 'two/active' )
240
+ expect ( hub.callbacks ['two/active'][0]).toBe ( 'showme' )
236
241
  FsmHub.prototype._debugger = originalDebugger
237
242
  }) // it wrong reactivity record
238
243
 
@@ -240,8 +245,9 @@ it ( 'Wrong length of reactivity record', () => {
240
245
 
241
246
 
242
247
 
248
+
243
249
  it ( 'Wrong type of reactivity record', () => {
244
- const
250
+ const
245
251
  hubDetails = {
246
252
  reactivity : [
247
253
  { 'one' : 'something' }
@@ -250,24 +256,25 @@ it ( 'Wrong type of reactivity record', () => {
250
256
  , transformers : {
251
257
  // "from/to" : functionName
252
258
  'two/showme' : 'simple'
253
- }
259
+ }
254
260
  };
255
261
  const originalDebugger = FsmHub.prototype._debugger;
256
262
  FsmHub.prototype._debugger = function ( str, data ) {
257
- expect ( str ).to.be.equal ( WRONG_REACTIVITY_RECORD )
263
+ expect ( str ).toBe ( WRONG_REACTIVITY_RECORD )
258
264
  }
259
265
  const hub = new FsmHub ( hubDetails );
260
266
 
261
- expect ( hub.callbacks ).to.have.property ( 'two/active' )
262
- expect ( hub.callbacks ['two/active'][0]).to.be.equal ( 'showme' )
267
+ expect ( hub.callbacks ).toHaveProperty ( 'two/active' )
268
+ expect ( hub.callbacks ['two/active'][0]).toBe ( 'showme' )
263
269
  FsmHub.prototype._debugger = originalDebugger
264
270
  }) // it wrong reactivity record
265
271
 
266
272
 
267
273
 
268
274
 
275
+
269
276
  it ( 'Try to add FSM name that is already registered', () => {
270
- const
277
+ const
271
278
  miniOne = {
272
279
  init : 'none'
273
280
  , behavior : [
@@ -275,11 +282,11 @@ it ( 'Try to add FSM name that is already registered', () => {
275
282
  ]
276
283
  };
277
284
 
278
-
285
+
279
286
  const one = new Fsm ( miniOne );
280
287
 
281
288
  // Define hub
282
- const
289
+ const
283
290
  hubDescription = {
284
291
  reactivity : [
285
292
  [ 'one', 'active', 'two', 'activate' ]
@@ -289,23 +296,24 @@ it ( 'Try to add FSM name that is already registered', () => {
289
296
  // Initialize the hub
290
297
  const hub = new FsmHub ( hubDescription );
291
298
  hub._debugger = function ( str, data ) {
292
- expect ( str ).to.be.equal ( REGISTERED_FSM_NAME )
299
+ expect ( str ).toBe ( REGISTERED_FSM_NAME )
293
300
  }
294
301
 
295
302
  hub.addFsm ({one})
296
303
  hub.addFsm ({one})
297
304
 
298
305
  const fsmList = Object.keys ( hub.fsm );
299
- expect ( fsmList ).to.have.length ( 1 )
300
- expect ( fsmList[0]).to.be.equal ( 'one' )
306
+ expect ( fsmList ).toHaveLength ( 1 )
307
+ expect ( fsmList[0]).toBe ( 'one' )
301
308
 
302
309
  }) // it registered fsm name
303
310
 
304
311
 
305
312
 
306
313
 
314
+
307
315
  it ( 'Try to add function name that is already registered', () => {
308
- const
316
+ const
309
317
  machine = {
310
318
  reactivity : [
311
319
  [ 'one', 'active', 'two', 'activate' ]
@@ -314,11 +322,11 @@ it ( 'Try to add function name that is already registered', () => {
314
322
  };
315
323
  const hub = new FsmHub ( machine );
316
324
  hub._debugger = function ( str, data ) {
317
- expect ( str ).to.be.equal ( REGISTERED_FUNCTION_NAME )
325
+ expect ( str ).toBe ( REGISTERED_FUNCTION_NAME )
318
326
  }
319
327
 
320
328
 
321
- function dummy ( data ) {
329
+ function dummy ( data ) {
322
330
  console.log ( 'dummy function' )
323
331
  }
324
332
 
@@ -326,8 +334,8 @@ it ( 'Try to add function name that is already registered', () => {
326
334
  hub.addFunctions ({ dummy })
327
335
 
328
336
  const fnCallbacks = Object.keys ( hub.fnCallbacks );
329
- expect ( fnCallbacks ).to.have.length (1)
330
- expect ( fnCallbacks[0]).to.be.equal ( 'dummy' )
337
+ expect ( fnCallbacks ).toHaveLength (1)
338
+ expect ( fnCallbacks[0]).toBe ( 'dummy' )
331
339
  }) // it registered function name
332
340
 
333
341
 
@@ -335,8 +343,8 @@ it ( 'Try to add function name that is already registered', () => {
335
343
 
336
344
 
337
345
 
338
- it ( 'Not registered fsm subscriber', done => {
339
- const
346
+ it ( 'Not registered fsm subscriber', () => new Promise ( resolve => {
347
+ const
340
348
  miniOne = {
341
349
  init : 'none'
342
350
  , behavior : [
@@ -347,8 +355,8 @@ it ( 'Not registered fsm subscriber', done => {
347
355
  // Setup fsm transition libraries
348
356
  const transitionOne = {
349
357
  switchOn ( {task}, data ) {
350
- task.done ({
351
- success : true
358
+ task.done ({
359
+ success : true
352
360
  , response : data
353
361
  })
354
362
  }
@@ -361,7 +369,7 @@ it ( 'Not registered fsm subscriber', done => {
361
369
  ;
362
370
 
363
371
  // Define hub
364
- const
372
+ const
365
373
  machine = {
366
374
  reactivity : [
367
375
  [ 'one', 'active', 'two', 'activate' ]
@@ -370,7 +378,7 @@ it ( 'Not registered fsm subscriber', done => {
370
378
  , transformers : {
371
379
  // "from/to" : functionName
372
380
  'two/showme' : 'simple'
373
- }
381
+ }
374
382
  }
375
383
  , transformerLib = {
376
384
  simple : function ( state, resultResponseData ) {
@@ -379,7 +387,7 @@ it ( 'Not registered fsm subscriber', done => {
379
387
  , state
380
388
  , 'answer' : resultResponseData
381
389
  }
382
- }
390
+ }
383
391
  }
384
392
  ;
385
393
  // Initialize the hub
@@ -387,20 +395,21 @@ it ( 'Not registered fsm subscriber', done => {
387
395
 
388
396
  hub.addFsm ({ one })
389
397
  hub._debugger = function ( str, data ) {
390
- expect ( str ).to.be.equal ( MISSING_FSM )
391
- done ()
398
+ expect ( str ).toBe ( MISSING_FSM )
399
+ resolve ()
392
400
  }
393
401
 
394
402
  // Start!
395
403
  one.update ( 'activate', 'try' )
396
- }) // it not registered fsm
404
+ })) // it not registered fsm
405
+
397
406
 
398
407
 
399
408
 
400
409
 
401
410
 
402
411
  it ( 'Transformer is not a function', () => {
403
- const
412
+ const
404
413
  miniOne = {
405
414
  init : 'none'
406
415
  , behavior : [
@@ -411,8 +420,8 @@ it ( 'Transformer is not a function', () => {
411
420
  // Setup fsm transition libraries
412
421
  const transitionOne = {
413
422
  switchOn ( {task}, data ) {
414
- task.done ({
415
- success : true
423
+ task.done ({
424
+ success : true
416
425
  , response : data
417
426
  })
418
427
  }
@@ -425,7 +434,7 @@ it ( 'Transformer is not a function', () => {
425
434
  ;
426
435
 
427
436
  // Define hub
428
- const
437
+ const
429
438
  machine = {
430
439
  reactivity : [
431
440
  [ 'one', 'active', 'two', 'activate' ]
@@ -434,7 +443,7 @@ it ( 'Transformer is not a function', () => {
434
443
  , transformers : {
435
444
  // "from/to" : functionName
436
445
  'two/showme' : 'simple'
437
- }
446
+ }
438
447
  }
439
448
  , transformerLib = {
440
449
  simple : { fake : 'fake transformer' } // if transformer is not a function
@@ -445,7 +454,7 @@ it ( 'Transformer is not a function', () => {
445
454
 
446
455
  hub.addFsm ({ one, two })
447
456
  // hub._debugger = function ( str, data ) {
448
- // expect ( str ).to.be.equal ( MISSING_FSM )
457
+ // expect ( str ).toBe ( MISSING_FSM )
449
458
  // done ()
450
459
  // }
451
460
 
@@ -457,8 +466,9 @@ it ( 'Transformer is not a function', () => {
457
466
 
458
467
 
459
468
 
460
- it ( 'Callback-function with data argument', done => {
461
- const
469
+
470
+ it ( 'Callback-function with data argument', () => new Promise ( resolve => {
471
+ const
462
472
  miniOne = {
463
473
  init : 'none'
464
474
  , behavior : [
@@ -466,31 +476,31 @@ it ( 'Callback-function with data argument', done => {
466
476
  , [ 'active', 'stop', 'none', 'switchOff']
467
477
  ]
468
478
  };
469
-
479
+
470
480
  // Setup fsm transition libraries
471
481
  const transitionOne = {
472
482
  switchOn ( {task}, data ) {
473
- task.done ({
474
- success : true
483
+ task.done ({
484
+ success : true
475
485
  , response : data
476
486
  })
477
487
  }
478
488
  , switchOff ( {task}, data ) {
479
- task.done ({
480
- success : true
489
+ task.done ({
490
+ success : true
481
491
  , response : data
482
492
  })
483
493
  }
484
494
  };
485
-
495
+
486
496
  // Init fsm machines
487
- const
497
+ const
488
498
  one = new Fsm ( miniOne, transitionOne )
489
499
  , two = new Fsm ( miniOne, transitionOne )
490
500
  ;
491
-
501
+
492
502
  // Define hub
493
- const
503
+ const
494
504
  machine = {
495
505
  reactivity : [
496
506
  [ 'one', 'active', 'two', 'activate' ]
@@ -500,7 +510,7 @@ it ( 'Callback-function with data argument', done => {
500
510
  ]
501
511
  , transformers : {
502
512
  'one/showme' : 'simple'
503
- }
513
+ }
504
514
  }
505
515
  , transformerLib = {
506
516
  simple ( state, data ) { return { try: `simple-${state}-${data.try}`} }
@@ -509,27 +519,27 @@ it ( 'Callback-function with data argument', done => {
509
519
  // Initialize the hub
510
520
  const hub = new FsmHub ( machine, transformerLib );
511
521
  function showme ( data ) {
512
- expect ( data.try ).to.equal ( 'simple-active-try' )
522
+ expect ( data.try ).toBe ( 'simple-active-try' )
513
523
  expect ( two.getState () == 'active' )
514
524
  one.update ( 'stop' )
515
525
  } // showme func.
516
526
 
517
527
  function final ( data ) {
518
- expect ( two.getState() ).to.be.equal ( 'none' )
519
- done ()
528
+ expect ( two.getState() ).toBe ( 'none' )
529
+ resolve ()
520
530
  } // final func.
521
531
 
522
532
  hub.addFsm ({ one, two })
523
533
  hub.addFunctions ({ showme, final })
524
534
  // Start!
525
535
  one.update ( 'activate', { try:'try'} )
526
- }) // it callback-function with data argument
536
+ })) // it callback-function with data argument
527
537
 
528
538
 
529
539
 
530
540
 
531
541
  it ( 'Test a Debugger', () => {
532
- const
542
+ const
533
543
  machine = {
534
544
  reactivity : [
535
545
  [ 'one', 'active', 'two', 'activate' ]
@@ -543,7 +553,142 @@ it ( 'Callback-function with data argument', done => {
543
553
 
544
554
 
545
555
 
546
-
547
- }) // describe
548
556
 
557
+ // =====================================================================
558
+ // BUG REGRESSIONS
559
+ // =====================================================================
560
+
561
+ // -----------------------------------------------------------------
562
+ // BUG A — _callback.js passed `fsmSubscriber` (the whole array of
563
+ // subscriber names) as the data arg to MISSING_FSM, instead of
564
+ // `subscriberName` (the specific missing one). The warning message
565
+ // therefore looked like
566
+ // `Warning: Fsm "%s" is not registered to the hub. [ 'two' ]`
567
+ // instead of the intended
568
+ // `Warning: Fsm "%s" is not registered to the hub. two`.
569
+ // The existing test "Not registered fsm subscriber" only checks the
570
+ // `str` half of the call, so the wrong data was never noticed.
571
+ // -----------------------------------------------------------------
572
+ it ( 'BUG A — MISSING_FSM is logged with the missing name, not the array', () => new Promise ( resolve => {
573
+ const
574
+ mini = {
575
+ init : 'none'
576
+ , behavior : [
577
+ [ 'none', 'activate', 'active', 'switchOn' ]
578
+ ]
579
+ }
580
+ , lib = {
581
+ switchOn ({ task }, data) {
582
+ task.done ({ success : true, response : data })
583
+ }
584
+ }
585
+ , one = new Fsm ( mini, lib )
586
+ ;
587
+ const hub = new FsmHub ({
588
+ reactivity : [
589
+ [ 'one', 'active', 'two', 'activate' ]
590
+ ]
591
+ });
592
+ const calls = [];
593
+ hub._debugger = ( str, data ) => calls.push ({ str, data });
594
+ hub.addFsm ({ one }); // 'two' is intentionally NOT registered
595
+
596
+ one.update ( 'activate', 'try' );
597
+
598
+ setTimeout ( () => {
599
+ const missing = calls.find ( c => c.str === MISSING_FSM )
600
+ expect ( missing, 'MISSING_FSM was not logged' ).toBeDefined ()
601
+ // The data should be the missing name 'two' (a string),
602
+ // NOT the whole subscribers array.
603
+ expect ( missing.data ).toBe ( 'two' )
604
+ resolve ()
605
+ }, 50 )
606
+ })) // it BUG A
607
+
608
+ // -----------------------------------------------------------------
609
+ // BUG B — _callback.js crashed with
610
+ // `TypeError: Cannot read properties of null (reading 'answer')`
611
+ // when a callback rule (length 3 in `reactivity`) was triggered
612
+ // and the FSM's response was `null` (and no transformer was
613
+ // configured, or the transformer itself returned `null`).
614
+ //
615
+ // The existing test "Callback-function with data argument" always
616
+ // passes a non-null `response`, so this path was never exercised.
617
+ // -----------------------------------------------------------------
618
+ it ( 'BUG B — callback rule with null response does not crash', () => new Promise ( resolve => {
619
+ const
620
+ mini = {
621
+ init : 'none'
622
+ , behavior : [
623
+ [ 'none', 'activate', 'active', 'switchOn' ]
624
+ ]
625
+ }
626
+ // Transition returns response: null. No transformer.
627
+ , lib = {
628
+ switchOn ({ task }) {
629
+ task.done ({ success : true, response : null })
630
+ }
631
+ }
632
+ , one = new Fsm ( mini, lib )
633
+ ;
634
+ const hub = new FsmHub ({
635
+ reactivity : [
636
+ // length-3 rule = callback, no fsm subscriber
637
+ [ 'one', 'active', 'showme' ]
638
+ ]
639
+ });
640
+ function showme ( data ) {
641
+ // The crash happened BEFORE this was called.
642
+ // We just want to assert: the callback fires
643
+ // and `data` is what the response was (null).
644
+ expect ( data ).toBeNull ()
645
+ resolve ()
646
+ } // showme func.
647
+ hub.addFsm ({ one });
648
+ hub.addFunctions ({ showme });
649
+
650
+ one.update ( 'activate' );
651
+ })) // it BUG B — null response
652
+
653
+ it ( 'BUG B — callback rule with a transformer that returns null does not crash', () => new Promise ( resolve => {
654
+ const
655
+ mini = {
656
+ init : 'none'
657
+ , behavior : [
658
+ [ 'none', 'activate', 'active', 'switchOn' ]
659
+ ]
660
+ }
661
+ , lib = {
662
+ switchOn ({ task }, data) {
663
+ task.done ({ success : true, response : data })
664
+ }
665
+ }
666
+ , one = new Fsm ( mini, lib )
667
+ ;
668
+ const hub = new FsmHub ({
669
+ reactivity : [
670
+ [ 'one', 'active', 'showme' ]
671
+ ]
672
+ , transformers : {
673
+ 'one/showme' : 'nullTransformer'
674
+ }
675
+ }, {
676
+ // A transformer that returns null. This used to
677
+ // crash in _callback.js's `data.answer` check.
678
+ nullTransformer () { return null }
679
+ });
680
+ function showme ( data ) {
681
+ expect ( data ).toBeNull ()
682
+ resolve ()
683
+ } // showme func.
684
+ hub.addFsm ({ one });
685
+ hub.addFunctions ({ showme });
686
+
687
+ one.update ( 'activate', 'try' );
688
+ })) // it BUG B — null transformer
689
+
690
+
691
+
692
+
693
+ }) // describe
549
694
 
@@ -1,11 +1,11 @@
1
+ import { describe, it, expect } from 'vitest'
1
2
  import FsmHub from '../src/main.js'
2
3
  import Fsm from '@peter.naydenov/fsm'
3
- import { expect } from 'chai'
4
4
 
5
5
  describe ( 'Fsm Hub', () => {
6
6
 
7
- it ( 'Check multiple systems', done => {
8
-
7
+ it ( 'Check multiple systems', () => new Promise ( resolve => {
8
+
9
9
  /**
10
10
  * Description:
11
11
  * Create a 3 fsm systems - human, spy, and recorder
@@ -14,7 +14,7 @@ describe ( 'Fsm Hub', () => {
14
14
  * - Recorder: Storage for bad news. When messages are 3 will stop with the recording and will call function "TimeForChange"
15
15
  */
16
16
 
17
- const
17
+ const
18
18
  recorderDescription = { // Description of the recorder
19
19
  init : 'empty'
20
20
  , behavior : [
@@ -60,28 +60,28 @@ describe ( 'Fsm Hub', () => {
60
60
  const
61
61
  humanLib = {
62
62
  feel_happy ({task}, data ) {
63
- task.done ({
64
- success : true
63
+ task.done ({
64
+ success : true
65
65
  , response : data
66
66
  })
67
67
  }
68
- , feel_bad ( {task}, data ) {
69
- task.done ({
70
- success : true
68
+ , feel_bad ( {task}, data ) {
69
+ task.done ({
70
+ success : true
71
71
  , response: data
72
72
  })
73
73
  }
74
74
  }
75
75
  , spyLib = {
76
76
  onBad ( {task}, data ) {
77
- task.done ({
78
- success : true
77
+ task.done ({
78
+ success : true
79
79
  , response : data
80
80
  })
81
81
  }
82
82
  , onGood ( {task}, data ) {
83
- task.done ({
84
- success : true
83
+ task.done ({
84
+ success : true
85
85
  , response : data
86
86
  })
87
87
  }
@@ -90,8 +90,8 @@ describe ( 'Fsm Hub', () => {
90
90
  add_a_warning ( { task, extractList }, data ) {
91
91
  const [ reasons ] = extractList (['reasons']);
92
92
  if ( !reasons.includes(data.response) ) reasons.push ( data.response )
93
- task.done ({
94
- success : true
93
+ task.done ({
94
+ success : true
95
95
  , stateData : { reasons }
96
96
  , response : data
97
97
  })
@@ -103,9 +103,9 @@ describe ( 'Fsm Hub', () => {
103
103
  }
104
104
  }
105
105
  , hubLib = {
106
- emotion2spy ( state,response) {
106
+ emotion2spy ( state,response) {
107
107
  return { response }
108
- }
108
+ }
109
109
  , spy2record ( state, response ) { return response }
110
110
  }
111
111
  ;
@@ -117,24 +117,24 @@ describe ( 'Fsm Hub', () => {
117
117
  , theHub = new FsmHub ( hubDescription , hubLib )
118
118
  ;
119
119
  let result = false
120
-
121
-
120
+
121
+
122
122
  function timeForChange ( state, response ) {
123
123
  result = 'DONE'
124
124
  }
125
125
 
126
126
  function test ( state, response ) {
127
- expect ( result ).to.be.equal ( 'DONE' )
128
- expect ( theHub.cache.isEmpty () ).to.be.true
129
- expect ( theHub.cacheInternal.isEmpty () ).to.be.true
127
+ expect ( result ).toBe ( 'DONE' )
128
+ expect ( theHub.cache.isEmpty () ).toBe ( true )
129
+ expect ( theHub.cacheInternal.isEmpty () ).toBe ( true )
130
130
  let [ rec ] = recorder.extractList (['reasons'], { as: 'std'})
131
-
132
- expect ( rec ).to.be.an ( 'array' )
133
- expect ( rec ).to.have.length ( 3 )
134
- expect ( rec[0] ).to.be.equal ( 'Car crash' )
135
- expect ( rec[1] ).to.be.equal ( 'Airplane crash' )
136
- expect ( rec[2] ).to.be.equal ( 'Storm' )
137
- done ()
131
+
132
+ expect ( Array.isArray ( rec ) ).toBe ( true )
133
+ expect ( rec ).toHaveLength ( 3 )
134
+ expect ( rec[0] ).toBe ( 'Car crash' )
135
+ expect ( rec[1] ).toBe ( 'Airplane crash' )
136
+ expect ( rec[2] ).toBe ( 'Storm' )
137
+ resolve ()
138
138
  }
139
139
 
140
140
  theHub.addFsm ({ human, spy, recorder })
@@ -145,7 +145,7 @@ describe ( 'Fsm Hub', () => {
145
145
  human.update ( 'badNews', 'Airplane crash' )
146
146
  human.update ( 'badNews', 'Storm' )
147
147
 
148
- }) // it check multiple systems
148
+ })) // it check multiple systems
149
149
 
150
150
 
151
151
 
@@ -154,4 +154,3 @@ describe ( 'Fsm Hub', () => {
154
154
 
155
155
  }) // describe
156
156
 
157
-
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig ({
4
+ test: {
5
+ include : [ 'test/**/*.js' ]
6
+ , coverage : {
7
+ provider : 'v8'
8
+ , include : [ 'src/**/*.js' ]
9
+ , exclude : [ 'node_modules', 'test' ]
10
+ , reporter : [ 'lcov', 'text-summary' ]
11
+ }
12
+ }
13
+ })