@substrat-run/model-emit 0.6.0 → 0.7.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/emit-xstate.d.ts +72 -0
- package/dist/emit-xstate.d.ts.map +1 -0
- package/dist/emit-xstate.js +43 -0
- package/dist/emit-xstate.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The declared lifecycle, rendered as an XState v5 machine config (#844).
|
|
3
|
+
*
|
|
4
|
+
* One direction, and that is the design. XState's statechart *semantics* are the
|
|
5
|
+
* right vocabulary — nested states are K-17's substates exactly, and `setup()`
|
|
6
|
+
* splitting implementations out of the config is why a guard can be referenced
|
|
7
|
+
* by name here without it being a hack. Its *actor runtime* is not wanted: the
|
|
8
|
+
* state lives in a column in a scope DO, the transition happens inside the
|
|
9
|
+
* operation's transaction, and a second thing deciding transitions would be the
|
|
10
|
+
* duplication the declaration exists to delete.
|
|
11
|
+
*
|
|
12
|
+
* So this emits, and nothing here parses. The conversion is TOTAL — every valid
|
|
13
|
+
* lifecycle produces a valid machine — which is exactly what a narrow source
|
|
14
|
+
* format buys: it can refuse `invoke`, `context`, `after` and parallel regions,
|
|
15
|
+
* so the emitter never meets one.
|
|
16
|
+
*
|
|
17
|
+
* ## What it is for
|
|
18
|
+
*
|
|
19
|
+
* A **diagram** in an engine's docs page, and a **test oracle**: `xstate`'s own
|
|
20
|
+
* `machine.transition()` is a pure function, so it can stand beside
|
|
21
|
+
* `assertTransition` in a test and confirm the two agree on every state/event
|
|
22
|
+
* pair, with `xstate` never leaving devDependencies.
|
|
23
|
+
*
|
|
24
|
+
* ## What it must never become
|
|
25
|
+
*
|
|
26
|
+
* A round-trip. Editing the emitted machine in a visual editor and reading it
|
|
27
|
+
* back would make that editor a second authoring surface — the visual-builder
|
|
28
|
+
* tarpit arriving through the back door, without anyone deciding to open it. Any
|
|
29
|
+
* checked-in output of this belongs behind a `--check` re-emit, so an edit to it
|
|
30
|
+
* goes red rather than becoming the source.
|
|
31
|
+
*/
|
|
32
|
+
import type { EmittedLifecycle } from '@substrat-run/contracts';
|
|
33
|
+
/** A guard wired in a manifest: `{ before, predicate }`, where `before` is an operation id. */
|
|
34
|
+
export interface GuardWiring {
|
|
35
|
+
readonly before: string;
|
|
36
|
+
readonly predicate: string;
|
|
37
|
+
}
|
|
38
|
+
export interface XStateTransition {
|
|
39
|
+
readonly target: string;
|
|
40
|
+
readonly guard?: string;
|
|
41
|
+
readonly meta?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
export interface XStateNode {
|
|
44
|
+
readonly type?: 'final';
|
|
45
|
+
readonly on?: Record<string, XStateTransition | string>;
|
|
46
|
+
readonly meta?: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
export interface XStateMachine {
|
|
49
|
+
readonly id: string;
|
|
50
|
+
readonly initial: string;
|
|
51
|
+
readonly states: Record<string, XStateNode>;
|
|
52
|
+
}
|
|
53
|
+
export interface EmitXStateOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Manifest guard wirings, joined onto edges by operation id.
|
|
56
|
+
*
|
|
57
|
+
* Joined rather than declared: K-38 already puts guards in the manifest and has
|
|
58
|
+
* the kernel evaluate them before the guarded operation. Every edge names its
|
|
59
|
+
* operation, so the join key exists and a second declaration would only be a
|
|
60
|
+
* second thing to disagree.
|
|
61
|
+
*/
|
|
62
|
+
readonly guards?: readonly GuardWiring[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Event names are the operation ids verbatim — `workorder/complete`, not
|
|
66
|
+
* `COMPLETE`.
|
|
67
|
+
*
|
|
68
|
+
* XState imposes no naming convention, and SCREAMING_SNAKE would be a lossy
|
|
69
|
+
* rename: the diagram would stop naming the operation a reader can go and read.
|
|
70
|
+
*/
|
|
71
|
+
export declare function emitXState(entity: string, lifecycle: EmittedLifecycle, options?: EmitXStateOptions): XStateMachine;
|
|
72
|
+
//# sourceMappingURL=emit-xstate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-xstate.d.ts","sourceRoot":"","sources":["../src/emit-xstate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,+FAA+F;AAC/F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAAC,CAAC;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,gBAAgB,EAC3B,OAAO,GAAE,iBAAsB,GAC9B,aAAa,CAgCf"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event names are the operation ids verbatim — `workorder/complete`, not
|
|
3
|
+
* `COMPLETE`.
|
|
4
|
+
*
|
|
5
|
+
* XState imposes no naming convention, and SCREAMING_SNAKE would be a lossy
|
|
6
|
+
* rename: the diagram would stop naming the operation a reader can go and read.
|
|
7
|
+
*/
|
|
8
|
+
export function emitXState(entity, lifecycle, options = {}) {
|
|
9
|
+
const byOperation = new Map();
|
|
10
|
+
for (const g of options.guards ?? [])
|
|
11
|
+
byOperation.set(g.before, g.predicate);
|
|
12
|
+
const states = {};
|
|
13
|
+
for (const name of Object.keys(lifecycle.states).sort()) {
|
|
14
|
+
const state = lifecycle.states[name];
|
|
15
|
+
if (!state)
|
|
16
|
+
continue;
|
|
17
|
+
const on = {};
|
|
18
|
+
for (const op of Object.keys(state.on ?? {}).sort()) {
|
|
19
|
+
const target = state.on?.[op];
|
|
20
|
+
if (target === undefined)
|
|
21
|
+
continue;
|
|
22
|
+
const guard = byOperation.get(op);
|
|
23
|
+
on[op] = guard ? { target, guard } : target;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* `allow` deliberately does NOT become a self-transition.
|
|
27
|
+
*
|
|
28
|
+
* A self-loop in XState re-enters the state and fires its entry actions. The
|
|
29
|
+
* declaration says the opposite — this operation is legal here and changes
|
|
30
|
+
* nothing. Drawing it as an edge would put a loop on the diagram for every
|
|
31
|
+
* note a technician can add to a work order, which is both wrong and
|
|
32
|
+
* unreadable. It rides in `meta`, where a renderer can list it as what it is.
|
|
33
|
+
*/
|
|
34
|
+
const meta = state.allow?.length ? { allow: [...state.allow] } : undefined;
|
|
35
|
+
states[name] = {
|
|
36
|
+
...(state.terminal ? { type: 'final' } : {}),
|
|
37
|
+
...(Object.keys(on).length ? { on } : {}),
|
|
38
|
+
...(meta ? { meta } : {}),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return { id: entity, initial: lifecycle.initial, states };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=emit-xstate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-xstate.js","sourceRoot":"","sources":["../src/emit-xstate.ts"],"names":[],"mappings":"AAqEA;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACxB,MAAc,EACd,SAA2B,EAC3B,OAAO,GAAsB,EAAE;IAE/B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE;QAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;IAE7E,MAAM,MAAM,GAA+B,EAAE,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACxD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,EAAE,GAA8C,EAAE,CAAC;QACzD,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACpD,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9B,IAAI,MAAM,KAAK,SAAS;gBAAE,SAAS;YACnC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9C,CAAC;QACD;;;;;;;;WAQG;QACH,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,GAAG;YACb,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1B,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;AAC5D,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { journalColumns, journalUniques, journalPrimaryKeys } from './journal.js
|
|
|
3
3
|
export { readSchema, statements, type TableSchema } from './replay.js';
|
|
4
4
|
export { planMigration, parseJournal, type Journal, type JournalEntry, type MigrationPlan, } from './plan.js';
|
|
5
5
|
export { renderClient, ClientEmitError, tsTypeOf, methodName, type ClientConfig, } from './emit-client.js';
|
|
6
|
+
export { emitXState, type EmitXStateOptions, type GuardWiring, type XStateMachine, type XStateNode, type XStateTransition, } from './emit-xstate.js';
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,aAAa,EACb,YAAY,EACZ,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,UAAU,EACV,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,aAAa,EACb,YAAY,EACZ,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,UAAU,EACV,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,4 +3,5 @@ export { journalColumns, journalUniques, journalPrimaryKeys } from './journal.js
|
|
|
3
3
|
export { readSchema, statements } from './replay.js';
|
|
4
4
|
export { planMigration, parseJournal, } from './plan.js';
|
|
5
5
|
export { renderClient, ClientEmitError, tsTypeOf, methodName, } from './emit-client.js';
|
|
6
|
+
export { emitXState, } from './emit-xstate.js';
|
|
6
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EACT,oBAAoB,EACpB,iBAAiB,GAGlB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,aAAa,EACb,YAAY,GAIb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,UAAU,GAEX,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,SAAS,EACT,oBAAoB,EACpB,iBAAiB,GAGlB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAoB,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,aAAa,EACb,YAAY,GAIb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,UAAU,GAEX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,UAAU,GAMX,MAAM,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/model-emit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Build-time tooling over a Substrat model — DDL emitted from the entity registry, and the journal reader that holds it honest",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@substrat-run/contracts": "0.
|
|
25
|
+
"@substrat-run/contracts": "0.84.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^22.0.0",
|