@telorun/cel 0.107.0 → 0.108.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 (78) hide show
  1. package/dist/backend-runtime.d.ts +46 -8
  2. package/dist/backend-runtime.d.ts.map +1 -1
  3. package/dist/backend-runtime.js +133 -30
  4. package/dist/catalog-runtime.d.ts.map +1 -1
  5. package/dist/catalog-runtime.js +110 -109
  6. package/dist/cel-map-value.d.ts +20 -7
  7. package/dist/cel-map-value.d.ts.map +1 -1
  8. package/dist/cel-map-value.js +29 -18
  9. package/dist/cel-value.d.ts +10 -3
  10. package/dist/cel-value.d.ts.map +1 -1
  11. package/dist/check-diagnostic.d.ts +3 -2
  12. package/dist/check-diagnostic.d.ts.map +1 -1
  13. package/dist/checker.d.ts +9 -0
  14. package/dist/checker.d.ts.map +1 -1
  15. package/dist/checker.js +98 -13
  16. package/dist/closure-backend.js +66 -15
  17. package/dist/duration-value.d.ts +11 -0
  18. package/dist/duration-value.d.ts.map +1 -1
  19. package/dist/duration-value.js +17 -3
  20. package/dist/emitted-module.d.ts +1 -1
  21. package/dist/emitted-module.js +1 -1
  22. package/dist/engine-version.d.ts +1 -1
  23. package/dist/engine-version.js +1 -1
  24. package/dist/environment.d.ts +8 -0
  25. package/dist/environment.d.ts.map +1 -1
  26. package/dist/environment.js +20 -5
  27. package/dist/function-registry.d.ts +40 -0
  28. package/dist/function-registry.d.ts.map +1 -1
  29. package/dist/function-registry.js +105 -2
  30. package/dist/index.d.ts +10 -8
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +12 -6
  33. package/dist/js-emitter.d.ts +3 -2
  34. package/dist/js-emitter.d.ts.map +1 -1
  35. package/dist/js-emitter.js +11 -5
  36. package/dist/macro-check.d.ts +8 -0
  37. package/dist/macro-check.d.ts.map +1 -1
  38. package/dist/macro-check.js +1 -1
  39. package/dist/member-read.d.ts +42 -5
  40. package/dist/member-read.d.ts.map +1 -1
  41. package/dist/member-read.js +47 -6
  42. package/dist/resolved-call.d.ts +13 -0
  43. package/dist/resolved-call.d.ts.map +1 -1
  44. package/dist/runtime-library.d.ts +13 -2
  45. package/dist/runtime-library.d.ts.map +1 -1
  46. package/dist/runtime-library.js +134 -125
  47. package/dist/serializer.d.ts.map +1 -1
  48. package/dist/serializer.js +20 -4
  49. package/dist/timestamp-value.d.ts +9 -0
  50. package/dist/timestamp-value.d.ts.map +1 -1
  51. package/dist/timestamp-value.js +15 -0
  52. package/dist/type-expression.d.ts +18 -2
  53. package/dist/type-expression.d.ts.map +1 -1
  54. package/dist/type-expression.js +23 -3
  55. package/dist/value-equality.d.ts.map +1 -1
  56. package/package.json +1 -1
  57. package/src/backend-runtime.ts +180 -30
  58. package/src/catalog-runtime.ts +133 -133
  59. package/src/cel-map-value.ts +31 -20
  60. package/src/cel-value.ts +11 -3
  61. package/src/check-diagnostic.ts +4 -2
  62. package/src/checker.ts +123 -10
  63. package/src/closure-backend.ts +59 -14
  64. package/src/duration-value.ts +18 -3
  65. package/src/emitted-module.ts +1 -1
  66. package/src/engine-version.ts +1 -1
  67. package/src/environment.ts +26 -5
  68. package/src/function-registry.ts +114 -2
  69. package/src/index.ts +24 -3
  70. package/src/js-emitter.ts +13 -5
  71. package/src/macro-check.ts +7 -1
  72. package/src/member-read.ts +48 -7
  73. package/src/resolved-call.ts +13 -0
  74. package/src/runtime-library.ts +167 -143
  75. package/src/serializer.ts +19 -3
  76. package/src/timestamp-value.ts +16 -0
  77. package/src/type-expression.ts +25 -3
  78. package/src/value-equality.ts +3 -3
package/dist/checker.js CHANGED
@@ -73,6 +73,9 @@ class Checker {
73
73
  this.scopes.pop();
74
74
  }
75
75
  }
