@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.
@@ -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
@@ -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.6.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.83.0"
25
+ "@substrat-run/contracts": "0.84.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^22.0.0",