@telorun/cel 0.107.0 → 0.109.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
@@ -24,7 +24,12 @@ import { googleTypeNames } from "./standard-library.js";
24
24
  import { celTimestamp, formatTimestamp, parseTimestamp, timestampField, timestampNanos, } from "./timestamp-value.js";
25
25
  import { celCompare, celEqual } from "./value-equality.js";
26
26
  import { bytesToText, doubleText, textToBytes } from "./value-text.js";
27
+ /** The widest arity a registration declares, and so the number of direct parameters. */
28
+ export const CALL_SITE_DIRECT_ARITY = 4;
27
29
  // --- reading arguments the dispatcher has already typed ---------------------
30
+ // Each takes `CelValue | undefined` because a parameter list is as wide as the widest
31
+ // overload; the dispatcher has already resolved on this argument's type, so the cast is
32
+ // what reading it means.
28
33
  const text = (value) => value;
29
34
  const integer = (value) => value;
30
35
  const unsigned = (value) => value.value;
@@ -34,6 +39,8 @@ const list = (value) => value;
34
39
  const instant = (value) => value;
35
40
  const span = (value) => value;
36
41
  const optional = (value) => value;
42
+ /** The argument itself, where what is read of it is that the dispatcher resolved on it. */
43
+ const value = (held) => held;
37
44
  /** The code points of text — CEL counts and indexes a string by character. */
38
45
  const characters = (value) => [...value];
39
46
  // --- conversions -----------------------------------------------------------
@@ -185,119 +192,121 @@ function splitText(value, separator, limit) {
185
192
  }
186
193
  // --- the table -------------------------------------------------------------
187
194
  function timestampGetter(field) {
188
- return (args, ctx) => timestampField(instant(args[0]), field, args.length > 1 ? text(args[1]) : undefined, ctx.range);
195
+ // One implementation under both arities: the zone is absent where the call omits it, and
196
+ // no CEL value is `undefined`, so the absence is the argument's own answer.
197
+ return (ctx, a, b) => timestampField(instant(a), field, b === undefined ? undefined : text(b), ctx.range);
189
198
  }
190
199
  function durationGetter(field) {
191
- return (args) => durationField(span(args[0]), field);
200
+ return (ctx, a) => durationField(span(a), field);
192
201
  }
