@vsirotin/ts-stop 0.5.2 → 1.9.2
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.
- package/LICENSE +201 -0
- package/README.md +3 -40
- package/lib/FiniteStateMachine.d.ts +6 -1
- package/lib/FiniteStateMachine.d.ts.map +1 -1
- package/lib/FiniteStateMachine.js +114 -6
- package/lib/FiniteStateMachine.js.map +1 -1
- package/lib/esm/FiniteStateMachine.js +114 -6
- package/lib/esm/fa/DefaultState.js +10 -0
- package/lib/esm/fa/FiniteStateMachine.js +405 -0
- package/lib/esm/fa/IStateWithActions.js +1 -0
- package/lib/esm/fa/IStateWithOutputSignal.js +1 -0
- package/lib/esm/fa/MatrixBasedStateMachine.js +127 -0
- package/lib/esm/fa/TransitionMatrix.js +98 -0
- package/lib/esm/index.js +6 -6
- package/lib/esm/sfsm/ExternalWorldHub.js +80 -0
- package/lib/esm/sfsm/FaLoader.js +30 -0
- package/lib/esm/sfsm/FaReducer.js +36 -0
- package/lib/esm/sfsm/FaResolver.js +115 -0
- package/lib/esm/sfsm/FaUpdater.js +101 -0
- package/lib/esm/sfsm/Sfsm.js +225 -0
- package/lib/esm/sfsm/index.browser.js +5 -0
- package/lib/esm/sfsm/index.js +6 -0
- package/lib/esm/sfsm/interfaces.js +1 -0
- package/lib/esm/sfsm/types.js +1 -0
- package/lib/fa/DefaultState.d.ts +9 -0
- package/lib/fa/DefaultState.d.ts.map +1 -0
- package/lib/fa/DefaultState.js +15 -0
- package/lib/fa/DefaultState.js.map +1 -0
- package/lib/fa/FiniteStateMachine.d.ts +227 -0
- package/lib/fa/FiniteStateMachine.d.ts.map +1 -0
- package/lib/fa/FiniteStateMachine.js +410 -0
- package/lib/fa/FiniteStateMachine.js.map +1 -0
- package/lib/fa/IStateWithActions.d.ts +18 -0
- package/lib/fa/IStateWithActions.d.ts.map +1 -0
- package/lib/fa/IStateWithActions.js +3 -0
- package/lib/fa/IStateWithActions.js.map +1 -0
- package/lib/fa/IStateWithOutputSignal.d.ts +4 -0
- package/lib/fa/IStateWithOutputSignal.d.ts.map +1 -0
- package/lib/fa/IStateWithOutputSignal.js +3 -0
- package/lib/fa/IStateWithOutputSignal.js.map +1 -0
- package/lib/fa/MatrixBasedStateMachine.d.ts +108 -0
- package/lib/fa/MatrixBasedStateMachine.d.ts.map +1 -0
- package/lib/fa/MatrixBasedStateMachine.js +132 -0
- package/lib/fa/MatrixBasedStateMachine.js.map +1 -0
- package/lib/fa/TransitionMatrix.d.ts +61 -0
- package/lib/fa/TransitionMatrix.d.ts.map +1 -0
- package/lib/fa/TransitionMatrix.js +104 -0
- package/lib/fa/TransitionMatrix.js.map +1 -0
- package/lib/index.d.ts +6 -6
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +6 -6
- package/lib/index.js.map +1 -1
- package/lib/sfsm/ExternalWorldHub.d.ts +52 -0
- package/lib/sfsm/ExternalWorldHub.d.ts.map +1 -0
- package/lib/sfsm/ExternalWorldHub.js +85 -0
- package/lib/sfsm/ExternalWorldHub.js.map +1 -0
- package/lib/sfsm/FaLoader.d.ts +22 -0
- package/lib/sfsm/FaLoader.d.ts.map +1 -0
- package/lib/sfsm/FaLoader.js +68 -0
- package/lib/sfsm/FaLoader.js.map +1 -0
- package/lib/sfsm/FaReducer.d.ts +12 -0
- package/lib/sfsm/FaReducer.d.ts.map +1 -0
- package/lib/sfsm/FaReducer.js +40 -0
- package/lib/sfsm/FaReducer.js.map +1 -0
- package/lib/sfsm/FaResolver.d.ts +37 -0
- package/lib/sfsm/FaResolver.d.ts.map +1 -0
- package/lib/sfsm/FaResolver.js +120 -0
- package/lib/sfsm/FaResolver.js.map +1 -0
- package/lib/sfsm/FaUpdater.d.ts +25 -0
- package/lib/sfsm/FaUpdater.d.ts.map +1 -0
- package/lib/sfsm/FaUpdater.js +106 -0
- package/lib/sfsm/FaUpdater.js.map +1 -0
- package/lib/sfsm/Sfsm.d.ts +60 -0
- package/lib/sfsm/Sfsm.d.ts.map +1 -0
- package/lib/sfsm/Sfsm.js +230 -0
- package/lib/sfsm/Sfsm.js.map +1 -0
- package/lib/sfsm/index.browser.d.ts +7 -0
- package/lib/sfsm/index.d.ts +9 -0
- package/lib/sfsm/index.d.ts.map +1 -0
- package/lib/sfsm/index.js +18 -0
- package/lib/sfsm/index.js.map +1 -0
- package/lib/sfsm/interfaces.d.ts +22 -0
- package/lib/sfsm/interfaces.d.ts.map +1 -0
- package/lib/sfsm/interfaces.js +3 -0
- package/lib/sfsm/interfaces.js.map +1 -0
- package/lib/sfsm/types.d.ts +78 -0
- package/lib/sfsm/types.d.ts.map +1 -0
- package/lib/sfsm/types.js +3 -0
- package/lib/sfsm/types.js.map +1 -0
- package/package.json +16 -3
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FaDefinition } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Reads and parses a JSON file at the given path and returns it as a FaDefinition.
|
|
4
|
+
* Works with both extended and compact formats.
|
|
5
|
+
*
|
|
6
|
+
* Node.js only — uses `fs.readFileSync` and is not available in browser environments.
|
|
7
|
+
*
|
|
8
|
+
* @param filePath - Absolute or relative path to a JSON file containing an FA definition.
|
|
9
|
+
* @returns Parsed FaDefinition ready to pass to `Sfsm.loadFA()`.
|
|
10
|
+
* @throws If the file cannot be read or the contents are not valid JSON.
|
|
11
|
+
*/
|
|
12
|
+
export declare function loadFAFromFile(filePath: string): FaDefinition;
|
|
13
|
+
/**
|
|
14
|
+
* Fetches and parses a JSON FA definition from a URL.
|
|
15
|
+
* Works in both browser and Node.js (≥ 18) environments — uses the standard `fetch` API.
|
|
16
|
+
*
|
|
17
|
+
* @param url - Absolute URL to a JSON file containing an FA definition.
|
|
18
|
+
* @returns Promise resolving to a FaDefinition ready to pass to `Sfsm.loadFA()`.
|
|
19
|
+
* @throws If the request fails, the server returns a non-2xx status, or the body is not valid JSON.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadFAFromURL(url: string): Promise<FaDefinition>;
|
|
22
|
+
//# sourceMappingURL=FaLoader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaLoader.d.ts","sourceRoot":"","sources":["../../src/sfsm/FaLoader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAG7D;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAMtE"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadFAFromFile = loadFAFromFile;
|
|
37
|
+
exports.loadFAFromURL = loadFAFromURL;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
/**
|
|
40
|
+
* Reads and parses a JSON file at the given path and returns it as a FaDefinition.
|
|
41
|
+
* Works with both extended and compact formats.
|
|
42
|
+
*
|
|
43
|
+
* Node.js only — uses `fs.readFileSync` and is not available in browser environments.
|
|
44
|
+
*
|
|
45
|
+
* @param filePath - Absolute or relative path to a JSON file containing an FA definition.
|
|
46
|
+
* @returns Parsed FaDefinition ready to pass to `Sfsm.loadFA()`.
|
|
47
|
+
* @throws If the file cannot be read or the contents are not valid JSON.
|
|
48
|
+
*/
|
|
49
|
+
function loadFAFromFile(filePath) {
|
|
50
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
51
|
+
return JSON.parse(content);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Fetches and parses a JSON FA definition from a URL.
|
|
55
|
+
* Works in both browser and Node.js (≥ 18) environments — uses the standard `fetch` API.
|
|
56
|
+
*
|
|
57
|
+
* @param url - Absolute URL to a JSON file containing an FA definition.
|
|
58
|
+
* @returns Promise resolving to a FaDefinition ready to pass to `Sfsm.loadFA()`.
|
|
59
|
+
* @throws If the request fails, the server returns a non-2xx status, or the body is not valid JSON.
|
|
60
|
+
*/
|
|
61
|
+
async function loadFAFromURL(url) {
|
|
62
|
+
const response = await fetch(url);
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
throw new Error(`loadFAFromURL: request failed with status ${response.status} ${response.statusText} for URL: ${url}`);
|
|
65
|
+
}
|
|
66
|
+
return response.json();
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=FaLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaLoader.js","sourceRoot":"","sources":["../../src/sfsm/FaLoader.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,wCAGC;AAUD,sCAMC;AAhCD,uCAAyB;AAGzB;;;;;;;;;GASG;AACH,SAAgB,cAAc,CAAC,QAAgB;IAC3C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;AAC/C,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,aAAa,CAAC,GAAW;IAC3C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,6CAA6C,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,aAAa,GAAG,EAAE,CAAC,CAAC;IAC3H,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,EAA2B,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FaDefinition } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Converts an extended FA definition (nested FaNode tree) into compact format
|
|
4
|
+
* (flat Record<string, Transition[]> with each FA's name as a top-level key).
|
|
5
|
+
*
|
|
6
|
+
* If the input is already in compact multi-FA format (all values are Transition[]),
|
|
7
|
+
* it is returned unchanged.
|
|
8
|
+
*
|
|
9
|
+
* Metadata (state names, descriptions, signal/command metadata) is discarded in the output.
|
|
10
|
+
*/
|
|
11
|
+
export declare function reduceFA(definition: FaDefinition): FaDefinition;
|
|
12
|
+
//# sourceMappingURL=FaReducer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaReducer.d.ts","sourceRoot":"","sources":["../../src/sfsm/FaReducer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAsB,MAAM,SAAS,CAAC;AAE3D;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,YAAY,GAAG,YAAY,CAY/D"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reduceFA = reduceFA;
|
|
4
|
+
/**
|
|
5
|
+
* Converts an extended FA definition (nested FaNode tree) into compact format
|
|
6
|
+
* (flat Record<string, Transition[]> with each FA's name as a top-level key).
|
|
7
|
+
*
|
|
8
|
+
* If the input is already in compact multi-FA format (all values are Transition[]),
|
|
9
|
+
* it is returned unchanged.
|
|
10
|
+
*
|
|
11
|
+
* Metadata (state names, descriptions, signal/command metadata) is discarded in the output.
|
|
12
|
+
*/
|
|
13
|
+
function reduceFA(definition) {
|
|
14
|
+
const entries = Object.entries(definition);
|
|
15
|
+
// Already compact: all values are arrays
|
|
16
|
+
if (entries.every(([, v]) => Array.isArray(v))) {
|
|
17
|
+
return definition;
|
|
18
|
+
}
|
|
19
|
+
const result = {};
|
|
20
|
+
const [rootName, rootValue] = entries[0];
|
|
21
|
+
collectNodes(rootName, rootValue, result);
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
function collectNodes(name, node, result) {
|
|
25
|
+
result[name] = node.ts;
|
|
26
|
+
if (node.states) {
|
|
27
|
+
for (const [stateName, stateValue] of Object.entries(node.states)) {
|
|
28
|
+
if (isSubFaNode(stateValue)) {
|
|
29
|
+
collectNodes(stateName, stateValue, result);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function isSubFaNode(value) {
|
|
35
|
+
return (typeof value === 'object' &&
|
|
36
|
+
value !== null &&
|
|
37
|
+
'ts' in value &&
|
|
38
|
+
Array.isArray(value.ts));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=FaReducer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaReducer.js","sourceRoot":"","sources":["../../src/sfsm/FaReducer.ts"],"names":[],"mappings":";;AAWA,4BAYC;AArBD;;;;;;;;GAQG;AACH,SAAgB,QAAQ,CAAC,UAAwB;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE3C,yCAAyC;IACzC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,OAAO,UAAU,CAAC;IACtB,CAAC;IAED,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzC,YAAY,CAAC,QAAQ,EAAE,SAAmB,EAAE,MAAM,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY,EAAE,MAAoC;IAClF,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;IAEvB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAChE,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC1B,YAAY,CAAC,SAAS,EAAE,UAAoB,EAAE,MAAM,CAAC,CAAC;YAC1D,CAAC;QACL,CAAC;IACL,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IAC/B,OAAO,CACH,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,IAAI,IAAI,KAAK;QACb,KAAK,CAAC,OAAO,CAAE,KAAgB,CAAC,EAAE,CAAC,CACtC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FaDefinition, FaNode, Transition } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Resolved, flat representation of one FA ready for engine processing.
|
|
4
|
+
*/
|
|
5
|
+
export interface ResolvedFa {
|
|
6
|
+
name: string;
|
|
7
|
+
transitions: Transition[];
|
|
8
|
+
/** Keys of states that are themselves sub-FAs (have their own ts list). */
|
|
9
|
+
subFaNames: Set<string>;
|
|
10
|
+
node: FaNode;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parses a raw FaDefinition and builds a flat index of all FAs by name.
|
|
14
|
+
*
|
|
15
|
+
* A state entry is considered a sub-FA if its value object contains a "ts" key.
|
|
16
|
+
* Leaf states (no "ts") are plain named states.
|
|
17
|
+
*/
|
|
18
|
+
export declare class FaResolver {
|
|
19
|
+
private definition;
|
|
20
|
+
private index;
|
|
21
|
+
constructor(definition: FaDefinition);
|
|
22
|
+
/** Returns the resolved FA for the given name, or throws if not found. */
|
|
23
|
+
get(name: string): ResolvedFa;
|
|
24
|
+
/** Returns the name of the root FA.
|
|
25
|
+
*
|
|
26
|
+
* For single-key definitions (compact single FA or extended FA), the sole key is the root.
|
|
27
|
+
* For multi-key compact definitions (all values are Transition[]), the root is the FA whose
|
|
28
|
+
* name is never referenced as a target state (3rd element) in any other FA's transitions.
|
|
29
|
+
*/
|
|
30
|
+
getRootName(): string;
|
|
31
|
+
private buildIndex;
|
|
32
|
+
private buildCompactMultiIndex;
|
|
33
|
+
private indexNode;
|
|
34
|
+
/** A state value is a sub-FA if it has a "ts" array property. */
|
|
35
|
+
private isSubFa;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=FaResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaResolver.d.ts","sourceRoot":"","sources":["../../src/sfsm/FaResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,2EAA2E;IAC3E,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,qBAAa,UAAU;IAIP,OAAO,CAAC,UAAU;IAF9B,OAAO,CAAC,KAAK,CAAiC;gBAE1B,UAAU,EAAE,YAAY;IAI5C,0EAA0E;IAC1E,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;IAQ7B;;;;;OAKG;IACH,WAAW,IAAI,MAAM;IAiCrB,OAAO,CAAC,UAAU;IA2BlB,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,SAAS;IAoBjB,iEAAiE;IACjE,OAAO,CAAC,OAAO;CAQlB"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FaResolver = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Parses a raw FaDefinition and builds a flat index of all FAs by name.
|
|
6
|
+
*
|
|
7
|
+
* A state entry is considered a sub-FA if its value object contains a "ts" key.
|
|
8
|
+
* Leaf states (no "ts") are plain named states.
|
|
9
|
+
*/
|
|
10
|
+
class FaResolver {
|
|
11
|
+
constructor(definition) {
|
|
12
|
+
this.definition = definition;
|
|
13
|
+
this.index = new Map();
|
|
14
|
+
this.buildIndex();
|
|
15
|
+
}
|
|
16
|
+
/** Returns the resolved FA for the given name, or throws if not found. */
|
|
17
|
+
get(name) {
|
|
18
|
+
const fa = this.index.get(name);
|
|
19
|
+
if (!fa) {
|
|
20
|
+
throw new Error(`SFSM: FA "${name}" not found in definition.`);
|
|
21
|
+
}
|
|
22
|
+
return fa;
|
|
23
|
+
}
|
|
24
|
+
/** Returns the name of the root FA.
|
|
25
|
+
*
|
|
26
|
+
* For single-key definitions (compact single FA or extended FA), the sole key is the root.
|
|
27
|
+
* For multi-key compact definitions (all values are Transition[]), the root is the FA whose
|
|
28
|
+
* name is never referenced as a target state (3rd element) in any other FA's transitions.
|
|
29
|
+
*/
|
|
30
|
+
getRootName() {
|
|
31
|
+
const keys = Object.keys(this.definition);
|
|
32
|
+
if (keys.length === 1) {
|
|
33
|
+
return keys[0];
|
|
34
|
+
}
|
|
35
|
+
// Multi-key: all values must be Transition[]
|
|
36
|
+
const allCompact = keys.every(k => Array.isArray(this.definition[k]));
|
|
37
|
+
if (!allCompact) {
|
|
38
|
+
throw new Error(`SFSM: Multi-key FA definition must use compact format (all values must be Transition[]).`);
|
|
39
|
+
}
|
|
40
|
+
// Collect all target state names referenced across all transitions
|
|
41
|
+
const referenced = new Set();
|
|
42
|
+
for (const key of keys) {
|
|
43
|
+
const transitions = this.definition[key];
|
|
44
|
+
for (const t of transitions) {
|
|
45
|
+
referenced.add(t[2]); // newState is at index 2
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Root = the FA name that is never a target in any other FA's transitions
|
|
49
|
+
const roots = keys.filter(k => !referenced.has(k));
|
|
50
|
+
if (roots.length !== 1) {
|
|
51
|
+
throw new Error(`SFSM: Cannot determine root FA. Candidates: [${roots.join(', ')}]. ` +
|
|
52
|
+
`All FA names: [${keys.join(', ')}].`);
|
|
53
|
+
}
|
|
54
|
+
return roots[0];
|
|
55
|
+
}
|
|
56
|
+
buildIndex() {
|
|
57
|
+
const entries = Object.entries(this.definition);
|
|
58
|
+
const allCompact = entries.every(([, v]) => Array.isArray(v));
|
|
59
|
+
if (allCompact && entries.length > 1) {
|
|
60
|
+
// Multi-key compact format: index all FAs, sub-FA names derived from definition keys
|
|
61
|
+
this.buildCompactMultiIndex();
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const rootName = this.getRootName();
|
|
65
|
+
const rootValue = this.definition[rootName];
|
|
66
|
+
if (Array.isArray(rootValue)) {
|
|
67
|
+
// Single-key compact format
|
|
68
|
+
const node = { ts: rootValue };
|
|
69
|
+
this.index.set(rootName, {
|
|
70
|
+
name: rootName,
|
|
71
|
+
transitions: rootValue,
|
|
72
|
+
subFaNames: new Set(),
|
|
73
|
+
node
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// Extended format
|
|
78
|
+
this.indexNode(rootName, rootValue);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
buildCompactMultiIndex() {
|
|
83
|
+
const definedFaNames = new Set(Object.keys(this.definition));
|
|
84
|
+
for (const [name, value] of Object.entries(this.definition)) {
|
|
85
|
+
const transitions = value;
|
|
86
|
+
// A state is a sub-FA if its name is a key in the definition
|
|
87
|
+
const subFaNames = new Set(transitions
|
|
88
|
+
.map(t => t[2])
|
|
89
|
+
.filter(target => definedFaNames.has(target)));
|
|
90
|
+
const node = { ts: transitions };
|
|
91
|
+
this.index.set(name, { name, transitions, subFaNames, node });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
indexNode(name, node) {
|
|
95
|
+
const subFaNames = new Set();
|
|
96
|
+
if (node.states) {
|
|
97
|
+
for (const [stateName, stateValue] of Object.entries(node.states)) {
|
|
98
|
+
if (this.isSubFa(stateValue)) {
|
|
99
|
+
subFaNames.add(stateName);
|
|
100
|
+
this.indexNode(stateName, stateValue);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
this.index.set(name, {
|
|
105
|
+
name,
|
|
106
|
+
transitions: node.ts,
|
|
107
|
+
subFaNames,
|
|
108
|
+
node
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/** A state value is a sub-FA if it has a "ts" array property. */
|
|
112
|
+
isSubFa(value) {
|
|
113
|
+
return (typeof value === 'object' &&
|
|
114
|
+
value !== null &&
|
|
115
|
+
'ts' in value &&
|
|
116
|
+
Array.isArray(value.ts));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.FaResolver = FaResolver;
|
|
120
|
+
//# sourceMappingURL=FaResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaResolver.js","sourceRoot":"","sources":["../../src/sfsm/FaResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FaDefinition, FaUpdate } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Apply an update to a compact FA definition (flat Record<string, Transition[]>).
|
|
4
|
+
*
|
|
5
|
+
* Steps (in order):
|
|
6
|
+
* 1. remove: delete the named top-level keys; also prune every remaining FA's
|
|
7
|
+
* transitions whose 3rd element (target state) is one of the removed names.
|
|
8
|
+
* 2. add: upsert the provided keys (existing entries are replaced, new ones are added).
|
|
9
|
+
*
|
|
10
|
+
* The source is not mutated — a deep-cloned result is returned.
|
|
11
|
+
*/
|
|
12
|
+
export declare function updateCompactFA(source: FaDefinition, update: FaUpdate): FaDefinition;
|
|
13
|
+
/**
|
|
14
|
+
* Apply an update to an extended (full/declaration) FA definition.
|
|
15
|
+
*
|
|
16
|
+
* Steps (in order):
|
|
17
|
+
* 1. remove: recursively locate each named FA in the tree; remove it from its
|
|
18
|
+
* parent's states map and prune the parent's ts of any transition targeting it.
|
|
19
|
+
* 2. add: for each entry, recursively locate the FA by name and replace it entirely.
|
|
20
|
+
* If the name matches the root key, the root node is replaced.
|
|
21
|
+
*
|
|
22
|
+
* The source is not mutated — a deep-cloned result is returned.
|
|
23
|
+
*/
|
|
24
|
+
export declare function updateFullFA(source: FaDefinition, update: FaUpdate): FaDefinition;
|
|
25
|
+
//# sourceMappingURL=FaUpdater.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaUpdater.d.ts","sourceRoot":"","sources":["../../src/sfsm/FaUpdater.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAU,QAAQ,EAAc,MAAM,SAAS,CAAC;AAErE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,GAAG,YAAY,CAwBpF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,GAAG,YAAY,CAqBjF"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateCompactFA = updateCompactFA;
|
|
4
|
+
exports.updateFullFA = updateFullFA;
|
|
5
|
+
/**
|
|
6
|
+
* Apply an update to a compact FA definition (flat Record<string, Transition[]>).
|
|
7
|
+
*
|
|
8
|
+
* Steps (in order):
|
|
9
|
+
* 1. remove: delete the named top-level keys; also prune every remaining FA's
|
|
10
|
+
* transitions whose 3rd element (target state) is one of the removed names.
|
|
11
|
+
* 2. add: upsert the provided keys (existing entries are replaced, new ones are added).
|
|
12
|
+
*
|
|
13
|
+
* The source is not mutated — a deep-cloned result is returned.
|
|
14
|
+
*/
|
|
15
|
+
function updateCompactFA(source, update) {
|
|
16
|
+
var _a;
|
|
17
|
+
const result = JSON.parse(JSON.stringify(source));
|
|
18
|
+
const toRemove = new Set((_a = update.remove) !== null && _a !== void 0 ? _a : []);
|
|
19
|
+
for (const name of toRemove) {
|
|
20
|
+
delete result[name];
|
|
21
|
+
}
|
|
22
|
+
// Prune transitions referencing removed FAs from all surviving FAs.
|
|
23
|
+
for (const transitions of Object.values(result)) {
|
|
24
|
+
const arr = transitions;
|
|
25
|
+
const filtered = arr.filter(t => !toRemove.has(t[2]));
|
|
26
|
+
arr.length = 0;
|
|
27
|
+
arr.push(...filtered);
|
|
28
|
+
}
|
|
29
|
+
if (update.add) {
|
|
30
|
+
for (const [name, value] of Object.entries(update.add)) {
|
|
31
|
+
result[name] = JSON.parse(JSON.stringify(value));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Apply an update to an extended (full/declaration) FA definition.
|
|
38
|
+
*
|
|
39
|
+
* Steps (in order):
|
|
40
|
+
* 1. remove: recursively locate each named FA in the tree; remove it from its
|
|
41
|
+
* parent's states map and prune the parent's ts of any transition targeting it.
|
|
42
|
+
* 2. add: for each entry, recursively locate the FA by name and replace it entirely.
|
|
43
|
+
* If the name matches the root key, the root node is replaced.
|
|
44
|
+
*
|
|
45
|
+
* The source is not mutated — a deep-cloned result is returned.
|
|
46
|
+
*/
|
|
47
|
+
function updateFullFA(source, update) {
|
|
48
|
+
var _a;
|
|
49
|
+
const result = JSON.parse(JSON.stringify(source));
|
|
50
|
+
for (const name of ((_a = update.remove) !== null && _a !== void 0 ? _a : [])) {
|
|
51
|
+
const rootNode = Object.values(result)[0];
|
|
52
|
+
removeFromNode(rootNode, name);
|
|
53
|
+
}
|
|
54
|
+
if (update.add) {
|
|
55
|
+
const rootKey = Object.keys(result)[0];
|
|
56
|
+
for (const [name, newNode] of Object.entries(update.add)) {
|
|
57
|
+
if (name === rootKey) {
|
|
58
|
+
result[rootKey] = JSON.parse(JSON.stringify(newNode));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const rootNode = Object.values(result)[0];
|
|
62
|
+
replaceInNode(rootNode, name, newNode);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Helpers
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
function removeFromNode(node, targetName) {
|
|
72
|
+
if (!node.states)
|
|
73
|
+
return false;
|
|
74
|
+
if (targetName in node.states && isSubFaNode(node.states[targetName])) {
|
|
75
|
+
delete node.states[targetName];
|
|
76
|
+
node.ts = node.ts.filter(t => t[2] !== targetName);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
for (const stateValue of Object.values(node.states)) {
|
|
80
|
+
if (isSubFaNode(stateValue) && removeFromNode(stateValue, targetName)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
function replaceInNode(node, targetName, newNode) {
|
|
87
|
+
if (!node.states)
|
|
88
|
+
return false;
|
|
89
|
+
if (targetName in node.states) {
|
|
90
|
+
node.states[targetName] = JSON.parse(JSON.stringify(newNode));
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
for (const stateValue of Object.values(node.states)) {
|
|
94
|
+
if (isSubFaNode(stateValue) && replaceInNode(stateValue, targetName, newNode)) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
function isSubFaNode(value) {
|
|
101
|
+
return (typeof value === 'object' &&
|
|
102
|
+
value !== null &&
|
|
103
|
+
'ts' in value &&
|
|
104
|
+
Array.isArray(value.ts));
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=FaUpdater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FaUpdater.js","sourceRoot":"","sources":["../../src/sfsm/FaUpdater.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { FaDefinition, LogEntry, SfsmOptions } from './types';
|
|
2
|
+
import { ICommandReceiver, ISignalReceiver } from './interfaces';
|
|
3
|
+
/**
|
|
4
|
+
* Stacked Finite State Machine engine.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* const sfsm = new Sfsm(options);
|
|
8
|
+
* sfsm.setCommandReceiver(receiver);
|
|
9
|
+
* sfsm.loadFA(definition); // auto-activates state I of root FA
|
|
10
|
+
* sfsm.receiveSignal('TS.s');
|
|
11
|
+
*
|
|
12
|
+
* Signal re-entrancy: if receiveSignal is called while the engine is already
|
|
13
|
+
* processing a signal (e.g. from within a command receiver callback), the
|
|
14
|
+
* incoming signal is queued and processed after the current step completes.
|
|
15
|
+
* This prevents stack corruption and ensures deterministic ordering.
|
|
16
|
+
*/
|
|
17
|
+
export declare class Sfsm implements ISignalReceiver {
|
|
18
|
+
private resolver;
|
|
19
|
+
private stack;
|
|
20
|
+
private commandReceiver;
|
|
21
|
+
private options;
|
|
22
|
+
private log;
|
|
23
|
+
private processing;
|
|
24
|
+
private signalQueue;
|
|
25
|
+
constructor(options?: SfsmOptions);
|
|
26
|
+
/** Register the single command receiver for this SFSM instance. */
|
|
27
|
+
setCommandReceiver(receiver: ICommandReceiver): void;
|
|
28
|
+
/**
|
|
29
|
+
* Load a FA definition and initialise the engine.
|
|
30
|
+
* The root FA is pushed onto the stack with active state "I".
|
|
31
|
+
* No signal is sent automatically — the caller is responsible for
|
|
32
|
+
* sending the first signal (e.g. "TS.s") to drive out of state I.
|
|
33
|
+
*/
|
|
34
|
+
loadFA(definition: FaDefinition): void;
|
|
35
|
+
/**
|
|
36
|
+
* Send a signal to the SFSM.
|
|
37
|
+
* If called re-entrantly (from within a command receiver), the signal
|
|
38
|
+
* is queued and will be processed after the current step finishes.
|
|
39
|
+
*/
|
|
40
|
+
receiveSignal(signal: string, data?: unknown): void;
|
|
41
|
+
/** Returns the accumulated log entries. */
|
|
42
|
+
getLog(): LogEntry[];
|
|
43
|
+
/** Returns the current FA name stack (bottom = index 0, head = last). */
|
|
44
|
+
getCurrentStack(): string[];
|
|
45
|
+
/** Returns the active state of the head FA. */
|
|
46
|
+
getHeadState(): string;
|
|
47
|
+
private processSignal;
|
|
48
|
+
/**
|
|
49
|
+
* Rule 2: find a matching transition, searching from head down the stack.
|
|
50
|
+
* Returns { frameIndex, transition } or null if not found anywhere.
|
|
51
|
+
*/
|
|
52
|
+
private findTransition;
|
|
53
|
+
private applySignal;
|
|
54
|
+
private resolveStateMeta;
|
|
55
|
+
private resolveSignalMeta;
|
|
56
|
+
private resolveCommandMeta;
|
|
57
|
+
private handleMissingTransition;
|
|
58
|
+
private handleMissingData;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=Sfsm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sfsm.d.ts","sourceRoot":"","sources":["../../src/sfsm/Sfsm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAQjE;;;;;;;;;;;;;GAaG;AACH,qBAAa,IAAK,YAAW,eAAe;IAExC,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,eAAe,CAAiC;IACxD,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAiD;gBAExD,OAAO,GAAE,WAAgB;IAOrC,mEAAmE;IACnE,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAIpD;;;;;OAKG;IACH,MAAM,CAAC,UAAU,EAAE,YAAY,GAAG,IAAI;IAStC;;;;OAIG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAanD,2CAA2C;IAC3C,MAAM,IAAI,QAAQ,EAAE;IAIpB,yEAAyE;IACzE,eAAe,IAAI,MAAM,EAAE;IAI3B,+CAA+C;IAC/C,YAAY,IAAI,MAAM;IAOtB,OAAO,CAAC,aAAa;IAarB;;;OAGG;IACH,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,WAAW;IAqFnB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,iBAAiB;CAM5B"}
|