@statewalker/fsm-charts 0.0.6 → 0.1.0
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/dist/{StateChart-pFSQIvtE.d.ts → StateChart-PdtJDEPy.d.ts} +10 -12
- package/dist/chunk-XPUWN37Q.js +150 -0
- package/dist/{chunk-FYTJYHEQ.js → chunk-YYNW6Q2T.js} +4 -4
- package/dist/{chunk-IT7GBMYV.js → chunk-ZSGS37QH.js} +1 -0
- package/dist/{index-svg-DCwEyX8X.d.ts → index-html-CbDZzk2n.d.ts} +1 -1
- package/dist/{index-svg.d.ts → index-html.d.ts} +2 -2
- package/dist/{index-svg.js → index-html.js} +1 -1
- package/dist/index-layout.d.ts +2 -2
- package/dist/index-layout.js +1 -1
- package/dist/index-runtime.d.ts +56 -3
- package/dist/index-runtime.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/package.json +3 -1
- package/src/{svg → html}/buildStatechartStyles.ts +1 -1
- package/src/{index-svg.ts → index-html.ts} +1 -1
- package/src/index.ts +1 -1
- package/src/layout/buildCharts.ts +5 -1
- package/src/runtime/StateChartIndex.ts +152 -0
- package/src/runtime/index.ts +1 -211
- package/src/types/StateChart.ts +5 -5
- package/dist/chunk-X2UPWZLX.js +0 -4
- package/src/{svg → html}/buildStatechartCss.ts +0 -0
- package/src/{svg → html}/buildStatechartSvg.ts +0 -0
- package/src/{svg → html}/buildStatechartsPanel.ts +1 -1
- /package/src/{svg → html}/index.ts +0 -0
|
@@ -40,6 +40,15 @@ type Position = {
|
|
|
40
40
|
y: number;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Information about a state node in the graph.
|
|
45
|
+
*/
|
|
46
|
+
type StateGraphNode = Dimensions & Position & {
|
|
47
|
+
id: string;
|
|
48
|
+
key: string;
|
|
49
|
+
state: string;
|
|
50
|
+
} & Record<string, any>;
|
|
51
|
+
|
|
43
52
|
/**
|
|
44
53
|
* Information about a state graph edge.
|
|
45
54
|
*/
|
|
@@ -51,15 +60,6 @@ type StateGraphEdge = Dimensions & Position & {
|
|
|
51
60
|
points: Position[];
|
|
52
61
|
} & Record<string, any>;
|
|
53
62
|
|
|
54
|
-
/**
|
|
55
|
-
* Information about a state node in the graph.
|
|
56
|
-
*/
|
|
57
|
-
type StateGraphNode = Dimensions & Position & {
|
|
58
|
-
id: string;
|
|
59
|
-
key: string;
|
|
60
|
-
state: string;
|
|
61
|
-
} & Record<string, any>;
|
|
62
|
-
|
|
63
63
|
/**
|
|
64
64
|
* Coordinates for state nodes and endges corresponding to state transitions.
|
|
65
65
|
*/
|
|
@@ -68,9 +68,7 @@ type TransitionsGraph = Position & Dimensions & {
|
|
|
68
68
|
edges: StateGraphEdge[];
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
-
type StateChart = TransitionsGraph & {
|
|
72
|
-
id: string;
|
|
73
|
-
key: string;
|
|
71
|
+
type StateChart = TransitionsGraph & StateGraphNode & {
|
|
74
72
|
children?: StateChart[];
|
|
75
73
|
} & Record<string, any>;
|
|
76
74
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { __publicField } from './chunk-XEO3YXBM.js';
|
|
2
|
+
|
|
3
|
+
// src/runtime/StateChartIndex.ts
|
|
4
|
+
var StateChartIndex = class {
|
|
5
|
+
constructor({ statechart }) {
|
|
6
|
+
__publicField(this, "statechart");
|
|
7
|
+
__publicField(this, "_chartsIndex", {});
|
|
8
|
+
__publicField(this, "_nodesIndex", {});
|
|
9
|
+
__publicField(this, "_nodesParentsIndex", {});
|
|
10
|
+
__publicField(this, "_edgeIndex", {});
|
|
11
|
+
__publicField(this, "_edgesParentsIndex", {});
|
|
12
|
+
this.statechart = statechart;
|
|
13
|
+
this._buildIndexes();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Transforms a stack of state keys to the corresponding identifiers.
|
|
17
|
+
* If a key in the stack was not found then this method returns
|
|
18
|
+
* an empty stack.
|
|
19
|
+
* @param stack a stack of state keys
|
|
20
|
+
* @returns a stack of state identifiers for the given states
|
|
21
|
+
*/
|
|
22
|
+
getStatesIds(...stack) {
|
|
23
|
+
let result = [];
|
|
24
|
+
let list = [this.statechart];
|
|
25
|
+
for (let i = 0; list?.length > 0 && i < stack.length; i++) {
|
|
26
|
+
const key = stack[i];
|
|
27
|
+
const node = list.find((node2) => node2.key === key);
|
|
28
|
+
if (!node)
|
|
29
|
+
break;
|
|
30
|
+
result.push(node.id);
|
|
31
|
+
list = node.children;
|
|
32
|
+
if (!list?.length)
|
|
33
|
+
list = node.nodes;
|
|
34
|
+
}
|
|
35
|
+
return result.length === stack.length ? result : [];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns graph nodes for the specified identifier.
|
|
39
|
+
* @param id the id of a node
|
|
40
|
+
* @returns a stack of nodes
|
|
41
|
+
*/
|
|
42
|
+
getStackByStateId(id) {
|
|
43
|
+
if (!id)
|
|
44
|
+
return [];
|
|
45
|
+
const node = this._chartsIndex[id] || this._nodesIndex[id];
|
|
46
|
+
if (!node)
|
|
47
|
+
return [];
|
|
48
|
+
const parentId = this._nodesParentsIndex[id];
|
|
49
|
+
if (parentId) {
|
|
50
|
+
const parentStack = this.getStackByStateId(parentId);
|
|
51
|
+
if (!parentStack.length)
|
|
52
|
+
return [];
|
|
53
|
+
parentStack.push(node);
|
|
54
|
+
return parentStack;
|
|
55
|
+
} else {
|
|
56
|
+
return [node];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns an edge object corresponding to the transition from the state
|
|
61
|
+
* @param stateId identifier of the source state
|
|
62
|
+
* @param event an event triggering the transition
|
|
63
|
+
* @returns graph edge
|
|
64
|
+
*/
|
|
65
|
+
getTransition(stateId, event) {
|
|
66
|
+
const stack = this.getStackByStateId(stateId);
|
|
67
|
+
const state = stack.pop();
|
|
68
|
+
if (!state || !stack.length)
|
|
69
|
+
return;
|
|
70
|
+
const parent = stack[stack.length - 1];
|
|
71
|
+
const t = parent.edges.find(
|
|
72
|
+
(t2) => t2.from === state.key && t2.event === event
|
|
73
|
+
);
|
|
74
|
+
return t;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns a graph node corresponding to the specified state id.
|
|
78
|
+
* @param stateId identifier of the state
|
|
79
|
+
* @returns graph node
|
|
80
|
+
* @see getStateChart
|
|
81
|
+
*/
|
|
82
|
+
getStateNode(stateId) {
|
|
83
|
+
return stateId ? this._nodesIndex[stateId] : void 0;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Returns a chart corresponding to the specified state id.
|
|
87
|
+
* @param stateId identifier of the state
|
|
88
|
+
* @returns graph node
|
|
89
|
+
* @see getStateNode
|
|
90
|
+
*/
|
|
91
|
+
getStateChart(stateId) {
|
|
92
|
+
return stateId ? this._chartsIndex[stateId] : void 0;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Returns ids of the previous and next state for the specified transition
|
|
96
|
+
* @param transition a graph edge instance defining transition
|
|
97
|
+
* @returns an array with two identifiers - [sourceStateId, targetStateId] - the source state id and target state id
|
|
98
|
+
*/
|
|
99
|
+
getTransitionStateIds(transition) {
|
|
100
|
+
const result = [
|
|
101
|
+
void 0,
|
|
102
|
+
void 0
|
|
103
|
+
];
|
|
104
|
+
if (!transition)
|
|
105
|
+
return result;
|
|
106
|
+
const parentId = this._edgesParentsIndex[transition.id];
|
|
107
|
+
if (!parentId)
|
|
108
|
+
return result;
|
|
109
|
+
const parent = this._chartsIndex[parentId];
|
|
110
|
+
if (!parent)
|
|
111
|
+
return result;
|
|
112
|
+
parent.nodes.forEach((node) => {
|
|
113
|
+
if (node.key === transition.from) {
|
|
114
|
+
result[0] = node.id;
|
|
115
|
+
}
|
|
116
|
+
if (node.key === transition.to) {
|
|
117
|
+
result[1] = node.id;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
// ----------------------------------------------------------
|
|
123
|
+
// Internal methods
|
|
124
|
+
_buildIndexes() {
|
|
125
|
+
const addToIndex = (chart) => {
|
|
126
|
+
const chartId = chart.id;
|
|
127
|
+
this._chartsIndex[chartId] = chart;
|
|
128
|
+
if (!(chartId in this._nodesIndex)) {
|
|
129
|
+
this._nodesIndex[chartId] = chart;
|
|
130
|
+
}
|
|
131
|
+
chart.nodes.forEach((node) => {
|
|
132
|
+
const nodeId = node.id;
|
|
133
|
+
this._nodesIndex[nodeId] = node;
|
|
134
|
+
this._nodesParentsIndex[nodeId] = chartId;
|
|
135
|
+
});
|
|
136
|
+
chart.edges.forEach((edge) => {
|
|
137
|
+
const edgeId = edge.id;
|
|
138
|
+
this._edgeIndex[edgeId] = edge;
|
|
139
|
+
this._edgesParentsIndex[edgeId] = chartId;
|
|
140
|
+
});
|
|
141
|
+
(chart.children || []).forEach((child) => {
|
|
142
|
+
this._nodesParentsIndex[child.id] = chartId;
|
|
143
|
+
addToIndex(child);
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
addToIndex(this.statechart);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export { StateChartIndex };
|
|
@@ -47,7 +47,7 @@ function serializeCss(obj) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
// src/
|
|
50
|
+
// src/html/buildStatechartStyles.ts
|
|
51
51
|
function buildStateDetailsStyle() {
|
|
52
52
|
return {
|
|
53
53
|
".state-details": {
|
|
@@ -214,7 +214,7 @@ function buildStatechartStyles({
|
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
// src/
|
|
217
|
+
// src/html/buildStatechartCss.ts
|
|
218
218
|
function buildStatechartCss({ prefix = "" } = {}) {
|
|
219
219
|
const cssObject = buildStatechartStyles({ root: prefix || ":root" });
|
|
220
220
|
return serializeCss(cssObject);
|
|
@@ -310,7 +310,7 @@ var BasisCurve = class {
|
|
|
310
310
|
}
|
|
311
311
|
};
|
|
312
312
|
|
|
313
|
-
// src/
|
|
313
|
+
// src/html/buildStatechartSvg.ts
|
|
314
314
|
function getBoxParams({
|
|
315
315
|
x,
|
|
316
316
|
y,
|
|
@@ -500,7 +500,7 @@ function buildStatechartSvg({
|
|
|
500
500
|
println("</svg>");
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
-
// src/
|
|
503
|
+
// src/html/buildStatechartsPanel.ts
|
|
504
504
|
function buildStatechartsPanel({
|
|
505
505
|
statechart,
|
|
506
506
|
newId,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { D as Dimensions, F as FsmStateConfig, G as GraphParamsProvider, P as Padding, a as Position, S as StateChart, b as StateGraphEdge, c as StateGraphNode, T as Transition, d as TransitionsGraph } from './StateChart-
|
|
2
|
-
export { b as buildStatechartCss, c as buildStatechartStyles, d as buildStatechartSvg, a as buildStatechartsPanel } from './index-
|
|
1
|
+
export { D as Dimensions, F as FsmStateConfig, G as GraphParamsProvider, P as Padding, a as Position, S as StateChart, b as StateGraphEdge, c as StateGraphNode, T as Transition, d as TransitionsGraph } from './StateChart-PdtJDEPy.js';
|
|
2
|
+
export { b as buildStatechartCss, c as buildStatechartStyles, d as buildStatechartSvg, a as buildStatechartsPanel } from './index-html-CbDZzk2n.js';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { buildStatechartCss, buildStatechartStyles, buildStatechartSvg, buildStatechartsPanel } from './chunk-
|
|
1
|
+
export { buildStatechartCss, buildStatechartStyles, buildStatechartSvg, buildStatechartsPanel } from './chunk-YYNW6Q2T.js';
|
|
2
2
|
import './chunk-NXWOFQMO.js';
|
|
3
3
|
import './chunk-XEO3YXBM.js';
|
package/dist/index-layout.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as Transition, P as Padding, G as GraphParamsProvider, d as TransitionsGraph, F as FsmStateConfig, S as StateChart } from './StateChart-
|
|
2
|
-
export { D as Dimensions, a as Position, b as StateGraphEdge, c as StateGraphNode } from './StateChart-
|
|
1
|
+
import { T as Transition, P as Padding, G as GraphParamsProvider, d as TransitionsGraph, F as FsmStateConfig, S as StateChart } from './StateChart-PdtJDEPy.js';
|
|
2
|
+
export { D as Dimensions, a as Position, b as StateGraphEdge, c as StateGraphNode } from './StateChart-PdtJDEPy.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Build graphs corresponding to the specified transitions.
|
package/dist/index-layout.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-
|
|
1
|
+
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-ZSGS37QH.js';
|
|
2
2
|
import './chunk-NXWOFQMO.js';
|
|
3
3
|
import './chunk-XEO3YXBM.js';
|
package/dist/index-runtime.d.ts
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
|
-
|
|
1
|
+
import { S as StateChart, c as StateGraphNode, b as StateGraphEdge } from './StateChart-PdtJDEPy.js';
|
|
2
|
+
export { D as Dimensions, F as FsmStateConfig, G as GraphParamsProvider, P as Padding, a as Position, T as Transition, d as TransitionsGraph } from './StateChart-PdtJDEPy.js';
|
|
2
3
|
|
|
3
|
-
declare
|
|
4
|
+
declare class StateChartIndex {
|
|
5
|
+
statechart: StateChart;
|
|
6
|
+
_chartsIndex: Record<string, StateChart>;
|
|
7
|
+
_nodesIndex: Record<string, StateGraphNode>;
|
|
8
|
+
_nodesParentsIndex: Record<string, string>;
|
|
9
|
+
_edgeIndex: Record<string, StateGraphEdge>;
|
|
10
|
+
_edgesParentsIndex: Record<string, string>;
|
|
11
|
+
constructor({ statechart }: {
|
|
12
|
+
statechart: StateChart;
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Transforms a stack of state keys to the corresponding identifiers.
|
|
16
|
+
* If a key in the stack was not found then this method returns
|
|
17
|
+
* an empty stack.
|
|
18
|
+
* @param stack a stack of state keys
|
|
19
|
+
* @returns a stack of state identifiers for the given states
|
|
20
|
+
*/
|
|
21
|
+
getStatesIds(...stack: string[]): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Returns graph nodes for the specified identifier.
|
|
24
|
+
* @param id the id of a node
|
|
25
|
+
* @returns a stack of nodes
|
|
26
|
+
*/
|
|
27
|
+
getStackByStateId(id?: string): StateGraphNode[];
|
|
28
|
+
/**
|
|
29
|
+
* Returns an edge object corresponding to the transition from the state
|
|
30
|
+
* @param stateId identifier of the source state
|
|
31
|
+
* @param event an event triggering the transition
|
|
32
|
+
* @returns graph edge
|
|
33
|
+
*/
|
|
34
|
+
getTransition(stateId?: string, event?: string): StateGraphEdge | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Returns a graph node corresponding to the specified state id.
|
|
37
|
+
* @param stateId identifier of the state
|
|
38
|
+
* @returns graph node
|
|
39
|
+
* @see getStateChart
|
|
40
|
+
*/
|
|
41
|
+
getStateNode(stateId?: string): StateGraphNode | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Returns a chart corresponding to the specified state id.
|
|
44
|
+
* @param stateId identifier of the state
|
|
45
|
+
* @returns graph node
|
|
46
|
+
* @see getStateNode
|
|
47
|
+
*/
|
|
48
|
+
getStateChart(stateId?: string): StateChart | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Returns ids of the previous and next state for the specified transition
|
|
51
|
+
* @param transition a graph edge instance defining transition
|
|
52
|
+
* @returns an array with two identifiers - [sourceStateId, targetStateId] - the source state id and target state id
|
|
53
|
+
*/
|
|
54
|
+
getTransitionStateIds(transition?: StateGraphEdge): [string | undefined, string | undefined];
|
|
55
|
+
_buildIndexes(): void;
|
|
56
|
+
}
|
|
4
57
|
|
|
5
|
-
export {
|
|
58
|
+
export { StateChart, StateChartIndex, StateGraphEdge, StateGraphNode };
|
package/dist/index-runtime.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { StateChartIndex } from './chunk-XPUWN37Q.js';
|
|
2
2
|
import './chunk-XEO3YXBM.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { D as Dimensions, F as FsmStateConfig, G as GraphParamsProvider, P as Padding, a as Position, S as StateChart, b as StateGraphEdge, c as StateGraphNode, T as Transition, d as TransitionsGraph } from './StateChart-
|
|
1
|
+
export { D as Dimensions, F as FsmStateConfig, G as GraphParamsProvider, P as Padding, a as Position, S as StateChart, b as StateGraphEdge, c as StateGraphNode, T as Transition, d as TransitionsGraph } from './StateChart-PdtJDEPy.js';
|
|
2
2
|
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './index-layout.js';
|
|
3
|
-
export { C as CssTree, b as buildStatechartCss, c as buildStatechartStyles, d as buildStatechartSvg, a as buildStatechartsPanel, s as serializeCss } from './index-
|
|
4
|
-
export {
|
|
3
|
+
export { C as CssTree, b as buildStatechartCss, c as buildStatechartStyles, d as buildStatechartSvg, a as buildStatechartsPanel, s as serializeCss } from './index-html-CbDZzk2n.js';
|
|
4
|
+
export { StateChartIndex } from './index-runtime.js';
|
|
5
5
|
|
|
6
6
|
declare function toKebabCase(str: string): string;
|
|
7
7
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-
|
|
2
|
-
export { buildStatechartCss, buildStatechartStyles, buildStatechartSvg, buildStatechartsPanel, serializeCss, toKebabCase } from './chunk-
|
|
1
|
+
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-ZSGS37QH.js';
|
|
2
|
+
export { buildStatechartCss, buildStatechartStyles, buildStatechartSvg, buildStatechartsPanel, serializeCss, toKebabCase } from './chunk-YYNW6Q2T.js';
|
|
3
3
|
import './chunk-NXWOFQMO.js';
|
|
4
|
-
export {
|
|
4
|
+
export { StateChartIndex } from './chunk-XPUWN37Q.js';
|
|
5
5
|
import './chunk-XEO3YXBM.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/fsm-charts",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "HFSM Implementation",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/statewalker/statewalker-fsm-charts",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@statewalker/typescript-config": "*",
|
|
29
|
+
"@types/jsdom": "^21.1.7",
|
|
29
30
|
"@types/lodash-es": "^4.17.12",
|
|
30
31
|
"@typescript-eslint/eslint-plugin": "^6.4.0",
|
|
31
32
|
"eslint": "^8.0.1",
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"eslint-plugin-import": "^2.25.2",
|
|
34
35
|
"eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
|
|
35
36
|
"eslint-plugin-promise": "^6.0.0",
|
|
37
|
+
"jsdom": "^24.1.0",
|
|
36
38
|
"lodash": "^4.17.21",
|
|
37
39
|
"lodash-es": "^4.17.21",
|
|
38
40
|
"tsup": "^8.0.2",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from "./types/index.ts";
|
|
2
|
-
export * from "./
|
|
2
|
+
export * from "./html/index.ts";
|
package/src/index.ts
CHANGED
|
@@ -33,7 +33,10 @@ export function buildCharts({
|
|
|
33
33
|
} & GraphParamsProvider): StateChart {
|
|
34
34
|
return buildChart(config);
|
|
35
35
|
|
|
36
|
-
function buildChart(
|
|
36
|
+
function buildChart(
|
|
37
|
+
config: FsmStateConfig,
|
|
38
|
+
id: string = newId("s")
|
|
39
|
+
): StateChart {
|
|
37
40
|
const graph = buildFlatCharts({
|
|
38
41
|
lodash,
|
|
39
42
|
transitions: config.transitions,
|
|
@@ -59,6 +62,7 @@ export function buildCharts({
|
|
|
59
62
|
return {
|
|
60
63
|
id,
|
|
61
64
|
key: config.key,
|
|
65
|
+
state: config.key,
|
|
62
66
|
...graph,
|
|
63
67
|
children,
|
|
64
68
|
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
StateChart,
|
|
3
|
+
StateGraphNode,
|
|
4
|
+
StateGraphEdge,
|
|
5
|
+
} from "../types/index.ts";
|
|
6
|
+
|
|
7
|
+
export class StateChartIndex {
|
|
8
|
+
statechart: StateChart;
|
|
9
|
+
_chartsIndex: Record<string, StateChart> = {};
|
|
10
|
+
_nodesIndex: Record<string, StateGraphNode> = {};
|
|
11
|
+
_nodesParentsIndex: Record<string, string> = {};
|
|
12
|
+
_edgeIndex: Record<string, StateGraphEdge> = {};
|
|
13
|
+
_edgesParentsIndex: Record<string, string> = {};
|
|
14
|
+
|
|
15
|
+
constructor({ statechart }: { statechart: StateChart }) {
|
|
16
|
+
this.statechart = statechart;
|
|
17
|
+
this._buildIndexes();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Transforms a stack of state keys to the corresponding identifiers.
|
|
22
|
+
* If a key in the stack was not found then this method returns
|
|
23
|
+
* an empty stack.
|
|
24
|
+
* @param stack a stack of state keys
|
|
25
|
+
* @returns a stack of state identifiers for the given states
|
|
26
|
+
*/
|
|
27
|
+
getStatesIds(...stack: string[]): string[] {
|
|
28
|
+
let result = [];
|
|
29
|
+
let list = [this.statechart] as (StateChart | StateGraphNode)[];
|
|
30
|
+
for (let i = 0; list?.length > 0 && i < stack.length; i++) {
|
|
31
|
+
const key = stack[i];
|
|
32
|
+
const node = list.find((node) => node.key === key);
|
|
33
|
+
if (!node) break;
|
|
34
|
+
result.push(node.id);
|
|
35
|
+
list = node.children;
|
|
36
|
+
if (!list?.length) list = node.nodes;
|
|
37
|
+
}
|
|
38
|
+
return result.length === stack.length ? result : [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns graph nodes for the specified identifier.
|
|
43
|
+
* @param id the id of a node
|
|
44
|
+
* @returns a stack of nodes
|
|
45
|
+
*/
|
|
46
|
+
getStackByStateId(id?: string): StateGraphNode[] {
|
|
47
|
+
if (!id) return [];
|
|
48
|
+
const node = this._chartsIndex[id] || this._nodesIndex[id];
|
|
49
|
+
if (!node) return [];
|
|
50
|
+
const parentId = this._nodesParentsIndex[id];
|
|
51
|
+
if (parentId) {
|
|
52
|
+
const parentStack = this.getStackByStateId(parentId);
|
|
53
|
+
if (!parentStack.length) return [];
|
|
54
|
+
parentStack.push(node);
|
|
55
|
+
return parentStack;
|
|
56
|
+
} else {
|
|
57
|
+
return [node];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns an edge object corresponding to the transition from the state
|
|
63
|
+
* @param stateId identifier of the source state
|
|
64
|
+
* @param event an event triggering the transition
|
|
65
|
+
* @returns graph edge
|
|
66
|
+
*/
|
|
67
|
+
getTransition(stateId?: string, event?: string): StateGraphEdge | undefined {
|
|
68
|
+
const stack = this.getStackByStateId(stateId);
|
|
69
|
+
const state = stack.pop();
|
|
70
|
+
if (!state || !stack.length) return;
|
|
71
|
+
const parent = stack[stack.length - 1];
|
|
72
|
+
const t = parent.edges.find(
|
|
73
|
+
(t: StateGraphEdge) => t.from === state.key && t.event === event
|
|
74
|
+
);
|
|
75
|
+
return t;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Returns a graph node corresponding to the specified state id.
|
|
80
|
+
* @param stateId identifier of the state
|
|
81
|
+
* @returns graph node
|
|
82
|
+
* @see getStateChart
|
|
83
|
+
*/
|
|
84
|
+
getStateNode(stateId?: string): StateGraphNode | undefined {
|
|
85
|
+
return stateId ? this._nodesIndex[stateId] : undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Returns a chart corresponding to the specified state id.
|
|
90
|
+
* @param stateId identifier of the state
|
|
91
|
+
* @returns graph node
|
|
92
|
+
* @see getStateNode
|
|
93
|
+
*/
|
|
94
|
+
getStateChart(stateId?: string): StateChart | undefined {
|
|
95
|
+
return stateId ? this._chartsIndex[stateId] : undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Returns ids of the previous and next state for the specified transition
|
|
100
|
+
* @param transition a graph edge instance defining transition
|
|
101
|
+
* @returns an array with two identifiers - [sourceStateId, targetStateId] - the source state id and target state id
|
|
102
|
+
*/
|
|
103
|
+
getTransitionStateIds(
|
|
104
|
+
transition?: StateGraphEdge
|
|
105
|
+
): [string | undefined, string | undefined] {
|
|
106
|
+
const result: [string | undefined, string | undefined] = [
|
|
107
|
+
undefined,
|
|
108
|
+
undefined,
|
|
109
|
+
];
|
|
110
|
+
if (!transition) return result;
|
|
111
|
+
const parentId = this._edgesParentsIndex[transition.id];
|
|
112
|
+
if (!parentId) return result;
|
|
113
|
+
const parent = this._chartsIndex[parentId];
|
|
114
|
+
if (!parent) return result;
|
|
115
|
+
parent.nodes.forEach((node: StateGraphNode) => {
|
|
116
|
+
if (node.key === transition.from) {
|
|
117
|
+
result[0] = node.id;
|
|
118
|
+
}
|
|
119
|
+
if (node.key === transition.to) {
|
|
120
|
+
result[1] = node.id;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ----------------------------------------------------------
|
|
127
|
+
// Internal methods
|
|
128
|
+
_buildIndexes() {
|
|
129
|
+
const addToIndex = (chart: StateChart) => {
|
|
130
|
+
const chartId = chart.id;
|
|
131
|
+
this._chartsIndex[chartId] = chart;
|
|
132
|
+
if (!(chartId in this._nodesIndex)) {
|
|
133
|
+
this._nodesIndex[chartId] = chart;
|
|
134
|
+
}
|
|
135
|
+
chart.nodes.forEach((node) => {
|
|
136
|
+
const nodeId = node.id;
|
|
137
|
+
this._nodesIndex[nodeId] = node;
|
|
138
|
+
this._nodesParentsIndex[nodeId] = chartId;
|
|
139
|
+
});
|
|
140
|
+
chart.edges.forEach((edge) => {
|
|
141
|
+
const edgeId = edge.id;
|
|
142
|
+
this._edgeIndex[edgeId] = edge;
|
|
143
|
+
this._edgesParentsIndex[edgeId] = chartId;
|
|
144
|
+
});
|
|
145
|
+
(chart.children || []).forEach((child) => {
|
|
146
|
+
this._nodesParentsIndex[child.id] = chartId;
|
|
147
|
+
addToIndex(child);
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
addToIndex(this.statechart);
|
|
151
|
+
}
|
|
152
|
+
}
|
package/src/runtime/index.ts
CHANGED
|
@@ -1,211 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
// class RuntimeStatechartsApi {
|
|
4
|
-
// constructor({ element, statechart }) {
|
|
5
|
-
// this.element = element;
|
|
6
|
-
// this.statechart = statechart;
|
|
7
|
-
// // this._statesIndex = {};
|
|
8
|
-
// // this._transitionsIndex = {};
|
|
9
|
-
// // this._buildIndexes(this.statechart);
|
|
10
|
-
// }
|
|
11
|
-
|
|
12
|
-
// _applyStateModifier(cssSelector, modifier = "selected", apply) {
|
|
13
|
-
// const detailsModifier = `state-details--${modifier}`;
|
|
14
|
-
// const stateLabelsModifier = `state-details__label--${modifier}`;
|
|
15
|
-
// const stateModifier = `state--${modifier}`;
|
|
16
|
-
// [...this.element.querySelectorAll(cssSelector)].forEach((elm) => {
|
|
17
|
-
// if (elm.tagName.toLowerCase() === "details") {
|
|
18
|
-
// apply(elm, detailsModifier);
|
|
19
|
-
// const labelElm = elm.querySelector(".state-details__label");
|
|
20
|
-
// if (labelElm) apply(labelElm, stateLabelsModifier);
|
|
21
|
-
// } else {
|
|
22
|
-
// apply(elm, stateModifier);
|
|
23
|
-
// }
|
|
24
|
-
// });
|
|
25
|
-
// }
|
|
26
|
-
|
|
27
|
-
// _applyTransitionsModifier(cssSelector, modifier = "selected", action) {}
|
|
28
|
-
|
|
29
|
-
// deselectAllTransitions() {
|
|
30
|
-
// const removeClass = (elm, cls) => elm.classList.remove(cls);
|
|
31
|
-
// this._applyTransitionsModifier(
|
|
32
|
-
// "[data-transition-id]",
|
|
33
|
-
// "selected",
|
|
34
|
-
// removeClass
|
|
35
|
-
// );
|
|
36
|
-
// }
|
|
37
|
-
// deselectTransitions(...ids) {
|
|
38
|
-
// const removeClass = (elm, cls) => elm.classList.remove(cls);
|
|
39
|
-
// for (const id of ids) {
|
|
40
|
-
// this._applyTransitionsModifier(
|
|
41
|
-
// `[data-transition-id="${id}"]`,
|
|
42
|
-
// "selected",
|
|
43
|
-
// removeClass
|
|
44
|
-
// );
|
|
45
|
-
// }
|
|
46
|
-
// }
|
|
47
|
-
// selectTransitions(...ids) {
|
|
48
|
-
// const addClass = (elm, cls) => elm.classList.add(cls);
|
|
49
|
-
// for (const id of ids) {
|
|
50
|
-
// this._applyTransitionsModifier(
|
|
51
|
-
// `[data-transition-id="${id}"]`,
|
|
52
|
-
// "selected",
|
|
53
|
-
// addClass
|
|
54
|
-
// );
|
|
55
|
-
// }
|
|
56
|
-
// }
|
|
57
|
-
|
|
58
|
-
// deselectAllStates() {
|
|
59
|
-
// const removeClass = (elm, cls) => elm.classList.remove(cls);
|
|
60
|
-
// this._applyStateModifier("[data-state-id]", "selected", removeClass);
|
|
61
|
-
// }
|
|
62
|
-
// deselectStates(...ids) {
|
|
63
|
-
// const removeClass = (elm, cls) => elm.classList.remove(cls);
|
|
64
|
-
// for (const id of ids) {
|
|
65
|
-
// this._applyStateModifier(
|
|
66
|
-
// `[data-state-id="${id}"]`,
|
|
67
|
-
// "selected",
|
|
68
|
-
// removeClass
|
|
69
|
-
// );
|
|
70
|
-
// }
|
|
71
|
-
// }
|
|
72
|
-
// selectStates(...ids) {
|
|
73
|
-
// const addClass = (elm, cls) => elm.classList.add(cls);
|
|
74
|
-
// for (const id of ids) {
|
|
75
|
-
// this._applyStateModifier(`[data-state-id="${id}"]`, "selected", addClass);
|
|
76
|
-
// }
|
|
77
|
-
// }
|
|
78
|
-
|
|
79
|
-
// // -----------------------------------------------
|
|
80
|
-
// // Access to charts data
|
|
81
|
-
// // - get state ids by stack of state keys
|
|
82
|
-
// // - get stack of states by state id
|
|
83
|
-
// // - get transitionId by stateId + event
|
|
84
|
-
// // - get targetId, sourceId, event by transitionId
|
|
85
|
-
// getStatesIds(...stack) {
|
|
86
|
-
// let statechart = this.statechart;
|
|
87
|
-
// let result = [];
|
|
88
|
-
// if (statechart.key === stack[0]) {
|
|
89
|
-
// result.push(statechart.id);
|
|
90
|
-
// for (let i = 1; i < stack.length; i++) {
|
|
91
|
-
// const key = stack[i];
|
|
92
|
-
// let id = statechart.graph.nodes.find((node) => node.key === key)?.id;
|
|
93
|
-
// if (!id) break;
|
|
94
|
-
// result.push(id);
|
|
95
|
-
// statechart = (statechart.children || []).find(
|
|
96
|
-
// (child) => child.key === key
|
|
97
|
-
// );
|
|
98
|
-
// }
|
|
99
|
-
// }
|
|
100
|
-
// return result.length === stack.length ? result : [];
|
|
101
|
-
// }
|
|
102
|
-
|
|
103
|
-
// getStackByStateId(id) {
|
|
104
|
-
// return this._getStack(id, ({ id, key }) => key);
|
|
105
|
-
// }
|
|
106
|
-
|
|
107
|
-
// getTransition(stateId, event) {
|
|
108
|
-
// const stack = this._getStack(stateId);
|
|
109
|
-
// const state = stack.pop();
|
|
110
|
-
// if (!state || !stack.length) return;
|
|
111
|
-
// const parent = stack[stack.length - 1];
|
|
112
|
-
// const t = parent.graph.edges.find(
|
|
113
|
-
// (t) => t.from === state.key && t.event === event
|
|
114
|
-
// );
|
|
115
|
-
// if (!t) return;
|
|
116
|
-
// const to = parent.graph.nodes.find((n) => n.key === t.to);
|
|
117
|
-
// return to && { id: t.id, fromId: state.id, event: t.event, toId: to.id };
|
|
118
|
-
// }
|
|
119
|
-
|
|
120
|
-
// _getStack(id, get = (d) => d) {
|
|
121
|
-
// return findById(this.statechart, id, get);
|
|
122
|
-
|
|
123
|
-
// function findById(statechart, id, get, stack = []) {
|
|
124
|
-
// try {
|
|
125
|
-
// stack.push(get(statechart));
|
|
126
|
-
// if (statechart.id === id) {
|
|
127
|
-
// return [...stack];
|
|
128
|
-
// } else {
|
|
129
|
-
// let node = statechart.graph.nodes.find((node) => node.id === id);
|
|
130
|
-
// if (node) {
|
|
131
|
-
// return [...stack, get(node)];
|
|
132
|
-
// } else {
|
|
133
|
-
// let result;
|
|
134
|
-
// if (statechart.children) {
|
|
135
|
-
// for (const child of statechart.children) {
|
|
136
|
-
// result = findById(child, id, get, stack);
|
|
137
|
-
// if (result) break;
|
|
138
|
-
// }
|
|
139
|
-
// }
|
|
140
|
-
// return result;
|
|
141
|
-
// }
|
|
142
|
-
// }
|
|
143
|
-
// } finally {
|
|
144
|
-
// stack.pop();
|
|
145
|
-
// }
|
|
146
|
-
// }
|
|
147
|
-
// }
|
|
148
|
-
|
|
149
|
-
// // getTransitionId(stateId, event) {
|
|
150
|
-
// // }
|
|
151
|
-
|
|
152
|
-
// // const stateInfo = this._statesIndex[stateId];
|
|
153
|
-
// // if (!stateInfo) return;
|
|
154
|
-
// // if (stateInfo.parent) return ;
|
|
155
|
-
// // const targetState = stateInfo.parent.
|
|
156
|
-
// // const fromId = stateIds.pop();
|
|
157
|
-
// // const parentId = stateIds.pop();
|
|
158
|
-
// // const parent = parentId ? this._statesIndex[parentId] : null;
|
|
159
|
-
// // return parent
|
|
160
|
-
// // ? parent.graph?.edges.find(
|
|
161
|
-
// // (edge) => edge.from === fromId && edge.event === event
|
|
162
|
-
// // )
|
|
163
|
-
// // : undefined;
|
|
164
|
-
// // }
|
|
165
|
-
|
|
166
|
-
// // _getInfo(index, id, create) {
|
|
167
|
-
// // let info = index[id];
|
|
168
|
-
// // if (!info && create) {
|
|
169
|
-
// // info = index[id] = { id };
|
|
170
|
-
// // }
|
|
171
|
-
// // return info;
|
|
172
|
-
// // }
|
|
173
|
-
// // _getStateInfo(id, create) {
|
|
174
|
-
// // return this._getInfo(this._statesIndex, id, create);
|
|
175
|
-
// // }
|
|
176
|
-
// // _getTransitionInfo(id, create) {
|
|
177
|
-
// // return this._getInfo(this._transitionsIndex, id, create);
|
|
178
|
-
// // }
|
|
179
|
-
// // _buildIndexes(statechart) {
|
|
180
|
-
// // const { id, key } = statechart;
|
|
181
|
-
// // const stateInfo = this._getStateInfo(id, true);
|
|
182
|
-
// // stateInfo.key = key;
|
|
183
|
-
// // stateInfo.detailsElement = this.element.querySelector(
|
|
184
|
-
// // `details[data-state-id="${id}"]`
|
|
185
|
-
// // );
|
|
186
|
-
// // for (const node of statechart.graph?.nodes || []) {
|
|
187
|
-
// // const info = this._getStateInfo(node.id, true);
|
|
188
|
-
// // info.parent = stateInfo;
|
|
189
|
-
// // // info.parentId = id;
|
|
190
|
-
// // info.node = node;
|
|
191
|
-
// // info.key = node.key;
|
|
192
|
-
// // info.svgGroupElement = this.element.querySelector(
|
|
193
|
-
// // `g[data-state-id="${info.id}"]`
|
|
194
|
-
// // );
|
|
195
|
-
// // }
|
|
196
|
-
// // for (const edge of statechart.graph?.edges || []) {
|
|
197
|
-
// // const info = this._getTransitionInfo(edge.id, true);
|
|
198
|
-
// // info.transition = edge;
|
|
199
|
-
// // info.from = edge.from;
|
|
200
|
-
// // info.event = edge.event;
|
|
201
|
-
// // info.to = edge.to;
|
|
202
|
-
// // info.svgGroupElement = this.element.querySelector(
|
|
203
|
-
// // `g[data-transition-id="${info.id}"]`
|
|
204
|
-
// // );
|
|
205
|
-
// // }
|
|
206
|
-
|
|
207
|
-
// // for (const child of statechart.children) {
|
|
208
|
-
// // this._buildIndexes(child);
|
|
209
|
-
// // }
|
|
210
|
-
// // }
|
|
211
|
-
// }
|
|
1
|
+
export * from "./StateChartIndex.ts";
|
package/src/types/StateChart.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import type { StateGraphNode } from "./StateGraphNode.ts";
|
|
1
2
|
import type { TransitionsGraph } from "./TransitionsGraph.ts";
|
|
2
3
|
|
|
3
|
-
export type StateChart = TransitionsGraph &
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} & Record<string, any>;
|
|
4
|
+
export type StateChart = TransitionsGraph &
|
|
5
|
+
StateGraphNode & {
|
|
6
|
+
children?: StateChart[];
|
|
7
|
+
} & Record<string, any>;
|
package/dist/chunk-X2UPWZLX.js
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|