@acpus/core 0.3.0 → 0.3.1

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,466 @@
1
+ import { COMPOSITE_CONTRACTS } from "./composite-contract.js";
2
+ import { EXPRESSION_PATTERN } from "./expressions-shared.js";
3
+ import { extractReferences, isStaticReference, referenceToString } from "./cel-ast.js";
4
+ /** Scope-gated local roots: valid only inside the composite that introduces them. */
5
+ const SCOPED_LOCAL_ROOTS = new Set(["loop", "item", "item_id", "item_index"]);
6
+ export function validateScopedExpressions(input) {
7
+ const { root, inputSchema, outputs, agents, allStepIds, diagnostics } = input;
8
+ const globalNodes = new Map();
9
+ indexNodes(root, globalNodes);
10
+ const r = { globalNodes, inputSchema, allStepIds, diagnostics };
11
+ // The implicit root pipeline threads its children sequentially.
12
+ walkChildScope(root, new Set(), [], undefined, r);
13
+ // outputs / agents are top-scope template positions evaluated after the
14
+ // workflow body, so every step id is visible; we keep visibility global there
15
+ // to avoid false positives while still validating field paths.
16
+ const topScope = (path) => ({
17
+ visibleSteps: allStepIds,
18
+ locals: new Set(),
19
+ path,
20
+ isCmd: false
21
+ });
22
+ visitStrings(outputs, "$.outputs", (source, path) => checkTemplateString(source, topScope(path), r));
23
+ visitStrings(agents, "$.agents", (source, path) => checkTemplateString(source, topScope(path), r));
24
+ // input defaults are evaluated before any step runs, so no step is visible;
25
+ // an input default referencing a step output is a guaranteed runtime error.
26
+ const inputScope = (path) => ({
27
+ visibleSteps: new Set(),
28
+ locals: new Set(),
29
+ path,
30
+ isCmd: false
31
+ });
32
+ visitStrings(inputSchema, "$.input", (source, path) => checkTemplateString(source, inputScope(path), r));
33
+ }
34
+ /** All step ids strictly inside a node (children/branches, recursive), excluding the node itself. */
35
+ function descendantStepIds(node) {
36
+ const out = new Set();
37
+ const visit = (n) => {
38
+ for (const child of n.children ?? []) {
39
+ out.add(child.id);
40
+ visit(child);
41
+ }
42
+ for (const branch of n.branches ?? []) {
43
+ for (const child of branch.children) {
44
+ out.add(child.id);
45
+ visit(child);
46
+ }
47
+ }
48
+ };
49
+ visit(node);
50
+ return out;
51
+ }
52
+ /**
53
+ * Walk a node's child list, threading step visibility. Visibility rules,
54
+ * deliberately conservative (prefer false negatives over false positives):
55
+ * - Sequential siblings: each child sees the steps declared before it.
56
+ * - When a sibling completes, its id AND all its descendant ids leak to later
57
+ * siblings (matches the runtime, where loop/switch/guard bodies share the
58
+ * step context and surface their inner outputs to later steps).
59
+ * - Loop bodies are treated as fully mutual (every body step sees every other),
60
+ * because re-runs and the `until` check make ordering ambiguous; this only
61
+ * relaxes detection (never adds false positives).
62
+ */
63
+ function walkChildScope(node, inheritedVisible, localsStack, itemSchema, r) {
64
+ const isLoopBody = node.kind === "loop";
65
+ const isParallel = node.kind === "parallel";
66
+ const childLists = node.branches
67
+ ? node.branches.map((b) => b.children)
68
+ : node.children
69
+ ? [node.children]
70
+ : [];
71
+ // Validate branch `when` (raw CEL, outer scope) before descending.
72
+ if (node.branches) {
73
+ const currentLocals = unionLocals(localsStack);
74
+ for (const branch of node.branches) {
75
+ if (branch.when !== undefined) {
76
+ checkRawCelString(branch.when, { visibleSteps: inheritedVisible, locals: currentLocals, itemSchema, path: `${node.nodePath.join("/")}.when`, isCmd: false }, r);
77
+ }
78
+ }
79
+ }
80
+ for (const children of childLists) {
81
+ const running = new Set(inheritedVisible);
82
+ if (isLoopBody) {
83
+ for (const child of children) {
84
+ running.add(child.id);
85
+ for (const id of descendantStepIds(child))
86
+ running.add(id);
87
+ }
88
+ }
89
+ for (const child of children) {
90
+ const childVisible = isParallel ? new Set(inheritedVisible) : new Set(running);
91
+ walkNode(child, childVisible, localsStack, itemSchema, r);
92
+ if (!isLoopBody) {
93
+ running.add(child.id);
94
+ for (const id of descendantStepIds(child))
95
+ running.add(id);
96
+ }
97
+ }
98
+ }
99
+ }
100
+ function walkNode(node, inheritedVisible, localsStack, itemSchema, r) {
101
+ const contract = COMPOSITE_CONTRACTS[node.kind];
102
+ const currentLocals = unionLocals(localsStack);
103
+ const nodePath = node.nodePath.join("/");
104
+ // Config expressions can reference this node's own body steps (loop.until,
105
+ // fanout.key/over). Add the node's descendants so those never false-positive.
106
+ const configVisible = new Set(inheritedVisible);
107
+ for (const id of descendantStepIds(node))
108
+ configVisible.add(id);
109
+ for (const cfg of nodeConfigExpressions(node)) {
110
+ const locals = cfg.bodyScoped ? new Set([...currentLocals, ...contract.bodyLocals]) : currentLocals;
111
+ // Body-scoped fanout config (key) sees `item`; resolve its element schema.
112
+ const cfgItemSchema = cfg.bodyScoped && node.kind === "fanout" ? fanoutItemSchema(node, r) : itemSchema;
113
+ const ctx = {
114
+ visibleSteps: configVisible,
115
+ locals,
116
+ itemSchema: cfgItemSchema,
117
+ path: `${nodePath}.${cfg.field}`,
118
+ isCmd: cfg.isCmd === true
119
+ };
120
+ if (cfg.rawCel) {
121
+ checkRawCelString(cfg.source, ctx, r);
122
+ }
123
+ else {
124
+ checkTemplateString(cfg.source, ctx, r);
125
+ }
126
+ }
127
+ // Recurse with this node's body locals added for its children. A fanout binds
128
+ // `item` to the element schema of its `over` array (when statically known).
129
+ const childLocalsStack = contract.bodyLocals.length > 0 ? [...localsStack, contract.bodyLocals] : localsStack;
130
+ const childItemSchema = node.kind === "fanout" ? fanoutItemSchema(node, r) : itemSchema;
131
+ if ((node.children && node.children.length > 0) || (node.branches && node.branches.length > 0)) {
132
+ walkChildScope(node, inheritedVisible, childLocalsStack, childItemSchema, r);
133
+ }
134
+ }
135
+ /**
136
+ * Resolve the element schema bound to `item` inside a fanout body. Only returns
137
+ * a schema when `over` is `steps.<id>.output[...typed array]`; literal arrays and
138
+ * dyn references yield undefined (fail-quiet → item.* not validated).
139
+ */
140
+ function fanoutItemSchema(node, r) {
141
+ const over = node.metadata.over;
142
+ if (typeof over !== "string")
143
+ return undefined;
144
+ // A coerced literal array (JSON string) has no element schema we can use.
145
+ if (over.trimStart().startsWith("["))
146
+ return undefined;
147
+ const { references, parseError } = extractReferences(over);
148
+ if (parseError || references.length !== 1)
149
+ return undefined;
150
+ const ref = references[0];
151
+ if (ref.root !== "steps")
152
+ return undefined;
153
+ const stepNode = r.globalNodes.get(ref.segments[0]?.name ?? "");
154
+ if (!stepNode)
155
+ return undefined;
156
+ if (COMPOSITE_CONTRACTS[stepNode.kind].outputShape !== "schema")
157
+ return undefined;
158
+ const schema = stepNode.metadata.output;
159
+ if (!isRecord(schema))
160
+ return undefined;
161
+ // Walk to the array referenced by `over`, then return its item schema.
162
+ const arr = resolveSchemaNode(schema, ref.segments, 2);
163
+ if (arr && arr.type === "array" && isRecord(arr.items))
164
+ return arr.items;
165
+ return undefined;
166
+ }
167
+ /** Resolve segments to the schema node they point at, or undefined if not closed. */
168
+ function resolveSchemaNode(schema, segments, start) {
169
+ let cur = schema;
170
+ for (let i = start; i < segments.length; i++) {
171
+ const seg = segments[i];
172
+ if (seg.kind === "index") {
173
+ if (cur.type === "array" && isRecord(cur.items)) {
174
+ cur = cur.items;
175
+ continue;
176
+ }
177
+ return undefined;
178
+ }
179
+ if (isClosedObject(cur)) {
180
+ const properties = cur.properties;
181
+ if (Object.prototype.hasOwnProperty.call(properties, seg.name)) {
182
+ cur = properties[seg.name];
183
+ continue;
184
+ }
185
+ }
186
+ return undefined;
187
+ }
188
+ return cur;
189
+ }
190
+ /** Yield the expression-bearing config strings for a node, by kind. */
191
+ function nodeConfigExpressions(node) {
192
+ const out = [];
193
+ const md = node.metadata;
194
+ const pushTemplate = (value, field, isCmd = false) => {
195
+ if (typeof value === "string")
196
+ out.push({ source: value, field, rawCel: false, isCmd });
197
+ };
198
+ switch (node.kind) {
199
+ case "run.agent":
200
+ pushTemplate(md.prompt, "prompt");
201
+ pushTemplate(md.cwd, "cwd");
202
+ pushTemplate(md.session_key, "session_key");
203
+ break;
204
+ case "run.program":
205
+ if (Array.isArray(md.cmd)) {
206
+ md.cmd.forEach((item, index) => pushTemplate(item, `cmd[${index}]`, true));
207
+ }
208
+ else if (typeof md.cmd === "string") {
209
+ pushTemplate(md.cmd, "cmd", true);
210
+ }
211
+ pushTemplate(md.cwd, "cwd");
212
+ if (isRecord(md.env)) {
213
+ for (const [key, value] of Object.entries(md.env))
214
+ pushTemplate(value, `env.${key}`);
215
+ }
216
+ break;
217
+ case "run.signal":
218
+ pushTemplate(md.prompt, "prompt");
219
+ break;
220
+ case "guard":
221
+ if (typeof md.when === "string")
222
+ out.push({ source: md.when, field: "when", rawCel: true });
223
+ pushTemplate(md.message, "message");
224
+ break;
225
+ case "switch":
226
+ if (typeof md.on === "string")
227
+ out.push({ source: md.on, field: "on", rawCel: true });
228
+ break;
229
+ case "loop":
230
+ if (typeof md.until === "string")
231
+ out.push({ source: md.until, field: "until", rawCel: true, bodyScoped: true });
232
+ break;
233
+ case "fanout":
234
+ if (typeof md.over === "string")
235
+ out.push({ source: md.over, field: "over", rawCel: true });
236
+ if (typeof md.key === "string")
237
+ out.push({ source: md.key, field: "key", rawCel: false, bodyScoped: true });
238
+ break;
239
+ case "subworkflow":
240
+ if (isRecord(md.input)) {
241
+ for (const [key, value] of Object.entries(md.input))
242
+ pushTemplate(value, `input.${key}`);
243
+ }
244
+ break;
245
+ default:
246
+ break;
247
+ }
248
+ return out;
249
+ }
250
+ /** Validate every ${{ }} expression inside a template string. */
251
+ function checkTemplateString(value, ctx, r) {
252
+ for (const match of value.matchAll(EXPRESSION_PATTERN)) {
253
+ const source = (match[1] ?? "").trim();
254
+ if (source.length === 0)
255
+ continue;
256
+ checkExpression(source, ctx, r);
257
+ }
258
+ EXPRESSION_PATTERN.lastIndex = 0;
259
+ }
260
+ /** Validate a raw-CEL field (when/until/over). Skip if it carries ${{ }} (flat collector warns). */
261
+ function checkRawCelString(value, ctx, r) {
262
+ if (EXPRESSION_PATTERN.test(value)) {
263
+ EXPRESSION_PATTERN.lastIndex = 0;
264
+ return;
265
+ }
266
+ EXPRESSION_PATTERN.lastIndex = 0;
267
+ checkExpression(value.trim(), ctx, r);
268
+ }
269
+ function checkExpression(source, ctx, r) {
270
+ const { references, functions, parseError } = extractReferences(source);
271
+ if (parseError)
272
+ return; // flat collector owns EXPR_PARSE
273
+ for (const ref of references) {
274
+ checkReference(ref, ctx, r);
275
+ }
276
+ if (ctx.isCmd) {
277
+ checkCmdScalar(source, references, functions, ctx, r);
278
+ }
279
+ }
280
+ function checkReference(ref, ctx, r) {
281
+ // Out-of-scope local root (loop/item/...) used where it is not bound.
282
+ if (SCOPED_LOCAL_ROOTS.has(ref.root) && !ctx.locals.has(ref.root)) {
283
+ r.diagnostics.error("EXPR_ROOT_OUT_OF_SCOPE", `Expression root '${ref.root}' is only available inside its ${ref.root === "loop" ? "loop" : "fanout"} body; it is not in scope here.${describeScope(ctx)}`, ctx.path);
284
+ return;
285
+ }
286
+ if (ref.root === "steps") {
287
+ checkStepReference(ref, ctx, r);
288
+ return;
289
+ }
290
+ if (ref.root === "input") {
291
+ const result = walkSchema(r.inputSchema, ref.segments, 0);
292
+ if (result.error) {
293
+ r.diagnostics.error("EXPR_UNKNOWN_FIELD", `Expression '${referenceToString(ref)}' references field '${result.error.field}' not declared on input. Available fields: ${result.error.available.join(", ") || "(none)"}.`, ctx.path);
294
+ }
295
+ }
296
+ if (ref.root === "item" && ctx.itemSchema) {
297
+ const result = walkSchema(ctx.itemSchema, ref.segments, 0);
298
+ if (result.error) {
299
+ r.diagnostics.error("EXPR_UNKNOWN_FIELD", `Expression '${referenceToString(ref)}' references field '${result.error.field}' not declared on the fanout item. Available fields: ${result.error.available.join(", ") || "(none)"}.`, ctx.path);
300
+ }
301
+ }
302
+ }
303
+ function checkStepReference(ref, ctx, r) {
304
+ const first = ref.segments[0];
305
+ if (!first || first.kind !== "field")
306
+ return; // steps[expr] — dynamic, skip
307
+ const stepId = first.name;
308
+ if (!r.allStepIds.has(stepId))
309
+ return; // genuinely unknown — flat collector owns EXPR_UNKNOWN_STEP
310
+ if (!ctx.visibleSteps.has(stepId)) {
311
+ const visible = [...ctx.visibleSteps].sort();
312
+ r.diagnostics.error("EXPR_UNKNOWN_STEP", `Expression references step '${stepId}' which is not visible at this position (it runs later or in a separate branch). Visible steps: ${visible.join(", ") || "(none)"}.`, ctx.path);
313
+ return;
314
+ }
315
+ resolveStepType(ref, r, ctx); // resolve for field-path errors (side-effecting diagnostics)
316
+ }
317
+ /**
318
+ * Resolve a `steps.<id>...` reference, emitting EXPR_UNKNOWN_FIELD on a closed
319
+ * schema miss. Returns the resolved kind for the shell-safety check.
320
+ */
321
+ function resolveStepType(ref, r, ctx) {
322
+ const first = ref.segments[0];
323
+ if (!first || first.kind !== "field")
324
+ return "unknown"; // bare `steps` or `steps[expr]`
325
+ const node = r.globalNodes.get(first.name);
326
+ if (!node)
327
+ return "unknown";
328
+ const seg1 = ref.segments[1];
329
+ if (!seg1)
330
+ return "unknown"; // bare `steps.x` — envelope object, treat dyn
331
+ if (seg1.kind !== "field")
332
+ return "unknown";
333
+ if (seg1.name === "exit_code")
334
+ return "scalar";
335
+ if (seg1.name !== "output") {
336
+ const available = node.kind === "run.program" ? "output, exit_code" : "output";
337
+ if (ctx) {
338
+ r.diagnostics.error("EXPR_UNKNOWN_FIELD", `Expression '${referenceToString(ref)}' accesses '${seg1.name}' on step '${node.id}'; step outputs are read via .output (available: ${available}).`, ctx.path);
339
+ }
340
+ return "unknown";
341
+ }
342
+ // seg1 === "output": project per the node's output shape.
343
+ const shape = COMPOSITE_CONTRACTS[node.kind].outputShape;
344
+ if (shape !== "schema" && shape !== "payload")
345
+ return "unknown"; // composite/dyn projection
346
+ const schema = node.metadata.output;
347
+ if (!isRecord(schema))
348
+ return "unknown"; // no declared schema → dyn
349
+ const result = walkSchema(schema, ref.segments, 2);
350
+ if (result.error && ctx) {
351
+ r.diagnostics.error("EXPR_UNKNOWN_FIELD", `Expression '${referenceToString(ref)}' references field '${result.error.field}' not declared on step '${node.id}' output. Available fields: ${result.error.available.join(", ") || "(none)"}.`, ctx.path);
352
+ }
353
+ return result.kind;
354
+ }
355
+ /** CEL functions whose result is a scalar, so their value is shell-safe even
356
+ * when an argument is an object/array. `json` is excluded: it serializes a
357
+ * whole structure into the command text, which is exactly what we warn about. */
358
+ const SCALAR_RETURNING_FUNCTIONS = new Set(["len", "startsWith", "matches", "size", "now"]);
359
+ /** Shell-safety: flag a non-scalar ${{ }} spliced into a cmd element. */
360
+ function checkCmdScalar(source, references, functions, ctx, r) {
361
+ let nonScalar = false;
362
+ let label = source.trim();
363
+ // A scalar-returning function wrapping the value makes the spliced result a
364
+ // scalar regardless of its argument shapes (e.g. len(steps.x.output.items)).
365
+ if (functions.some((fn) => SCALAR_RETURNING_FUNCTIONS.has(fn))) {
366
+ return;
367
+ }
368
+ if (functions.includes("json")) {
369
+ nonScalar = true;
370
+ }
371
+ else if (references.length === 1 && isStaticReference(references[0])) {
372
+ const ref = references[0];
373
+ const kind = ref.root === "steps" ? resolveStepType(ref, r) : ref.root === "input" ? walkSchema(r.inputSchema, ref.segments, 0).kind : "unknown";
374
+ if (kind === "object" || kind === "array") {
375
+ nonScalar = true;
376
+ label = referenceToString(ref);
377
+ }
378
+ }
379
+ if (nonScalar) {
380
+ r.diagnostics.warning("EXPR_NONSCALAR_IN_CMD", `Expression '${label}' evaluates to a non-scalar value spliced into a command; shell metacharacters will break it. Pass it through env: and read it with $VAR / os.environ instead.`, ctx.path);
381
+ }
382
+ }
383
+ /** Walk JSON-Schema segments from `start`. Stops (kind=unknown) on any open/dyn shape. */
384
+ function walkSchema(schema, segments, start) {
385
+ let cur = schema;
386
+ for (let i = start; i < segments.length; i++) {
387
+ const seg = segments[i];
388
+ if (seg.kind === "index") {
389
+ if (cur.type === "array" && isRecord(cur.items)) {
390
+ cur = cur.items;
391
+ continue;
392
+ }
393
+ return { kind: "unknown" };
394
+ }
395
+ // field segment
396
+ if (isClosedObject(cur)) {
397
+ const properties = cur.properties;
398
+ if (Object.prototype.hasOwnProperty.call(properties, seg.name)) {
399
+ cur = properties[seg.name];
400
+ continue;
401
+ }
402
+ return { kind: "unknown", error: { field: seg.name, available: Object.keys(properties) } };
403
+ }
404
+ // open object / scalar / dyn — cannot validate this access
405
+ return { kind: "unknown" };
406
+ }
407
+ return { kind: schemaKind(cur) };
408
+ }
409
+ function isClosedObject(schema) {
410
+ return schema.type === "object" && isRecord(schema.properties) && schema.additionalProperties === false;
411
+ }
412
+ function schemaKind(schema) {
413
+ switch (schema.type) {
414
+ case "object":
415
+ return "object";
416
+ case "array":
417
+ return "array";
418
+ case "string":
419
+ case "integer":
420
+ case "number":
421
+ case "boolean":
422
+ return "scalar";
423
+ default:
424
+ return "unknown";
425
+ }
426
+ }
427
+ function describeScope(ctx) {
428
+ const locals = [...ctx.locals].sort();
429
+ return locals.length > 0 ? ` In-scope locals: ${locals.join(", ")}.` : "";
430
+ }
431
+ function indexNodes(node, out) {
432
+ if (node.id)
433
+ out.set(node.id, node);
434
+ for (const child of node.children ?? [])
435
+ indexNodes(child, out);
436
+ for (const branch of node.branches ?? []) {
437
+ for (const child of branch.children)
438
+ indexNodes(child, out);
439
+ }
440
+ }
441
+ function unionLocals(stack) {
442
+ const out = new Set();
443
+ for (const frame of stack)
444
+ for (const local of frame)
445
+ out.add(local);
446
+ return out;
447
+ }
448
+ /** Visit every string leaf in a nested structure, yielding (value, jsonPath). */
449
+ function visitStrings(value, path, visit) {
450
+ if (typeof value === "string") {
451
+ visit(value, path);
452
+ return;
453
+ }
454
+ if (Array.isArray(value)) {
455
+ value.forEach((item, index) => visitStrings(item, `${path}[${index}]`, visit));
456
+ return;
457
+ }
458
+ if (isRecord(value)) {
459
+ for (const [key, child] of Object.entries(value))
460
+ visitStrings(child, `${path}.${key}`, visit);
461
+ }
462
+ }
463
+ function isRecord(value) {
464
+ return typeof value === "object" && value !== null && !Array.isArray(value);
465
+ }
466
+ //# sourceMappingURL=expression-scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expression-scope.js","sourceRoot":"","sources":["../src/expression-scope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Primitives shared by the expression collector (expressions.ts) and the AST
3
+ * reference extractor (cel-ast.ts), kept in their own module to avoid a circular
4
+ * import between those two files.
5
+ */
6
+ export declare const EXPRESSION_PATTERN: RegExp;
7
+ /**
8
+ * The CEL parser/evaluator does not allow `loop` as a bare identifier root in
9
+ * every position, so Acpus rewrites the logical `loop.` scope to `loop_ctx.`
10
+ * before parsing or evaluating. The runtime evaluator binds `loop_ctx`
11
+ * accordingly; the AST extractor normalizes it back to `loop`.
12
+ *
13
+ * The negative lookbehind keeps `loop.` rooted: a dotted access like
14
+ * `steps.loop.output` (a step named `loop`) is left untouched, since `\b`
15
+ * alone matches at the `.`→`l` boundary and would corrupt the reference.
16
+ */
17
+ export declare function toCelParseSource(source: string): string;
18
+ //# sourceMappingURL=expressions-shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expressions-shared.d.ts","sourceRoot":"","sources":["../src/expressions-shared.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,kBAAkB,QAAgC,CAAC;AAEhE;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Primitives shared by the expression collector (expressions.ts) and the AST
3
+ * reference extractor (cel-ast.ts), kept in their own module to avoid a circular
4
+ * import between those two files.
5
+ */
6
+ export const EXPRESSION_PATTERN = /\$\{\{\s*([\s\S]*?)\s*\}\}/g;
7
+ /**
8
+ * The CEL parser/evaluator does not allow `loop` as a bare identifier root in
9
+ * every position, so Acpus rewrites the logical `loop.` scope to `loop_ctx.`
10
+ * before parsing or evaluating. The runtime evaluator binds `loop_ctx`
11
+ * accordingly; the AST extractor normalizes it back to `loop`.
12
+ *
13
+ * The negative lookbehind keeps `loop.` rooted: a dotted access like
14
+ * `steps.loop.output` (a step named `loop`) is left untouched, since `\b`
15
+ * alone matches at the `.`→`l` boundary and would corrupt the reference.
16
+ */
17
+ export function toCelParseSource(source) {
18
+ return source.replace(/(?<!\.)\bloop\./g, "loop_ctx.");
19
+ }
20
+ //# sourceMappingURL=expressions-shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expressions-shared.js","sourceRoot":"","sources":["../src/expressions-shared.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,6BAA6B,CAAC;AAEhE;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,MAAM,CAAC,OAAO,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;AACzD,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import type { DiagnosticBag } from "./diagnostics.js";
2
2
  import type { IrExpression } from "./types.js";
