xstate 6.0.0-alpha.70 → 6.0.0-alpha.72
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/README.md +28 -0
- package/bin/agent.js +347 -0
- package/bin/xstate.js +16 -0
- package/dist/{createActor-11e36865.development.cjs.js → createActor-2136a8ad.development.cjs.js} +528 -461
- package/dist/{createActor-eaa95ae0.esm.js → createActor-22a0534b.esm.js} +528 -456
- package/dist/{createActor-9529bbaf.development.esm.js → createActor-286a0dbb.development.esm.js} +528 -462
- package/dist/{createActor-54296cf2.cjs.js → createActor-f4978450.cjs.js} +528 -455
- package/dist/declarations/src/StateMachine.d.ts +5 -3
- package/dist/declarations/src/base.types.d.ts +20 -20
- package/dist/declarations/src/durable/index.d.ts +16 -7
- package/dist/declarations/src/graph/types.d.ts +22 -1
- package/dist/declarations/src/index.d.ts +2 -2
- package/dist/declarations/src/serialize.d.ts +14 -0
- package/dist/declarations/src/setup.d.ts +3 -1
- package/dist/declarations/src/system.d.ts +14 -1
- package/dist/declarations/src/types.d.ts +5 -2
- package/dist/{effectDescriptor-97802bb8.esm.js → effectDescriptor-2ae7e5e3.esm.js} +1 -1
- package/dist/{effectDescriptor-df768c71.development.esm.js → effectDescriptor-86f04325.development.esm.js} +1 -1
- package/dist/{effectDescriptor-425644eb.cjs.js → effectDescriptor-a6247f92.cjs.js} +1 -1
- package/dist/{effectDescriptor-fd2aaf45.development.cjs.js → effectDescriptor-e41e1627.development.cjs.js} +1 -1
- package/dist/{index-9826ee1d.development.cjs.js → index-31b3c878.cjs.js} +3 -3
- package/dist/{index-986372f2.cjs.js → index-5ce9cbf9.development.cjs.js} +3 -3
- package/dist/{index-e30fe161.development.esm.js → index-6923de25.development.esm.js} +3 -3
- package/dist/{index-967ad7fa.esm.js → index-74b77771.esm.js} +3 -3
- package/dist/xstate-actors.cjs.js +2 -2
- package/dist/xstate-actors.development.cjs.js +2 -2
- package/dist/xstate-actors.development.esm.js +2 -2
- package/dist/xstate-actors.esm.js +2 -2
- package/dist/xstate-actors.umd.min.js +1 -1
- package/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/xstate-durable.cjs.js +11 -14
- package/dist/xstate-durable.development.cjs.js +11 -14
- package/dist/xstate-durable.development.esm.js +11 -14
- package/dist/xstate-durable.esm.js +11 -14
- package/dist/xstate-durable.umd.min.js +1 -1
- package/dist/xstate-durable.umd.min.js.map +1 -1
- package/dist/xstate-graph.cjs.js +32 -6
- package/dist/xstate-graph.development.cjs.js +32 -6
- package/dist/xstate-graph.development.esm.js +33 -7
- package/dist/xstate-graph.esm.js +33 -7
- package/dist/xstate-graph.umd.min.js +1 -1
- package/dist/xstate-graph.umd.min.js.map +1 -1
- package/dist/xstate-validation.cjs.js +1 -1
- package/dist/xstate-validation.development.cjs.js +1 -1
- package/dist/xstate-validation.development.esm.js +1 -1
- package/dist/xstate-validation.esm.js +1 -1
- package/dist/xstate.cjs.js +161 -49
- package/dist/xstate.cjs.mjs +1 -0
- package/dist/xstate.development.cjs.js +161 -49
- package/dist/xstate.development.cjs.mjs +1 -0
- package/dist/xstate.development.esm.js +163 -52
- package/dist/xstate.esm.js +163 -52
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/docs/agents.md +132 -0
- package/docs/api-stability.json +3672 -0
- package/docs/context.md +4 -0
- package/docs/create-actor.md +3 -2
- package/docs/durable-execution.md +10 -2
- package/docs/emitted-events.md +20 -1
- package/docs/index.md +4 -2
- package/docs/model-based-testing.md +3 -1
- package/docs/persist-and-restore-actors.md +1 -1
- package/docs/persistence.md +2 -2
- package/docs/scxml.md +32 -0
- package/docs/serialization.md +3 -0
- package/docs/systems.md +33 -1
- package/docs/transition-functions.md +3 -1
- package/docs/transitions.md +4 -2
- package/docs/xstate-v5-to-v6.md +16 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,11 @@ Before writing code with an installed package, read `docs/index.md` beside this
|
|
|
8
8
|
README, usually `node_modules/xstate/docs/index.md`. These bundled docs match the
|
|
9
9
|
installed package version.
|
|
10
10
|
|
|
11
|
+
For coding agents, start with `docs/agents.md`. Run `npx xstate docs` to locate
|
|
12
|
+
the installed documentation and read its machine-readable stability manifest.
|
|
13
|
+
The data-only CLI also supports `inspect`, `validate`, `simulate`, `test`,
|
|
14
|
+
`replay` and `diff`; see the agent guide for their contracts and limits.
|
|
15
|
+
|
|
11
16
|
Online, start with the [quick start](https://github.com/statelyai/xstate/blob/next/docs/quick-start.md)
|
|
12
17
|
or the [v5 to v6 migration guide](https://github.com/statelyai/xstate/blob/next/docs/xstate-v5-to-v6.md).
|
|
13
18
|
|
|
@@ -87,6 +92,29 @@ XState is a state management and orchestration solution for JavaScript and TypeS
|
|
|
87
92
|
|
|
88
93
|
It uses event-driven programming, state machines, statecharts, and the actor model to handle complex logic in predictable, robust, and visual ways. XState provides a powerful and flexible way to manage application and workflow state by allowing developers to model logic as actors and state machines.
|
|
89
94
|
|
|
95
|
+
<!-- system-wide emission observation from packages/core/src/setup.ts and packages/core/src/system.ts -->
|
|
96
|
+
|
|
97
|
+
Observe emitted events from root and child actors with `createSystem({ onEmitted })`:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { createMachine, createSystem } from 'xstate';
|
|
101
|
+
|
|
102
|
+
const machine = createMachine({
|
|
103
|
+
entry: (_, enq) => enq.emit({ type: 'started' })
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const system = createSystem({
|
|
107
|
+
onEmitted: ({ actorRef, event }) => {
|
|
108
|
+
console.log(actorRef.id, event);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const root = system.createActor(machine).start();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Use `system.onEmitted(listener)` for a removable subscription. `actor.on(...)`
|
|
116
|
+
observes only that actor. See [actor systems](https://github.com/statelyai/xstate/blob/next/docs/systems.md#observe-emitted-events-across-a-system).
|
|
117
|
+
|
|
90
118
|
<!-- experimental whole-system transitions from packages/core/src/systemTransition.ts -->
|
|
91
119
|
|
|
92
120
|
For pure actor-system simulation, `initialSystemTransition`, `systemTransition`
|
package/bin/agent.js
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
// Data-only agent operations. No application module loading, code evaluation or effect
|
|
2
|
+
// execution is needed to inspect and explore a JSON machine definition.
|
|
3
|
+
const { readFileSync } = require('node:fs');
|
|
4
|
+
const { join } = require('node:path');
|
|
5
|
+
const { createHash } = require('node:crypto');
|
|
6
|
+
const core = require('../dist/xstate.cjs.js');
|
|
7
|
+
const graph = require('../dist/xstate-graph.cjs.js');
|
|
8
|
+
const { version } = require('../package.json');
|
|
9
|
+
|
|
10
|
+
function fail(code, message, details) {
|
|
11
|
+
const error = new Error(message);
|
|
12
|
+
error.code = code;
|
|
13
|
+
error.details = details;
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readJSON(file) {
|
|
18
|
+
if (!file) fail('MISSING_ARGUMENT', 'Expected a JSON file path.');
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(readFileSync(file, 'utf8'));
|
|
21
|
+
} catch (error) {
|
|
22
|
+
fail('INVALID_JSON', `Cannot read JSON from ${file}: ${error.message}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function expressions(value, path = '') {
|
|
27
|
+
if (!value || typeof value !== 'object') return [];
|
|
28
|
+
if (Object.hasOwn(value, '@code')) return [path];
|
|
29
|
+
return Object.entries(value).flatMap(([key, entry]) =>
|
|
30
|
+
expressions(
|
|
31
|
+
entry,
|
|
32
|
+
`${path}/${key.replaceAll('~', '~0').replaceAll('/', '~1')}`
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function loadMachine(file) {
|
|
38
|
+
const definition = readJSON(file);
|
|
39
|
+
if (
|
|
40
|
+
!definition ||
|
|
41
|
+
typeof definition !== 'object' ||
|
|
42
|
+
Array.isArray(definition)
|
|
43
|
+
) {
|
|
44
|
+
fail('INVALID_MACHINE', 'Expected a machine definition object.');
|
|
45
|
+
}
|
|
46
|
+
const paths = expressions(definition);
|
|
47
|
+
if (paths.length) {
|
|
48
|
+
fail(
|
|
49
|
+
'EVALUATOR_REQUIRED',
|
|
50
|
+
'The data-only CLI does not evaluate code expressions. Use the library with explicit runtime sources.',
|
|
51
|
+
{ paths }
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
return {
|
|
56
|
+
definition,
|
|
57
|
+
machine: core.machineFromJSON(definition),
|
|
58
|
+
hash: createHash('sha256')
|
|
59
|
+
.update(JSON.stringify(definition))
|
|
60
|
+
.digest('hex')
|
|
61
|
+
};
|
|
62
|
+
} catch (error) {
|
|
63
|
+
fail('INVALID_MACHINE', error.message);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function view(snapshot) {
|
|
68
|
+
return {
|
|
69
|
+
value: snapshot.value,
|
|
70
|
+
context: snapshot.context,
|
|
71
|
+
stateInputs: snapshot.getInputs(),
|
|
72
|
+
status: snapshot.status,
|
|
73
|
+
output: snapshot.output,
|
|
74
|
+
error:
|
|
75
|
+
snapshot.error instanceof Error
|
|
76
|
+
? { name: snapshot.error.name, message: snapshot.error.message }
|
|
77
|
+
: snapshot.error
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function effectView(effect) {
|
|
82
|
+
return {
|
|
83
|
+
type: effect.type,
|
|
84
|
+
kind: effect.kind,
|
|
85
|
+
params: effect.params,
|
|
86
|
+
event: effect.event
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function eventList(value) {
|
|
91
|
+
const events = Array.isArray(value) ? value : value?.events;
|
|
92
|
+
if (
|
|
93
|
+
!Array.isArray(events) ||
|
|
94
|
+
events.some((event) => !event || typeof event.type !== 'string')
|
|
95
|
+
) {
|
|
96
|
+
fail(
|
|
97
|
+
'INVALID_EVENTS',
|
|
98
|
+
'Expected an array of event objects with string type fields.'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return events;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function replay(machine, events, input) {
|
|
105
|
+
let [snapshot, effects] = core.initialTransition(machine, input);
|
|
106
|
+
const trace = [
|
|
107
|
+
{ event: null, snapshot: view(snapshot), effects: effects.map(effectView) }
|
|
108
|
+
];
|
|
109
|
+
const snapshots = [snapshot];
|
|
110
|
+
for (const event of events) {
|
|
111
|
+
[snapshot, effects] = core.transition(machine, snapshot, event);
|
|
112
|
+
snapshots.push(snapshot);
|
|
113
|
+
trace.push({
|
|
114
|
+
event,
|
|
115
|
+
snapshot: view(snapshot),
|
|
116
|
+
effects: effects.map(effectView)
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return { trace, snapshots };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function assertions(machine, options) {
|
|
123
|
+
const states = new Set([
|
|
124
|
+
machine.root.id,
|
|
125
|
+
...graph.getDescendantStateNodes(machine.root).map((node) => node.id)
|
|
126
|
+
]);
|
|
127
|
+
for (const kind of ['never', 'reachable']) {
|
|
128
|
+
if (options[kind] === undefined) continue;
|
|
129
|
+
if (
|
|
130
|
+
!Array.isArray(options[kind]) ||
|
|
131
|
+
options[kind].some(
|
|
132
|
+
(id) =>
|
|
133
|
+
typeof id !== 'string' ||
|
|
134
|
+
!id.startsWith('#') ||
|
|
135
|
+
!states.has(id.slice(1))
|
|
136
|
+
)
|
|
137
|
+
) {
|
|
138
|
+
fail(
|
|
139
|
+
'INVALID_ASSERTION',
|
|
140
|
+
`${kind} must list existing state IDs prefixed with #.`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function violation(snapshots, never = []) {
|
|
147
|
+
for (const snapshot of snapshots) {
|
|
148
|
+
for (const state of never) {
|
|
149
|
+
if (snapshot.matches(state)) return { state, snapshot: view(snapshot) };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function difference(before, after, path = '') {
|
|
155
|
+
if (JSON.stringify(before) === JSON.stringify(after)) return [];
|
|
156
|
+
if (
|
|
157
|
+
before &&
|
|
158
|
+
after &&
|
|
159
|
+
typeof before === 'object' &&
|
|
160
|
+
typeof after === 'object' &&
|
|
161
|
+
!Array.isArray(before) &&
|
|
162
|
+
!Array.isArray(after)
|
|
163
|
+
) {
|
|
164
|
+
return [...new Set([...Object.keys(before), ...Object.keys(after)])]
|
|
165
|
+
.sort()
|
|
166
|
+
.flatMap((key) => {
|
|
167
|
+
const pointer = `${path}/${key.replaceAll('~', '~0').replaceAll('/', '~1')}`;
|
|
168
|
+
if (!Object.hasOwn(before, key))
|
|
169
|
+
return [{ op: 'add', path: pointer, after: after[key] }];
|
|
170
|
+
if (!Object.hasOwn(after, key))
|
|
171
|
+
return [{ op: 'remove', path: pointer, before: before[key] }];
|
|
172
|
+
return difference(before[key], after[key], pointer);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return [{ op: 'replace', path, before, after }];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function run(command, rawArgs) {
|
|
179
|
+
const args = rawArgs.filter((arg) => arg !== '--json');
|
|
180
|
+
if (command === 'docs') {
|
|
181
|
+
return {
|
|
182
|
+
index: join(__dirname, '../docs/index.md'),
|
|
183
|
+
agentGuide: join(__dirname, '../docs/agents.md'),
|
|
184
|
+
stability: readJSON(join(__dirname, '../docs/api-stability.json'))
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (command === 'diff') {
|
|
188
|
+
const changes = difference(readJSON(args[0]), readJSON(args[1]));
|
|
189
|
+
return {
|
|
190
|
+
changed: changes.length > 0,
|
|
191
|
+
changes,
|
|
192
|
+
compatibility: 'notChecked'
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const { machine, definition, hash } = loadMachine(args[0]);
|
|
196
|
+
if (command === 'validate')
|
|
197
|
+
return {
|
|
198
|
+
valid: true,
|
|
199
|
+
scope: 'definition',
|
|
200
|
+
runtimePayloadValidation: false
|
|
201
|
+
};
|
|
202
|
+
if (command === 'inspect') {
|
|
203
|
+
return {
|
|
204
|
+
definition,
|
|
205
|
+
graph: graph.toDirectedGraph(machine),
|
|
206
|
+
serializationDiagnostics:
|
|
207
|
+
core.getMachineSerializationDiagnostics(machine),
|
|
208
|
+
runtimePayloadValidation: false
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
if (command === 'simulate') {
|
|
212
|
+
const request = readJSON(args[1]);
|
|
213
|
+
return {
|
|
214
|
+
effectsExecuted: false,
|
|
215
|
+
...omitSnapshots(replay(machine, eventList(request), request.input))
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
if (command === 'replay') {
|
|
219
|
+
const fixture = readJSON(args[1]);
|
|
220
|
+
if (
|
|
221
|
+
fixture.schemaVersion !== 1 ||
|
|
222
|
+
fixture.machineHash !== hash ||
|
|
223
|
+
fixture.xstateVersion !== version
|
|
224
|
+
) {
|
|
225
|
+
fail(
|
|
226
|
+
'FIXTURE_MISMATCH',
|
|
227
|
+
'The fixture must match this definition, XState version and fixture format.'
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
assertions(machine, fixture);
|
|
231
|
+
const result = replay(machine, eventList(fixture), fixture.input);
|
|
232
|
+
const failure = violation(result.snapshots, fixture.never);
|
|
233
|
+
if (failure)
|
|
234
|
+
fail('PROPERTY_VIOLATION', 'A forbidden stable state was reached.', {
|
|
235
|
+
...failure,
|
|
236
|
+
trace: result.trace,
|
|
237
|
+
fixture
|
|
238
|
+
});
|
|
239
|
+
return { effectsExecuted: false, trace: result.trace };
|
|
240
|
+
}
|
|
241
|
+
if (command === 'test') {
|
|
242
|
+
const options = readJSON(args[1]);
|
|
243
|
+
assertions(machine, options);
|
|
244
|
+
if (!(options.never?.length || options.reachable?.length)) {
|
|
245
|
+
fail(
|
|
246
|
+
'MISSING_ASSERTION',
|
|
247
|
+
'Supply at least one never or reachable state assertion.'
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
if (
|
|
251
|
+
options.limit !== undefined &&
|
|
252
|
+
(!Number.isSafeInteger(options.limit) || options.limit <= 0)
|
|
253
|
+
) {
|
|
254
|
+
fail('INVALID_LIMIT', 'limit must be a positive safe integer.');
|
|
255
|
+
}
|
|
256
|
+
const paths = graph.getShortestPaths(machine, {
|
|
257
|
+
events: options.events,
|
|
258
|
+
input: options.input,
|
|
259
|
+
limit: options.limit ?? 10000
|
|
260
|
+
});
|
|
261
|
+
const visited = paths.map((path) => path.state);
|
|
262
|
+
const errored = visited.find((snapshot) => snapshot.status === 'error');
|
|
263
|
+
if (errored)
|
|
264
|
+
fail(
|
|
265
|
+
'MODEL_EXECUTION_FAILED',
|
|
266
|
+
'Model exploration entered an error snapshot.',
|
|
267
|
+
{ snapshot: view(errored) }
|
|
268
|
+
);
|
|
269
|
+
for (const path of paths) {
|
|
270
|
+
const failure = violation(
|
|
271
|
+
path.steps.map((step) => step.state),
|
|
272
|
+
options.never
|
|
273
|
+
);
|
|
274
|
+
if (failure) {
|
|
275
|
+
const fixture = {
|
|
276
|
+
schemaVersion: 1,
|
|
277
|
+
xstateVersion: version,
|
|
278
|
+
machineHash: hash,
|
|
279
|
+
events: path.steps.slice(1).map((step) => step.event),
|
|
280
|
+
input: options.input,
|
|
281
|
+
never: options.never
|
|
282
|
+
};
|
|
283
|
+
fail('PROPERTY_VIOLATION', 'A forbidden stable state was reached.', {
|
|
284
|
+
...failure,
|
|
285
|
+
fixture
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const missing = (options.reachable ?? []).filter(
|
|
290
|
+
(state) => !visited.some((snapshot) => snapshot.matches(state))
|
|
291
|
+
);
|
|
292
|
+
if (missing.length)
|
|
293
|
+
fail(
|
|
294
|
+
'REACHABILITY_NOT_WITNESSED',
|
|
295
|
+
'No supplied event representative reached these states.',
|
|
296
|
+
{ states: missing }
|
|
297
|
+
);
|
|
298
|
+
return {
|
|
299
|
+
passed: true,
|
|
300
|
+
scope: 'stableSnapshots',
|
|
301
|
+
effectsExecuted: false,
|
|
302
|
+
proof: false,
|
|
303
|
+
representativeEvents: options.events ?? null,
|
|
304
|
+
eventMode: Array.isArray(options.events)
|
|
305
|
+
? 'replaceDefaults'
|
|
306
|
+
: 'augmentDefaults',
|
|
307
|
+
limit: options.limit ?? 10000,
|
|
308
|
+
paths: paths.length,
|
|
309
|
+
states: visited.map(view)
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
fail('UNKNOWN_COMMAND', `Unknown agent command: ${command}`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function omitSnapshots({ trace }) {
|
|
316
|
+
return { trace };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = (command, args) => {
|
|
320
|
+
try {
|
|
321
|
+
const result = run(command, args);
|
|
322
|
+
console.log(
|
|
323
|
+
JSON.stringify({
|
|
324
|
+
schemaVersion: 1,
|
|
325
|
+
xstateVersion: version,
|
|
326
|
+
command,
|
|
327
|
+
ok: true,
|
|
328
|
+
result
|
|
329
|
+
})
|
|
330
|
+
);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
console.log(
|
|
333
|
+
JSON.stringify({
|
|
334
|
+
schemaVersion: 1,
|
|
335
|
+
xstateVersion: version,
|
|
336
|
+
command,
|
|
337
|
+
ok: false,
|
|
338
|
+
error: {
|
|
339
|
+
code: error.code ?? 'OPERATION_FAILED',
|
|
340
|
+
message: error.message,
|
|
341
|
+
details: error.details
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
);
|
|
345
|
+
process.exitCode = 1;
|
|
346
|
+
}
|
|
347
|
+
};
|
package/bin/xstate.js
CHANGED
|
@@ -6,6 +6,15 @@ const { spawnSync } = require('child_process');
|
|
|
6
6
|
const [command, ...rest] = process.argv.slice(2);
|
|
7
7
|
|
|
8
8
|
switch (command) {
|
|
9
|
+
case 'docs':
|
|
10
|
+
case 'inspect':
|
|
11
|
+
case 'validate':
|
|
12
|
+
case 'simulate':
|
|
13
|
+
case 'test':
|
|
14
|
+
case 'replay':
|
|
15
|
+
case 'diff':
|
|
16
|
+
require('./agent.js')(command, rest);
|
|
17
|
+
break;
|
|
9
18
|
case 'migrate': {
|
|
10
19
|
// Delegates to @xstate/codemod (ts-morph based v5 → v6 codemods).
|
|
11
20
|
const result = spawnSync(
|
|
@@ -24,6 +33,13 @@ switch (command) {
|
|
|
24
33
|
'Usage: xstate <command>',
|
|
25
34
|
'',
|
|
26
35
|
'Commands:',
|
|
36
|
+
' docs Installed docs and export stability (JSON)',
|
|
37
|
+
' inspect <machine.json> Definition and graph completeness (JSON)',
|
|
38
|
+
' validate <machine.json> Validate a data-only definition (JSON)',
|
|
39
|
+
' simulate <machine> <events> Calculate transitions without effects (JSON)',
|
|
40
|
+
' test <machine> <options> Check sampled stable-state properties (JSON)',
|
|
41
|
+
' replay <machine> <fixture> Replay a matching counterexample (JSON)',
|
|
42
|
+
' diff <before> <after> Structural definition changes (JSON)',
|
|
27
43
|
' migrate [globs...] [--dry] Migrate source files to the current XState version',
|
|
28
44
|
' (delegates to @xstate/codemod)'
|
|
29
45
|
].join('\n')
|