@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.
- package/dist/backend-runtime.d.ts +46 -8
- package/dist/backend-runtime.d.ts.map +1 -1
- package/dist/backend-runtime.js +133 -30
- package/dist/catalog-runtime.d.ts.map +1 -1
- package/dist/catalog-runtime.js +110 -109
- package/dist/cel-map-value.d.ts +20 -7
- package/dist/cel-map-value.d.ts.map +1 -1
- package/dist/cel-map-value.js +29 -18
- package/dist/cel-value.d.ts +10 -3
- package/dist/cel-value.d.ts.map +1 -1
- package/dist/check-diagnostic.d.ts +3 -2
- package/dist/check-diagnostic.d.ts.map +1 -1
- package/dist/checker.d.ts +9 -0
- package/dist/checker.d.ts.map +1 -1
- package/dist/checker.js +98 -13
- package/dist/closure-backend.js +66 -15
- package/dist/duration-value.d.ts +11 -0
- package/dist/duration-value.d.ts.map +1 -1
- package/dist/duration-value.js +17 -3
- package/dist/emitted-module.d.ts +1 -1
- package/dist/emitted-module.js +1 -1
- package/dist/engine-version.d.ts +1 -1
- package/dist/engine-version.js +1 -1
- package/dist/environment.d.ts +8 -0
- package/dist/environment.d.ts.map +1 -1
- package/dist/environment.js +20 -5
- package/dist/function-registry.d.ts +40 -0
- package/dist/function-registry.d.ts.map +1 -1
- package/dist/function-registry.js +105 -2
- package/dist/index.d.ts +10 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -6
- package/dist/js-emitter.d.ts +3 -2
- package/dist/js-emitter.d.ts.map +1 -1
- package/dist/js-emitter.js +11 -5
- package/dist/macro-check.d.ts +8 -0
- package/dist/macro-check.d.ts.map +1 -1
- package/dist/macro-check.js +1 -1
- package/dist/member-read.d.ts +42 -5
- package/dist/member-read.d.ts.map +1 -1
- package/dist/member-read.js +47 -6
- package/dist/resolved-call.d.ts +13 -0
- package/dist/resolved-call.d.ts.map +1 -1
- package/dist/runtime-library.d.ts +13 -2
- package/dist/runtime-library.d.ts.map +1 -1
- package/dist/runtime-library.js +134 -125
- package/dist/serializer.d.ts.map +1 -1
- package/dist/serializer.js +20 -4
- package/dist/timestamp-value.d.ts +9 -0
- package/dist/timestamp-value.d.ts.map +1 -1
- package/dist/timestamp-value.js +15 -0
- package/dist/type-expression.d.ts +18 -2
- package/dist/type-expression.d.ts.map +1 -1
- package/dist/type-expression.js +23 -3
- package/dist/value-equality.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/backend-runtime.ts +180 -30
- package/src/catalog-runtime.ts +133 -133
- package/src/cel-map-value.ts +31 -20
- package/src/cel-value.ts +11 -3
- package/src/check-diagnostic.ts +4 -2
- package/src/checker.ts +123 -10
- package/src/closure-backend.ts +59 -14
- package/src/duration-value.ts +18 -3
- package/src/emitted-module.ts +1 -1
- package/src/engine-version.ts +1 -1
- package/src/environment.ts +26 -5
- package/src/function-registry.ts +114 -2
- package/src/index.ts +24 -3
- package/src/js-emitter.ts +13 -5
- package/src/macro-check.ts +7 -1
- package/src/member-read.ts +48 -7
- package/src/resolved-call.ts +13 -0
- package/src/runtime-library.ts +167 -143
- package/src/serializer.ts +19 -3
- package/src/timestamp-value.ts +16 -0
- package/src/type-expression.ts +25 -3
- 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
|
-
|
|
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.
|
|
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.
|
|
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;
|
package/dist/closure-backend.js
CHANGED
|
@@ -138,7 +138,9 @@ class Compiler {
|
|
|
138
138
|
}));
|
|
139
139
|
const { range } = node;
|
|
140
140
|
return (frame) => {
|
|
141
|
-
|
|
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
|
-
|
|
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
|
-
|
|
159
|
+
flat.push(key, held.held);
|
|
158
160
|
}
|
|
159
|
-
return celMapFromEntries(
|
|
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
|
|
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
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
|
|
260
|
-
};
|
|
311
|
+
}
|
|
261
312
|
}
|
|
262
313
|
qualifiedCallStep(node, scope) {
|
|
263
314
|
const args = node.args.map((argument) => this.compile(argument, scope));
|
package/dist/duration-value.d.ts
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/duration-value.js
CHANGED
|
@@ -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
|
|
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
|
|
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) {
|
package/dist/emitted-module.d.ts
CHANGED
|
@@ -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 =
|
|
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
|
package/dist/emitted-module.js
CHANGED
|
@@ -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 =
|
|
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 ------------------------------------------------
|
package/dist/engine-version.d.ts
CHANGED
package/dist/engine-version.js
CHANGED
|
@@ -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.
|
|
8
|
+
export const ENGINE_VERSION = "0.108.0";
|
package/dist/environment.d.ts
CHANGED
|
@@ -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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"}
|
package/dist/environment.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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;
|
|
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"}
|