76
+ typeOfPresence(node) {
77
+ return this.selectType(node, true);
78
+ }
76
79
  // --- the walk -----------------------------------------------------------
77
80
  typeOf(node) {
78
81
  switch (node.kind) {
@@ -87,7 +90,7 @@ class Checker {
87
90
  case "map":
88
91
  return this.mapType(node);
89
92
  case "select":
90
- return this.selectType(node);
93
+ return this.selectType(node, node.optional);
91
94
  case "index":
92
95
  return this.indexType(node);
93
96
  case "unary":
@@ -191,7 +194,13 @@ class Checker {
191
194
  }
192
195
  return reduced;
193
196
  }
194
- selectType(node) {
197
+ /**
198
+ * `presence` is whether the read asks whether the member is THERE — written `.?b`, or
199
+ * standing as the argument of `has()`. It decides nothing about a type that is known to
200
+ * hold no members, which both forms refuse; it decides what a UNION's member-less
201
+ * branches are, which is the absence case a presence-shaped read answers for.
202
+ */
203
+ selectType(node, presence) {
195
204
  const qualified = this.qualifiedVariableType(node);
196
205
  if (qualified)
197
206
  return qualified;
@@ -199,7 +208,7 @@ class Checker {
199
208
  if (node.field === "")
200
209
  return DYN;
201
210
  const guarded = this.checkNullable(node.operand, operand, `.${node.field}`, node.fieldRange);
202
- const held = this.memberType(guarded, node.field, node.fieldRange);
211
+ const held = this.memberType(guarded, node.field, node.fieldRange, presence);
203
212
  // Reading through an optional answers an optional, whichever form the read is
204
213
  // written in: that is what makes a chain of reads over a value that may be absent
205
214
  // stay one expression instead of needing a guard at every step.
@@ -243,13 +252,14 @@ class Checker {
243
252
  return this.scopes.some((scope) => scope.has(name));
244
253
  }
245
254
  /** The type of a named member, reported against whatever the operand turned out to be. */
246
- memberType(operand, field, range) {
255
+ memberType(operand, field, range, presence = false) {
247
256
  if (isDyn(operand) || operand.kind === "parameter")
248
257
  return DYN;
249
- if (operand.kind === "optional")
250
- return this.memberType(operand.value, field, range);
258
+ if (operand.kind === "optional") {
259
+ return this.memberType(operand.value, field, range, presence);
260
+ }
251
261
  if (operand.kind === "union") {
252
- return unionOf(operand.members.map((member) => this.memberType(member, field, range)));
262
+ return unionOf(presenceBranches(operand, holdsMembers, presence).map((member) => this.memberType(member, field, range, presence)));
253
263
  }
254
264
  if (operand.kind === "record")
255
265
  return this.recordMemberType(operand, field, range);
@@ -277,16 +287,17 @@ class Checker {
277
287
  const operand = this.typeOf(node.operand);
278
288
  const index = this.typeOf(node.index);
279
289
  const guarded = this.checkNullable(node.operand, operand, "[…]", node.range);
280
- const held = this.elementType(guarded, index, node);
290
+ const held = this.elementType(guarded, index, node, node.optional);
281
291
  return node.optional || guarded.kind === "optional" ? optionalOf(unwrapOptional(held)) : held;
282
292
  }
283
- elementType(operand, index, node) {
293
+ elementType(operand, index, node, presence = false) {
284
294
  if (isDyn(operand) || operand.kind === "parameter")
285
295
  return DYN;
286
- if (operand.kind === "optional")
287
- return this.elementType(operand.value, index, node);
296
+ if (operand.kind === "optional") {
297
+ return this.elementType(operand.value, index, node, presence);
298
+ }
288
299
  if (operand.kind === "union") {
289
- return unionOf(operand.members.map((member) => this.elementType(member, index, node)));
300
+ return unionOf(presenceBranches(operand, holdsElements, presence).map((member) => this.elementType(member, index, node, presence)));
290
301
  }
291
302
  if (operand.kind === "list") {
292
303
  if (!assignable(index, INT) && !isDyn(index)) {
@@ -471,7 +482,7 @@ class Checker {
471
482
  reportCallFailure(node, form, args, receiver, failure) {
472
483
  const written = `${node.name}(${describeArguments(args)})`;
473
484
  if (failure.reason === "unknown") {
474
- this.report("CEL_UNKNOWN_FUNCTION", `no function named ${JSON.stringify(node.name)} is registered`, node.range, this.renameFix(node));
485
+ this.report("CEL_UNKNOWN_FUNCTION", `no function named ${JSON.stringify(node.name)} is registered${this.closestNames(node.name, form, args.length)}`, node.range, this.renameFix(node));
475
486
  return;
476
487
  }
477
488
  if (failure.reason === "wrong-form") {
@@ -487,6 +498,28 @@ class Checker {
487
498
  this.report(mismatch ? "CEL_TYPE_ARGUMENT_MISMATCH" : "CEL_TYPE_ERROR", mismatch ??
488
499
  `no overload of ${JSON.stringify(node.name)} takes ${form === "receiver" ? `${formatType(receiver ?? DYN)}.` : ""}${written}: ${describeCandidates(failure.candidates)}`, node.range);
489
500
  }
501
+ /**
502
+ * What a call on an unregistered name is offered instead: the registered names that
503
+ * accept its form and arity, nearest first, as a clause to hang off the refusal.
504
+ *
505
+ * **The alternatives belong in the MESSAGE, and the fix stays singular.** A reader of
506
+ * `no('x')` is one name away from the five functions that would have worked, and the
507
+ * engine this one replaces said so; losing it is a real loss of help. A list of five
508
+ * repairs, though, is not a repair — an editor applying one would be guessing which
509
+ * function the author meant — so the single rename fix is still offered only where
510
+ * exactly one name is a case-insensitive match.
511
+ *
512
+ * It names no command and no tool: which listing a host offers is the host's, and an
513
+ * engine embedded in one with no CLI would be pointing at nothing.
514
+ */
515
+ closestNames(name, form, arity) {
516
+ const candidates = this.context.registry.candidateNames(name, form, arity);
517
+ if (candidates.length === 0)
518
+ return "";
519
+ const written = arity === 0 ? "no arguments" : arity === 1 ? "1 argument" : `${arity} arguments`;
520
+ const shape = form === "receiver" ? `written on a value with ${written}` : `taking ${written}`;
521
+ return ` — the closest ${shape}: ${candidates.join(", ")}`;
522
+ }
490
523
  /** The one registered name this call might have meant, as a whole-source repair. */
491
524
  renameFix(node) {
492
525
  const wanted = node.name.toLowerCase();
@@ -550,6 +583,7 @@ class Checker {
550
583
  namespace: node.namespace,
551
584
  arity: args.length,
552
585
  range: node.range,
586
+ argumentTypes: args.map((type) => formatType(withoutParameters(type))),
553
587
  });
554
588
  // An OPEN namespace declares only part of what it reaches, so a name it does not
555
589
  // carry is not this engine's to refuse — it is listed and left to the host.
@@ -565,12 +599,23 @@ class Checker {
565
599
  namespace: node.namespace,
566
600
  arity: args.length,
567
601
  range: node.range,
602
+ argumentTypes: args.map((type) => formatType(withoutParameters(type))),
568
603
  ...(declared.signature === undefined ? {} : { signature: declared.signature }),
569
604
  returns: formatType(withoutParameters(declared.returns)),
570
605
  deterministic: declared.deterministic ?? true,
571
606
  hostBacked: declared.hostBacked ?? false,
572
607
  ...(declared.throws ? { throws: declared.throws } : {}),
573
608
  });
609
+ // A type the host named and its own registry does not carry: the declaration stands,
610
+ // reads `dyn` where that type stood, and the disagreement is a verdict HERE — this is
611
+ // the only place the name has a range.
612
+ const unregistered = declared.unregisteredTypes ?? [];
613
+ if (unregistered.length > 0) {
614
+ const names = unregistered.map((name) => JSON.stringify(name)).join(", ");
615
+ this.report("CEL_TYPE_ERROR", unregistered.length === 1
616
+ ? `${qualified} is declared over the type ${names}, and no type is registered under that name`
617
+ : `${qualified} is declared over the types ${names}, and no type is registered under those names`, node.range);
618
+ }
574
619
  // Parameters withheld: the host judges arity and arguments against its own, richer
575
620
  // signature grammar, and this engine types the result and says nothing else.
576
621
  if (parameters === undefined)
@@ -598,6 +643,46 @@ function isNullTest(args) {
598
643
  const isNull = (type) => type.kind === "primitive" && type.name === "null";
599
644
  return (isNull(left) && admitsNull(right)) || (isNull(right) && admitsNull(left));
600
645
  }
646
+ /**
647
+ * Which branches of a union a read is judged against.
648
+ *
649
+ * A **presence-shaped** read — `a.?b`, `a[?k]`, `has(a.b)` — asks whether the member is
650
+ * THERE, so a branch that can hold no member at all is the absence case it answers
651
+ * `optional.none()` / `false` for at runtime, not a mistake in the expression: that is how
652
+ * a two-shape field is discriminated without a type test. Where **no** branch can hold one
653
+ * the read is judged against them all, so an operand that is known to hold no members is
654
+ * still refused in the presence form exactly as in the plain one.
655
+ */
656
+ function presenceBranches(union, holds, presence) {
657
+ if (!presence)
658
+ return union.members;
659
+ const holding = union.members.filter(holds);
660
+ return holding.length > 0 ? holding : union.members;
661
+ }
662
+ /** Whether a type can hold a named member at all — what `memberType` reads one of. */
663
+ function holdsMembers(type) {
664
+ if (isDyn(type) || type.kind === "parameter")
665
+ return true;
666
+ if (type.kind === "record" || type.kind === "map")
667
+ return true;
668
+ if (type.kind === "optional")
669
+ return holdsMembers(type.value);
670
+ if (type.kind === "union")
671
+ return type.members.some(holdsMembers);
672
+ return false;
673
+ }
674
+ /** Whether a type can hold an element at all — what `elementType` reads one of. */
675
+ function holdsElements(type) {
676
+ if (isDyn(type) || type.kind === "parameter")
677
+ return true;
678
+ if (type.kind === "record" || type.kind === "map" || type.kind === "list")
679
+ return true;
680
+ if (type.kind === "optional")
681
+ return holdsElements(type.value);
682
+ if (type.kind === "union")
683
+ return type.members.some(holdsElements);
684
+ return false;
685
+ }
601
686
  /** An optional of an optional is one optional; a chain of reads does not nest them. */
602
687
  function unwrapOptional(type) {
603
688
  return type.kind === "optional" ? unwrapOptional(type.value) : type;
@@ -138,7 +138,9 @@ class Compiler {
138
138
  }));
139
139
  const { range } = node;
140
140
  return (frame) => {
141
- const pairs = [];
141
+ // Flat — key, value, key, value — so a literal of n entries costs one allocation
142
+ // rather than one per entry. The emitter writes the same call.
143
+ const flat = [];
142
144
  for (const entry of entries) {
143
145
  const key = entry.key(frame);
144
146
  if (isCelError(key))
@@ -147,16 +149,16 @@ class Compiler {
147
149
  if (isCelError(value))
148
150
  return value;
149
151
  if (!entry.optional) {
150
- pairs.push([key, value]);
152
+ flat.push(key, value);
151
153
  continue;
152
154
  }
153
155
  const held = optionalEntry(value, range);
154
156
  if (isCelError(held))
155
157
  return held;
156
158
  if (held.present)
157
- pairs.push([key, held.held]);
159
+ flat.push(key, held.held);
158
160
  }
159
- return celMapFromEntries(pairs, range);
161
+ return celMapFromEntries(flat, range);
160
162
  };
161
163
  }
162
164
  // --- member reads -------------------------------------------------------
@@ -243,21 +245,70 @@ class Compiler {
243
245
  }
244
246
  /**
245
247
  * One dispatch: evaluate the arguments, carry the first error out, then hand the values
246
- * to the site, which resolves the overload on their own types.
248
+ * to the site **positionally**, which resolves the overload on their own types. The arity
249
+ * is the dispatch key's and known at compile time, so the step is chosen once here and no
250
+ * argument array is built per call — the same choice the emitter writes into its text.
247
251
  */
248
252
  callStep(name, form, args, range) {
249
253
  const site = callSiteOf(this.target, name, form, range);
250
- const count = args.length;
251
- return (frame) => {
252
- const values = new Array(count);
253
- for (let at = 0; at < count; at += 1) {
254
- const value = args[at](frame);
255
- if (isCelError(value))
256
- return value;
257
- values[at] = value;
254
+ const [first, second, third, fourth] = args;
255
+ switch (args.length) {
256
+ case 0:
257
+ return () => site.call0();
258
+ case 1:
259
+ return (frame) => {
260
+ const a = first(frame);
261
+ return isCelError(a) ? a : site.call1(a);
262
+ };
263
+ case 2:
264
+ return (frame) => {
265
+ const a = first(frame);
266
+ if (isCelError(a))
267
+ return a;
268
+ const b = second(frame);
269
+ return isCelError(b) ? b : site.call2(a, b);
270
+ };
271
+ case 3:
272
+ return (frame) => {
273
+ const a = first(frame);
274
+ if (isCelError(a))
275
+ return a;
276
+ const b = second(frame);
277
+ if (isCelError(b))
278
+ return b;
279
+ const c = third(frame);
280
+ return isCelError(c) ? c : site.call3(a, b, c);
281
+ };
282
+ case 4:
283
+ return (frame) => {
284
+ const a = first(frame);
285
+ if (isCelError(a))
286
+ return a;
287
+ const b = second(frame);
288
+ if (isCelError(b))
289
+ return b;
290
+ const c = third(frame);
291
+ if (isCelError(c))
292
+ return c;
293
+ const d = fourth(frame);
294
+ return isCelError(d) ? d : site.call4(a, b, c, d);
295
+ };
296
+ default: {
297
+ // A call written wider than any signature may be. Its arguments are still evaluated
298
+ // in order, so an error in one carries out ahead of the refusal.
299
+ const count = args.length;
300
+ return (frame) => {
301
+ const values = new Array(count);
302
+ for (let at = 0; at < count; at += 1) {
303
+ const held = args[at](frame);
304
+ if (isCelError(held))
305
+ return held;
306
+ values[at] = held;
307
+ }
308
+ return site.call(values);
309
+ };
258
310
  }
259
- return site.call(values);
260
- };
311
+ }
261
312
  }
262
313
  qualifiedCallStep(node, scope) {
263
314
  const args = node.args.map((argument) => this.compile(argument, scope));
@@ -42,6 +42,17 @@ export declare function durationNanos(value: CelDuration): bigint;
42
42
  * `ns`, `us`, `ms`, `s`, `m` and `h` (`1h30m`, `1.5s`, `-10m`).
43
43
  */
44
44
  export declare function parseDuration(text: string, range?: SourceRange): CelDuration | CelError;
45
+ /**
46
+ * The same text as a TOTAL OF NANOSECONDS, with no range applied.
47
+ *
48
+ * The grammar and the range are separate questions, and a consumer outside CEL has the same
49
+ * grammar with a different range: protobuf's `google.protobuf.Duration` reaches ±10,000
50
+ * years, which **cannot be held in an int64 of nanoseconds at all**, so a reader that must
51
+ * carry one (a journal entry, a value off a transport) cannot go through `parseDuration` and
52
+ * would otherwise restate this grammar. It answers an unbounded `bigint`; applying a range
53
+ * is the caller's, and `celDurationFromNanos` is what applies CEL's.
54
+ */
55
+ export declare function durationNanosFromText(text: string, range?: SourceRange): bigint | CelError;
45
56
  /** Seconds with an `s` suffix, the fraction trimmed to what it carries. */
46
57
  export declare function formatDuration(value: CelDuration): string;
47
58
  /** Which field of a duration a getter answers. */
@@ -1 +1 @@
1
- {"version":3,"file":"duration-value.d.ts","sourceRoot":"","sources":["../src/duration-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAA4B,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,uBAA6B,CAAC;AAC7D,eAAO,MAAM,kBAAkB,wBAA8B,CAAC;AAI9D,kEAAkE;AAClE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CAS/F;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAIhG;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAExD;AAeD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CA4BvF;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAQzD;AAED,kDAAkD;AAClD,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,CAAC;AAEzF;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAY9E"}
1
+ {"version":3,"file":"duration-value.d.ts","sourceRoot":"","sources":["../src/duration-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAwC,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACvG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,uBAA6B,CAAC;AAC7D,eAAO,MAAM,kBAAkB,wBAA8B,CAAC;AAI9D,kEAAkE;AAClE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CAS/F;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAIhG;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAExD;AAeD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CAGvF;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAAQ,CA4B1F;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAQzD;AAED,kDAAkD;AAClD,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,CAAC;AAEzF;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAY9E"}
@@ -22,7 +22,7 @@
22
22
  * It is written as seconds with an `s` suffix (`1000000s`, `-1.5s`), which is cel-spec's
23
23
  * own spelling, and the one plain encoding a duration has wherever it is written down.
24
24
  */
25
- import { celError, CEL_VALUE_TYPE } from "./cel-value.js";
25
+ import { celError, CEL_VALUE_TYPE, isCelError } from "./cel-value.js";
26
26
  /** The widest and narrowest total a duration holds, in nanoseconds: int64. */
27
27
  export const MAX_DURATION_NANOS = 9223372036854775807n;
28
28
  export const MIN_DURATION_NANOS = -9223372036854775808n;
@@ -69,6 +69,20 @@ const PART = /([0-9]*)(?:\.([0-9]*))?(ns|us|µs|μs|ms|s|m|h)/g;
69
69
  * `ns`, `us`, `ms`, `s`, `m` and `h` (`1h30m`, `1.5s`, `-10m`).
70
70
  */
71
71
  export function parseDuration(text, range) {
72
+ const total = durationNanosFromText(text, range);
73
+ return isCelError(total) ? total : celDurationFromNanos(total, range);
74
+ }
75
+ /**
76
+ * The same text as a TOTAL OF NANOSECONDS, with no range applied.
77
+ *
78
+ * The grammar and the range are separate questions, and a consumer outside CEL has the same
79
+ * grammar with a different range: protobuf's `google.protobuf.Duration` reaches ±10,000
80
+ * years, which **cannot be held in an int64 of nanoseconds at all**, so a reader that must
81
+ * carry one (a journal entry, a value off a transport) cannot go through `parseDuration` and
82
+ * would otherwise restate this grammar. It answers an unbounded `bigint`; applying a range
83
+ * is the caller's, and `celDurationFromNanos` is what applies CEL's.
84
+ */
85
+ export function durationNanosFromText(text, range) {
72
86
  const refuse = () => celError("invalid_conversion", `${JSON.stringify(text)} is not a duration`, range);
73
87
  let body = text;
74
88
  let negative = false;
@@ -77,7 +91,7 @@ export function parseDuration(text, range) {
77
91
  body = body.slice(1);
78
92
  }
79
93
  if (body === "0")
80
- return celDurationFromNanos(0n, range);
94
+ return 0n;
81
95
  if (body === "")
82
96
  return refuse();
83
97
  PART.lastIndex = 0;
@@ -99,7 +113,7 @@ export function parseDuration(text, range) {
99
113
  }
100
114
  if (at !== body.length)
101
115
  return refuse();
102
- return celDurationFromNanos(negative ? -total : total, range);
116
+ return negative ? -total : total;
103
117
  }
104
118
  /** Seconds with an `s` suffix, the fraction trimmed to what it carries. */
105
119
  export function formatDuration(value) {
@@ -65,7 +65,7 @@ import type { CelNode } from "./syntax-tree.js";
65
65
  * code the emitter writes for a corpus drawn from the package's own total enumerations, beside
66
66
  * this number, so a change to that text fails naming the bump it owes.
67
67
  */
68
- export declare const EMITTER_FORMAT_GENERATION = 1;
68
+ export declare const EMITTER_FORMAT_GENERATION = 2;
69
69
  /**
70
70
  * What an emitted module declares about itself in its `integrity` export: its provenance and
71
71
  * its own key. These are the four a loaded module can be held to, because checking them needs
@@ -72,7 +72,7 @@ import { sha256OfText } from "./sha256.js";
72
72
  * code the emitter writes for a corpus drawn from the package's own total enumerations, beside
73
73
  * this number, so a change to that text fails naming the bump it owes.
74
74
  */
75
- export const EMITTER_FORMAT_GENERATION = 1;
75
+ export const EMITTER_FORMAT_GENERATION = 2;
76
76
  /** The prefix of the one line a stored module's header is read from. */
77
77
  const HEADER_PREFIX = "//@telo.cel ";
78
78
  // --- the key and the header ------------------------------------------------
@@ -1,3 +1,3 @@
1
1
  /** This build of the CEL engine, as an emitted module names it. */
2
- export declare const ENGINE_VERSION = "0.107.0";
2
+ export declare const ENGINE_VERSION = "0.108.0";
3
3
  //# sourceMappingURL=engine-version.d.ts.map
@@ -5,4 +5,4 @@
5
5
  // It is a component of every emitted module's cache key and a field of its
6
6
  // integrity header, so a module one build wrote is never run by another.
7
7
  /** This build of the CEL engine, as an emitted module names it. */
8
- export const ENGINE_VERSION = "0.107.0";
8
+ export const ENGINE_VERSION = "0.108.0";
@@ -134,6 +134,14 @@ export interface SchemaRegistrationReport {
134
134
  * by construction rather than by a flag: a declaration that carried parameters and asked for
135
135
  * them to be ignored would hold a list nothing reads, which no reader can tell from a list
136
136
  * that is simply wrong.
137
+ *
138
+ * **A type name this environment registers nothing under is accepted and reads `dyn`**, and
139
+ * every call to such a function carries a ranged `CEL_TYPE_ERROR` naming it. A declaration
140
+ * is a host's own data — a module function's declared result out of a manifest — so a typo
141
+ * in one is the host disagreeing with its own registry, which is reported where there is a
142
+ * range rather than thrown where there is none. A type registered AFTER a declaration naming
143
+ * it does not change that declaration: a declaration resolves its types once, when it is
144
+ * made.
137
145
  */
138
146
  export type NamespaceFunctionDeclaration = ({
139
147
  readonly signature: string;
@@ -1 +1 @@
1
- {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"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"}
@@ -23,7 +23,7 @@ import { compileExpression } from "./cel-program.js";
23
23
  import { emitModule, emitterRuntime, storedEmittedModule } from "./emitted-module.js";
24
24
  import { environmentDigest } from "./environment-digest.js";
25
25
  import { CEL_VALUE_KEYS } from "./cel-value.js";
26
- import { formatType } from "./cel-type.js";
26
+ import { DYN, formatType } from "./cel-type.js";
27
27
  import { CelEngineError } from "./check-diagnostic.js";
28
28
  import { checkExpression } from "./checker.js";
29
29
  import { FunctionRegistry } from "./function-registry.js";
@@ -208,8 +208,23 @@ export class CelEnvironment {
208
208
  ...(entry.hostBacked === undefined ? {} : { hostBacked: entry.hostBacked }),
209
209
  ...(entry.throws === undefined ? {} : { throws: entry.throws }),
210
210
  };
211
+ // A name this environment registers no type under is RECORDED and read as `dyn`,
212
+ // never thrown: a namespace declaration is a host's own data — a module function's
213
+ // declared result out of a manifest — so a typo there would otherwise be a crash
214
+ // with no line, and the consumer that knows where it was written is the one that
215
+ // can anchor the diagnostic. The checker reports it at each call.
216
+ const unregistered = [];
217
+ const resolver = (named, args) => {
218
+ const resolved = this.nominalResolver(named, args);
219
+ if (resolved)
220
+ return resolved;
221
+ if (!unregistered.includes(named))
222
+ unregistered.push(named);
223
+ return DYN;
224
+ };
225
+ const recorded = () => (unregistered.length > 0 ? { unregisteredTypes: [...unregistered] } : {});
211
226
  if (entry.signature !== undefined) {
212
- const signature = parseSignature(entry.signature, this.nominalResolver);
227
+ const signature = parseSignature(entry.signature, resolver);
213
228
  if (signature.form !== "global") {
214
229
  throw new CelTypeRegistrationError(`a namespaced function is declared without a receiver: ${JSON.stringify(entry.signature)}`);
215
230
  }
@@ -218,15 +233,15 @@ export class CelEnvironment {
218
233
  returns: signature.returns,
219
234
  parameters: signature.parameters,
220
235
  signature: formatSignature(signature),
236
+ ...recorded(),
221
237
  ...flags,
222
238
  });
223
239
  continue;
224
240
  }
225
241
  declared.set(entry.name, {
226
242
  name: entry.name,
227
- returns: typeof entry.returns === "string"
228
- ? parseTypeExpression(entry.returns, this.nominalResolver)
229
- : entry.returns,
243
+ returns: typeof entry.returns === "string" ? parseTypeExpression(entry.returns, resolver) : entry.returns,
244
+ ...recorded(),
230
245
  ...flags,
231
246
  });
232
247
  }
@@ -36,6 +36,15 @@ export type ResolutionFailure =
36
36
  readonly reason: "no-overload";
37
37
  readonly candidates: readonly RegisteredFunction[];
38
38
  };
39
+ /**
40
+ * How many names a refused call may name as candidates.
41
+ *
42
+ * It is **declared** rather than left to a message's taste, because the conformance
43
+ * vectors pin that message byte for byte: a bound and an order a second engine cannot
44
+ * reproduce would be a row no port can pass. The order is edit distance then name, both
45
+ * over the name exactly as it was written.
46
+ */
47
+ export declare const UNKNOWN_FUNCTION_CANDIDATES = 5;
39
48
  export interface Resolution {
40
49
  readonly resolved: RegisteredFunction;
41
50
  /** The return type with every type parameter substituted by what this call bound. */
@@ -54,11 +63,42 @@ export declare class FunctionRegistry {
54
63
  /** Every registration, in name order then registration order. */
55
64
  list(): readonly RegisteredFunction[];
56
65
  named(name: string): readonly RegisteredFunction[];
66
+ /**
67
+ * The names this environment registers that would accept a call of that form and
68
+ * arity, nearest first — what a call on a name nothing registers is offered instead.
69
+ *
70
+ * **Form and arity are a filter rather than a ranking**, because a nearer name a call
71
+ * cannot be written on is not a repair: `'a'.size()` is not helped by `size`. A name
72
+ * that is not a name is filtered for the same reason — the operators register under
73
+ * their own symbols (`!`, `-`, `+`), and `no(1)` offered `!` and `-` as its two
74
+ * nearest spellings, neither of which can be written as a call at all. Among what
75
+ * passes the filter the order is edit distance then name, and the list is cut at
76
+ * {@link UNKNOWN_FUNCTION_CANDIDATES} — a declared bound and a declared order, so the
77
+ * message is the same text on every engine. Distance is counted over the name as
78
+ * written, with no case folding: a port reproduces one rule and not a host language's
79
+ * notion of lower case.
80
+ */
81
+ candidateNames(wanted: string, form: CallForm, arity: number): readonly string[];
57
82
  /**
58
83
  * The function a call resolves to. `receiver` is the type the call is written on,
59
84
  * absent for a global call.
60
85
  */
61
86
  resolve(name: string, form: CallForm, args: readonly CelType[], receiver?: CelType): Resolution | ResolutionFailure;
87
+ /**
88
+ * The loose pass: a `dyn` argument makes a candidate viable, and **where several become
89
+ * viable and they do not agree on a return type, the call answers `dyn`.**
90
+ *
91
+ * Taking the first one instead is a concrete type nothing established. `dyn('a') +
92
+ * dyn('b')` answered `int` — the first `+` overload — so a host that declares nothing
93
+ * about a name had `a + b` typed `int`, and a consumer comparing that against a declared
94
+ * `string` slot refused a manifest that runs correctly. The honest answer is the one the
95
+ * engine's own design already states: overloads are resolved per call site on the VALUES'
96
+ * own types, so a `dyn` operand is exactly the case where the static answer is unknown.
97
+ *
98
+ * The candidate is still carried for the caller that wants one (a listing, a flag), and a
99
+ * single viable overload still answers its own return type — `dyn` only where they differ.
100
+ */
101
+ private matchLoosely;
62
102
  private match;
63
103
  /**
64
104
  * Whether an argument fits a parameter, binding type parameters as it goes.
@@ -1 +1 @@
1
- {"version":3,"file":"function-registry.d.ts","sourceRoot":"","sources":["../src/function-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAG/E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACrC;AAED,MAAM,MAAM,iBAAiB;AAC3B,2DAA2D;AACzD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAAE;AACpF,+DAA+D;GAC7D;IAAE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAAE;AACvF,2EAA2E;GACzE;IAAE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAAE,CAAC;AAE3F,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;gBAE/C,SAAS,CAAC,EAAE,gBAAgB;IAOxC,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,YAAY,EAAE,QAAQ,GAAE,gBAAqB,GAAG,IAAI;IAUxE,sFAAsF;IACtF,MAAM,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO;IAWxC,mEAAmE;IACnE,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAOhC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,iEAAiE;IACjE,IAAI,IAAI,SAAS,kBAAkB,EAAE;IAIrC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE;IAIlD;;;OAGG;IACH,OAAO,CACL,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,QAAQ,CAAC,EAAE,OAAO,GACjB,UAAU,GAAG,iBAAiB;IAiBjC,OAAO,CAAC,KAAK;IAiBb;;;;;;;OAOG;IACH,OAAO,CAAC,IAAI;CA8Cb;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAwBzF;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAEpF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAElE"}
1
+ {"version":3,"file":"function-registry.d.ts","sourceRoot":"","sources":["../src/function-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAK/E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;CACrC;AAED,MAAM,MAAM,iBAAiB;AAC3B,2DAA2D;AACzD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAAE;AACpF,+DAA+D;GAC7D;IAAE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAAE;AACvF,2EAA2E;GACzE;IAAE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAAE,CAAC;AAE3F;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;gBAE/C,SAAS,CAAC,EAAE,gBAAgB;IAOxC,gFAAgF;IAChF,QAAQ,CAAC,SAAS,EAAE,YAAY,EAAE,QAAQ,GAAE,gBAAqB,GAAG,IAAI;IAoBxE,sFAAsF;IACtF,MAAM,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO;IAWxC,mEAAmE;IACnE,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAOhC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,iEAAiE;IACjE,IAAI,IAAI,SAAS,kBAAkB,EAAE;IAIrC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE;IAIlD;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE;IAiBhF;;;OAGG;IACH,OAAO,CACL,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,QAAQ,CAAC,EAAE,OAAO,GACjB,UAAU,GAAG,iBAAiB;IAiBjC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,KAAK;IAiBb;;;;;;;OAOG;IACH,OAAO,CAAC,IAAI;CA8Cb;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAwBzF;AA6BD,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAEpF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,CAElE"}