@loomwork/compiler 0.0.0-stage → 0.1.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.
Files changed (59) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +62 -2
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +81 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/hash.d.ts +3 -0
  9. package/dist/hash.d.ts.map +1 -0
  10. package/dist/hash.js +16 -0
  11. package/dist/hash.js.map +1 -0
  12. package/dist/importResolve.d.ts +5 -0
  13. package/dist/importResolve.d.ts.map +1 -0
  14. package/dist/importResolve.js +130 -0
  15. package/dist/importResolve.js.map +1 -0
  16. package/dist/index.d.ts +14 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +26 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/loopIdentity.d.ts +18 -0
  21. package/dist/loopIdentity.d.ts.map +1 -0
  22. package/dist/loopIdentity.js +179 -0
  23. package/dist/loopIdentity.js.map +1 -0
  24. package/dist/manifest.d.ts +98 -0
  25. package/dist/manifest.d.ts.map +1 -0
  26. package/dist/manifest.js +123 -0
  27. package/dist/manifest.js.map +1 -0
  28. package/dist/nondeterminism.d.ts +25 -0
  29. package/dist/nondeterminism.d.ts.map +1 -0
  30. package/dist/nondeterminism.js +88 -0
  31. package/dist/nondeterminism.js.map +1 -0
  32. package/dist/plugin.d.ts +3 -0
  33. package/dist/plugin.d.ts.map +1 -0
  34. package/dist/plugin.js +71 -0
  35. package/dist/plugin.js.map +1 -0
  36. package/dist/runnerReach.d.ts +136 -0
  37. package/dist/runnerReach.d.ts.map +1 -0
  38. package/dist/runnerReach.js +1809 -0
  39. package/dist/runnerReach.js.map +1 -0
  40. package/dist/transform.d.ts +6 -0
  41. package/dist/transform.d.ts.map +1 -0
  42. package/dist/transform.js +416 -0
  43. package/dist/transform.js.map +1 -0
  44. package/dist/types.d.ts +73 -0
  45. package/dist/types.d.ts.map +1 -0
  46. package/dist/types.js +3 -0
  47. package/dist/types.js.map +1 -0
  48. package/package.json +64 -3
  49. package/src/cli.ts +90 -0
  50. package/src/hash.ts +12 -0
  51. package/src/importResolve.ts +133 -0
  52. package/src/index.ts +23 -0
  53. package/src/loopIdentity.ts +210 -0
  54. package/src/manifest.ts +185 -0
  55. package/src/nondeterminism.ts +133 -0
  56. package/src/plugin.ts +74 -0
  57. package/src/runnerReach.ts +1964 -0
  58. package/src/transform.ts +523 -0
  59. package/src/types.ts +79 -0
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.analyzeLoopIdentityNode = analyzeLoopIdentityNode;
7
+ exports.analyzeLoopIdentity = analyzeLoopIdentity;
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ const CALLBACK_LOOPS = new Set(["map", "forEach", "flatMap"]);
10
+ function isRunOrExecuteCall(node) {
11
+ if (!typescript_1.default.isCallExpression(node))
12
+ return false;
13
+ const e = node.expression;
14
+ return (typescript_1.default.isPropertyAccessExpression(e) &&
15
+ typescript_1.default.isIdentifier(e.name) &&
16
+ (e.name.text === "run" || e.name.text === "execute"));
17
+ }
18
+ /** Collect binding names a loop scope introduces or mutates (iteration-varying names). */
19
+ function collectLoopBindings(loop, body) {
20
+ const names = new Set();
21
+ const addDeclarationList = (list) => {
22
+ if (list !== undefined && typescript_1.default.isVariableDeclarationList(list)) {
23
+ for (const d of list.declarations)
24
+ collectBoundNames(d.name, names);
25
+ }
26
+ };
27
+ if (typescript_1.default.isForStatement(loop))
28
+ addDeclarationList(loop.initializer);
29
+ if (typescript_1.default.isForOfStatement(loop) || typescript_1.default.isForInStatement(loop))
30
+ addDeclarationList(loop.initializer);
31
+ // Counters mutated inside the body (`i++`, `i += 1`, `i = i + 1`) vary per
32
+ // iteration even when declared outside the loop (the `while` idiom).
33
+ const scanMutations = (node) => {
34
+ if ((typescript_1.default.isPostfixUnaryExpression(node) || typescript_1.default.isPrefixUnaryExpression(node)) &&
35
+ (node.operator === typescript_1.default.SyntaxKind.PlusPlusToken ||
36
+ node.operator === typescript_1.default.SyntaxKind.MinusMinusToken) &&
37
+ typescript_1.default.isIdentifier(node.operand)) {
38
+ names.add(node.operand.text);
39
+ }
40
+ else if (typescript_1.default.isBinaryExpression(node) &&
41
+ node.operatorToken.kind >= typescript_1.default.SyntaxKind.FirstAssignment &&
42
+ node.operatorToken.kind <= typescript_1.default.SyntaxKind.LastAssignment &&
43
+ typescript_1.default.isIdentifier(node.left)) {
44
+ names.add(node.left.text);
45
+ }
46
+ typescript_1.default.forEachChild(node, scanMutations);
47
+ };
48
+ scanMutations(body);
49
+ return names;
50
+ }
51
+ /** Add every identifier bound by a (possibly destructuring) binding name. */
52
+ function collectBoundNames(name, into) {
53
+ if (typescript_1.default.isIdentifier(name)) {
54
+ into.add(name.text);
55
+ return;
56
+ }
57
+ for (const element of name.elements) {
58
+ if (typescript_1.default.isBindingElement(element))
59
+ collectBoundNames(element.name, into);
60
+ }
61
+ }
62
+ /** True if the subtree references any of the given names as a VALUE (not a property name). */
63
+ function referencesAny(node, names) {
64
+ let found = false;
65
+ const visit = (n) => {
66
+ if (found)
67
+ return;
68
+ if (typescript_1.default.isIdentifier(n) && names.has(n.text)) {
69
+ const parent = n.parent;
70
+ // `obj.i` — the `.i` name position is not a reference to the loop variable.
71
+ const isPropertyNamePosition = (typescript_1.default.isPropertyAccessExpression(parent) && parent.name === n) ||
72
+ (typescript_1.default.isPropertyAssignment(parent) && parent.name === n);
73
+ if (!isPropertyNamePosition) {
74
+ found = true;
75
+ return;
76
+ }
77
+ }
78
+ typescript_1.default.forEachChild(n, visit);
79
+ };
80
+ visit(node);
81
+ return found;
82
+ }
83
+ /** A `.map`/`.forEach`/`.flatMap` call whose first argument is a function — treat as a loop. */
84
+ function callbackLoop(node) {
85
+ if (!typescript_1.default.isCallExpression(node))
86
+ return undefined;
87
+ const e = node.expression;
88
+ if (!typescript_1.default.isPropertyAccessExpression(e) || !typescript_1.default.isIdentifier(e.name))
89
+ return undefined;
90
+ if (!CALLBACK_LOOPS.has(e.name.text))
91
+ return undefined;
92
+ const cb = node.arguments[0];
93
+ if (cb === undefined || (!typescript_1.default.isArrowFunction(cb) && !typescript_1.default.isFunctionExpression(cb))) {
94
+ return undefined;
95
+ }
96
+ const params = new Set();
97
+ for (const p of cb.parameters)
98
+ collectBoundNames(p.name, params);
99
+ return { body: cb.body, params, kind: `.${e.name.text}()` };
100
+ }
101
+ /** Analyze a parsed node (a flow runner / orchestration body) for loop-identity hazards. */
102
+ function analyzeLoopIdentityNode(root, location) {
103
+ const findings = [];
104
+ // Stack of active loop scopes; bindings accumulate (an id derived from ANY
105
+ // enclosing loop's variable is accepted — the nested-loop case is documented
106
+ // as out of scope for the heuristic).
107
+ const loopStack = [];
108
+ const classify = (call) => {
109
+ if (loopStack.length === 0)
110
+ return;
111
+ const step = call.arguments[0];
112
+ if (step === undefined)
113
+ return;
114
+ const callee = call.expression.name.text;
115
+ const loopKind = loopStack[loopStack.length - 1].kind;
116
+ if (typescript_1.default.isIdentifier(step) || typescript_1.default.isPropertyAccessExpression(step)) {
117
+ // A static StepDefinition reference — its id is fixed across iterations.
118
+ findings.push({
119
+ callee,
120
+ loopKind,
121
+ reason: "static-step-in-loop",
122
+ ...(location !== undefined && { location }),
123
+ });
124
+ return;
125
+ }
126
+ if (typescript_1.default.isCallExpression(step) || typescript_1.default.isObjectLiteralExpression(step)) {
127
+ const union = new Set();
128
+ for (const scope of loopStack)
129
+ for (const n of scope.bindings)
130
+ union.add(n);
131
+ if (!referencesAny(step, union)) {
132
+ findings.push({
133
+ callee,
134
+ loopKind,
135
+ reason: "id-not-derived-from-loop-variable",
136
+ ...(location !== undefined && { location }),
137
+ });
138
+ }
139
+ return;
140
+ }
141
+ // Anything else (conditional, array index, helper-derived) — stay quiet.
142
+ };
143
+ const visit = (node) => {
144
+ if (isRunOrExecuteCall(node))
145
+ classify(node);
146
+ if (typescript_1.default.isIterationStatement(node, false)) {
147
+ const body = node.statement;
148
+ loopStack.push({
149
+ kind: typescript_1.default.SyntaxKind[node.kind],
150
+ bindings: collectLoopBindings(node, body),
151
+ });
152
+ typescript_1.default.forEachChild(node, visit);
153
+ loopStack.pop();
154
+ return;
155
+ }
156
+ const cb = callbackLoop(node);
157
+ if (cb !== undefined) {
158
+ // Visit the receiver/arguments outside the loop scope, then the callback
159
+ // body inside it.
160
+ loopStack.push({ kind: cb.kind, bindings: cb.params });
161
+ visit(cb.body);
162
+ loopStack.pop();
163
+ return;
164
+ }
165
+ typescript_1.default.forEachChild(node, visit);
166
+ };
167
+ visit(root);
168
+ return findings;
169
+ }
170
+ /**
171
+ * Analyze a source string (a flow runner / orchestration body) for `ctx.run`/
172
+ * `ctx.execute` calls inside loops whose step id cannot vary per iteration
173
+ * (ADR 0061). Feed the result to `@loomwork/verify` via `FlowSpec.loopIdentityCalls`.
174
+ */
175
+ function analyzeLoopIdentity(source, location) {
176
+ const sf = typescript_1.default.createSourceFile("loopid.ts", source, typescript_1.default.ScriptTarget.ESNext, true);
177
+ return analyzeLoopIdentityNode(sf, location);
178
+ }
179
+ //# sourceMappingURL=loopIdentity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopIdentity.js","sourceRoot":"","sources":["../src/loopIdentity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ import type { PluginState } from "./types";
2
+ /** The compiler manifest schema version (not semver — a monotonic integer string). */
3
+ export declare const COMPILER_MANIFEST_VERSION = "1";
4
+ export interface ManifestFlow {
5
+ version: string;
6
+ steps: string[];
7
+ chunkMap: Record<string, string>;
8
+ suspendPoints: string[];
9
+ warnings: string[];
10
+ /**
11
+ * ADR 0061 — structured loop step-identity findings for this flow's module
12
+ * (also rendered into `warnings`). Feed to `@loomwork/verify` via
13
+ * `FlowSpec.loopIdentityCalls`; additive manifest field.
14
+ */
15
+ loopIdentity?: Array<{
16
+ callee: string;
17
+ loopKind: string;
18
+ reason: string;
19
+ location?: string;
20
+ }>;
21
+ /**
22
+ * Issue #82 — non-deterministic calls in this flow's module, and whether each
23
+ * sits inside a `ctx.decide`/`ctx.execute` boundary. Feed to `@loomwork/verify`
24
+ * via `FlowSpec.nonDeterministicCalls`; additive manifest field.
25
+ */
26
+ nonDeterministic?: Array<{
27
+ callee: string;
28
+ insideDecide: boolean;
29
+ location?: string;
30
+ }>;
31
+ /**
32
+ * ADR 0086 — runner-body reach: resolved `ctx.run` targets, `ctx.suspend`
33
+ * conditions, and the targets analysis could NOT resolve. Feeds
34
+ * `FlowSpec.effects` / `suspends` / `unresolvedReach`, which is what lets
35
+ * capability-compat, effect-class and suspension-safety see past the flow's
36
+ * DECLARED steps — and state their own coverage when they cannot.
37
+ */
38
+ runnerReach?: {
39
+ steps: Array<{
40
+ stepId?: string;
41
+ toolId: string;
42
+ viaDecider?: boolean;
43
+ }>;
44
+ unresolved: Array<{
45
+ expr: string;
46
+ kind: "step" | "suspend";
47
+ location?: string;
48
+ }>;
49
+ suspends: Array<{
50
+ id?: string;
51
+ correlationKey?: string;
52
+ timed?: boolean;
53
+ wakeAt?: boolean;
54
+ }>;
55
+ /** L32 — `ctx` (or `ctx.decide`) handed to out-of-module callees; resolved against `verify.reach`. */
56
+ escapes?: Array<{
57
+ callee: string;
58
+ root?: string;
59
+ via: "ctx" | "decide";
60
+ member?: string;
61
+ /** L34 — the hand-off's arguments that resolve to a step, by position. */
62
+ args?: Array<{
63
+ index: number;
64
+ step: {
65
+ stepId?: string;
66
+ toolId: string;
67
+ };
68
+ }>;
69
+ location?: string;
70
+ }>;
71
+ };
72
+ /**
73
+ * The source module that declared this flow (relative to the project root).
74
+ * Enables tooling and `@loomwork/app`'s manifest cross-check to know where a flow
75
+ * lives. Registration itself stays a static import (see `registerFlowsFrom`) —
76
+ * this is metadata, never a dynamic-import target, so wiring stays
77
+ * deterministic/replay-safe.
78
+ */
79
+ module: string;
80
+ }
81
+ export interface ManifestSkill {
82
+ chunk: string;
83
+ }
84
+ export interface ManifestProjection {
85
+ eventTypes: string[];
86
+ chunk: string;
87
+ }
88
+ export interface LoomManifest {
89
+ version: "1";
90
+ flows: Record<string, ManifestFlow>;
91
+ skills: Record<string, ManifestSkill>;
92
+ projections: Record<string, ManifestProjection>;
93
+ /** Deduplicated, sorted list of source modules that declare flows. */
94
+ flowModules: string[];
95
+ }
96
+ export declare function buildManifest(state: PluginState, outDir?: string, root?: string): LoomManifest;
97
+ export declare function printWarnings(manifest: LoomManifest): void;
98
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.COMPILER_MANIFEST_VERSION = void 0;
37
+ exports.buildManifest = buildManifest;
38
+ exports.printWarnings = printWarnings;
39
+ const path = __importStar(require("node:path"));
40
+ /** The compiler manifest schema version (not semver — a monotonic integer string). */
41
+ exports.COMPILER_MANIFEST_VERSION = "1";
42
+ function relModule(sourceFile, root) {
43
+ if (!sourceFile)
44
+ return sourceFile;
45
+ const rel = path.isAbsolute(sourceFile) ? path.relative(root, sourceFile) : sourceFile;
46
+ return rel.split(path.sep).join("/");
47
+ }
48
+ function buildManifest(state, outDir = ".", root = process.cwd()) {
49
+ const flows = {};
50
+ const skills = {};
51
+ const flowModuleSet = new Set();
52
+ for (const [flowId, flow] of state.flows) {
53
+ const chunkMap = {};
54
+ const warnings = [];
55
+ for (const stepId of flow.stepIds) {
56
+ const step = state.steps.get(stepId);
57
+ if (!step) {
58
+ warnings.push(`Step "${stepId}" is referenced in flow "${flowId}" but not found in analysis.`);
59
+ continue;
60
+ }
61
+ if (step.chunkVirtualId !== undefined) {
62
+ const fileName = `chunks/${stepId}_${step.hash}.js`;
63
+ chunkMap[stepId] = `${outDir}/${fileName}`;
64
+ }
65
+ else if (!step.toolId) {
66
+ warnings.push(`Step "${stepId}" in flow "${flowId}" has neither a handler$ nor a toolId — it must be registered manually. (Steps minted dynamically in the runner body — the interpreter pattern — should instead bind a static toolId to a registered effect and derive ids as \`\${id}#\${index}\`; see ADR 0061.)`);
67
+ }
68
+ }
69
+ // ADR 0061 — surface loop step-identity findings as warnings (rendered) AND
70
+ // structurally (for @loomwork/verify's determinism rule via loopIdentityCalls).
71
+ for (const f of flow.loopIdentityFindings ?? []) {
72
+ warnings.push(`Flow "${flowId}": ctx.${f.callee} inside ${f.loopKind} uses a step id that cannot vary per iteration (${f.reason}) — frames are keyed by id, so later iterations replay iteration 0's output. Mint \`\${id}#\${index}\` (ADR 0061).`);
73
+ }
74
+ const module = relModule(flow.sourceFile, root);
75
+ if (module)
76
+ flowModuleSet.add(module);
77
+ flows[flowId] = {
78
+ version: flow.version,
79
+ steps: flow.stepIds,
80
+ chunkMap,
81
+ suspendPoints: flow.suspendPoints,
82
+ warnings,
83
+ module,
84
+ ...(flow.loopIdentityFindings !== undefined &&
85
+ flow.loopIdentityFindings.length > 0 && { loopIdentity: flow.loopIdentityFindings }),
86
+ ...(flow.nonDeterministicCalls !== undefined &&
87
+ flow.nonDeterministicCalls.length > 0 && { nonDeterministic: flow.nonDeterministicCalls }),
88
+ ...(flow.runnerReach !== undefined && { runnerReach: flow.runnerReach }),
89
+ };
90
+ }
91
+ for (const [skillId, skill] of state.skills) {
92
+ skills[skillId] = {
93
+ chunk: skill.chunkVirtualId ? `${outDir}/chunks/${skillId}_${skill.hash}.js` : "",
94
+ };
95
+ }
96
+ const projections = {};
97
+ for (const [projectionId, projection] of state.projections) {
98
+ projections[projectionId] = {
99
+ eventTypes: projection.eventTypes,
100
+ chunk: projection.chunkVirtualId
101
+ ? `${outDir}/chunks/${projectionId}_${projection.hash}.js`
102
+ : "",
103
+ };
104
+ }
105
+ return {
106
+ version: exports.COMPILER_MANIFEST_VERSION,
107
+ flows,
108
+ skills,
109
+ projections,
110
+ flowModules: [...flowModuleSet].sort(),
111
+ };
112
+ }
113
+ function printWarnings(manifest) {
114
+ for (const [flowId, flow] of Object.entries(manifest.flows)) {
115
+ for (const warning of flow.warnings) {
116
+ console.warn(`[loom-compiler] ⚠ ${warning}`);
117
+ }
118
+ if (flow.warnings.length === 0) {
119
+ console.info(`[loom-compiler] ✓ flow "${flowId}" — ${flow.steps.length} step(s), ${Object.keys(flow.chunkMap).length} lazy chunk(s)`);
120
+ }
121
+ }
122
+ }
123
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import ts from "typescript";
2
+ export interface NonDeterministicCall {
3
+ callee: string;
4
+ /** True if the call is inside a `ctx.decide`/`ctx.execute` call (its result is logged). */
5
+ insideDecide: boolean;
6
+ location?: string;
7
+ }
8
+ export interface AnalyzeOptions {
9
+ /**
10
+ * Skip `handler$(...)` bodies. Required when analyzing a whole MODULE rather
11
+ * than an isolated runner: a flow module contains both, and reporting a
12
+ * handler's `Math.random` is a false positive — which is precisely the
13
+ * distinction this file's header describes, and precisely what a caller
14
+ * feeding it whole modules will otherwise get wrong.
15
+ */
16
+ skipMemoized?: boolean;
17
+ }
18
+ /** Analyze a parsed node (a function/body) for non-deterministic calls. */
19
+ export declare function analyzeNode(root: ts.Node, location?: string, options?: AnalyzeOptions): NonDeterministicCall[];
20
+ /**
21
+ * Analyze a source string (e.g. a flow runner / orchestration body) for non-deterministic
22
+ * calls. Feed the result to `@loomwork/verify` via `resolveVerifyInput({ nonDeterministicByFlow })`.
23
+ */
24
+ export declare function analyzeNonDeterminism(source: string, location?: string, options?: AnalyzeOptions): NonDeterministicCall[];
25
+ //# sourceMappingURL=nondeterminism.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nondeterminism.d.ts","sourceRoot":"","sources":["../src/nondeterminism.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAgB5B,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAkDD,MAAM,WAAW,cAAc;IAC7B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,GAAE,cAAmB,GAC3B,oBAAoB,EAAE,CAgCxB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,GAAE,cAAmB,GAC3B,oBAAoB,EAAE,CAGxB"}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.analyzeNode = analyzeNode;
7
+ exports.analyzeNonDeterminism = analyzeNonDeterminism;
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ /** Member calls whose result is non-deterministic (object.method form). */
10
+ const NON_DET_MEMBER_CALLS = new Set([
11
+ "Date.now",
12
+ "Math.random",
13
+ "crypto.randomUUID",
14
+ "crypto.getRandomValues",
15
+ "performance.now",
16
+ ]);
17
+ /** Bare (identifier) calls that are non-deterministic / side-effectful. */
18
+ const NON_DET_BARE_CALLS = new Set(["fetch"]);
19
+ function calleeName(node) {
20
+ const e = node.expression;
21
+ if (typescript_1.default.isIdentifier(e))
22
+ return e.text;
23
+ if (typescript_1.default.isPropertyAccessExpression(e) &&
24
+ typescript_1.default.isIdentifier(e.name) &&
25
+ typescript_1.default.isIdentifier(e.expression)) {
26
+ return `${e.expression.text}.${e.name.text}`;
27
+ }
28
+ return undefined;
29
+ }
30
+ /** A `ctx.decide(...)`/`ctx.execute(...)`-shaped call (any receiver, method name decide/execute). */
31
+ function isDecideBoundary(node) {
32
+ if (!typescript_1.default.isCallExpression(node))
33
+ return false;
34
+ const e = node.expression;
35
+ return (typescript_1.default.isPropertyAccessExpression(e) &&
36
+ typescript_1.default.isIdentifier(e.name) &&
37
+ (e.name.text === "decide" || e.name.text === "execute"));
38
+ }
39
+ /**
40
+ * A `handler$(...)` call — a MEMOIZED region. Its result is written to
41
+ * STEP_COMPLETED and served from the log on replay, so `Math.random()` inside
42
+ * one is safe by construction; the same call in a runner diverges the fold.
43
+ */
44
+ function isMemoizedBoundary(node) {
45
+ return (typescript_1.default.isCallExpression(node) &&
46
+ typescript_1.default.isIdentifier(node.expression) &&
47
+ node.expression.text === "handler$");
48
+ }
49
+ /** Analyze a parsed node (a function/body) for non-deterministic calls. */
50
+ function analyzeNode(root, location, options = {}) {
51
+ const calls = [];
52
+ const ancestors = [];
53
+ function record(callee) {
54
+ const insideDecide = ancestors.some(isDecideBoundary);
55
+ calls.push({ callee, insideDecide, ...(location !== undefined && { location }) });
56
+ }
57
+ function visit(node) {
58
+ if (options.skipMemoized === true && isMemoizedBoundary(node))
59
+ return;
60
+ ancestors.push(node);
61
+ if (typescript_1.default.isCallExpression(node)) {
62
+ const name = calleeName(node);
63
+ if (name !== undefined && (NON_DET_MEMBER_CALLS.has(name) || NON_DET_BARE_CALLS.has(name))) {
64
+ record(name);
65
+ }
66
+ }
67
+ else if (typescript_1.default.isNewExpression(node) &&
68
+ typescript_1.default.isIdentifier(node.expression) &&
69
+ node.expression.text === "Date" &&
70
+ (node.arguments === undefined || node.arguments.length === 0)) {
71
+ // `new Date()` with no args reads the current time.
72
+ record("new Date");
73
+ }
74
+ typescript_1.default.forEachChild(node, visit);
75
+ ancestors.pop();
76
+ }
77
+ visit(root);
78
+ return calls;
79
+ }
80
+ /**
81
+ * Analyze a source string (e.g. a flow runner / orchestration body) for non-deterministic
82
+ * calls. Feed the result to `@loomwork/verify` via `resolveVerifyInput({ nonDeterministicByFlow })`.
83
+ */
84
+ function analyzeNonDeterminism(source, location, options = {}) {
85
+ const sf = typescript_1.default.createSourceFile("nondet.ts", source, typescript_1.default.ScriptTarget.ESNext, true);
86
+ return analyzeNode(sf, location, options);
87
+ }
88
+ //# sourceMappingURL=nondeterminism.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nondeterminism.js","sourceRoot":"","sources":["../src/nondeterminism.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from "vite";
2
+ export declare function loomPlugin(): Plugin;
3
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAC;AAOnD,wBAAgB,UAAU,IAAI,MAAM,CAgEnC"}
package/dist/plugin.js ADDED
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loomPlugin = loomPlugin;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ const manifest_1 = require("./manifest");
10
+ const transform_1 = require("./transform");
11
+ const VIRTUAL_PREFIX = "\0loom:chunk:";
12
+ function loomPlugin() {
13
+ const state = {
14
+ chunks: new Map(),
15
+ steps: new Map(),
16
+ stepsByVarName: new Map(),
17
+ flows: new Map(),
18
+ skills: new Map(),
19
+ skillsByVarName: new Map(),
20
+ projections: new Map(),
21
+ };
22
+ let resolvedConfig;
23
+ return {
24
+ name: "loom",
25
+ enforce: "pre",
26
+ configResolved(config) {
27
+ resolvedConfig = config;
28
+ },
29
+ resolveId(id) {
30
+ if (id.startsWith(VIRTUAL_PREFIX) || id.startsWith("\0loom:")) {
31
+ return id;
32
+ }
33
+ return undefined;
34
+ },
35
+ load(id) {
36
+ if (id.startsWith(VIRTUAL_PREFIX)) {
37
+ const chunk = state.chunks.get(id);
38
+ if (chunk) {
39
+ // Transpile TS → JS so Vite/Rollup can parse the chunk (no .ts extension on virtual ids)
40
+ const result = typescript_1.default.transpileModule(chunk.chunkSource, {
41
+ compilerOptions: {
42
+ target: typescript_1.default.ScriptTarget.ESNext,
43
+ module: typescript_1.default.ModuleKind.ESNext,
44
+ },
45
+ });
46
+ return { code: result.outputText };
47
+ }
48
+ }
49
+ return undefined;
50
+ },
51
+ transform(code, id) {
52
+ if (!/\.[jt]sx?$/.test(id) || id.includes("node_modules"))
53
+ return undefined;
54
+ const result = (0, transform_1.transformFile)(code, id, state);
55
+ if (!result)
56
+ return undefined;
57
+ return { code: result.code, map: result.map };
58
+ },
59
+ generateBundle() {
60
+ const outDir = resolvedConfig?.build?.outDir ?? "dist";
61
+ const manifest = (0, manifest_1.buildManifest)(state, node_path_1.default.relative(process.cwd(), outDir));
62
+ (0, manifest_1.printWarnings)(manifest);
63
+ this.emitFile({
64
+ type: "asset",
65
+ fileName: "loom-manifest.json",
66
+ source: JSON.stringify(manifest, null, 2),
67
+ });
68
+ },
69
+ };
70
+ }
71
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";;;;;AASA,gCAgEC;AAzED,0DAA6B;AAC7B,4DAA4B;AAE5B,yCAA0D;AAC1D,2CAA4C;AAG5C,MAAM,cAAc,GAAG,eAAe,CAAC;AAEvC,SAAgB,UAAU;IACxB,MAAM,KAAK,GAAgB;QACzB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,cAAc,EAAE,IAAI,GAAG,EAAE;QACzB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,eAAe,EAAE,IAAI,GAAG,EAAE;QAC1B,WAAW,EAAE,IAAI,GAAG,EAAE;KACvB,CAAC;IAEF,IAAI,cAA8B,CAAC;IAEnC,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,KAAK;QAEd,cAAc,CAAC,MAAM;YACnB,cAAc,GAAG,MAAM,CAAC;QAC1B,CAAC;QAED,SAAS,CAAC,EAAE;YACV,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC9D,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,EAAE;YACL,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;gBAClC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACnC,IAAI,KAAK,EAAE,CAAC;oBACV,yFAAyF;oBACzF,MAAM,MAAM,GAAG,oBAAE,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,EAAE;wBACnD,eAAe,EAAE;4BACf,MAAM,EAAE,oBAAE,CAAC,YAAY,CAAC,MAAM;4BAC9B,MAAM,EAAE,oBAAE,CAAC,UAAU,CAAC,MAAM;yBAC7B;qBACF,CAAC,CAAC;oBACH,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;gBACrC,CAAC;YACH,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,SAAS,CAAC,IAAI,EAAE,EAAE;YAChB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;gBAAE,OAAO,SAAS,CAAC;YAC5E,MAAM,MAAM,GAAG,IAAA,yBAAa,EAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAC;YAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;QAChD,CAAC;QAED,cAAc;YACZ,MAAM,MAAM,GAAG,cAAc,EAAE,KAAK,EAAE,MAAM,IAAI,MAAM,CAAC;YACvD,MAAM,QAAQ,GAAG,IAAA,wBAAa,EAAC,KAAK,EAAE,mBAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;YAC5E,IAAA,wBAAa,EAAC,QAAQ,CAAC,CAAC;YAExB,IAAI,CAAC,QAAQ,CAAC;gBACZ,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,oBAAoB;gBAC9B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;aAC1C,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}