3
- export declare const EXPRESSION_PATTERN: RegExp;
3
+ export { EXPRESSION_PATTERN, toCelParseSource } from "./expressions-shared.js";
4
4
  export declare const ALLOWED_ROOTS: Set<string>;
5
5
  export declare const ALLOWED_FUNCTIONS: Set<string>;
6
6
  export interface ExpressionCollector {
@@ -8,5 +8,4 @@ export interface ExpressionCollector {
8
8
  visit(value: unknown, path: string): void;
9
9
  }
10
10
  export declare function createExpressionCollector(diagnostics: DiagnosticBag, knownStepIds: Set<string>, stepKinds: Map<string, string>): ExpressionCollector;
11
- export declare function toCelParseSource(source: string): string;
12
11
  //# sourceMappingURL=expressions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../src/expressions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,eAAO,MAAM,kBAAkB,QAAgC,CAAC;AAShE,eAAO,MAAM,aAAa,aAAiF,CAAC;AAC5G,eAAO,MAAM,iBAAiB,aAAuE,CAAC;AAEtG,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,mBAAmB,CAuEpJ;AAMD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEvD"}
1
+ {"version":3,"file":"expressions.d.ts","sourceRoot":"","sources":["../src/expressions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAM/E,eAAO,MAAM,aAAa,aAAiF,CAAC;AAC5G,eAAO,MAAM,iBAAiB,aAAuE,CAAC;AAEtG,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,YAAY,EAAE,CAAC;IAC5B,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,mBAAmB,CAiFpJ"}
@@ -1,10 +1,9 @@
1
- import { parse as parseCel } from "@marcbachmann/cel-js";
2
- export const EXPRESSION_PATTERN = /\$\{\{\s*([\s\S]*?)\s*\}\}/g;
1
+ import { extractReferences } from "./cel-ast.js";
2
+ import { EXPRESSION_PATTERN } from "./expressions-shared.js";
3
+ export { EXPRESSION_PATTERN, toCelParseSource } from "./expressions-shared.js";
3
4
  /** Fields that are evaluated as raw CEL (evaluateExpression), not templates.
4
5
  * Using ${{ }} in these fields causes a runtime CEL parse error. */
5
6
  const RAW_CEL_FIELDS = new Set(["over", "until", "when"]);
6
- const STEP_REFERENCE_PATTERN = /\bsteps\.([A-Za-z_][A-Za-z0-9_-]*)\b/g;
7
- const ROOT_REFERENCE_PATTERN = /(?<![\w.])([A-Za-z_][A-Za-z0-9_]*)\s*(?:\.|\()/g;
8
7
  export const ALLOWED_ROOTS = new Set(["input", "steps", "loop", "item", "item_id", "item_index", "run_id"]);
9
8
  export const ALLOWED_FUNCTIONS = new Set(["now", "len", "startsWith", "matches", "coalesce", "json"]);
10
9
  export function createExpressionCollector(diagnostics, knownStepIds, stepKinds) {
@@ -23,29 +22,38 @@ export function createExpressionCollector(diagnostics, knownStepIds, stepKinds)
23
22
  diagnostics.error("EXPR_EMPTY", "Expression cannot be empty.", path);
24
23
  continue;
25
24
  }
26
- try {
27
- parseCel(toCelParseSource(source));
28
- }
29
- catch (error) {
30
- diagnostics.error("EXPR_PARSE", `Invalid CEL expression: ${errorMessage(error)}`, path);
25
+ const { references, functions, parseError } = extractReferences(source);
26
+ if (parseError) {
27
+ diagnostics.error("EXPR_PARSE", `Invalid CEL expression: ${parseError}`, path);
28
+ continue;
31
29
  }
32
- const references = [...source.matchAll(STEP_REFERENCE_PATTERN)].map((reference) => reference[1]);
33
- for (const reference of references) {
34
- if (!knownStepIds.has(reference)) {
35
- diagnostics.error("EXPR_UNKNOWN_STEP", `Expression references unknown step '${reference}'.`, path);
30
+ const stepReferences = [];
31
+ for (const ref of references) {
32
+ // Unknown root (not an allowed context variable). Functions are reported
33
+ // separately below so a function name is never mistaken for a root.
34
+ if (!ALLOWED_ROOTS.has(ref.root)) {
35
+ diagnostics.warning("EXPR_UNKNOWN_ROOT", `Expression root '${ref.root}' is not part of the M1 DSL context.`, path);
36
+ }
37
+ if (ref.root === "steps") {
38
+ const first = ref.segments[0];
39
+ if (first && first.kind === "field") {
40
+ stepReferences.push(first.name);
41
+ if (!knownStepIds.has(first.name)) {
42
+ diagnostics.error("EXPR_UNKNOWN_STEP", `Expression references unknown step '${first.name}'.`, path);
43
+ }
44
+ }
36
45
  }
37
46
  }
38
- for (const root of source.matchAll(ROOT_REFERENCE_PATTERN)) {
39
- const name = root[1];
40
- if (!ALLOWED_ROOTS.has(name) && !ALLOWED_FUNCTIONS.has(name)) {
41
- diagnostics.warning("EXPR_UNKNOWN_ROOT", `Expression root '${name}' is not part of the M1 DSL context.`, path);
47
+ for (const fn of functions) {
48
+ if (!ALLOWED_FUNCTIONS.has(fn)) {
49
+ diagnostics.warning("EXPR_UNKNOWN_ROOT", `Expression function '${fn}' is not part of the M1 DSL context.`, path);
42
50
  }
43
51
  }
44
52
  expressions.push({
45
53
  id: `expr_${expressions.length + 1}`,
46
54
  source,
47
55
  path,
48
- references
56
+ references: stepReferences
49
57
  });
50
58
  }
51
59
  }
@@ -66,12 +74,6 @@ export function createExpressionCollector(diagnostics, knownStepIds, stepKinds)
66
74
  }
67
75
  return { expressions, visit };
68
76
  }
69
- function errorMessage(error) {
70
- return error instanceof Error ? error.message : String(error);
71
- }
72
- export function toCelParseSource(source) {
73
- return source.replace(/\bloop\./g, "loop_ctx.");
74
- }
75
77
  function isRecord(value) {
76
78
  return typeof value === "object" && value !== null;
77
79
  }