@systemfsoftware/xstate 0.0.0-stage → 6.0.0-beta.65
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/CHANGELOG.md +57 -0
- package/LICENSE +22 -0
- package/README.md +640 -2
- package/dist/actors-LxMBvgxO.mjs +472 -0
- package/dist/actors.d.ts +3 -0
- package/dist/actors.mjs +3 -0
- package/dist/base.types-DF8ZPiXj.d.ts +210 -0
- package/dist/createActor-BGHd7i8Q.mjs +4851 -0
- package/dist/durable.d.ts +211 -0
- package/dist/durable.mjs +283 -0
- package/dist/effectDescriptor-EvNuy6U3.d.ts +91 -0
- package/dist/fsm.d.ts +139 -0
- package/dist/fsm.mjs +60 -0
- package/dist/graph.d.ts +160 -0
- package/dist/graph.mjs +667 -0
- package/dist/index-CKUyiMZC.d.ts +1832 -0
- package/dist/index-DDWoKIF5.d.ts +512 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.mjs +7 -0
- package/dist/schema.types-tsIbgQd-.mjs +46 -0
- package/dist/src-zLWug7SF.mjs +2641 -0
- package/dist/transition-ZMXyPI-x.mjs +258 -0
- package/dist/types-B2EAwOk-.d.ts +3511 -0
- package/dist/utils-CXBxxp3Z.mjs +146 -0
- package/dist/validation.d.ts +49 -0
- package/dist/validation.mjs +216 -0
- package/package.json +83 -3
package/dist/graph.mjs
ADDED
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
import { t as createEmptyActor } from "./actors-LxMBvgxO.mjs";
|
|
2
|
+
import { g as XSTATE_INIT, h as defaultWarn, r as getAllOwnEvents } from "./utils-CXBxxp3Z.mjs";
|
|
3
|
+
// src/graph/actorScope.ts
|
|
4
|
+
function actorSystem(actor) {
|
|
5
|
+
return actor.system;
|
|
6
|
+
}
|
|
7
|
+
function createMockActorScope() {
|
|
8
|
+
const emptyActor = createEmptyActor();
|
|
9
|
+
return {
|
|
10
|
+
self: emptyActor,
|
|
11
|
+
logger: console.log,
|
|
12
|
+
warn: defaultWarn,
|
|
13
|
+
id: "",
|
|
14
|
+
sessionId: "mock-actor-scope",
|
|
15
|
+
defer: () => {},
|
|
16
|
+
system: actorSystem(emptyActor),
|
|
17
|
+
stopChild: () => {},
|
|
18
|
+
emit: () => {},
|
|
19
|
+
actionExecutor: () => {}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// src/graph/graph.ts
|
|
23
|
+
const isActorLogic = (value) => value !== void 0 && "transition" in value;
|
|
24
|
+
const logicFirstOrLast = (compute) => (first, second) => isActorLogic(first) ? compute(first, second) : (logic) => compute(logic, first);
|
|
25
|
+
/**
|
|
26
|
+
* Returns all state nodes of the given `node`.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
* @param stateNode State node to recursively get child state nodes from
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
function getDescendantStateNodes(stateNode) {
|
|
33
|
+
const { states } = stateNode;
|
|
34
|
+
return Object.keys(states).reduce((accNodes, stateKey) => {
|
|
35
|
+
const childStateNode = states[stateKey];
|
|
36
|
+
if (childStateNode === void 0) return accNodes;
|
|
37
|
+
accNodes.push(childStateNode, ...getDescendantStateNodes(childStateNode));
|
|
38
|
+
return accNodes;
|
|
39
|
+
}, []);
|
|
40
|
+
}
|
|
41
|
+
function getChildren(stateNode) {
|
|
42
|
+
return Object.values(stateNode.states);
|
|
43
|
+
}
|
|
44
|
+
function isFilled(context) {
|
|
45
|
+
return context !== void 0 && Object.keys(context).length > 0;
|
|
46
|
+
}
|
|
47
|
+
function nonEmptyContext(context) {
|
|
48
|
+
return isFilled(context) ? context : void 0;
|
|
49
|
+
}
|
|
50
|
+
function snapshotFields(snapshot) {
|
|
51
|
+
const { value, context } = snapshot;
|
|
52
|
+
return {
|
|
53
|
+
value,
|
|
54
|
+
context: nonEmptyContext(context)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function toSerializedSnapshot(value) {
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
function toSerializedEvent(value) {
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
/** @public */
|
|
64
|
+
function serializeSnapshot(snapshot) {
|
|
65
|
+
return toSerializedSnapshot(JSON.stringify(snapshotFields(snapshot)));
|
|
66
|
+
}
|
|
67
|
+
function serializeEvent(event) {
|
|
68
|
+
return toSerializedEvent(JSON.stringify(event));
|
|
69
|
+
}
|
|
70
|
+
function ownLogicEvents(state) {
|
|
71
|
+
return getAllOwnEvents(state);
|
|
72
|
+
}
|
|
73
|
+
function defaultSerializeState(state) {
|
|
74
|
+
return JSON.stringify(state);
|
|
75
|
+
}
|
|
76
|
+
function optionFromState(options) {
|
|
77
|
+
return options?.fromState;
|
|
78
|
+
}
|
|
79
|
+
function optionStopWhen(options) {
|
|
80
|
+
return options?.toState;
|
|
81
|
+
}
|
|
82
|
+
function startState(logic, options) {
|
|
83
|
+
return options.fromState ?? logic.getInitialSnapshot(createMockActorScope(), options.input);
|
|
84
|
+
}
|
|
85
|
+
function createDefaultMachineOptions(machine, options = {}) {
|
|
86
|
+
return {
|
|
87
|
+
serializeState: serializeSnapshot,
|
|
88
|
+
serializeEvent,
|
|
89
|
+
events: ownLogicEvents,
|
|
90
|
+
fromState: startState(machine, options)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const memberOf = (value, key) => new Object(Reflect.get(value, key));
|
|
94
|
+
const memberIs = (value, key, kind) => typeof Reflect.get(value, key) === kind;
|
|
95
|
+
const machineMethods = [
|
|
96
|
+
"getStateNodeById",
|
|
97
|
+
"resolveState",
|
|
98
|
+
"getTransitionData"
|
|
99
|
+
];
|
|
100
|
+
function isMachineLogic(logic) {
|
|
101
|
+
const root = memberOf(logic, "root");
|
|
102
|
+
return [
|
|
103
|
+
typeof logic === "object",
|
|
104
|
+
memberIs(logic, "root", "object"),
|
|
105
|
+
memberIs(root, "id", "string"),
|
|
106
|
+
memberIs(root, "states", "object"),
|
|
107
|
+
memberIs(memberOf(root, "transitions"), "values", "function"),
|
|
108
|
+
...machineMethods.map((method) => memberIs(logic, method, "function"))
|
|
109
|
+
].every(Boolean);
|
|
110
|
+
}
|
|
111
|
+
function transitionEventType(transition) {
|
|
112
|
+
return transition.eventType;
|
|
113
|
+
}
|
|
114
|
+
/** @public */
|
|
115
|
+
function toDirectedGraph(stateMachine) {
|
|
116
|
+
const stateNode = isMachineLogic(stateMachine) ? stateMachine.root : stateMachine;
|
|
117
|
+
const edges = [...stateNode.transitions.values()].flat().flatMap((t, transitionIndex) => {
|
|
118
|
+
const targets = t.target !== void 0 ? t.target : [stateNode];
|
|
119
|
+
const eventType = transitionEventType(t);
|
|
120
|
+
return targets.map((target, targetIndex) => {
|
|
121
|
+
const edge = {
|
|
122
|
+
id: `${stateNode.id}:${transitionIndex}:${targetIndex}`,
|
|
123
|
+
source: stateNode,
|
|
124
|
+
target,
|
|
125
|
+
transition: t,
|
|
126
|
+
label: {
|
|
127
|
+
text: eventType,
|
|
128
|
+
toJSON: () => ({ text: eventType })
|
|
129
|
+
},
|
|
130
|
+
toJSON: () => {
|
|
131
|
+
const { label } = edge;
|
|
132
|
+
return {
|
|
133
|
+
source: stateNode.id,
|
|
134
|
+
target: target.id,
|
|
135
|
+
label
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
return edge;
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
const graph = {
|
|
143
|
+
id: stateNode.id,
|
|
144
|
+
stateNode,
|
|
145
|
+
children: getChildren(stateNode).map(toDirectedGraph),
|
|
146
|
+
edges,
|
|
147
|
+
toJSON: () => {
|
|
148
|
+
const { id, children, edges: graphEdges } = graph;
|
|
149
|
+
return {
|
|
150
|
+
id,
|
|
151
|
+
children,
|
|
152
|
+
edges: graphEdges
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
return graph;
|
|
157
|
+
}
|
|
158
|
+
function resolveDefaultOptions(logic, traversalOptions) {
|
|
159
|
+
return isMachineLogic(logic) ? createDefaultMachineOptions(logic, traversalOptions) : void 0;
|
|
160
|
+
}
|
|
161
|
+
function resolveTraversalOptions({ logic, options: traversalOptions }) {
|
|
162
|
+
const resolvedDefaultOptions = resolveDefaultOptions(logic, traversalOptions);
|
|
163
|
+
const serializeState = defaultSerializeState;
|
|
164
|
+
const fromState = optionFromState(traversalOptions) ?? optionFromState(resolvedDefaultOptions);
|
|
165
|
+
return {
|
|
166
|
+
serializeState,
|
|
167
|
+
serializeEvent,
|
|
168
|
+
events: [],
|
|
169
|
+
filterEvents: void 0,
|
|
170
|
+
limit: Infinity,
|
|
171
|
+
toState: void 0,
|
|
172
|
+
stopWhen: optionStopWhen(traversalOptions),
|
|
173
|
+
...resolvedDefaultOptions,
|
|
174
|
+
...traversalOptions,
|
|
175
|
+
fromState
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function requireFirstStep(path) {
|
|
179
|
+
const firstStep = path.steps[0];
|
|
180
|
+
if (firstStep === void 0) throw new Error(`Paths cannot be joined`);
|
|
181
|
+
return firstStep;
|
|
182
|
+
}
|
|
183
|
+
const joinPathsDataFirst = (headPath, tailPath) => {
|
|
184
|
+
if (requireFirstStep(tailPath).state !== headPath.state) throw new Error(`Paths cannot be joined`);
|
|
185
|
+
return {
|
|
186
|
+
state: tailPath.state,
|
|
187
|
+
steps: headPath.steps.concat(tailPath.steps.slice(1)),
|
|
188
|
+
weight: headPath.weight + tailPath.weight
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
function joinPaths(...args) {
|
|
192
|
+
if (args.length === 2) return joinPathsDataFirst(args[0], args[1]);
|
|
193
|
+
const [tailPath] = args;
|
|
194
|
+
return (headPath) => joinPathsDataFirst(headPath, tailPath);
|
|
195
|
+
}
|
|
196
|
+
// src/graph/adjacency.ts
|
|
197
|
+
const createNullDict$2 = () => {
|
|
198
|
+
const dict = {};
|
|
199
|
+
Object.setPrototypeOf(dict, null);
|
|
200
|
+
return dict;
|
|
201
|
+
};
|
|
202
|
+
function resolveTransitionSnapshot(result) {
|
|
203
|
+
return Array.isArray(result) ? result[0] : result;
|
|
204
|
+
}
|
|
205
|
+
const initialSnapshotOf$3 = (logic, input, actorScope) => logic.getInitialSnapshot(actorScope, input);
|
|
206
|
+
function actorScopeOf$1(scope) {
|
|
207
|
+
return scope;
|
|
208
|
+
}
|
|
209
|
+
const isVisited = (adj, serialized) => adj[serialized] !== void 0;
|
|
210
|
+
const stopsAt = (traversal, state) => {
|
|
211
|
+
const { stopWhen } = traversal.config;
|
|
212
|
+
return stopWhen === void 0 ? false : stopWhen(state);
|
|
213
|
+
};
|
|
214
|
+
const countIteration = (traversal) => {
|
|
215
|
+
const exceeded = traversal.iterations > traversal.config.limit;
|
|
216
|
+
traversal.iterations += 1;
|
|
217
|
+
if (exceeded) throw new Error("Traversal limit exceeded");
|
|
218
|
+
};
|
|
219
|
+
const registerQueued = (adj, queued, traversal) => {
|
|
220
|
+
countIteration(traversal);
|
|
221
|
+
const { nextState, event, prevState } = queued;
|
|
222
|
+
const serialized = toSerializedSnapshot(traversal.config.serializeState(nextState, event, prevState));
|
|
223
|
+
if (isVisited(adj, serialized)) return;
|
|
224
|
+
return storeValue(adj, serialized, nextState, traversal);
|
|
225
|
+
};
|
|
226
|
+
const storeValue = (adj, serialized, state, traversal) => {
|
|
227
|
+
const value = {
|
|
228
|
+
state,
|
|
229
|
+
transitions: createNullDict$2()
|
|
230
|
+
};
|
|
231
|
+
adj[serialized] = value;
|
|
232
|
+
return stopsAt(traversal, state) ? void 0 : value;
|
|
233
|
+
};
|
|
234
|
+
const eventsFor = (traversal, state) => {
|
|
235
|
+
const { events } = traversal.config;
|
|
236
|
+
return typeof events === "function" ? events(state) : events;
|
|
237
|
+
};
|
|
238
|
+
const passesFilter = (traversal, state, event) => {
|
|
239
|
+
const { filterEvents } = traversal.config;
|
|
240
|
+
return filterEvents === void 0 ? true : filterEvents(state, event);
|
|
241
|
+
};
|
|
242
|
+
const recordTransition = (value, queue, queued, event, traversal) => {
|
|
243
|
+
const nextState = resolveTransitionSnapshot(traversal.logic.transition(queued.nextState, event, actorScopeOf$1(traversal.actorScope)));
|
|
244
|
+
value.transitions[toSerializedEvent(traversal.config.serializeEvent(event))] = {
|
|
245
|
+
event,
|
|
246
|
+
state: nextState
|
|
247
|
+
};
|
|
248
|
+
queue.push({
|
|
249
|
+
nextState,
|
|
250
|
+
event,
|
|
251
|
+
prevState: queued.nextState
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
const enqueueTransitions = (value, queue, queued, traversal) => {
|
|
255
|
+
for (const event of eventsFor(traversal, queued.nextState)) enqueueFiltered(value, queue, queued, event, traversal);
|
|
256
|
+
};
|
|
257
|
+
const enqueueFiltered = (value, queue, queued, event, traversal) => {
|
|
258
|
+
if (passesFilter(traversal, queued.nextState, event)) recordTransition(value, queue, queued, event, traversal);
|
|
259
|
+
};
|
|
260
|
+
const expand = (adj, queue, queued, traversal) => {
|
|
261
|
+
const value = registerQueued(adj, queued, traversal);
|
|
262
|
+
if (value === void 0) return;
|
|
263
|
+
enqueueTransitions(value, queue, queued, traversal);
|
|
264
|
+
};
|
|
265
|
+
const expandLevel = (adj, level, traversal) => {
|
|
266
|
+
const nextLevel = [];
|
|
267
|
+
for (const queued of level) expand(adj, nextLevel, queued, traversal);
|
|
268
|
+
return nextLevel;
|
|
269
|
+
};
|
|
270
|
+
const drain = (adj, start, traversal) => {
|
|
271
|
+
let level = [start];
|
|
272
|
+
while (level.length !== 0) level = expandLevel(adj, level, traversal);
|
|
273
|
+
};
|
|
274
|
+
function computeAdjacencyMap(logic, options) {
|
|
275
|
+
"use strict";
|
|
276
|
+
const config = resolveTraversalOptions({
|
|
277
|
+
logic,
|
|
278
|
+
options
|
|
279
|
+
});
|
|
280
|
+
const actorScope = createMockActorScope();
|
|
281
|
+
const traversal = {
|
|
282
|
+
config,
|
|
283
|
+
logic,
|
|
284
|
+
actorScope,
|
|
285
|
+
iterations: 0
|
|
286
|
+
};
|
|
287
|
+
const fromState = config.fromState ?? initialSnapshotOf$3(logic, options.input, actorScope);
|
|
288
|
+
const adj = createNullDict$2();
|
|
289
|
+
drain(adj, {
|
|
290
|
+
nextState: fromState,
|
|
291
|
+
event: void 0,
|
|
292
|
+
prevState: void 0
|
|
293
|
+
}, traversal);
|
|
294
|
+
return adj;
|
|
295
|
+
}
|
|
296
|
+
function getAdjacencyMap(...args) {
|
|
297
|
+
if (args.length === 1) {
|
|
298
|
+
const [options] = args;
|
|
299
|
+
return (logic) => computeAdjacencyMap(logic, options);
|
|
300
|
+
}
|
|
301
|
+
return computeAdjacencyMap(args[0], args[1]);
|
|
302
|
+
}
|
|
303
|
+
/** @public */
|
|
304
|
+
function adjacencyMapToArray(adjMap) {
|
|
305
|
+
return Object.values({ ...adjMap }).flatMap((adjValue) => adjacencyRow(adjValue));
|
|
306
|
+
}
|
|
307
|
+
const adjacencyRow = (adjValue) => Object.values({ ...adjValue.transitions }).map((transition) => ({
|
|
308
|
+
state: adjValue.state,
|
|
309
|
+
event: transition.event,
|
|
310
|
+
nextState: transition.state
|
|
311
|
+
}));
|
|
312
|
+
// src/graph/alterPath.ts
|
|
313
|
+
const initStepOf = (state) => ({
|
|
314
|
+
state,
|
|
315
|
+
event: { type: XSTATE_INIT }
|
|
316
|
+
});
|
|
317
|
+
const previousStepOf = (steps, index) => steps[index - 1];
|
|
318
|
+
const eventForStep = (steps, index) => {
|
|
319
|
+
const previous = previousStepOf(steps, index);
|
|
320
|
+
return previous === void 0 ? { type: XSTATE_INIT } : previous.event;
|
|
321
|
+
};
|
|
322
|
+
const replaySteps = (path) => path.steps.flatMap((step, index) => [{
|
|
323
|
+
state: step.state,
|
|
324
|
+
event: eventForStep(path.steps, index)
|
|
325
|
+
}]);
|
|
326
|
+
const finalStepOf = (path) => {
|
|
327
|
+
const last = path.steps[path.steps.length - 1];
|
|
328
|
+
return last === void 0 ? void 0 : {
|
|
329
|
+
state: path.state,
|
|
330
|
+
event: last.event
|
|
331
|
+
};
|
|
332
|
+
};
|
|
333
|
+
const appendedSteps = (path) => {
|
|
334
|
+
const steps = replaySteps(path);
|
|
335
|
+
const finalStep = finalStepOf(path);
|
|
336
|
+
steps.push(finalStep === void 0 ? initStepOf(path.state) : finalStep);
|
|
337
|
+
return steps;
|
|
338
|
+
};
|
|
339
|
+
function alterPath(path) {
|
|
340
|
+
return {
|
|
341
|
+
...path,
|
|
342
|
+
steps: appendedSteps(path)
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
// src/graph/pathFromEvents.ts
|
|
346
|
+
const inputOf$2 = (options) => options === void 0 ? void 0 : options.input;
|
|
347
|
+
const initialSnapshotOf$2 = (logic, input, actorScope) => logic.getInitialSnapshot(actorScope, input);
|
|
348
|
+
function actorScopeOf(scope) {
|
|
349
|
+
return scope;
|
|
350
|
+
}
|
|
351
|
+
const passesFilterEvents = (filterEvents, state, event) => filterEvents === void 0 ? true : filterEvents(state, event);
|
|
352
|
+
const matchesCandidate = (filterEvents, serializeEvent, state, candidate, eventSerial) => passesFilterEvents(filterEvents, state, candidate) && serializeEvent(candidate) === eventSerial;
|
|
353
|
+
const lastMatchingCandidate = (candidates, filterEvents, serializeEvent, state, eventSerial) => [...candidates].reverse().find((candidate) => matchesCandidate(filterEvents, serializeEvent, state, candidate, eventSerial));
|
|
354
|
+
const eventsFrom = (events, state) => typeof events === "function" ? events(state) : events;
|
|
355
|
+
const overrideEvents = (options, state) => options === void 0 ? void 0 : eventsFrom(options.events, state);
|
|
356
|
+
const replayEvent = (filterEvents, state, event) => passesFilterEvents(filterEvents, state, event) ? event : void 0;
|
|
357
|
+
const nextEventFor = (context, state, event, eventSerial) => {
|
|
358
|
+
const override = overrideEvents(context.options, state);
|
|
359
|
+
if (override !== void 0) return lastMatchingCandidate(override, context.config.filterEvents, context.config.serializeEvent, state, eventSerial);
|
|
360
|
+
return replayEvent(context.config.filterEvents, state, event);
|
|
361
|
+
};
|
|
362
|
+
const assertWithinLimit = (stepCount, limit) => {
|
|
363
|
+
if (stepCount >= limit) throw new Error("Traversal limit exceeded");
|
|
364
|
+
};
|
|
365
|
+
const stopsBefore = (stopWhen, state) => stopWhen === void 0 ? false : stopWhen(state);
|
|
366
|
+
const isReplayable = (nextEvent, stopWhen, state) => nextEvent !== void 0 && !stopsBefore(stopWhen, state);
|
|
367
|
+
const invalidTransition = (stateSerial, eventSerial) => /* @__PURE__ */ new Error(`Invalid transition from ${stateSerial} with ${eventSerial}`);
|
|
368
|
+
const assertReplayable = (nextEvent, stopWhen, state, stateSerial, eventSerial) => {
|
|
369
|
+
if (isReplayable(nextEvent, stopWhen, state)) return nextEvent;
|
|
370
|
+
throw invalidTransition(stateSerial, eventSerial);
|
|
371
|
+
};
|
|
372
|
+
const advanceState = (context, replay, nextEvent, event) => {
|
|
373
|
+
const result = context.logic.transition(replay.state, nextEvent, actorScopeOf(context.actorScope));
|
|
374
|
+
const nextState = Array.isArray(result) ? result[0] : result;
|
|
375
|
+
return {
|
|
376
|
+
state: nextState,
|
|
377
|
+
stateSerial: toSerializedSnapshot(context.config.serializeState(nextState, event, replay.state))
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
const replayOne = (context, replay, event) => {
|
|
381
|
+
assertWithinLimit(context.steps.length, context.config.limit);
|
|
382
|
+
const eventSerial = toSerializedEvent(context.config.serializeEvent(event));
|
|
383
|
+
const nextEvent = assertReplayable(nextEventFor(context, replay.state, event, eventSerial), context.config.stopWhen, replay.state, replay.stateSerial, eventSerial);
|
|
384
|
+
context.steps.push({
|
|
385
|
+
state: replay.state,
|
|
386
|
+
event
|
|
387
|
+
});
|
|
388
|
+
return advanceState(context, replay, nextEvent, event);
|
|
389
|
+
};
|
|
390
|
+
const initialReplay = (config, logic, options, actorScope) => {
|
|
391
|
+
const state = config.fromState ?? initialSnapshotOf$2(logic, inputOf$2(options), actorScope);
|
|
392
|
+
return {
|
|
393
|
+
state,
|
|
394
|
+
stateSerial: toSerializedSnapshot(config.serializeState(state, void 0, void 0))
|
|
395
|
+
};
|
|
396
|
+
};
|
|
397
|
+
const reachesTarget = (toState, state) => toState === void 0 ? true : toState(state);
|
|
398
|
+
const buildPaths = (context, replay) => {
|
|
399
|
+
if (!reachesTarget(context.config.toState, replay.state)) return [];
|
|
400
|
+
return [alterPath({
|
|
401
|
+
state: replay.state,
|
|
402
|
+
steps: context.steps,
|
|
403
|
+
weight: context.steps.length
|
|
404
|
+
})];
|
|
405
|
+
};
|
|
406
|
+
function computePathsFromEvents(logic, events, options) {
|
|
407
|
+
const config = resolveTraversalOptions({
|
|
408
|
+
logic,
|
|
409
|
+
options: {
|
|
410
|
+
events,
|
|
411
|
+
...options
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
const actorScope = createMockActorScope();
|
|
415
|
+
const context = {
|
|
416
|
+
config,
|
|
417
|
+
options,
|
|
418
|
+
logic,
|
|
419
|
+
actorScope,
|
|
420
|
+
steps: []
|
|
421
|
+
};
|
|
422
|
+
let replay = initialReplay(config, logic, options, actorScope);
|
|
423
|
+
for (const event of events) replay = replayOne(context, replay, event);
|
|
424
|
+
return buildPaths(context, replay);
|
|
425
|
+
}
|
|
426
|
+
const isDataLastReplay = (args) => Array.isArray(args[0]);
|
|
427
|
+
function getPathsFromEvents(...args) {
|
|
428
|
+
return isDataLastReplay(args) ? (logic) => computePathsFromEvents(logic, args[0], args[1]) : computePathsFromEvents(args[0], args[1], args[2]);
|
|
429
|
+
}
|
|
430
|
+
// src/graph/shortestPaths.ts
|
|
431
|
+
const createNullDict$1 = () => {
|
|
432
|
+
const dict = {};
|
|
433
|
+
Object.setPrototypeOf(dict, null);
|
|
434
|
+
return dict;
|
|
435
|
+
};
|
|
436
|
+
const inputOf$1 = (options) => options === void 0 ? void 0 : options.input;
|
|
437
|
+
const initialSnapshotOf$1 = (logic, input, actorScope) => logic.getInitialSnapshot(actorScope, input);
|
|
438
|
+
const discover = (context, nextSerialized, entry) => {
|
|
439
|
+
if (!context.visited.has(nextSerialized)) context.unvisited.set(nextSerialized, entry);
|
|
440
|
+
};
|
|
441
|
+
const recordReach = (context, nextSerialized, weight, origin, snapshot, event) => {
|
|
442
|
+
const existing = context.weightMap.get(nextSerialized);
|
|
443
|
+
const entry = existing === void 0 ? {
|
|
444
|
+
weight,
|
|
445
|
+
snapshot,
|
|
446
|
+
origin,
|
|
447
|
+
event
|
|
448
|
+
} : {
|
|
449
|
+
...existing,
|
|
450
|
+
snapshot
|
|
451
|
+
};
|
|
452
|
+
context.weightMap.set(nextSerialized, entry);
|
|
453
|
+
discover(context, nextSerialized, entry);
|
|
454
|
+
};
|
|
455
|
+
const relaxTransition = (context, fromSerialized, fromSnapshot, weight, transitions, serializedEvent) => {
|
|
456
|
+
const transition = transitions[serializedEvent];
|
|
457
|
+
if (transition === void 0) return;
|
|
458
|
+
const nextSerialized = toSerializedSnapshot(context.serializeState(transition.state, transition.event, fromSnapshot));
|
|
459
|
+
recordReach(context, nextSerialized, weight + 1, fromSerialized, transition.state, transition.event);
|
|
460
|
+
};
|
|
461
|
+
const relaxTransitions = (context, fromSerialized, fromSnapshot, weight, adjacencyValue) => {
|
|
462
|
+
for (const serializedEvent of Object.keys(adjacencyValue.transitions).map(toSerializedEvent)) relaxTransition(context, fromSerialized, fromSnapshot, weight, adjacencyValue.transitions, serializedEvent);
|
|
463
|
+
};
|
|
464
|
+
const relaxState = (context, fromSerialized, entry) => {
|
|
465
|
+
const adjacencyValue = context.adjacency[fromSerialized];
|
|
466
|
+
if (adjacencyValue === void 0) return;
|
|
467
|
+
relaxTransitions(context, fromSerialized, entry.snapshot, entry.weight, adjacencyValue);
|
|
468
|
+
context.visited.add(fromSerialized);
|
|
469
|
+
context.unvisited.delete(fromSerialized);
|
|
470
|
+
};
|
|
471
|
+
const runTraversal = (context) => {
|
|
472
|
+
for (const [fromSerialized, entry] of context.unvisited) relaxState(context, fromSerialized, entry);
|
|
473
|
+
};
|
|
474
|
+
const firstPlanPath = (statePlanMap, fromSerialized) => {
|
|
475
|
+
const plan = statePlanMap[fromSerialized];
|
|
476
|
+
return plan === void 0 ? void 0 : plan.paths[0];
|
|
477
|
+
};
|
|
478
|
+
const stepTo = (fromState, event) => event === void 0 ? [] : [{
|
|
479
|
+
state: fromState,
|
|
480
|
+
event
|
|
481
|
+
}];
|
|
482
|
+
const stepsToward = (statePlanMap, fromSerialized, event) => {
|
|
483
|
+
const path = firstPlanPath(statePlanMap, fromSerialized);
|
|
484
|
+
return path === void 0 ? [] : path.steps.concat(stepTo(path.state, event));
|
|
485
|
+
};
|
|
486
|
+
const predecessorSteps = (statePlanMap, entry) => {
|
|
487
|
+
const origin = entry.origin;
|
|
488
|
+
return origin === void 0 ? [] : stepsToward(statePlanMap, origin, entry.event);
|
|
489
|
+
};
|
|
490
|
+
const buildPath = (statePlanMap, entry, stateSerial) => {
|
|
491
|
+
const state = entry.snapshot;
|
|
492
|
+
const steps = predecessorSteps(statePlanMap, entry);
|
|
493
|
+
statePlanMap[stateSerial] = {
|
|
494
|
+
state,
|
|
495
|
+
paths: [{
|
|
496
|
+
state,
|
|
497
|
+
steps,
|
|
498
|
+
weight: entry.weight
|
|
499
|
+
}]
|
|
500
|
+
};
|
|
501
|
+
return {
|
|
502
|
+
state,
|
|
503
|
+
steps,
|
|
504
|
+
weight: entry.weight
|
|
505
|
+
};
|
|
506
|
+
};
|
|
507
|
+
const collectPaths = (weightMap) => {
|
|
508
|
+
const statePlanMap = createNullDict$1();
|
|
509
|
+
const paths = [];
|
|
510
|
+
weightMap.forEach((entry, stateSerial) => {
|
|
511
|
+
paths.push(buildPath(statePlanMap, entry, stateSerial));
|
|
512
|
+
});
|
|
513
|
+
return paths;
|
|
514
|
+
};
|
|
515
|
+
const applyTarget$1 = (paths, toState) => {
|
|
516
|
+
const target = toState;
|
|
517
|
+
if (target === void 0) return paths.map(alterPath);
|
|
518
|
+
return paths.filter((path) => target(path.state)).map(alterPath);
|
|
519
|
+
};
|
|
520
|
+
const seed$1 = (context, fromState) => {
|
|
521
|
+
const serialized = toSerializedSnapshot(context.serializeState(fromState, void 0, void 0));
|
|
522
|
+
const entry = {
|
|
523
|
+
weight: 0,
|
|
524
|
+
snapshot: fromState,
|
|
525
|
+
origin: void 0,
|
|
526
|
+
event: void 0
|
|
527
|
+
};
|
|
528
|
+
context.weightMap.set(serialized, entry);
|
|
529
|
+
context.unvisited.set(serialized, entry);
|
|
530
|
+
};
|
|
531
|
+
function computeShortestPaths(logic, options) {
|
|
532
|
+
const resolvedOptions = resolveTraversalOptions({
|
|
533
|
+
logic,
|
|
534
|
+
options
|
|
535
|
+
});
|
|
536
|
+
const fromState = resolvedOptions.fromState ?? initialSnapshotOf$1(logic, inputOf$1(options), createMockActorScope());
|
|
537
|
+
const context = {
|
|
538
|
+
adjacency: getAdjacencyMap(logic, {
|
|
539
|
+
...resolvedOptions,
|
|
540
|
+
fromState
|
|
541
|
+
}),
|
|
542
|
+
serializeState: resolvedOptions.serializeState,
|
|
543
|
+
weightMap: /* @__PURE__ */ new Map(),
|
|
544
|
+
visited: /* @__PURE__ */ new Set(),
|
|
545
|
+
unvisited: /* @__PURE__ */ new Map()
|
|
546
|
+
};
|
|
547
|
+
seed$1(context, fromState);
|
|
548
|
+
runTraversal(context);
|
|
549
|
+
return applyTarget$1(collectPaths(context.weightMap), resolvedOptions.toState);
|
|
550
|
+
}
|
|
551
|
+
function getShortestPaths(...args) {
|
|
552
|
+
const [first, second] = args;
|
|
553
|
+
return logicFirstOrLast(computeShortestPaths)(first, second);
|
|
554
|
+
}
|
|
555
|
+
// src/graph/simplePaths.ts
|
|
556
|
+
const createNullDict = () => {
|
|
557
|
+
const dict = {};
|
|
558
|
+
Object.setPrototypeOf(dict, null);
|
|
559
|
+
return dict;
|
|
560
|
+
};
|
|
561
|
+
const inputOf = (options) => options === void 0 ? void 0 : options.input;
|
|
562
|
+
const initialSnapshotOf = (logic, input, actorScope) => logic.getInitialSnapshot(actorScope, input);
|
|
563
|
+
const boxFor = (context, serialized, snapshot) => {
|
|
564
|
+
const existing = context.stateMap.get(serialized);
|
|
565
|
+
const box = existing === void 0 ? { snapshot } : existing;
|
|
566
|
+
box.snapshot = snapshot;
|
|
567
|
+
context.stateMap.set(serialized, box);
|
|
568
|
+
return box;
|
|
569
|
+
};
|
|
570
|
+
const createPlan = (pathMap, serialized, state) => {
|
|
571
|
+
const plan = {
|
|
572
|
+
state,
|
|
573
|
+
paths: []
|
|
574
|
+
};
|
|
575
|
+
pathMap[serialized] = plan;
|
|
576
|
+
return plan;
|
|
577
|
+
};
|
|
578
|
+
const planAt = (pathMap, serialized, state) => {
|
|
579
|
+
const existing = pathMap[serialized];
|
|
580
|
+
return existing === void 0 ? createPlan(pathMap, serialized, state) : existing;
|
|
581
|
+
};
|
|
582
|
+
const recordPath = (context, toSerialized, fromState) => {
|
|
583
|
+
planAt(context.pathMap, toSerialized, fromState).paths.push({
|
|
584
|
+
state: fromState,
|
|
585
|
+
weight: context.steps.length,
|
|
586
|
+
steps: [...context.steps]
|
|
587
|
+
});
|
|
588
|
+
};
|
|
589
|
+
function expandInto(context, box, toSerialized, serializedEvent, event, nextSerialized, nextBox) {
|
|
590
|
+
context.visitCtx.edges.add(serializedEvent);
|
|
591
|
+
context.steps.push({
|
|
592
|
+
state: box.snapshot,
|
|
593
|
+
event
|
|
594
|
+
});
|
|
595
|
+
visit(context, nextSerialized, nextBox, toSerialized);
|
|
596
|
+
}
|
|
597
|
+
const descendInto = (context, box, toSerialized, serializedEvent, transition) => {
|
|
598
|
+
const nextSerialized = toSerializedSnapshot(context.serializeState(transition.state, transition.event, box.snapshot));
|
|
599
|
+
const nextBox = boxFor(context, nextSerialized, transition.state);
|
|
600
|
+
if (!context.visitCtx.vertices.has(nextSerialized)) expandInto(context, box, toSerialized, serializedEvent, transition.event, nextSerialized, nextBox);
|
|
601
|
+
};
|
|
602
|
+
const descendTransition = (context, box, toSerialized, transitions, serializedEvent) => {
|
|
603
|
+
const transition = transitions[serializedEvent];
|
|
604
|
+
if (transition === void 0) return;
|
|
605
|
+
descendInto(context, box, toSerialized, serializedEvent, transition);
|
|
606
|
+
};
|
|
607
|
+
const descendTransitions = (context, box, toSerialized, adjacencyValue) => {
|
|
608
|
+
for (const serializedEvent of Object.keys(adjacencyValue.transitions).map(toSerializedEvent)) descendTransition(context, box, toSerialized, adjacencyValue.transitions, serializedEvent);
|
|
609
|
+
};
|
|
610
|
+
const descend = (context, fromSerialized, box, toSerialized) => {
|
|
611
|
+
const adjacencyValue = context.adjacency[fromSerialized];
|
|
612
|
+
if (adjacencyValue === void 0) return;
|
|
613
|
+
descendTransitions(context, box, toSerialized, adjacencyValue);
|
|
614
|
+
};
|
|
615
|
+
function visit(context, fromSerialized, box, toSerialized) {
|
|
616
|
+
context.visitCtx.vertices.add(fromSerialized);
|
|
617
|
+
if (fromSerialized === toSerialized) recordPath(context, toSerialized, box.snapshot);
|
|
618
|
+
else descend(context, fromSerialized, box, toSerialized);
|
|
619
|
+
context.steps.pop();
|
|
620
|
+
context.visitCtx.vertices.delete(fromSerialized);
|
|
621
|
+
}
|
|
622
|
+
const seed = (context, fromState) => {
|
|
623
|
+
const serialized = toSerializedSnapshot(context.serializeState(fromState, void 0));
|
|
624
|
+
return {
|
|
625
|
+
serialized,
|
|
626
|
+
box: boxFor(context, serialized, fromState)
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
const visitEachStart = (context, fromSerialized, box) => {
|
|
630
|
+
for (const nextSerialized of Object.keys(context.adjacency).map(toSerializedSnapshot)) visit(context, fromSerialized, box, nextSerialized);
|
|
631
|
+
};
|
|
632
|
+
const applyTarget = (paths, toState) => {
|
|
633
|
+
const target = toState;
|
|
634
|
+
if (target === void 0) return paths.map(alterPath);
|
|
635
|
+
return paths.filter((path) => target(path.state)).map(alterPath);
|
|
636
|
+
};
|
|
637
|
+
function computeSimplePaths(logic, options) {
|
|
638
|
+
const resolvedOptions = resolveTraversalOptions({
|
|
639
|
+
logic,
|
|
640
|
+
options
|
|
641
|
+
});
|
|
642
|
+
const actorScope = createMockActorScope();
|
|
643
|
+
const fromState = resolvedOptions.fromState ?? initialSnapshotOf(logic, inputOf(options), actorScope);
|
|
644
|
+
const context = {
|
|
645
|
+
adjacency: getAdjacencyMap(logic, {
|
|
646
|
+
...resolvedOptions,
|
|
647
|
+
fromState
|
|
648
|
+
}),
|
|
649
|
+
serializeState: resolvedOptions.serializeState,
|
|
650
|
+
stateMap: /* @__PURE__ */ new Map(),
|
|
651
|
+
visitCtx: {
|
|
652
|
+
vertices: /* @__PURE__ */ new Set(),
|
|
653
|
+
edges: /* @__PURE__ */ new Set()
|
|
654
|
+
},
|
|
655
|
+
steps: [],
|
|
656
|
+
pathMap: createNullDict()
|
|
657
|
+
};
|
|
658
|
+
const { serialized: fromSerialized, box } = seed(context, fromState);
|
|
659
|
+
visitEachStart(context, fromSerialized, box);
|
|
660
|
+
const simplePaths = Object.values(context.pathMap).flatMap((plan) => plan.paths);
|
|
661
|
+
return applyTarget(simplePaths, resolvedOptions.toState);
|
|
662
|
+
}
|
|
663
|
+
function getSimplePaths(...args) {
|
|
664
|
+
const [first, second] = args;
|
|
665
|
+
return logicFirstOrLast(computeSimplePaths)(first, second);
|
|
666
|
+
}
|
|
667
|
+
export { adjacencyMapToArray, getAdjacencyMap, getDescendantStateNodes, getPathsFromEvents, getShortestPaths, getSimplePaths, joinPaths, serializeSnapshot, toDirectedGraph };
|