aifsmjs 0.5.9 → 0.6.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/README.md +14 -7
- package/README_ZHTW.md +14 -7
- package/dist/{chunk-ZLQ7HZCE.js → chunk-D6H64FSI.js} +66 -46
- package/dist/chunk-D6H64FSI.js.map +1 -0
- package/dist/{chunk-NEJYZAKR.js → chunk-Q45LGXHO.js} +3 -3
- package/dist/{chunk-NEJYZAKR.js.map → chunk-Q45LGXHO.js.map} +1 -1
- package/dist/{chunk-CDK25FTD.cjs → chunk-QCTA2X4J.cjs} +7 -3
- package/dist/chunk-QCTA2X4J.cjs.map +1 -0
- package/dist/{chunk-A7U7QQL5.js → chunk-SSNKGEVB.js} +7 -4
- package/dist/chunk-SSNKGEVB.js.map +1 -0
- package/dist/{chunk-I354FONA.cjs → chunk-VGLF5NQH.cjs} +69 -46
- package/dist/chunk-VGLF5NQH.cjs.map +1 -0
- package/dist/{chunk-FHTQ7LSQ.cjs → chunk-VV5TKFQO.cjs} +4 -4
- package/dist/{chunk-FHTQ7LSQ.cjs.map → chunk-VV5TKFQO.cjs.map} +1 -1
- package/dist/{chunk-LG2AH5X6.js → chunk-XA24A7VP.js} +143 -152
- package/dist/chunk-XA24A7VP.js.map +1 -0
- package/dist/{chunk-TPCDOVU4.cjs → chunk-YK25NVFC.cjs} +147 -156
- package/dist/chunk-YK25NVFC.cjs.map +1 -0
- package/dist/effects/index.cjs +3 -4
- package/dist/effects/index.cjs.map +1 -1
- package/dist/effects/index.d.cts +1 -1
- package/dist/effects/index.d.ts +1 -1
- package/dist/effects/index.js +2 -3
- package/dist/effects/index.js.map +1 -1
- package/dist/guards/index.cjs +5 -6
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.d.cts +1 -1
- package/dist/guards/index.d.ts +1 -1
- package/dist/guards/index.js +2 -3
- package/dist/guards/index.js.map +1 -1
- package/dist/index.cjs +31 -28
- package/dist/index.d.cts +66 -18
- package/dist/index.d.ts +66 -18
- package/dist/index.js +3 -4
- package/dist/inspect/index.cjs +0 -2
- package/dist/inspect/index.cjs.map +1 -1
- package/dist/inspect/index.d.cts +1 -1
- package/dist/inspect/index.d.ts +1 -1
- package/dist/inspect/index.js +0 -2
- package/dist/inspect/index.js.map +1 -1
- package/dist/pbt/index.cjs +65 -49
- package/dist/pbt/index.cjs.map +1 -1
- package/dist/pbt/index.d.cts +13 -17
- package/dist/pbt/index.d.ts +13 -17
- package/dist/pbt/index.js +57 -41
- package/dist/pbt/index.js.map +1 -1
- package/dist/replay/index.cjs +4 -5
- package/dist/replay/index.d.cts +1 -1
- package/dist/replay/index.d.ts +1 -1
- package/dist/replay/index.js +3 -4
- package/dist/timer/index.cjs +18 -5
- package/dist/timer/index.cjs.map +1 -1
- package/dist/timer/index.d.cts +6 -0
- package/dist/timer/index.d.ts +6 -0
- package/dist/timer/index.js +18 -5
- package/dist/timer/index.js.map +1 -1
- package/dist/{types-DIM7QTtf.d.ts → types-CrDxFfBx.d.cts} +64 -16
- package/dist/{types-DIM7QTtf.d.cts → types-CrDxFfBx.d.ts} +64 -16
- package/llms-full.txt +70 -16
- package/package.json +57 -22
- package/dist/chunk-A7U7QQL5.js.map +0 -1
- package/dist/chunk-CDK25FTD.cjs.map +0 -1
- package/dist/chunk-I354FONA.cjs.map +0 -1
- package/dist/chunk-LG2AH5X6.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -9
- package/dist/chunk-PZ5AY32C.js.map +0 -1
- package/dist/chunk-Q7SFCCGT.cjs +0 -11
- package/dist/chunk-Q7SFCCGT.cjs.map +0 -1
- package/dist/chunk-TPCDOVU4.cjs.map +0 -1
- package/dist/chunk-ZLQ7HZCE.js.map +0 -1
package/dist/pbt/index.cjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
3
|
+
var chunkYK25NVFC_cjs = require('../chunk-YK25NVFC.cjs');
|
|
4
|
+
var chunkVV5TKFQO_cjs = require('../chunk-VV5TKFQO.cjs');
|
|
5
|
+
var chunkVGLF5NQH_cjs = require('../chunk-VGLF5NQH.cjs');
|
|
6
6
|
require('../chunk-3B2USJ3H.cjs');
|
|
7
|
-
require('../chunk-
|
|
8
|
-
var chunkQ7SFCCGT_cjs = require('../chunk-Q7SFCCGT.cjs');
|
|
7
|
+
var chunkQCTA2X4J_cjs = require('../chunk-QCTA2X4J.cjs');
|
|
9
8
|
var fc2 = require('fast-check');
|
|
10
9
|
var util = require('util');
|
|
11
10
|
|
|
@@ -53,7 +52,7 @@ var SendCommand = class {
|
|
|
53
52
|
const before = r.getSnapshot();
|
|
54
53
|
r.send(this.event);
|
|
55
54
|
const after = r.getSnapshot();
|
|
56
|
-
const predicted =
|
|
55
|
+
const predicted = chunkVGLF5NQH_cjs.step(this.def, before, this.event, this.impl);
|
|
57
56
|
if (predicted.snapshot.value !== after.value) {
|
|
58
57
|
throw new Error(
|
|
59
58
|
`aifsmjs/pbt: determinism violation \u2014 predicted "${String(predicted.snapshot.value)}" but runtime returned "${String(after.value)}" after ${this.toString()}`
|
|
@@ -75,19 +74,6 @@ function commandsFromMachine(def, impl, eventArbitraries) {
|
|
|
75
74
|
}
|
|
76
75
|
return fc2__namespace.commands(arbs, { size: "+1" });
|
|
77
76
|
}
|
|
78
|
-
|
|
79
|
-
// src/pbt/properties.ts
|
|
80
|
-
var properties_exports = {};
|
|
81
|
-
chunkQ7SFCCGT_cjs.__export(properties_exports, {
|
|
82
|
-
assertAll: () => assertAll,
|
|
83
|
-
assignDoesNotMutate: () => assignDoesNotMutate,
|
|
84
|
-
contextEquals: () => contextEquals,
|
|
85
|
-
guardsFalseNoTransition: () => guardsFalseNoTransition,
|
|
86
|
-
reachableStatesSubsetDeclared: () => reachableStatesSubsetDeclared,
|
|
87
|
-
replayEqualsFold: () => replayEqualsFold,
|
|
88
|
-
snapshotAlwaysFrozen: () => snapshotAlwaysFrozen,
|
|
89
|
-
unknownEventNoOp: () => unknownEventNoOp
|
|
90
|
-
});
|
|
91
77
|
function buildAssertOpts(opts) {
|
|
92
78
|
const out = {};
|
|
93
79
|
if (opts?.numRuns !== void 0) out.numRuns = opts.numRuns;
|
|
@@ -101,10 +87,14 @@ function contextEquals(a, b) {
|
|
|
101
87
|
function snapshotAlwaysFrozen(def, impl, eventArbitraries, opts) {
|
|
102
88
|
fc2__namespace.assert(
|
|
103
89
|
fc2__namespace.property(commandsFromMachine(def, impl, eventArbitraries), (cmds) => {
|
|
104
|
-
const real =
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
90
|
+
const real = chunkYK25NVFC_cjs.createRuntime(def, impl, { dispatchEffects: false });
|
|
91
|
+
try {
|
|
92
|
+
const model = initialModel(def);
|
|
93
|
+
fc2__namespace.modelRun(() => ({ model, real }), cmds);
|
|
94
|
+
return Object.isFrozen(real.getSnapshot());
|
|
95
|
+
} finally {
|
|
96
|
+
real.dispose();
|
|
97
|
+
}
|
|
108
98
|
}),
|
|
109
99
|
buildAssertOpts(opts)
|
|
110
100
|
);
|
|
@@ -112,8 +102,8 @@ function snapshotAlwaysFrozen(def, impl, eventArbitraries, opts) {
|
|
|
112
102
|
function unknownEventNoOp(def, impl, unknownType, opts) {
|
|
113
103
|
fc2__namespace.assert(
|
|
114
104
|
fc2__namespace.property(fc2__namespace.constant(unknownType), (t) => {
|
|
115
|
-
const initial =
|
|
116
|
-
const result =
|
|
105
|
+
const initial = chunkYK25NVFC_cjs.initialSnapshot(def);
|
|
106
|
+
const result = chunkVGLF5NQH_cjs.step(def, initial, { type: t }, impl);
|
|
117
107
|
return result.changed === false && result.snapshot === initial && result.effects.length === 0;
|
|
118
108
|
}),
|
|
119
109
|
buildAssertOpts(opts)
|
|
@@ -123,13 +113,17 @@ function reachableStatesSubsetDeclared(def, impl, eventArbitraries, opts) {
|
|
|
123
113
|
const declared = new Set(Object.keys(def.states));
|
|
124
114
|
fc2__namespace.assert(
|
|
125
115
|
fc2__namespace.property(commandsFromMachine(def, impl, eventArbitraries), (cmds) => {
|
|
126
|
-
const real =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
116
|
+
const real = chunkYK25NVFC_cjs.createRuntime(def, impl, { dispatchEffects: false });
|
|
117
|
+
try {
|
|
118
|
+
const model = initialModel(def);
|
|
119
|
+
fc2__namespace.modelRun(() => ({ model, real }), cmds);
|
|
120
|
+
for (const s of model.reached) {
|
|
121
|
+
if (!declared.has(s)) return false;
|
|
122
|
+
}
|
|
123
|
+
return declared.has(real.getSnapshot().value);
|
|
124
|
+
} finally {
|
|
125
|
+
real.dispose();
|
|
131
126
|
}
|
|
132
|
-
return declared.has(real.getSnapshot().value);
|
|
133
127
|
}),
|
|
134
128
|
buildAssertOpts(opts)
|
|
135
129
|
);
|
|
@@ -138,11 +132,15 @@ function replayEqualsFold(def, impl, eventArbitraries, opts) {
|
|
|
138
132
|
const eventArb = fc2__namespace.oneof(...Object.values(eventArbitraries));
|
|
139
133
|
fc2__namespace.assert(
|
|
140
134
|
fc2__namespace.property(fc2__namespace.array(eventArb, { maxLength: 32 }), (events) => {
|
|
141
|
-
const real =
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
135
|
+
const real = chunkYK25NVFC_cjs.createRuntime(def, impl, { dispatchEffects: false });
|
|
136
|
+
try {
|
|
137
|
+
for (const e of events) real.send(e);
|
|
138
|
+
const live = real.getSnapshot();
|
|
139
|
+
const replayed = chunkVV5TKFQO_cjs.replay(chunkYK25NVFC_cjs.initialSnapshot(def), events, def, impl).snapshot;
|
|
140
|
+
return live.value === replayed.value && contextEquals(live.context, replayed.context);
|
|
141
|
+
} finally {
|
|
142
|
+
real.dispose();
|
|
143
|
+
}
|
|
146
144
|
}),
|
|
147
145
|
buildAssertOpts(opts)
|
|
148
146
|
);
|
|
@@ -151,7 +149,8 @@ function guardsFalseNoTransition(def, impl, eventArbitraries, opts) {
|
|
|
151
149
|
const blockedGuards = new Proxy(
|
|
152
150
|
{},
|
|
153
151
|
{
|
|
154
|
-
get: () => () => false
|
|
152
|
+
get: () => () => false,
|
|
153
|
+
getOwnPropertyDescriptor: () => ({ configurable: true })
|
|
155
154
|
}
|
|
156
155
|
);
|
|
157
156
|
const blockedImpl = {
|
|
@@ -159,17 +158,17 @@ function guardsFalseNoTransition(def, impl, eventArbitraries, opts) {
|
|
|
159
158
|
guards: blockedGuards
|
|
160
159
|
};
|
|
161
160
|
const isFullyGuarded = (value, eventType) => {
|
|
162
|
-
const candidates =
|
|
161
|
+
const candidates = chunkVGLF5NQH_cjs.normalizeTransitions(chunkQCTA2X4J_cjs.ownValue(def.states[value]?.on, eventType));
|
|
163
162
|
return candidates.length > 0 && candidates.every((t) => t.guard !== void 0);
|
|
164
163
|
};
|
|
165
164
|
fc2__namespace.assert(
|
|
166
165
|
fc2__namespace.property(
|
|
167
166
|
fc2__namespace.array(fc2__namespace.oneof(...Object.values(eventArbitraries)), { maxLength: 16 }),
|
|
168
167
|
(events) => {
|
|
169
|
-
let snap =
|
|
168
|
+
let snap = chunkYK25NVFC_cjs.initialSnapshot(def);
|
|
170
169
|
for (const e of events) {
|
|
171
170
|
const fullyGuarded = isFullyGuarded(snap.value, e.type);
|
|
172
|
-
const r =
|
|
171
|
+
const r = chunkVGLF5NQH_cjs.step(def, snap, e, blockedImpl);
|
|
173
172
|
if (fullyGuarded && r.changed !== false) return false;
|
|
174
173
|
snap = r.snapshot;
|
|
175
174
|
}
|
|
@@ -179,20 +178,28 @@ function guardsFalseNoTransition(def, impl, eventArbitraries, opts) {
|
|
|
179
178
|
buildAssertOpts(opts)
|
|
180
179
|
);
|
|
181
180
|
}
|
|
181
|
+
var ownState = (v) => [
|
|
182
|
+
...Reflect.ownKeys(v).flatMap((k) => [k, v[k]]),
|
|
183
|
+
...v instanceof Map || v instanceof Set ? [...v.entries()].flat() : [],
|
|
184
|
+
v instanceof Date && v.getTime()
|
|
185
|
+
];
|
|
182
186
|
function assignDoesNotMutate(def, impl, eventArbitraries, opts) {
|
|
183
|
-
const dummy = { a: 1, b: 2 };
|
|
184
|
-
const merged = chunkI354FONA_cjs.mergeContext(dummy, { b: 3 });
|
|
185
|
-
if (merged === dummy) throw new Error("aifsmjs/pbt: mergeContext returned the same reference");
|
|
186
187
|
fc2__namespace.assert(
|
|
187
188
|
fc2__namespace.property(
|
|
188
189
|
fc2__namespace.array(fc2__namespace.oneof(...Object.values(eventArbitraries)), { maxLength: 16 }),
|
|
189
190
|
(events) => {
|
|
190
|
-
let snap =
|
|
191
|
+
let snap = chunkYK25NVFC_cjs.initialSnapshot(def);
|
|
191
192
|
for (const e of events) {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
const before = /* @__PURE__ */ new Map();
|
|
194
|
+
const walk = (v) => {
|
|
195
|
+
if (!v || typeof v !== "object" || before.has(v)) return;
|
|
196
|
+
const own = ownState(v);
|
|
197
|
+
before.set(v, own);
|
|
198
|
+
own.forEach(walk);
|
|
199
|
+
};
|
|
200
|
+
walk(snap.context);
|
|
201
|
+
snap = chunkVGLF5NQH_cjs.step(def, snap, e, impl).snapshot;
|
|
202
|
+
for (const [obj, own] of before) if (!contextEquals(ownState(obj), own)) return false;
|
|
196
203
|
}
|
|
197
204
|
return true;
|
|
198
205
|
}
|
|
@@ -210,7 +217,16 @@ function assertAll(def, impl, eventArbitraries, opts) {
|
|
|
210
217
|
}
|
|
211
218
|
|
|
212
219
|
// src/pbt/index.ts
|
|
213
|
-
var properties =
|
|
220
|
+
var properties = Object.freeze({
|
|
221
|
+
assertAll,
|
|
222
|
+
assignDoesNotMutate,
|
|
223
|
+
contextEquals,
|
|
224
|
+
guardsFalseNoTransition,
|
|
225
|
+
reachableStatesSubsetDeclared,
|
|
226
|
+
replayEqualsFold,
|
|
227
|
+
snapshotAlwaysFrozen,
|
|
228
|
+
unknownEventNoOp
|
|
229
|
+
});
|
|
214
230
|
|
|
215
231
|
exports.assertAll = assertAll;
|
|
216
232
|
exports.assignDoesNotMutate = assignDoesNotMutate;
|
package/dist/pbt/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pbt/commands.ts","../../src/pbt/properties.ts","../../src/pbt/index.ts"],"names":["step","fc","__export","isDeepStrictEqual","fc2","createRuntime","initialSnapshot","replay","normalizeTransitions","mergeContext"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as fc from \"fast-check\";\nimport { step } from \"../fsm/lifecycle.js\";\nimport type { Implementations, MachineDef, Runtime, Snapshot } from \"../fsm/types.js\";\n\n/**\n * Pure-model representation of an FSM run, used by `fc.commands`.\n * `reached` tracks every state visited so generic properties can check\n * containment without re-running.\n */\nexport type FsmModel<Ctx, States extends string> = {\n value: States;\n context: Ctx;\n status: \"active\" | \"final\";\n reached: Set<States>;\n};\n\nexport type EventArbitraries<Evt extends { type: string }> = Readonly<\n Record<string, fc.Arbitrary<Evt>>\n>;\n\nexport type FsmCommand<Ctx, Evt extends { type: string }, States extends string> = fc.Command<\n FsmModel<Ctx, States>,\n Runtime<Ctx, Evt, States>\n>;\n\nexport function initialModel<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n): FsmModel<Ctx, States> {\n return {\n value: def.initial,\n context: def.context,\n status: def.states[def.initial]?.final ? \"final\" : \"active\",\n reached: new Set([def.initial]),\n };\n}\n\nclass SendCommand<Ctx, Evt extends { type: string }, States extends string>\n implements FsmCommand<Ctx, Evt, States>\n{\n constructor(\n private readonly event: Evt,\n private readonly def: MachineDef<Ctx, Evt, States>,\n private readonly impl: Implementations<Ctx, Evt>,\n ) {}\n\n check(_m: Readonly<FsmModel<Ctx, States>>): boolean {\n // Every event is always applicable; invariants are asserted in run().\n return true;\n }\n\n run(m: FsmModel<Ctx, States>, r: Runtime<Ctx, Evt, States>): void {\n const before: Snapshot<Ctx, States> = r.getSnapshot();\n r.send(this.event);\n const after = r.getSnapshot();\n\n const predicted = step(this.def, before, this.event, this.impl);\n\n /* v8 ignore start — invariant guard: fires only when the live runtime\n diverges from the pure step() prediction, i.e. an internal bug. */\n if (predicted.snapshot.value !== after.value) {\n throw new Error(\n `aifsmjs/pbt: determinism violation — predicted \"${String(predicted.snapshot.value)}\" but runtime returned \"${String(after.value)}\" after ${this.toString()}`,\n );\n }\n /* v8 ignore stop */\n\n m.value = after.value;\n m.context = after.context as Ctx;\n m.status = after.status;\n m.reached.add(after.value);\n }\n\n toString(): string {\n return `send(${JSON.stringify(this.event)})`;\n }\n}\n\n/**\n * Build an `fc.Arbitrary` of FSM command sequences. Each command pulls one\n * event from the user-supplied arbitrary map and, when run, asserts that the\n * pure `step()` prediction matches the runtime's observable outcome.\n *\n * Pair this arbitrary with `fc.property(...)` inside a `fc.assert(...)` call,\n * or use the helpers in `aifsmjs/pbt` properties to get the six generic\n * invariants for free.\n */\nexport function commandsFromMachine<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n): fc.Arbitrary<Iterable<FsmCommand<Ctx, Evt, States>>> {\n const arbs: fc.Arbitrary<FsmCommand<Ctx, Evt, States>>[] = [];\n for (const arb of Object.values(eventArbitraries)) {\n arbs.push(arb.map((event) => new SendCommand(event, def, impl)));\n }\n return fc.commands(arbs, { size: \"+1\" });\n}\n","import { isDeepStrictEqual } from \"node:util\";\nimport * as fc from \"fast-check\";\nimport { initialSnapshot } from \"../fsm/definition.js\";\nimport { step } from \"../fsm/lifecycle.js\";\nimport { normalizeTransitions } from \"../fsm/resolver.js\";\nimport { createRuntime } from \"../fsm/runtime.js\";\nimport type { Guard, Implementations, MachineDef } from \"../fsm/types.js\";\nimport { mergeContext } from \"../fsm/updater.js\";\nimport { replay } from \"../replay/index.js\";\nimport {\n type EventArbitraries,\n type FsmModel,\n commandsFromMachine,\n initialModel,\n} from \"./commands.js\";\n\nexport type AssertOpts = Readonly<{\n numRuns?: number;\n seed?: number;\n verbose?: boolean;\n}>;\n\nfunction buildAssertOpts(opts: AssertOpts | undefined): fc.Parameters<unknown> {\n const out: fc.Parameters<unknown> = {};\n if (opts?.numRuns !== undefined) out.numRuns = opts.numRuns;\n if (opts?.seed !== undefined) out.seed = opts.seed;\n if (opts?.verbose) out.verbose = true;\n return out;\n}\n\n/**\n * Structural deep-equality for two context values (C3). Backed by `node:util`\n * `isDeepStrictEqual`, replacing the previous `JSON.stringify(a) === JSON.stringify(b)`\n * oracle which was unsound:\n *\n * - key-order-sensitive → false-FAIL on `{a:1,b:2}` vs `{b:2,a:1}`;\n * - drops undefined keys → false-PASS on `{v:undefined,w:1}` vs `{w:1}`;\n * - lossy for `Map`/`Set`/`Date` (all serialise to `{}` or an ISO string);\n * - throws on `BigInt`.\n *\n * `isDeepStrictEqual` distinguishes present-but-undefined from absent keys,\n * compares `Map`/`Set`/`Date` by contents, and tolerates `BigInt` — exactly\n * the verdicts a context-equality oracle for PBT requires. No new dependency\n * (Node built-in; the package already targets Node >=18).\n */\nexport function contextEquals(a: unknown, b: unknown): boolean {\n return isDeepStrictEqual(a, b);\n}\n\n/**\n * #1 snapshotAlwaysFrozen — after any event sequence the live snapshot remains\n * frozen at the top level.\n */\nexport function snapshotAlwaysFrozen<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n fc.assert(\n fc.property(commandsFromMachine(def, impl, eventArbitraries), (cmds) => {\n const real = createRuntime(def, impl);\n const model: FsmModel<Ctx, States> = initialModel(def);\n fc.modelRun(() => ({ model, real }), cmds);\n return Object.isFrozen(real.getSnapshot());\n }),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #2 unknownEventNoOp — sending an event whose `type` is not declared in any\n * state's `on` map never changes the snapshot.\n */\nexport function unknownEventNoOp<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n unknownType: string,\n opts?: AssertOpts,\n): void {\n fc.assert(\n fc.property(fc.constant(unknownType), (t) => {\n const initial = initialSnapshot(def);\n const result = step(def, initial, { type: t } as unknown as Evt, impl);\n return result.changed === false && result.snapshot === initial && result.effects.length === 0;\n }),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #3 reachableStatesSubsetDeclared — every state visited during a run belongs\n * to `def.states`.\n */\nexport function reachableStatesSubsetDeclared<\n Ctx,\n Evt extends { type: string },\n States extends string,\n>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n const declared = new Set<string>(Object.keys(def.states));\n fc.assert(\n fc.property(commandsFromMachine(def, impl, eventArbitraries), (cmds) => {\n const real = createRuntime(def, impl);\n const model: FsmModel<Ctx, States> = initialModel(def);\n fc.modelRun(() => ({ model, real }), cmds);\n for (const s of model.reached as Set<string>) {\n /* v8 ignore next — property failure branch; an unreachable state would indicate a bug. */\n if (!declared.has(s)) return false;\n }\n return declared.has(real.getSnapshot().value);\n }),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #4 replayEqualsFold — `replay(initial, log)` produces the same final state\n * as a live runtime fed the same events. Effects dispatched by the runtime are\n * ignored; the comparison is on `{ value, context }`.\n */\nexport function replayEqualsFold<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n const eventArb = fc.oneof(...Object.values(eventArbitraries));\n fc.assert(\n fc.property(fc.array(eventArb, { maxLength: 32 }), (events) => {\n const real = createRuntime(def, impl, { dispatchEffects: false });\n for (const e of events) real.send(e);\n const live = real.getSnapshot();\n const replayed = replay(initialSnapshot(def), events, def, impl).snapshot;\n return live.value === replayed.value && contextEquals(live.context, replayed.context);\n }),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #5 guardsFalseNoTransition — when every candidate transition for the current\n * (state, event) pair carries a guard and every guard returns `false`, the\n * snapshot is unchanged (`changed === false`).\n *\n * Implementation: synthesise an impl that forces every guard to `false`, then\n * for each step whose candidate list is fully guarded, assert the step did not\n * change state. Steps with an unguarded fallback candidate (which fires even\n * when all guards are false) are skipped — the README claim is specifically\n * about the all-guards-false case.\n */\nexport function guardsFalseNoTransition<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n const blockedGuards = new Proxy(\n {},\n {\n get: () => () => false,\n },\n ) as Readonly<Record<string, Guard<Ctx, Evt>>>;\n const blockedImpl: Implementations<Ctx, Evt> = {\n ...impl,\n guards: blockedGuards,\n };\n // True when every candidate transition for (value, eventType) carries a\n // guard — i.e. blocking all guards leaves no unconditional fallback, so a\n // correct step() must report changed === false.\n const isFullyGuarded = (value: States, eventType: string): boolean => {\n const candidates = normalizeTransitions(def.states[value]?.on?.[eventType]);\n return candidates.length > 0 && candidates.every((t) => t.guard !== undefined);\n };\n fc.assert(\n fc.property(\n fc.array(fc.oneof(...Object.values(eventArbitraries)), { maxLength: 16 }),\n (events) => {\n let snap = initialSnapshot(def);\n for (const e of events) {\n const fullyGuarded = isFullyGuarded(snap.value, e.type);\n const r = step(def, snap, e, blockedImpl);\n // The named invariant: all guards false + no unconditional fallback\n // ⇒ no transition. Without this assertion the property was vacuous\n // (it only failed if step() threw).\n if (fullyGuarded && r.changed !== false) return false;\n snap = r.snapshot;\n }\n return true;\n },\n ),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #6 assignDoesNotMutate — running an `assign`-style action never mutates the\n * previous context object. Verified by deep-equality check on a snapshot taken\n * before each event.\n */\nexport function assignDoesNotMutate<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n // Quick sanity guard: mergeContext is the only context mutator used by step.\n const dummy = { a: 1, b: 2 };\n const merged = mergeContext(dummy, { b: 3 });\n /* v8 ignore next — invariant guard; mergeContext returning the same ref would mean unit tests have already broken. */\n if (merged === dummy) throw new Error(\"aifsmjs/pbt: mergeContext returned the same reference\");\n\n fc.assert(\n fc.property(\n fc.array(fc.oneof(...Object.values(eventArbitraries)), { maxLength: 16 }),\n (events) => {\n let snap = initialSnapshot(def);\n for (const e of events) {\n // Structural snapshot of the pre-step context (C3). structuredClone +\n // contextEquals replaces the old JSON.stringify round-trip, which was\n // lossy for Map/Set/Date and threw on BigInt. structuredClone produces\n // an independent copy so a subsequent in-place mutation by step() is\n // detectable by deep comparison.\n const beforeCtx = structuredClone(snap.context);\n step(def, snap, e, impl);\n /* v8 ignore next — property failure branch; step() mutating snap.context would indicate a bug. */\n if (!contextEquals(snap.context, beforeCtx)) return false;\n // Continue with the actual result for subsequent events\n snap = step(def, snap, e, impl).snapshot;\n }\n return true;\n },\n ),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * Assert every generic property in one call. Use this when you don't need\n * fine-grained control over per-property options.\n */\nexport function assertAll<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts & { unknownEventType?: string },\n): void {\n snapshotAlwaysFrozen(def, impl, eventArbitraries, opts);\n unknownEventNoOp(def, impl, opts?.unknownEventType ?? \"__AIFSMJS_UNKNOWN__\", opts);\n reachableStatesSubsetDeclared(def, impl, eventArbitraries, opts);\n replayEqualsFold(def, impl, eventArbitraries, opts);\n guardsFalseNoTransition(def, impl, eventArbitraries, opts);\n assignDoesNotMutate(def, impl, eventArbitraries, opts);\n}\n","export {\n commandsFromMachine,\n initialModel,\n type EventArbitraries,\n type FsmCommand,\n type FsmModel,\n} from \"./commands.js\";\n\nexport {\n assertAll,\n assignDoesNotMutate,\n guardsFalseNoTransition,\n reachableStatesSubsetDeclared,\n replayEqualsFold,\n snapshotAlwaysFrozen,\n unknownEventNoOp,\n type AssertOpts,\n} from \"./properties.js\";\n\n// Convenience namespace mirroring the README:\n// import { properties } from \"aifsmjs/pbt\"\n// properties.snapshotAlwaysFrozen(...)\nimport * as propertiesModule from \"./properties.js\";\nexport const properties = propertiesModule;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/pbt/commands.ts","../../src/pbt/properties.ts","../../src/pbt/index.ts"],"names":["step","fc","isDeepStrictEqual","fc2","createRuntime","initialSnapshot","replay","normalizeTransitions","ownValue"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as fc from \"fast-check\";\nimport { step } from \"../fsm/lifecycle.js\";\nimport type { Implementations, MachineDef, Runtime, Snapshot } from \"../fsm/types.js\";\n\n/**\n * Pure-model representation of an FSM run, used by `fc.commands`.\n * `reached` tracks every state visited so generic properties can check\n * containment without re-running.\n */\nexport type FsmModel<Ctx, States extends string> = {\n value: States;\n context: Ctx;\n status: \"active\" | \"final\";\n reached: Set<States>;\n};\n\nexport type EventArbitraries<Evt extends { type: string }> = Readonly<\n Record<string, fc.Arbitrary<Evt>>\n>;\n\nexport type FsmCommand<Ctx, Evt extends { type: string }, States extends string> = fc.Command<\n FsmModel<Ctx, States>,\n Runtime<Ctx, Evt, States>\n>;\n\nexport function initialModel<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n): FsmModel<Ctx, States> {\n return {\n value: def.initial,\n context: def.context,\n status: def.states[def.initial]?.final ? \"final\" : \"active\",\n reached: new Set([def.initial]),\n };\n}\n\nclass SendCommand<Ctx, Evt extends { type: string }, States extends string>\n implements FsmCommand<Ctx, Evt, States>\n{\n constructor(\n private readonly event: Evt,\n private readonly def: MachineDef<Ctx, Evt, States>,\n private readonly impl: Implementations<Ctx, Evt>,\n ) {}\n\n check(_m: Readonly<FsmModel<Ctx, States>>): boolean {\n // Every event is always applicable; invariants are asserted in run().\n return true;\n }\n\n run(m: FsmModel<Ctx, States>, r: Runtime<Ctx, Evt, States>): void {\n const before: Snapshot<Ctx, States> = r.getSnapshot();\n r.send(this.event);\n const after = r.getSnapshot();\n\n const predicted = step(this.def, before, this.event, this.impl);\n\n /* v8 ignore start — invariant guard: fires only when the live runtime\n diverges from the pure step() prediction, i.e. an internal bug. */\n if (predicted.snapshot.value !== after.value) {\n throw new Error(\n `aifsmjs/pbt: determinism violation — predicted \"${String(predicted.snapshot.value)}\" but runtime returned \"${String(after.value)}\" after ${this.toString()}`,\n );\n }\n /* v8 ignore stop */\n\n m.value = after.value;\n m.context = after.context as Ctx;\n m.status = after.status;\n m.reached.add(after.value);\n }\n\n toString(): string {\n return `send(${JSON.stringify(this.event)})`;\n }\n}\n\n/**\n * Build an `fc.Arbitrary` of FSM command sequences. Each command pulls one\n * event from the user-supplied arbitrary map and, when run, asserts that the\n * pure `step()` prediction matches the runtime's observable outcome.\n *\n * Pair this arbitrary with `fc.property(...)` inside a `fc.assert(...)` call,\n * or use the helpers in `aifsmjs/pbt` properties to get the six generic\n * invariants for free.\n */\nexport function commandsFromMachine<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n): fc.Arbitrary<Iterable<FsmCommand<Ctx, Evt, States>>> {\n const arbs: fc.Arbitrary<FsmCommand<Ctx, Evt, States>>[] = [];\n for (const arb of Object.values(eventArbitraries)) {\n arbs.push(arb.map((event) => new SendCommand(event, def, impl)));\n }\n return fc.commands(arbs, { size: \"+1\" });\n}\n","import { isDeepStrictEqual } from \"node:util\";\nimport * as fc from \"fast-check\";\nimport { initialSnapshot } from \"../fsm/definition.js\";\nimport { ownValue } from \"../fsm/evaluator.js\";\nimport { step } from \"../fsm/lifecycle.js\";\nimport { normalizeTransitions } from \"../fsm/resolver.js\";\nimport { createRuntime } from \"../fsm/runtime.js\";\nimport type { Guard, Implementations, MachineDef } from \"../fsm/types.js\";\nimport { replay } from \"../replay/index.js\";\nimport {\n type EventArbitraries,\n type FsmModel,\n commandsFromMachine,\n initialModel,\n} from \"./commands.js\";\n\nexport type AssertOpts = Readonly<{\n numRuns?: number;\n seed?: number;\n verbose?: boolean;\n}>;\n\nfunction buildAssertOpts(opts: AssertOpts | undefined): fc.Parameters<unknown> {\n const out: fc.Parameters<unknown> = {};\n if (opts?.numRuns !== undefined) out.numRuns = opts.numRuns;\n if (opts?.seed !== undefined) out.seed = opts.seed;\n if (opts?.verbose) out.verbose = true;\n return out;\n}\n\n/**\n * Structural deep-equality for two context values (C3). Backed by `node:util`\n * `isDeepStrictEqual`, replacing the previous `JSON.stringify(a) === JSON.stringify(b)`\n * oracle which was unsound:\n *\n * - key-order-sensitive → false-FAIL on `{a:1,b:2}` vs `{b:2,a:1}`;\n * - drops undefined keys → false-PASS on `{v:undefined,w:1}` vs `{w:1}`;\n * - lossy for `Map`/`Set`/`Date` (all serialise to `{}` or an ISO string);\n * - throws on `BigInt`.\n *\n * `isDeepStrictEqual` distinguishes present-but-undefined from absent keys,\n * compares `Map`/`Set`/`Date` by contents, and tolerates `BigInt` — exactly\n * the verdicts a context-equality oracle for PBT requires. No new dependency\n * (Node built-in; the package already targets Node >=18).\n */\nexport function contextEquals(a: unknown, b: unknown): boolean {\n return isDeepStrictEqual(a, b);\n}\n\n/**\n * #1 snapshotAlwaysFrozen — after any event sequence the live snapshot remains\n * frozen at the top level.\n */\nexport function snapshotAlwaysFrozen<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n fc.assert(\n fc.property(commandsFromMachine(def, impl, eventArbitraries), (cmds) => {\n const real = createRuntime(def, impl, { dispatchEffects: false });\n // Dispose every generated run's runtime (its signal aborts, its child\n // runtimes are torn down); the asserted value is computed first.\n try {\n const model: FsmModel<Ctx, States> = initialModel(def);\n fc.modelRun(() => ({ model, real }), cmds);\n return Object.isFrozen(real.getSnapshot());\n } finally {\n real.dispose();\n }\n }),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #2 unknownEventNoOp — sending an event whose `type` is not declared in any\n * state's `on` map never changes the snapshot.\n */\nexport function unknownEventNoOp<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n unknownType: string,\n opts?: AssertOpts,\n): void {\n fc.assert(\n fc.property(fc.constant(unknownType), (t) => {\n const initial = initialSnapshot(def);\n const result = step(def, initial, { type: t } as unknown as Evt, impl);\n return result.changed === false && result.snapshot === initial && result.effects.length === 0;\n }),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #3 reachableStatesSubsetDeclared — every state visited during a run belongs\n * to `def.states`.\n */\nexport function reachableStatesSubsetDeclared<\n Ctx,\n Evt extends { type: string },\n States extends string,\n>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n const declared = new Set<string>(Object.keys(def.states));\n fc.assert(\n fc.property(commandsFromMachine(def, impl, eventArbitraries), (cmds) => {\n const real = createRuntime(def, impl, { dispatchEffects: false });\n try {\n const model: FsmModel<Ctx, States> = initialModel(def);\n fc.modelRun(() => ({ model, real }), cmds);\n for (const s of model.reached as Set<string>) {\n /* v8 ignore next — property failure branch; an unreachable state would indicate a bug. */\n if (!declared.has(s)) return false;\n }\n return declared.has(real.getSnapshot().value);\n } finally {\n real.dispose();\n }\n }),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #4 replayEqualsFold — `replay(initial, log)` produces the same final state\n * as a live runtime fed the same events. Effects dispatched by the runtime are\n * ignored; the comparison is on `{ value, context }`.\n */\nexport function replayEqualsFold<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n const eventArb = fc.oneof(...Object.values(eventArbitraries));\n fc.assert(\n fc.property(fc.array(eventArb, { maxLength: 32 }), (events) => {\n const real = createRuntime(def, impl, { dispatchEffects: false });\n try {\n for (const e of events) real.send(e);\n const live = real.getSnapshot();\n const replayed = replay(initialSnapshot(def), events, def, impl).snapshot;\n return live.value === replayed.value && contextEquals(live.context, replayed.context);\n } finally {\n real.dispose();\n }\n }),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * #5 guardsFalseNoTransition — when every candidate transition for the current\n * (state, event) pair carries a guard and every guard returns `false`, the\n * snapshot is unchanged (`changed === false`).\n *\n * Implementation: synthesise an impl that forces every guard to `false`, then\n * for each step whose candidate list is fully guarded, assert the step did not\n * change state. Steps with an unguarded fallback candidate (which fires even\n * when all guards are false) are skipped — the README claim is specifically\n * about the all-guards-false case.\n */\nexport function guardsFalseNoTransition<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n // Every key reads as an own property: step() resolves guard refs with an\n // own-key lookup (the value itself still comes from `get`), so a `get` trap\n // alone would surface as UnknownGuardError.\n const blockedGuards = new Proxy(\n {},\n {\n get: () => () => false,\n getOwnPropertyDescriptor: () => ({ configurable: true }),\n },\n ) as Readonly<Record<string, Guard<Ctx, Evt>>>;\n const blockedImpl: Implementations<Ctx, Evt> = {\n ...impl,\n guards: blockedGuards,\n };\n // True when every candidate transition for (value, eventType) carries a\n // guard — i.e. blocking all guards leaves no unconditional fallback, so a\n // correct step() must report changed === false.\n const isFullyGuarded = (value: States, eventType: string): boolean => {\n const candidates = normalizeTransitions(ownValue(def.states[value]?.on, eventType));\n return candidates.length > 0 && candidates.every((t) => t.guard !== undefined);\n };\n fc.assert(\n fc.property(\n fc.array(fc.oneof(...Object.values(eventArbitraries)), { maxLength: 16 }),\n (events) => {\n let snap = initialSnapshot(def);\n for (const e of events) {\n const fullyGuarded = isFullyGuarded(snap.value, e.type);\n const r = step(def, snap, e, blockedImpl);\n // The named invariant: all guards false + no unconditional fallback\n // ⇒ no transition. Without this assertion the property was vacuous\n // (it only failed if step() threw).\n if (fullyGuarded && r.changed !== false) return false;\n snap = r.snapshot;\n }\n return true;\n },\n ),\n buildAssertOpts(opts),\n );\n}\n\n// Own keys/values of one object, plus Map/Set entries and Date time.\nconst ownState = (v: object): unknown[] => [\n ...Reflect.ownKeys(v).flatMap((k) => [k, (v as Record<PropertyKey, unknown>)[k]]),\n ...(v instanceof Map || v instanceof Set ? [...v.entries()].flat() : []),\n v instanceof Date && v.getTime(),\n];\n\n/**\n * #6 assignDoesNotMutate — running an `assign`-style action never mutates the\n * previous context object. Verified by re-checking the own state of every\n * object reachable from the pre-step context.\n */\nexport function assignDoesNotMutate<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts,\n): void {\n fc.assert(\n fc.property(\n fc.array(fc.oneof(...Object.values(eventArbitraries)), { maxLength: 16 }),\n (events) => {\n let snap = initialSnapshot(def);\n for (const e of events) {\n // Record, not clone (clones drop prototypes, throw on functions).\n const before = new Map<object, unknown[]>();\n const walk = (v: unknown): void => {\n if (!v || typeof v !== \"object\" || before.has(v)) return;\n const own = ownState(v);\n before.set(v, own);\n own.forEach(walk);\n };\n walk(snap.context);\n // `before` keeps the pre-step objects, so advancing `snap` first is safe.\n snap = step(def, snap, e, impl).snapshot;\n for (const [obj, own] of before) if (!contextEquals(ownState(obj), own)) return false;\n }\n return true;\n },\n ),\n buildAssertOpts(opts),\n );\n}\n\n/**\n * Assert every generic property in one call. Use this when you don't need\n * fine-grained control over per-property options.\n */\nexport function assertAll<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n eventArbitraries: EventArbitraries<Evt>,\n opts?: AssertOpts & { unknownEventType?: string },\n): void {\n snapshotAlwaysFrozen(def, impl, eventArbitraries, opts);\n unknownEventNoOp(def, impl, opts?.unknownEventType ?? \"__AIFSMJS_UNKNOWN__\", opts);\n reachableStatesSubsetDeclared(def, impl, eventArbitraries, opts);\n replayEqualsFold(def, impl, eventArbitraries, opts);\n guardsFalseNoTransition(def, impl, eventArbitraries, opts);\n assignDoesNotMutate(def, impl, eventArbitraries, opts);\n}\n","export {\n commandsFromMachine,\n initialModel,\n type EventArbitraries,\n type FsmCommand,\n type FsmModel,\n} from \"./commands.js\";\n\nexport {\n assertAll,\n assignDoesNotMutate,\n guardsFalseNoTransition,\n reachableStatesSubsetDeclared,\n replayEqualsFold,\n snapshotAlwaysFrozen,\n unknownEventNoOp,\n type AssertOpts,\n} from \"./properties.js\";\n\n// Convenience namespace mirroring the README:\n// import { properties } from \"aifsmjs/pbt\"\n// properties.snapshotAlwaysFrozen(...)\n// A frozen object literal rather than `import * as`: a namespace re-export\n// makes tsup emit a shared `__export` helper chunk that every subpath entry\n// (root, guards, timer, ...) then imports and pays for.\nimport {\n assertAll,\n assignDoesNotMutate,\n contextEquals,\n guardsFalseNoTransition,\n reachableStatesSubsetDeclared,\n replayEqualsFold,\n snapshotAlwaysFrozen,\n unknownEventNoOp,\n} from \"./properties.js\";\nexport const properties = Object.freeze({\n assertAll,\n assignDoesNotMutate,\n contextEquals,\n guardsFalseNoTransition,\n reachableStatesSubsetDeclared,\n replayEqualsFold,\n snapshotAlwaysFrozen,\n unknownEventNoOp,\n});\n"]}
|
package/dist/pbt/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as fc from 'fast-check';
|
|
2
|
-
import { j as Runtime, f as MachineDef, I as Implementations } from '../types-
|
|
2
|
+
import { j as Runtime, f as MachineDef, I as Implementations } from '../types-CrDxFfBx.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Pure-model representation of an FSM run, used by `fc.commands`.
|
|
@@ -100,8 +100,8 @@ declare function guardsFalseNoTransition<Ctx, Evt extends {
|
|
|
100
100
|
}, States extends string>(def: MachineDef<Ctx, Evt, States>, impl: Implementations<Ctx, Evt>, eventArbitraries: EventArbitraries<Evt>, opts?: AssertOpts): void;
|
|
101
101
|
/**
|
|
102
102
|
* #6 assignDoesNotMutate — running an `assign`-style action never mutates the
|
|
103
|
-
* previous context object. Verified by
|
|
104
|
-
*
|
|
103
|
+
* previous context object. Verified by re-checking the own state of every
|
|
104
|
+
* object reachable from the pre-step context.
|
|
105
105
|
*/
|
|
106
106
|
declare function assignDoesNotMutate<Ctx, Evt extends {
|
|
107
107
|
type: string;
|
|
@@ -116,19 +116,15 @@ declare function assertAll<Ctx, Evt extends {
|
|
|
116
116
|
unknownEventType?: string;
|
|
117
117
|
}): void;
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
export { type propertiesModule_AssertOpts as AssertOpts, propertiesModule_assertAll as assertAll, propertiesModule_assignDoesNotMutate as assignDoesNotMutate, propertiesModule_contextEquals as contextEquals, propertiesModule_guardsFalseNoTransition as guardsFalseNoTransition, propertiesModule_reachableStatesSubsetDeclared as reachableStatesSubsetDeclared, propertiesModule_replayEqualsFold as replayEqualsFold, propertiesModule_snapshotAlwaysFrozen as snapshotAlwaysFrozen, propertiesModule_unknownEventNoOp as unknownEventNoOp };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
declare const properties: typeof propertiesModule;
|
|
119
|
+
declare const properties: Readonly<{
|
|
120
|
+
assertAll: typeof assertAll;
|
|
121
|
+
assignDoesNotMutate: typeof assignDoesNotMutate;
|
|
122
|
+
contextEquals: typeof contextEquals;
|
|
123
|
+
guardsFalseNoTransition: typeof guardsFalseNoTransition;
|
|
124
|
+
reachableStatesSubsetDeclared: typeof reachableStatesSubsetDeclared;
|
|
125
|
+
replayEqualsFold: typeof replayEqualsFold;
|
|
126
|
+
snapshotAlwaysFrozen: typeof snapshotAlwaysFrozen;
|
|
127
|
+
unknownEventNoOp: typeof unknownEventNoOp;
|
|
128
|
+
}>;
|
|
133
129
|
|
|
134
130
|
export { type AssertOpts, type EventArbitraries, type FsmCommand, type FsmModel, assertAll, assignDoesNotMutate, commandsFromMachine, guardsFalseNoTransition, initialModel, properties, reachableStatesSubsetDeclared, replayEqualsFold, snapshotAlwaysFrozen, unknownEventNoOp };
|
package/dist/pbt/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as fc from 'fast-check';
|
|
2
|
-
import { j as Runtime, f as MachineDef, I as Implementations } from '../types-
|
|
2
|
+
import { j as Runtime, f as MachineDef, I as Implementations } from '../types-CrDxFfBx.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Pure-model representation of an FSM run, used by `fc.commands`.
|
|
@@ -100,8 +100,8 @@ declare function guardsFalseNoTransition<Ctx, Evt extends {
|
|
|
100
100
|
}, States extends string>(def: MachineDef<Ctx, Evt, States>, impl: Implementations<Ctx, Evt>, eventArbitraries: EventArbitraries<Evt>, opts?: AssertOpts): void;
|
|
101
101
|
/**
|
|
102
102
|
* #6 assignDoesNotMutate — running an `assign`-style action never mutates the
|
|
103
|
-
* previous context object. Verified by
|
|
104
|
-
*
|
|
103
|
+
* previous context object. Verified by re-checking the own state of every
|
|
104
|
+
* object reachable from the pre-step context.
|
|
105
105
|
*/
|
|
106
106
|
declare function assignDoesNotMutate<Ctx, Evt extends {
|
|
107
107
|
type: string;
|
|
@@ -116,19 +116,15 @@ declare function assertAll<Ctx, Evt extends {
|
|
|
116
116
|
unknownEventType?: string;
|
|
117
117
|
}): void;
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
export { type propertiesModule_AssertOpts as AssertOpts, propertiesModule_assertAll as assertAll, propertiesModule_assignDoesNotMutate as assignDoesNotMutate, propertiesModule_contextEquals as contextEquals, propertiesModule_guardsFalseNoTransition as guardsFalseNoTransition, propertiesModule_reachableStatesSubsetDeclared as reachableStatesSubsetDeclared, propertiesModule_replayEqualsFold as replayEqualsFold, propertiesModule_snapshotAlwaysFrozen as snapshotAlwaysFrozen, propertiesModule_unknownEventNoOp as unknownEventNoOp };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
declare const properties: typeof propertiesModule;
|
|
119
|
+
declare const properties: Readonly<{
|
|
120
|
+
assertAll: typeof assertAll;
|
|
121
|
+
assignDoesNotMutate: typeof assignDoesNotMutate;
|
|
122
|
+
contextEquals: typeof contextEquals;
|
|
123
|
+
guardsFalseNoTransition: typeof guardsFalseNoTransition;
|
|
124
|
+
reachableStatesSubsetDeclared: typeof reachableStatesSubsetDeclared;
|
|
125
|
+
replayEqualsFold: typeof replayEqualsFold;
|
|
126
|
+
snapshotAlwaysFrozen: typeof snapshotAlwaysFrozen;
|
|
127
|
+
unknownEventNoOp: typeof unknownEventNoOp;
|
|
128
|
+
}>;
|
|
133
129
|
|
|
134
130
|
export { type AssertOpts, type EventArbitraries, type FsmCommand, type FsmModel, assertAll, assignDoesNotMutate, commandsFromMachine, guardsFalseNoTransition, initialModel, properties, reachableStatesSubsetDeclared, replayEqualsFold, snapshotAlwaysFrozen, unknownEventNoOp };
|
package/dist/pbt/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { createRuntime, initialSnapshot } from '../chunk-
|
|
2
|
-
import { replay } from '../chunk-
|
|
3
|
-
import { step,
|
|
1
|
+
import { createRuntime, initialSnapshot } from '../chunk-XA24A7VP.js';
|
|
2
|
+
import { replay } from '../chunk-Q45LGXHO.js';
|
|
3
|
+
import { step, normalizeTransitions } from '../chunk-D6H64FSI.js';
|
|
4
4
|
import '../chunk-JKZAOPQC.js';
|
|
5
|
-
import '../chunk-
|
|
6
|
-
import { __export } from '../chunk-PZ5AY32C.js';
|
|
5
|
+
import { ownValue } from '../chunk-SSNKGEVB.js';
|
|
7
6
|
import * as fc2 from 'fast-check';
|
|
8
7
|
import { isDeepStrictEqual } from 'util';
|
|
9
8
|
|
|
@@ -53,19 +52,6 @@ function commandsFromMachine(def, impl, eventArbitraries) {
|
|
|
53
52
|
}
|
|
54
53
|
return fc2.commands(arbs, { size: "+1" });
|
|
55
54
|
}
|
|
56
|
-
|
|
57
|
-
// src/pbt/properties.ts
|
|
58
|
-
var properties_exports = {};
|
|
59
|
-
__export(properties_exports, {
|
|
60
|
-
assertAll: () => assertAll,
|
|
61
|
-
assignDoesNotMutate: () => assignDoesNotMutate,
|
|
62
|
-
contextEquals: () => contextEquals,
|
|
63
|
-
guardsFalseNoTransition: () => guardsFalseNoTransition,
|
|
64
|
-
reachableStatesSubsetDeclared: () => reachableStatesSubsetDeclared,
|
|
65
|
-
replayEqualsFold: () => replayEqualsFold,
|
|
66
|
-
snapshotAlwaysFrozen: () => snapshotAlwaysFrozen,
|
|
67
|
-
unknownEventNoOp: () => unknownEventNoOp
|
|
68
|
-
});
|
|
69
55
|
function buildAssertOpts(opts) {
|
|
70
56
|
const out = {};
|
|
71
57
|
if (opts?.numRuns !== void 0) out.numRuns = opts.numRuns;
|
|
@@ -79,10 +65,14 @@ function contextEquals(a, b) {
|
|
|
79
65
|
function snapshotAlwaysFrozen(def, impl, eventArbitraries, opts) {
|
|
80
66
|
fc2.assert(
|
|
81
67
|
fc2.property(commandsFromMachine(def, impl, eventArbitraries), (cmds) => {
|
|
82
|
-
const real = createRuntime(def, impl);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
68
|
+
const real = createRuntime(def, impl, { dispatchEffects: false });
|
|
69
|
+
try {
|
|
70
|
+
const model = initialModel(def);
|
|
71
|
+
fc2.modelRun(() => ({ model, real }), cmds);
|
|
72
|
+
return Object.isFrozen(real.getSnapshot());
|
|
73
|
+
} finally {
|
|
74
|
+
real.dispose();
|
|
75
|
+
}
|
|
86
76
|
}),
|
|
87
77
|
buildAssertOpts(opts)
|
|
88
78
|
);
|
|
@@ -101,13 +91,17 @@ function reachableStatesSubsetDeclared(def, impl, eventArbitraries, opts) {
|
|
|
101
91
|
const declared = new Set(Object.keys(def.states));
|
|
102
92
|
fc2.assert(
|
|
103
93
|
fc2.property(commandsFromMachine(def, impl, eventArbitraries), (cmds) => {
|
|
104
|
-
const real = createRuntime(def, impl);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
94
|
+
const real = createRuntime(def, impl, { dispatchEffects: false });
|
|
95
|
+
try {
|
|
96
|
+
const model = initialModel(def);
|
|
97
|
+
fc2.modelRun(() => ({ model, real }), cmds);
|
|
98
|
+
for (const s of model.reached) {
|
|
99
|
+
if (!declared.has(s)) return false;
|
|
100
|
+
}
|
|
101
|
+
return declared.has(real.getSnapshot().value);
|
|
102
|
+
} finally {
|
|
103
|
+
real.dispose();
|
|
109
104
|
}
|
|
110
|
-
return declared.has(real.getSnapshot().value);
|
|
111
105
|
}),
|
|
112
106
|
buildAssertOpts(opts)
|
|
113
107
|
);
|
|
@@ -117,10 +111,14 @@ function replayEqualsFold(def, impl, eventArbitraries, opts) {
|
|
|
117
111
|
fc2.assert(
|
|
118
112
|
fc2.property(fc2.array(eventArb, { maxLength: 32 }), (events) => {
|
|
119
113
|
const real = createRuntime(def, impl, { dispatchEffects: false });
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
114
|
+
try {
|
|
115
|
+
for (const e of events) real.send(e);
|
|
116
|
+
const live = real.getSnapshot();
|
|
117
|
+
const replayed = replay(initialSnapshot(def), events, def, impl).snapshot;
|
|
118
|
+
return live.value === replayed.value && contextEquals(live.context, replayed.context);
|
|
119
|
+
} finally {
|
|
120
|
+
real.dispose();
|
|
121
|
+
}
|
|
124
122
|
}),
|
|
125
123
|
buildAssertOpts(opts)
|
|
126
124
|
);
|
|
@@ -129,7 +127,8 @@ function guardsFalseNoTransition(def, impl, eventArbitraries, opts) {
|
|
|
129
127
|
const blockedGuards = new Proxy(
|
|
130
128
|
{},
|
|
131
129
|
{
|
|
132
|
-
get: () => () => false
|
|
130
|
+
get: () => () => false,
|
|
131
|
+
getOwnPropertyDescriptor: () => ({ configurable: true })
|
|
133
132
|
}
|
|
134
133
|
);
|
|
135
134
|
const blockedImpl = {
|
|
@@ -137,7 +136,7 @@ function guardsFalseNoTransition(def, impl, eventArbitraries, opts) {
|
|
|
137
136
|
guards: blockedGuards
|
|
138
137
|
};
|
|
139
138
|
const isFullyGuarded = (value, eventType) => {
|
|
140
|
-
const candidates = normalizeTransitions(def.states[value]?.on
|
|
139
|
+
const candidates = normalizeTransitions(ownValue(def.states[value]?.on, eventType));
|
|
141
140
|
return candidates.length > 0 && candidates.every((t) => t.guard !== void 0);
|
|
142
141
|
};
|
|
143
142
|
fc2.assert(
|
|
@@ -157,20 +156,28 @@ function guardsFalseNoTransition(def, impl, eventArbitraries, opts) {
|
|
|
157
156
|
buildAssertOpts(opts)
|
|
158
157
|
);
|
|
159
158
|
}
|
|
159
|
+
var ownState = (v) => [
|
|
160
|
+
...Reflect.ownKeys(v).flatMap((k) => [k, v[k]]),
|
|
161
|
+
...v instanceof Map || v instanceof Set ? [...v.entries()].flat() : [],
|
|
162
|
+
v instanceof Date && v.getTime()
|
|
163
|
+
];
|
|
160
164
|
function assignDoesNotMutate(def, impl, eventArbitraries, opts) {
|
|
161
|
-
const dummy = { a: 1, b: 2 };
|
|
162
|
-
const merged = mergeContext(dummy, { b: 3 });
|
|
163
|
-
if (merged === dummy) throw new Error("aifsmjs/pbt: mergeContext returned the same reference");
|
|
164
165
|
fc2.assert(
|
|
165
166
|
fc2.property(
|
|
166
167
|
fc2.array(fc2.oneof(...Object.values(eventArbitraries)), { maxLength: 16 }),
|
|
167
168
|
(events) => {
|
|
168
169
|
let snap = initialSnapshot(def);
|
|
169
170
|
for (const e of events) {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
const before = /* @__PURE__ */ new Map();
|
|
172
|
+
const walk = (v) => {
|
|
173
|
+
if (!v || typeof v !== "object" || before.has(v)) return;
|
|
174
|
+
const own = ownState(v);
|
|
175
|
+
before.set(v, own);
|
|
176
|
+
own.forEach(walk);
|
|
177
|
+
};
|
|
178
|
+
walk(snap.context);
|
|
173
179
|
snap = step(def, snap, e, impl).snapshot;
|
|
180
|
+
for (const [obj, own] of before) if (!contextEquals(ownState(obj), own)) return false;
|
|
174
181
|
}
|
|
175
182
|
return true;
|
|
176
183
|
}
|
|
@@ -188,7 +195,16 @@ function assertAll(def, impl, eventArbitraries, opts) {
|
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
// src/pbt/index.ts
|
|
191
|
-
var properties =
|
|
198
|
+
var properties = Object.freeze({
|
|
199
|
+
assertAll,
|
|
200
|
+
assignDoesNotMutate,
|
|
201
|
+
contextEquals,
|
|
202
|
+
guardsFalseNoTransition,
|
|
203
|
+
reachableStatesSubsetDeclared,
|
|
204
|
+
replayEqualsFold,
|
|
205
|
+
snapshotAlwaysFrozen,
|
|
206
|
+
unknownEventNoOp
|
|
207
|
+
});
|
|
192
208
|
|
|
193
209
|
export { assertAll, assignDoesNotMutate, commandsFromMachine, guardsFalseNoTransition, initialModel, properties, reachableStatesSubsetDeclared, replayEqualsFold, snapshotAlwaysFrozen, unknownEventNoOp };
|
|
194
210
|
//# sourceMappingURL=index.js.map
|