193
202
  const IMPLEMENTATIONS = new Map([
194
203
  // conversions
195
- ["bool(bool)", (args) => args[0]],
204
+ ["bool(bool)", (ctx, a) => value(a)],
196
205
  [
197
206
  "bool(string)",
198
- (args, ctx) => {
199
- const held = BOOL_WORDS[text(args[0])];
200
- return held === undefined ? conversionError("bool()", JSON.stringify(args[0]), ctx.range) : held;
207
+ (ctx, a) => {
208
+ const held = BOOL_WORDS[text(a)];
209
+ return held === undefined ? conversionError("bool()", JSON.stringify(a), ctx.range) : held;
201
210
  },
202
211
  ],
203
- ["bytes(bytes)", (args) => args[0]],
204
- ["bytes(string)", (args) => textToBytes(text(args[0]))],
205
- ["double(double)", (args) => args[0]],
206
- ["double(int)", (args) => Number(integer(args[0]))],
207
- ["double(uint)", (args) => Number(unsigned(args[0]))],
208
- ["double(string)", (args, ctx) => doubleFromText(text(args[0]), ctx.range)],
209
- ["duration(string)", (args, ctx) => parseDuration(text(args[0]), ctx.range)],
210
- ["duration(google.protobuf.Duration)", (args) => args[0]],
211
- ["dyn(A)", (args) => args[0]],
212
- ["int(int)", (args) => args[0]],
213
- ["int(uint)", (args, ctx) => intResult(unsigned(args[0]), ctx.range)],
214
- ["int(double)", (args, ctx) => intFromDouble(double(args[0]), ctx.range)],
212
+ ["bytes(bytes)", (ctx, a) => value(a)],
213
+ ["bytes(string)", (ctx, a) => textToBytes(text(a))],
214
+ ["double(double)", (ctx, a) => value(a)],
215
+ ["double(int)", (ctx, a) => Number(integer(a))],
216
+ ["double(uint)", (ctx, a) => Number(unsigned(a))],
217
+ ["double(string)", (ctx, a) => doubleFromText(text(a), ctx.range)],
218
+ ["duration(string)", (ctx, a) => parseDuration(text(a), ctx.range)],
219
+ ["duration(google.protobuf.Duration)", (ctx, a) => value(a)],
220
+ ["dyn(A)", (ctx, a) => value(a)],
221
+ ["int(int)", (ctx, a) => value(a)],
222
+ ["int(uint)", (ctx, a) => intResult(unsigned(a), ctx.range)],
223
+ ["int(double)", (ctx, a) => intFromDouble(double(a), ctx.range)],
215
224
  [
216
225
  "int(string)",
217
- (args, ctx) => {
218
- const written = text(args[0]);
226
+ (ctx, a) => {
227
+ const written = text(a);
219
228
  if (!DECIMAL_INT.test(written))
220
229
  return conversionError("int()", JSON.stringify(written), ctx.range);
221
230
  return intResult(BigInt(written), ctx.range);
222
231
  },
223
232
  ],
224
- ["int(google.protobuf.Timestamp)", (args) => instant(args[0]).seconds],
233
+ ["int(google.protobuf.Timestamp)", (ctx, a) => instant(a).seconds],
225
234
  // A duration's whole seconds, truncated toward zero — no row pins it, cel-spec does.
226
- ["int(google.protobuf.Duration)", (args) => durationField(span(args[0]), "getSeconds")],
227
- ["matches(string, string)", (args, ctx) => celMatches(text(args[0]), text(args[1]), ctx.range)],
228
- ["size(string)", (args) => BigInt(characters(text(args[0])).length)],
229
- ["size(bytes)", (args) => BigInt(bytes(args[0]).length)],
230
- ["size(list<A>)", (args) => BigInt(list(args[0]).length)],
231
- ["size(map<K, V>)", (args) => BigInt(sizeOfMap(args[0]))],
232
- ["string(string)", (args) => args[0]],
233
- ["string(bool)", (args) => String(args[0])],
234
- ["string(int)", (args) => String(integer(args[0]))],
235
- ["string(uint)", (args) => String(unsigned(args[0]))],
236
- ["string(double)", (args) => doubleText(double(args[0]))],
237
- ["string(bytes)", (args, ctx) => bytesToText(bytes(args[0]), ctx.range)],
238
- ["string(google.protobuf.Timestamp)", (args) => formatTimestamp(instant(args[0]))],
239
- ["string(google.protobuf.Duration)", (args) => formatDuration(span(args[0]))],
240
- ["timestamp(string)", (args, ctx) => parseTimestamp(text(args[0]), ctx.range)],
241
- ["timestamp(int)", (args, ctx) => celTimestamp(integer(args[0]), 0, ctx.range)],
242
- ["timestamp(google.protobuf.Timestamp)", (args) => args[0]],
243
- ["uint(uint)", (args) => args[0]],
244
- ["uint(int)", (args, ctx) => uintResult(integer(args[0]), ctx.range)],
245
- ["uint(double)", (args, ctx) => uintFromDouble(double(args[0]), ctx.range)],
235
+ ["int(google.protobuf.Duration)", (ctx, a) => durationField(span(a), "getSeconds")],
236
+ ["matches(string, string)", (ctx, a, b) => celMatches(text(a), text(b), ctx.range)],
237
+ ["size(string)", (ctx, a) => BigInt(characters(text(a)).length)],
238
+ ["size(bytes)", (ctx, a) => BigInt(bytes(a).length)],
239
+ ["size(list<A>)", (ctx, a) => BigInt(list(a).length)],
240
+ ["size(map<K, V>)", (ctx, a) => BigInt(sizeOfMap(a))],
241
+ ["string(string)", (ctx, a) => value(a)],
242
+ ["string(bool)", (ctx, a) => String(a)],
243
+ ["string(int)", (ctx, a) => String(integer(a))],
244
+ ["string(uint)", (ctx, a) => String(unsigned(a))],
245
+ ["string(double)", (ctx, a) => doubleText(double(a))],
246
+ ["string(bytes)", (ctx, a) => bytesToText(bytes(a), ctx.range)],
247
+ ["string(google.protobuf.Timestamp)", (ctx, a) => formatTimestamp(instant(a))],
248
+ ["string(google.protobuf.Duration)", (ctx, a) => formatDuration(span(a))],
249
+ ["timestamp(string)", (ctx, a) => parseTimestamp(text(a), ctx.range)],
250
+ ["timestamp(int)", (ctx, a) => celTimestamp(integer(a), 0, ctx.range)],
251
+ ["timestamp(google.protobuf.Timestamp)", (ctx, a) => value(a)],
252
+ ["uint(uint)", (ctx, a) => value(a)],
253
+ ["uint(int)", (ctx, a) => uintResult(integer(a), ctx.range)],
254
+ ["uint(double)", (ctx, a) => uintFromDouble(double(a), ctx.range)],
246
255
  [
247
256
  "uint(string)",
248
- (args, ctx) => {
249
- const written = text(args[0]);
257
+ (ctx, a) => {
258
+ const written = text(a);
250
259
  if (!DECIMAL_UINT.test(written))
251
260
  return conversionError("uint()", JSON.stringify(written), ctx.range);
252
261
  return uintResult(BigInt(written), ctx.range);
253
262
  },
254
263
  ],
255
264
  // string members
256
- ["string.size()", (args) => BigInt(characters(text(args[0])).length)],
257
- ["bytes.size()", (args) => BigInt(bytes(args[0]).length)],
258
- ["list<A>.size()", (args) => BigInt(list(args[0]).length)],
259
- ["map<K, V>.size()", (args) => BigInt(sizeOfMap(args[0]))],
260
- ["string.startsWith(string)", (args) => text(args[0]).startsWith(text(args[1]))],
261
- ["string.endsWith(string)", (args) => text(args[0]).endsWith(text(args[1]))],
262
- ["string.contains(string)", (args) => text(args[0]).includes(text(args[1]))],
263
- ["string.matches(string)", (args, ctx) => celMatches(text(args[0]), text(args[1]), ctx.range)],
265
+ ["string.size()", (ctx, a) => BigInt(characters(text(a)).length)],
266
+ ["bytes.size()", (ctx, a) => BigInt(bytes(a).length)],
267
+ ["list<A>.size()", (ctx, a) => BigInt(list(a).length)],
268
+ ["map<K, V>.size()", (ctx, a) => BigInt(sizeOfMap(a))],
269
+ ["string.startsWith(string)", (ctx, a, b) => text(a).startsWith(text(b))],
270
+ ["string.endsWith(string)", (ctx, a, b) => text(a).endsWith(text(b))],
271
+ ["string.contains(string)", (ctx, a, b) => text(a).includes(text(b))],
272
+ ["string.matches(string)", (ctx, a, b) => celMatches(text(a), text(b), ctx.range)],
264
273
  // Named for ASCII and not limited to it — see the declaration's own `spec: false` reason.
265
- ["string.lowerAscii()", (args) => text(args[0]).toLowerCase()],
266
- ["string.upperAscii()", (args) => text(args[0]).toUpperCase()],
267
- ["string.trim()", (args) => text(args[0]).trim()],
268
- ["string.indexOf(string)", (args) => BigInt(text(args[0]).indexOf(text(args[1])))],
274
+ ["string.lowerAscii()", (ctx, a) => text(a).toLowerCase()],
275
+ ["string.upperAscii()", (ctx, a) => text(a).toUpperCase()],
276
+ ["string.trim()", (ctx, a) => text(a).trim()],
277
+ ["string.indexOf(string)", (ctx, a, b) => BigInt(text(a).indexOf(text(b)))],
269
278
  [
270
279
  "string.indexOf(string, int)",
271
- (args, ctx) => {
272
- const from = boundedIndex(integer(args[2]), text(args[0]).length, ctx.range);
273
- return typeof from === "number" ? BigInt(text(args[0]).indexOf(text(args[1]), from)) : from;
280
+ (ctx, a, b, c) => {
281
+ const from = boundedIndex(integer(c), text(a).length, ctx.range);
282
+ return typeof from === "number" ? BigInt(text(a).indexOf(text(b), from)) : from;
274
283
  },
275
284
  ],
276
- ["string.lastIndexOf(string)", (args) => BigInt(text(args[0]).lastIndexOf(text(args[1])))],
285
+ ["string.lastIndexOf(string)", (ctx, a, b) => BigInt(text(a).lastIndexOf(text(b)))],
277
286
  [
278
287
  "string.lastIndexOf(string, int)",
279
- (args, ctx) => {
280
- const from = boundedIndex(integer(args[2]), text(args[0]).length, ctx.range);
281
- return typeof from === "number" ? BigInt(text(args[0]).lastIndexOf(text(args[1]), from)) : from;
288
+ (ctx, a, b, c) => {
289
+ const from = boundedIndex(integer(c), text(a).length, ctx.range);
290
+ return typeof from === "number" ? BigInt(text(a).lastIndexOf(text(b), from)) : from;
282
291
  },
283
292
  ],
284
- ["string.substring(int)", (args, ctx) => substring(text(args[0]), integer(args[1]), undefined, ctx.range)],
293
+ ["string.substring(int)", (ctx, a, b) => substring(text(a), integer(b), undefined, ctx.range)],
285
294
  [
286
295
  "string.substring(int, int)",
287
- (args, ctx) => substring(text(args[0]), integer(args[1]), integer(args[2]), ctx.range),
296
+ (ctx, a, b, c) => substring(text(a), integer(b), integer(c), ctx.range),
288
297
  ],
289
- ["string.split(string)", (args) => splitText(text(args[0]), text(args[1]))],
290
- ["string.split(string, int)", (args) => splitText(text(args[0]), text(args[1]), integer(args[2]))],
291
- ["list<string>.join()", (args) => list(args[0]).join("")],
292
- ["list<string>.join(string)", (args) => list(args[0]).join(text(args[1]))],
298
+ ["string.split(string)", (ctx, a, b) => splitText(text(a), text(b))],
299
+ ["string.split(string, int)", (ctx, a, b, c) => splitText(text(a), text(b), integer(c))],
300
+ ["list<string>.join()", (ctx, a) => list(a).join("")],
301
+ ["list<string>.join(string)", (ctx, a, b) => list(a).join(text(b))],
293
302
  // bytes members, each a compatibility member rather than CEL's
294
- ["bytes.string()", (args, ctx) => bytesToText(bytes(args[0]), ctx.range)],
295
- ["bytes.hex()", (args) => hexText(bytes(args[0]))],
296
- ["bytes.base64()", (args) => base64Text(bytes(args[0]))],
303
+ ["bytes.string()", (ctx, a) => bytesToText(bytes(a), ctx.range)],
304
+ ["bytes.hex()", (ctx, a) => hexText(bytes(a))],
305
+ ["bytes.base64()", (ctx, a) => base64Text(bytes(a))],
297
306
  [
298
307
  "bytes.json()",
299
- (args, ctx) => {
300
- const decoded = bytesToText(bytes(args[0]), ctx.range);
308
+ (ctx, a) => {
309
+ const decoded = bytesToText(bytes(a), ctx.range);
301
310
  if (typeof decoded !== "string")
302
311
  return decoded;
303
312
  try {
@@ -310,9 +319,9 @@ const IMPLEMENTATIONS = new Map([
310
319
  ],
311
320
  [
312
321
  "bytes.at(int)",
313
- (args, ctx) => {
314
- const held = bytes(args[0]);
315
- const at = integer(args[1]);
322
+ (ctx, a, b) => {
323
+ const held = bytes(a);
324
+ const at = integer(b);
316
325
  if (at < 0n || at >= BigInt(held.length)) {
317
326
  return celError("index_out_of_range", `index out of range: ${at}`, ctx.range);
318
327
  }
@@ -320,96 +329,96 @@ const IMPLEMENTATIONS = new Map([
320
329
  },
321
330
  ],
322
331
  // arithmetic
323
- ["!(bool)", (args) => !args[0]],
324
- ["-(int)", (args, ctx) => intResult(-integer(args[0]), ctx.range)],
325
- ["-(double)", (args) => -double(args[0])],
326
- ["+(int, int)", (args, ctx) => intResult(integer(args[0]) + integer(args[1]), ctx.range)],
327
- ["+(uint, uint)", (args, ctx) => uintResult(unsigned(args[0]) + unsigned(args[1]), ctx.range)],
328
- ["+(double, double)", (args) => double(args[0]) + double(args[1])],
329
- ["+(string, string)", (args) => text(args[0]) + text(args[1])],
332
+ ["!(bool)", (ctx, a) => !a],
333
+ ["-(int)", (ctx, a) => intResult(-integer(a), ctx.range)],
334
+ ["-(double)", (ctx, a) => -double(a)],
335
+ ["+(int, int)", (ctx, a, b) => intResult(integer(a) + integer(b), ctx.range)],
336
+ ["+(uint, uint)", (ctx, a, b) => uintResult(unsigned(a) + unsigned(b), ctx.range)],
337
+ ["+(double, double)", (ctx, a, b) => double(a) + double(b)],
338
+ ["+(string, string)", (ctx, a, b) => text(a) + text(b)],
330
339
  [
331
340
  "+(bytes, bytes)",
332
- (args) => {
333
- const left = bytes(args[0]);
334
- const right = bytes(args[1]);
341
+ (ctx, a, b) => {
342
+ const left = bytes(a);
343
+ const right = bytes(b);
335
344
  const out = new Uint8Array(left.length + right.length);
336
345
  out.set(left);
337
346
  out.set(right, left.length);
338
347
  return out;
339
348
  },
340
349
  ],
341
- ["+(list<A>, list<A>)", (args) => [...list(args[0]), ...list(args[1])]],
350
+ ["+(list<A>, list<A>)", (ctx, a, b) => [...list(a), ...list(b)]],
342
351
  [
343
352
  "+(google.protobuf.Timestamp, google.protobuf.Duration)",
344
- (args, ctx) => durationOutOfRange(span(args[1]), ctx.range) ??
345
- celTimestamp(0n, timestampNanos(instant(args[0])) + durationNanos(span(args[1])), ctx.range),
353
+ (ctx, a, b) => durationOutOfRange(span(b), ctx.range) ??
354
+ celTimestamp(0n, timestampNanos(instant(a)) + durationNanos(span(b)), ctx.range),
346
355
  ],
347
356
  [
348
357
  "+(google.protobuf.Duration, google.protobuf.Timestamp)",
349
- (args, ctx) => durationOutOfRange(span(args[0]), ctx.range) ??
350
- celTimestamp(0n, durationNanos(span(args[0])) + timestampNanos(instant(args[1])), ctx.range),
358
+ (ctx, a, b) => durationOutOfRange(span(a), ctx.range) ??
359
+ celTimestamp(0n, durationNanos(span(a)) + timestampNanos(instant(b)), ctx.range),
351
360
  ],
352
361
  [
353
362
  "+(google.protobuf.Duration, google.protobuf.Duration)",
354
- (args, ctx) => celDurationFromNanos(durationNanos(span(args[0])) + durationNanos(span(args[1])), ctx.range),
363
+ (ctx, a, b) => celDurationFromNanos(durationNanos(span(a)) + durationNanos(span(b)), ctx.range),
355
364
  ],
356
- ["-(int, int)", (args, ctx) => intResult(integer(args[0]) - integer(args[1]), ctx.range)],
357
- ["-(uint, uint)", (args, ctx) => uintResult(unsigned(args[0]) - unsigned(args[1]), ctx.range)],
358
- ["-(double, double)", (args) => double(args[0]) - double(args[1])],
365
+ ["-(int, int)", (ctx, a, b) => intResult(integer(a) - integer(b), ctx.range)],
366
+ ["-(uint, uint)", (ctx, a, b) => uintResult(unsigned(a) - unsigned(b), ctx.range)],
367
+ ["-(double, double)", (ctx, a, b) => double(a) - double(b)],
359
368
  [
360
369
  "-(google.protobuf.Timestamp, google.protobuf.Timestamp)",
361
- (args, ctx) => celDurationFromNanos(timestampNanos(instant(args[0])) - timestampNanos(instant(args[1])), ctx.range),
370
+ (ctx, a, b) => celDurationFromNanos(timestampNanos(instant(a)) - timestampNanos(instant(b)), ctx.range),
362
371
  ],
363
372
  [
364
373
  "-(google.protobuf.Timestamp, google.protobuf.Duration)",
365
- (args, ctx) => durationOutOfRange(span(args[1]), ctx.range) ??
366
- celTimestamp(0n, timestampNanos(instant(args[0])) - durationNanos(span(args[1])), ctx.range),
374
+ (ctx, a, b) => durationOutOfRange(span(b), ctx.range) ??
375
+ celTimestamp(0n, timestampNanos(instant(a)) - durationNanos(span(b)), ctx.range),
367
376
  ],
368
377
  [
369
378
  "-(google.protobuf.Duration, google.protobuf.Duration)",
370
- (args, ctx) => celDurationFromNanos(durationNanos(span(args[0])) - durationNanos(span(args[1])), ctx.range),
379
+ (ctx, a, b) => celDurationFromNanos(durationNanos(span(a)) - durationNanos(span(b)), ctx.range),
371
380
  ],
372
- ["*(int, int)", (args, ctx) => intResult(integer(args[0]) * integer(args[1]), ctx.range)],
373
- ["*(uint, uint)", (args, ctx) => uintResult(unsigned(args[0]) * unsigned(args[1]), ctx.range)],
374
- ["*(double, double)", (args) => double(args[0]) * double(args[1])],
375
- ["/(int, int)", (args, ctx) => intDivide(integer(args[0]), integer(args[1]), ctx.range)],
376
- ["/(uint, uint)", (args, ctx) => uintDivide(unsigned(args[0]), unsigned(args[1]), ctx.range)],
381
+ ["*(int, int)", (ctx, a, b) => intResult(integer(a) * integer(b), ctx.range)],
382
+ ["*(uint, uint)", (ctx, a, b) => uintResult(unsigned(a) * unsigned(b), ctx.range)],
383
+ ["*(double, double)", (ctx, a, b) => double(a) * double(b)],
384
+ ["/(int, int)", (ctx, a, b) => intDivide(integer(a), integer(b), ctx.range)],
385
+ ["/(uint, uint)", (ctx, a, b) => uintDivide(unsigned(a), unsigned(b), ctx.range)],
377
386
  // A double divided by zero is an infinity, as IEEE 754 says; only the integers refuse.
378
- ["/(double, double)", (args) => double(args[0]) / double(args[1])],
379
- ["%(int, int)", (args, ctx) => intModulo(integer(args[0]), integer(args[1]), ctx.range)],
380
- ["%(uint, uint)", (args, ctx) => uintModulo(unsigned(args[0]), unsigned(args[1]), ctx.range)],
387
+ ["/(double, double)", (ctx, a, b) => double(a) / double(b)],
388
+ ["%(int, int)", (ctx, a, b) => intModulo(integer(a), integer(b), ctx.range)],
389
+ ["%(uint, uint)", (ctx, a, b) => uintModulo(unsigned(a), unsigned(b), ctx.range)],
381
390
  [
382
391
  "in(A, list<A>)",
383
- (args) => {
392
+ (ctx, a, b) => {
384
393
  // Membership reads every element, so an element that must be awaited is a door too, and
385
394
  // the refusal is TERMINAL as it is in a comprehension: answering `true` off the one
386
395
  // element that is readable decides the question against a list this engine cannot read.
387
- for (const held of list(args[1])) {
396
+ for (const held of list(b)) {
388
397
  const refused = asyncValueRefused(held);
389
398
  if (refused)
390
399
  return refused;
391
- if (celEqual(held, args[0]))
400
+ if (celEqual(held, value(a)))
392
401
  return true;
393
402
  }
394
403
  return false;
395
404
  },
396
405
  ],
397
- ["in(K, map<K, V>)", (args) => typeof celLookup(args[1], args[0]) !== "symbol"],
406
+ ["in(K, map<K, V>)", (ctx, a, b) => typeof celLookup(value(b), value(a)) !== "symbol"],
398
407
  // the optional library
399
- ["optional<A>.hasValue()", (args) => optional(args[0]).present],
408
+ ["optional<A>.hasValue()", (ctx, a) => optional(a).present],
400
409
  [
401
410
  "optional<A>.value()",
402
- (args, ctx) => {
403
- const held = optional(args[0]);
411
+ (ctx, a) => {
412
+ const held = optional(a);
404
413
  return held.present
405
414
  ? held.held
406
415
  : celError("optional_value_missing", "the optional holds no value", ctx.range);
407
416
  },
408
417
  ],
409
- ["optional<A>.or(optional<A>)", (args) => (optional(args[0]).present ? args[0] : args[1])],
418
+ ["optional<A>.or(optional<A>)", (ctx, a, b) => (optional(a).present ? value(a) : value(b))],
410
419
  [
411
420
  "optional<A>.orValue(A)",
412
- (args) => (optional(args[0]).present ? optional(args[0]).held : args[1]),
421
+ (ctx, a, b) => (optional(a).present ? optional(a).held : value(b)),
413
422
  ],
414
423
  // timestamp and duration fields
415
424
  ["google.protobuf.Timestamp.getDate()", timestampGetter("getDate")],
@@ -451,23 +460,23 @@ function sizeOfMap(value) {
451
460
  * would then have no implementation.
452
461
  */
453
462
  const BY_NAME = new Map([
454
- ["==", (args) => celEqual(args[0], args[1])],
455
- ["!=", (args) => !celEqual(args[0], args[1])],
463
+ ["==", (ctx, a, b) => celEqual(value(a), value(b))],
464
+ ["!=", (ctx, a, b) => !celEqual(value(a), value(b))],
456
465
  ["<", ordering((compared) => compared < 0)],
457
466
  ["<=", ordering((compared) => compared <= 0)],
458
467
  [">", ordering((compared) => compared > 0)],
459
468
  [">=", ordering((compared) => compared >= 0)],
460
- ["type", (args, ctx) => celTypeValueOf(args[0], ctx.range)],
469
+ ["type", (ctx, a) => celTypeValueOf(value(a), ctx.range)],
461
470
  ]);
462
471
  function ordering(holds) {
463
- return (args, ctx) => {
464
- const compared = celCompare(args[0], args[1]);
472
+ return (ctx, a, b) => {
473
+ const compared = celCompare(value(a), value(b));
465
474
  // Values that do not order at all — unrelated types, or a NaN. NaN orders with
466
475
  // nothing, including itself, so every comparison against it is false.
467
476
  if (compared === undefined) {
468
- if (isNotANumber(args[0]) || isNotANumber(args[1]))
477
+ if (isNotANumber(a) || isNotANumber(b))
469
478
  return false;
470
- return celError("no_matching_overload", `${celTypeNameOf(args[0]) ?? "this value"} and ${celTypeNameOf(args[1]) ?? "this value"} do not order`, ctx.range);
479
+ return celError("no_matching_overload", `${celTypeNameOf(a) ?? "this value"} and ${celTypeNameOf(b) ?? "this value"} do not order`, ctx.range);
471
480
  }
472
481
  return holds(compared);
473
482
  };
@@ -512,8 +521,8 @@ export function standardConstantValues(optionalTypes) {
512
521
  * `optional.ofNonZeroValue(v)`: present unless the value is its type's zero — which is
513
522
  * what makes it different from `optional.of`, and what three of the vectors' rows read.
514
523
  */
515
- export function optionalOfNonZero(value) {
516
- return isZeroValue(value) ? celNone() : celSome(value);
524
+ export function optionalOfNonZero(held) {
525
+ return isZeroValue(held) ? celNone() : celSome(held);
517
526
  }
518
527
  /**
519
528
  * Whether a value is its type's zero. Every type that HAS one is listed; the types left out
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAc,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE5D,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAuND,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAEnD"}
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAc,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE5D,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAuOD,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAEnD"}
@@ -121,14 +121,30 @@ function writeDouble(value) {
121
121
  const text = String(Math.abs(value));
122
122
  return `${sign}${/[.e]/.test(text) ? text : `${text}.0`}`;
123
123
  }
124
+ /**
125
+ * A string literal, always in double quotes.
126
+ *
127
+ * **One spelling, chosen rather than remembered.** The tree records a string's VALUE and not
128
+ * the quote the author typed — the source's own formatting is not structure, which is the
129
+ * same rule that makes the serializer drop redundant parentheses — so a round trip
130
+ * normalizes `'x'` to `"x"`. Both are CEL and the parser reads either.
131
+ *
132
+ * The cost lands on a quick fix, which is written by rewriting the tree and serializing it
133
+ * back **into a YAML scalar**: a double-quoted CEL literal inside a double-quoted scalar has
134
+ * to be escaped, so a repair reads `!cel "a.startsWith(\"x\")"` where the author wrote
135
+ * `'x'`. Choosing the quote here cannot fix that — a single-quoted YAML scalar wants the
136
+ * opposite choice, and this engine does not know which scalar the text will land in. Picking
137
+ * the YAML quoting that needs no escaping is the EDITOR's, which has both halves in hand.
138
+ */
124
139
  function writeString(value) {
125
- let text = '"';
140
+ const quote = '"';
141
+ let text = quote;
126
142
  for (const unit of value) {
127
143
  const code = unit.codePointAt(0);
128
144
  if (unit === "\\")
129
145
  text += "\\\\";
130
- else if (unit === '"')
131
- text += '\\"';
146
+ else if (unit === quote)
147
+ text += `\\${quote}`;
132
148
  else if (unit === "\n")
133
149
  text += "\\n";
134
150
  else if (unit === "\r")
@@ -140,7 +156,7 @@ function writeString(value) {
140
156
  else
141
157
  text += unit;
142
158
  }
143
- return `${text}"`;
159
+ return `${text}${quote}`;
144
160
  }
145
161
  function writeBytes(value) {
146
162
  let text = 'b"';
@@ -19,6 +19,15 @@ export declare const MIN_TIMESTAMP_SECONDS = -62135596800n;
19
19
  export declare const MAX_TIMESTAMP_SECONDS = 253402300799n;
20
20
  /** An instant from seconds and nanoseconds of any sign, normalized, or the range error. */
21
21
  export declare function celTimestamp(seconds: bigint, nanos?: bigint | number, range?: SourceRange): CelTimestamp | CelError;
22
+ /**
23
+ * An instant from epoch MILLISECONDS — the mirror of `celDurationFromNanos` for a host
24
+ * clock reading (`Date.now()`, a driver's epoch-millis column), or the range error.
25
+ *
26
+ * It exists so that a host never has to reach for its own date type to say "now": the
27
+ * instance type is seconds plus nanos, and a millisecond reading is the one other shape
28
+ * a host actually holds. A fractional reading keeps its sub-millisecond part.
29
+ */
30
+ export declare function celTimestampFromMillis(millis: number, range?: SourceRange): CelTimestamp | CelError;
22
31
  /** The instant's nanoseconds since the epoch — what arithmetic and ordering compare. */
23
32
  export declare function timestampNanos(value: CelTimestamp): bigint;
24
33
  /** An instant from RFC 3339 text, with any offset and any fractional precision. */
@@ -1 +1 @@
1
- {"version":3,"file":"timestamp-value.d.ts","sourceRoot":"","sources":["../src/timestamp-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,qFAAqF;AACrF,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAInD,2FAA2F;AAC3F,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,MAAM,GAAG,MAAU,EAC1B,KAAK,CAAC,EAAE,WAAW,GAClB,YAAY,GAAG,QAAQ,CAYzB;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE1D;AAKD,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,QAAQ,CAgCzF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAK3D;AAaD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAgED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,KAAK,CAAC,EAAE,WAAW,GAClB,WAAW,GAAG,QAAQ,CAYxB;AAsCD,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GACtB,aAAa,GACb,UAAU,GACV,cAAc,GACd,eAAe,GACf,SAAS,GACT,cAAc,GACd,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,iBAAiB,CAAC;AAEtB;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,cAAc,EACrB,IAAI,CAAC,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,WAAW,GAClB,MAAM,GAAG,QAAQ,CA0BnB"}
1
+ {"version":3,"file":"timestamp-value.d.ts","sourceRoot":"","sources":["../src/timestamp-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,qFAAqF;AACrF,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAInD,2FAA2F;AAC3F,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,MAAM,GAAG,MAAU,EAC1B,KAAK,CAAC,EAAE,WAAW,GAClB,YAAY,GAAG,QAAQ,CAYzB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,QAAQ,CAMnG;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE1D;AAKD,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,QAAQ,CAgCzF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAK3D;AAaD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAgED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,KAAK,CAAC,EAAE,WAAW,GAClB,WAAW,GAAG,QAAQ,CAYxB;AAsCD,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GACtB,aAAa,GACb,UAAU,GACV,cAAc,GACd,eAAe,GACf,SAAS,GACT,cAAc,GACd,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,iBAAiB,CAAC;AAEtB;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,cAAc,EACrB,IAAI,CAAC,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,WAAW,GAClB,MAAM,GAAG,QAAQ,CA0BnB"}
@@ -31,6 +31,21 @@ export function celTimestamp(seconds, nanos = 0, range) {
31
31
  }
32
32
  return { [CEL_VALUE_TYPE]: "google.protobuf.Timestamp", seconds: whole, nanos: Number(rest) };
33
33
  }
34
+ /**
35
+ * An instant from epoch MILLISECONDS — the mirror of `celDurationFromNanos` for a host
36
+ * clock reading (`Date.now()`, a driver's epoch-millis column), or the range error.
37
+ *
38
+ * It exists so that a host never has to reach for its own date type to say "now": the
39
+ * instance type is seconds plus nanos, and a millisecond reading is the one other shape
40
+ * a host actually holds. A fractional reading keeps its sub-millisecond part.
41
+ */
42
+ export function celTimestampFromMillis(millis, range) {
43
+ if (!Number.isFinite(millis)) {
44
+ return celError("invalid_conversion", "timestamp out of range", range);
45
+ }
46
+ const whole = Math.floor(millis / 1000);
47
+ return celTimestamp(BigInt(whole), Math.round((millis - whole * 1000) * 1_000_000), range);
48
+ }
34
49
  /** The instant's nanoseconds since the epoch — what arithmetic and ordering compare. */
35
50
  export function timestampNanos(value) {
36
51
  return value.seconds * NANOS_PER_SECOND + BigInt(value.nanos);
@@ -9,13 +9,29 @@
9
9
  *
10
10
  * A bare capital letter is a type **parameter**, which is how a signature says "the
11
11
  * same type here and there". A name the host registered as a nominal type resolves
12
- * to it; any other name is refused rather than guessed, because a misspelled type in
13
- * a signature would otherwise register a function nothing can call.
12
+ * to it; any other name is refused rather than guessed — as a
13
+ * {@link CelUnknownTypeNameError}, which a caller holding the name's source may turn
14
+ * into a verdict — because a misspelled type in a signature would otherwise register a
15
+ * function nothing can call.
14
16
  */
15
17
  import type { CelType } from "./cel-type.js";
16
18
  export declare class CelTypeExpressionError extends Error {
17
19
  constructor(message: string);
18
20
  }
21
+ /**
22
+ * A well-formed type expression naming a type nothing is registered under.
23
+ *
24
+ * It is **not** a `CelTypeExpressionError`, and the split is the whole point: that error
25
+ * is about text this grammar cannot read, while this one is about a name the HOST and its
26
+ * own registry disagree about. A caller that holds where the name was written can turn it
27
+ * into a ranged verdict instead of a crash — which is what a namespace declaration built
28
+ * out of a host's data does — and a caller that cannot still lets it fly.
29
+ */
30
+ export declare class CelUnknownTypeNameError extends Error {
31
+ /** The name nothing is registered under. */
32
+ readonly typeName: string;
33
+ constructor(typeName: string);
34
+ }
19
35
  /** What a name that is neither a primitive nor a parameter resolves to. */
20
36
  export type NominalResolver = (name: string, args: readonly CelType[]) => CelType | undefined;
21
37
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"type-expression.d.ts","sourceRoot":"","sources":["../src/type-expression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAiB,MAAM,eAAe,CAAC;AAoB5D,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAmBD,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,KAAK,OAAO,GAAG,SAAS,CAAC;AAE9F;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,eAAe,GAAG,OAAO,CAK3F"}
1
+ {"version":3,"file":"type-expression.d.ts","sourceRoot":"","sources":["../src/type-expression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAiB,MAAM,eAAe,CAAC;AAoB5D,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;;;GAQG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,MAAM;CAK7B;AAmBD,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,KAAK,OAAO,GAAG,SAAS,CAAC;AAE9F;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,eAAe,GAAG,OAAO,CAK3F"}
@@ -9,8 +9,10 @@
9
9
  *
10
10
  * A bare capital letter is a type **parameter**, which is how a signature says "the
11
11
  * same type here and there". A name the host registered as a nominal type resolves
12
- * to it; any other name is refused rather than guessed, because a misspelled type in
13
- * a signature would otherwise register a function nothing can call.
12
+ * to it; any other name is refused rather than guessed — as a
13
+ * {@link CelUnknownTypeNameError}, which a caller holding the name's source may turn
14
+ * into a verdict — because a misspelled type in a signature would otherwise register a
15
+ * function nothing can call.
14
16
  */
15
17
  import { BOOL, BYTES, DOUBLE, DYN, DURATION, INT, listOf, mapOf, NULL, optionalOf, parameterOf, STRING, TIMESTAMP, TYPE, UINT, WELL_KNOWN_TYPE_NAMES, } from "./cel-type.js";
16
18
  export class CelTypeExpressionError extends Error {
@@ -19,6 +21,24 @@ export class CelTypeExpressionError extends Error {
19
21
  this.name = "CelTypeExpressionError";
20
22
  }
21
23
  }
24
+ /**
25
+ * A well-formed type expression naming a type nothing is registered under.
26
+ *
27
+ * It is **not** a `CelTypeExpressionError`, and the split is the whole point: that error
28
+ * is about text this grammar cannot read, while this one is about a name the HOST and its
29
+ * own registry disagree about. A caller that holds where the name was written can turn it
30
+ * into a ranged verdict instead of a crash — which is what a namespace declaration built
31
+ * out of a host's data does — and a caller that cannot still lets it fly.
32
+ */
33
+ export class CelUnknownTypeNameError extends Error {
34
+ /** The name nothing is registered under. */
35
+ typeName;
36
+ constructor(typeName) {
37
+ super(`no type is registered under the name ${JSON.stringify(typeName)}`);
38
+ this.name = "CelUnknownTypeNameError";
39
+ this.typeName = typeName;
40
+ }
41
+ }
22
42
  const PRIMITIVES = {
23
43
  dyn: DYN,
24
44
  int: INT,
@@ -124,7 +144,7 @@ class TypeReader {
124
144
  const nominal = this.resolveNominal?.(name, args);
125
145
  if (nominal)
126
146
  return nominal;
127
- throw new CelTypeExpressionError(`no type is registered under the name ${JSON.stringify(name)}`);
147
+ throw new CelUnknownTypeNameError(name);
128
148
  }
129
149
  noArguments(name, args, type) {
130
150
  if (args.length > 0)
@@ -1 +1 @@
1
- {"version":3,"file":"value-equality.d.ts","sourceRoot":"","sources":["../src/value-equality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AA8E/C;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAgB9E;AAED,2FAA2F;AAC3F,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAgCjE"}
1
+ {"version":3,"file":"value-equality.d.ts","sourceRoot":"","sources":["../src/value-equality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAIH,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AA8E1D;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAgB9E;AAED,2FAA2F;AAC3F,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAgCjE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/cel",
3
- "version": "0.107.0",
3
+ "version": "0.109.0",
4
4
  "description": "The Common Expression Language for Telo: read, type-check and evaluate an expression, hold it as a tree, write it back.",
5
5
  "keywords": [
6
6
  "telo",