@telorun/cel 0.0.0-stage → 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/LICENSE +17 -0
- package/README.md +281 -2
- package/dist/activation.d.ts +27 -0
- package/dist/activation.d.ts.map +1 -0
- package/dist/activation.js +24 -0
- package/dist/backend-runtime.d.ts +184 -0
- package/dist/backend-runtime.d.ts.map +1 -0
- package/dist/backend-runtime.js +425 -0
- package/dist/bounded-cache.d.ts +21 -0
- package/dist/bounded-cache.d.ts.map +1 -0
- package/dist/bounded-cache.js +42 -0
- package/dist/catalog-runtime.d.ts +59 -0
- package/dist/catalog-runtime.d.ts.map +1 -0
- package/dist/catalog-runtime.js +786 -0
- package/dist/cel-expression.d.ts +32 -0
- package/dist/cel-expression.d.ts.map +1 -0
- package/dist/cel-expression.js +29 -0
- package/dist/cel-map-value.d.ts +47 -0
- package/dist/cel-map-value.d.ts.map +1 -0
- package/dist/cel-map-value.js +85 -0
- package/dist/cel-program.d.ts +44 -0
- package/dist/cel-program.d.ts.map +1 -0
- package/dist/cel-program.js +72 -0
- package/dist/cel-type.d.ts +131 -0
- package/dist/cel-type.d.ts.map +1 -0
- package/dist/cel-type.js +293 -0
- package/dist/cel-value.d.ts +166 -0
- package/dist/cel-value.d.ts.map +1 -0
- package/dist/cel-value.js +225 -0
- package/dist/check-diagnostic.d.ts +54 -0
- package/dist/check-diagnostic.d.ts.map +1 -0
- package/dist/check-diagnostic.js +66 -0
- package/dist/checker.d.ts +86 -0
- package/dist/checker.d.ts.map +1 -0
- package/dist/checker.js +806 -0
- package/dist/closure-backend.d.ts +21 -0
- package/dist/closure-backend.d.ts.map +1 -0
- package/dist/closure-backend.js +487 -0
- package/dist/comprehension-bindings.d.ts +33 -0
- package/dist/comprehension-bindings.d.ts.map +1 -0
- package/dist/comprehension-bindings.js +50 -0
- package/dist/comprehension-runtime.d.ts +44 -0
- package/dist/comprehension-runtime.d.ts.map +1 -0
- package/dist/comprehension-runtime.js +137 -0
- package/dist/declared-chain.d.ts +35 -0
- package/dist/declared-chain.d.ts.map +1 -0
- package/dist/declared-chain.js +36 -0
- package/dist/duration-value.d.ts +70 -0
- package/dist/duration-value.d.ts.map +1 -0
- package/dist/duration-value.js +149 -0
- package/dist/emitted-module.d.ts +207 -0
- package/dist/emitted-module.d.ts.map +1 -0
- package/dist/emitted-module.js +359 -0
- package/dist/engine-version.d.ts +3 -0
- package/dist/engine-version.d.ts.map +1 -0
- package/dist/engine-version.js +8 -0
- package/dist/environment-digest.d.ts +44 -0
- package/dist/environment-digest.d.ts.map +1 -0
- package/dist/environment-digest.js +98 -0
- package/dist/environment.d.ts +291 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +474 -0
- package/dist/function-catalog.d.ts +66 -0
- package/dist/function-catalog.d.ts.map +1 -0
- package/dist/function-catalog.js +77 -0
- package/dist/function-registry.d.ts +118 -0
- package/dist/function-registry.d.ts.map +1 -0
- package/dist/function-registry.js +292 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/integer-arithmetic.d.ts +27 -0
- package/dist/integer-arithmetic.d.ts.map +1 -0
- package/dist/integer-arithmetic.js +58 -0
- package/dist/js-emitter.d.ts +133 -0
- package/dist/js-emitter.d.ts.map +1 -0
- package/dist/js-emitter.js +568 -0
- package/dist/json-schema-type.d.ts +182 -0
- package/dist/json-schema-type.d.ts.map +1 -0
- package/dist/json-schema-type.js +487 -0
- package/dist/json-text-scan.d.ts +28 -0
- package/dist/json-text-scan.d.ts.map +1 -0
- package/dist/json-text-scan.js +159 -0
- package/dist/lexer.d.ts +103 -0
- package/dist/lexer.d.ts.map +1 -0
- package/dist/lexer.js +458 -0
- package/dist/macro-check.d.ts +41 -0
- package/dist/macro-check.d.ts.map +1 -0
- package/dist/macro-check.js +162 -0
- package/dist/macro-shape.d.ts +24 -0
- package/dist/macro-shape.d.ts.map +1 -0
- package/dist/macro-shape.js +55 -0
- package/dist/member-read.d.ts +89 -0
- package/dist/member-read.d.ts.map +1 -0
- package/dist/member-read.js +166 -0
- package/dist/namespace-resolution.d.ts +35 -0
- package/dist/namespace-resolution.d.ts.map +1 -0
- package/dist/namespace-resolution.js +160 -0
- package/dist/nominal-type.d.ts +63 -0
- package/dist/nominal-type.d.ts.map +1 -0
- package/dist/nominal-type.js +98 -0
- package/dist/nullable-access.d.ts +38 -0
- package/dist/nullable-access.d.ts.map +1 -0
- package/dist/nullable-access.js +93 -0
- package/dist/parse-limits.d.ts +26 -0
- package/dist/parse-limits.d.ts.map +1 -0
- package/dist/parse-limits.js +21 -0
- package/dist/parser.d.ts +48 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +503 -0
- package/dist/qualified-calls.d.ts +22 -0
- package/dist/qualified-calls.d.ts.map +1 -0
- package/dist/qualified-calls.js +27 -0
- package/dist/regular-expression.d.ts +48 -0
- package/dist/regular-expression.d.ts.map +1 -0
- package/dist/regular-expression.js +77 -0
- package/dist/reserved-words.d.ts +52 -0
- package/dist/reserved-words.d.ts.map +1 -0
- package/dist/reserved-words.js +77 -0
- package/dist/resolved-call.d.ts +46 -0
- package/dist/resolved-call.d.ts.map +1 -0
- package/dist/resolved-call.js +15 -0
- package/dist/root-references.d.ts +23 -0
- package/dist/root-references.d.ts.map +1 -0
- package/dist/root-references.js +120 -0
- package/dist/runtime-library.d.ts +67 -0
- package/dist/runtime-library.d.ts.map +1 -0
- package/dist/runtime-library.js +554 -0
- package/dist/serializer.d.ts +24 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/serializer.js +256 -0
- package/dist/sha256.d.ts +20 -0
- package/dist/sha256.d.ts.map +1 -0
- package/dist/sha256.js +103 -0
- package/dist/signature.d.ts +72 -0
- package/dist/signature.d.ts.map +1 -0
- package/dist/signature.js +61 -0
- package/dist/signatures/function-catalog.json +788 -0
- package/dist/signatures/standard-library.json +229 -0
- package/dist/standard-library.d.ts +41 -0
- package/dist/standard-library.d.ts.map +1 -0
- package/dist/standard-library.js +85 -0
- package/dist/syntax-diagnostic.d.ts +61 -0
- package/dist/syntax-diagnostic.d.ts.map +1 -0
- package/dist/syntax-diagnostic.js +28 -0
- package/dist/syntax-tree.d.ts +160 -0
- package/dist/syntax-tree.d.ts.map +1 -0
- package/dist/syntax-tree.js +58 -0
- package/dist/timestamp-value.d.ts +62 -0
- package/dist/timestamp-value.d.ts.map +1 -0
- package/dist/timestamp-value.js +238 -0
- package/dist/tree-equality.d.ts +15 -0
- package/dist/tree-equality.d.ts.map +1 -0
- package/dist/tree-equality.js +105 -0
- package/dist/type-expression.d.ts +42 -0
- package/dist/type-expression.d.ts.map +1 -0
- package/dist/type-expression.js +154 -0
- package/dist/value-equality.d.ts +38 -0
- package/dist/value-equality.d.ts.map +1 -0
- package/dist/value-equality.js +196 -0
- package/dist/value-text.d.ts +25 -0
- package/dist/value-text.d.ts.map +1 -0
- package/dist/value-text.js +44 -0
- package/dist/zoned-calendar.d.ts +61 -0
- package/dist/zoned-calendar.d.ts.map +1 -0
- package/dist/zoned-calendar.js +143 -0
- package/package.json +56 -3
- package/src/activation.ts +32 -0
- package/src/backend-runtime.ts +604 -0
- package/src/bounded-cache.ts +45 -0
- package/src/catalog-runtime.ts +921 -0
- package/src/cel-expression.ts +53 -0
- package/src/cel-map-value.ts +97 -0
- package/src/cel-program.ts +103 -0
- package/src/cel-type.ts +359 -0
- package/src/cel-value.ts +361 -0
- package/src/check-diagnostic.ts +104 -0
- package/src/checker.ts +1045 -0
- package/src/closure-backend.ts +547 -0
- package/src/comprehension-bindings.ts +66 -0
- package/src/comprehension-runtime.ts +157 -0
- package/src/declared-chain.ts +45 -0
- package/src/duration-value.ts +160 -0
- package/src/emitted-module.ts +494 -0
- package/src/engine-version.ts +9 -0
- package/src/environment-digest.ts +111 -0
- package/src/environment.ts +761 -0
- package/src/function-catalog.ts +140 -0
- package/src/function-registry.ts +341 -0
- package/src/index.ts +407 -0
- package/src/integer-arithmetic.ts +64 -0
- package/src/js-emitter.ts +721 -0
- package/src/json-schema-type.ts +664 -0
- package/src/json-text-scan.ts +163 -0
- package/src/lexer.ts +562 -0
- package/src/macro-check.ts +197 -0
- package/src/macro-shape.ts +66 -0
- package/src/member-read.ts +167 -0
- package/src/namespace-resolution.ts +167 -0
- package/src/nominal-type.ts +149 -0
- package/src/nullable-access.ts +95 -0
- package/src/parse-limits.ts +36 -0
- package/src/parser.ts +554 -0
- package/src/qualified-calls.ts +39 -0
- package/src/regular-expression.ts +101 -0
- package/src/reserved-words.ts +94 -0
- package/src/resolved-call.ts +47 -0
- package/src/root-references.ts +126 -0
- package/src/runtime-library.ts +639 -0
- package/src/serializer.ts +262 -0
- package/src/sha256.ts +112 -0
- package/src/signature.ts +127 -0
- package/src/signatures/function-catalog.json +788 -0
- package/src/signatures/standard-library.json +235 -0
- package/src/standard-library.ts +149 -0
- package/src/syntax-diagnostic.ts +72 -0
- package/src/syntax-tree.ts +229 -0
- package/src/timestamp-value.ts +310 -0
- package/src/tree-equality.ts +130 -0
- package/src/type-expression.ts +182 -0
- package/src/value-equality.ts +201 -0
- package/src/value-text.ts +45 -0
- package/src/zoned-calendar.ts +178 -0
package/dist/cel-type.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CEL's types.
|
|
3
|
+
*
|
|
4
|
+
* The domain is deliberately richer than the one an expression can spell, because
|
|
5
|
+
* the checker's whole value is in what it can be *told*: a variable typed from a
|
|
6
|
+
* JSON Schema carries its nested objects, its element types and its unions, and a
|
|
7
|
+
* typo two levels down is then a type error rather than something only a running
|
|
8
|
+
* request discovers.
|
|
9
|
+
*
|
|
10
|
+
* Four shapes exist for that reason and have no syntax of their own:
|
|
11
|
+
*
|
|
12
|
+
* - `record` — an object with named fields, each typed in turn; `open` says whether
|
|
13
|
+
* a field it does not declare is unjudged (a schema with no `properties`) or
|
|
14
|
+
* undeclared (a closed schema).
|
|
15
|
+
* - `union` — carried as a union rather than collapsed to `dyn`, so `int|null` keeps
|
|
16
|
+
* both the arithmetic and the null that makes a dereference worth reporting.
|
|
17
|
+
* - `nominal` — a named type over a base, with invariant arguments: the mechanism a
|
|
18
|
+
* host registers its own vocabulary through. **A nominal is not its base**: it
|
|
19
|
+
* accepts only what is registered for it, which is what makes a slot expecting one
|
|
20
|
+
* refuse a plain value of the base. (The vectors pin this: an operator the base
|
|
21
|
+
* accepts is refused on the named type.)
|
|
22
|
+
* - `parameter` — a type variable in a signature, unified per call and invariant.
|
|
23
|
+
*
|
|
24
|
+
* `dyn` is the top: it is assignable both ways, which is what keeps an unlisted
|
|
25
|
+
* variable or an unknown call result from cascading into a second error.
|
|
26
|
+
*/
|
|
27
|
+
export const DYN = { kind: "dyn" };
|
|
28
|
+
const primitive = (name) => ({ kind: "primitive", name });
|
|
29
|
+
export const INT = primitive("int");
|
|
30
|
+
export const UINT = primitive("uint");
|
|
31
|
+
export const DOUBLE = primitive("double");
|
|
32
|
+
export const BOOL = primitive("bool");
|
|
33
|
+
export const STRING = primitive("string");
|
|
34
|
+
export const BYTES = primitive("bytes");
|
|
35
|
+
export const NULL = primitive("null");
|
|
36
|
+
export const TYPE = primitive("type");
|
|
37
|
+
export const TIMESTAMP = primitive("timestamp");
|
|
38
|
+
export const DURATION = primitive("duration");
|
|
39
|
+
export const listOf = (element) => ({ kind: "list", element });
|
|
40
|
+
export const mapOf = (key, value) => ({ kind: "map", key, value });
|
|
41
|
+
export const optionalOf = (value) => ({ kind: "optional", value });
|
|
42
|
+
export const parameterOf = (name) => ({ kind: "parameter", name });
|
|
43
|
+
/** A union of its distinct members; one member is that member, none is `dyn`. */
|
|
44
|
+
export function unionOf(members) {
|
|
45
|
+
const flat = [];
|
|
46
|
+
for (const member of members) {
|
|
47
|
+
for (const part of member.kind === "union" ? member.members : [member]) {
|
|
48
|
+
if (!flat.some((held) => typesEqual(held, part)))
|
|
49
|
+
flat.push(part);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (flat.length === 0)
|
|
53
|
+
return DYN;
|
|
54
|
+
if (flat.length === 1)
|
|
55
|
+
return flat[0];
|
|
56
|
+
if (flat.some((member) => member.kind === "dyn"))
|
|
57
|
+
return DYN;
|
|
58
|
+
return { kind: "union", members: flat };
|
|
59
|
+
}
|
|
60
|
+
/** The names the timestamp and duration types are written and printed under. */
|
|
61
|
+
export const WELL_KNOWN_TYPE_NAMES = {
|
|
62
|
+
"google.protobuf.Timestamp": "timestamp",
|
|
63
|
+
"google.protobuf.Duration": "duration",
|
|
64
|
+
};
|
|
65
|
+
const PRIMITIVE_PRINTED = {
|
|
66
|
+
int: "int",
|
|
67
|
+
uint: "uint",
|
|
68
|
+
double: "double",
|
|
69
|
+
bool: "bool",
|
|
70
|
+
string: "string",
|
|
71
|
+
bytes: "bytes",
|
|
72
|
+
null: "null",
|
|
73
|
+
type: "type",
|
|
74
|
+
timestamp: "google.protobuf.Timestamp",
|
|
75
|
+
duration: "google.protobuf.Duration",
|
|
76
|
+
};
|
|
77
|
+
export function isDyn(type) {
|
|
78
|
+
return type.kind === "dyn";
|
|
79
|
+
}
|
|
80
|
+
export function typesEqual(left, right) {
|
|
81
|
+
if (left.kind !== right.kind)
|
|
82
|
+
return false;
|
|
83
|
+
switch (left.kind) {
|
|
84
|
+
case "dyn":
|
|
85
|
+
return true;
|
|
86
|
+
case "primitive":
|
|
87
|
+
return left.name === right.name;
|
|
88
|
+
case "list":
|
|
89
|
+
return typesEqual(left.element, right.element);
|
|
90
|
+
case "map": {
|
|
91
|
+
const other = right;
|
|
92
|
+
return typesEqual(left.key, other.key) && typesEqual(left.value, other.value);
|
|
93
|
+
}
|
|
94
|
+
case "optional":
|
|
95
|
+
return typesEqual(left.value, right.value);
|
|
96
|
+
case "record": {
|
|
97
|
+
const other = right;
|
|
98
|
+
if (left.name !== other.name || left.open !== other.open || left.fields.size !== other.fields.size) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
for (const [field, type] of left.fields) {
|
|
102
|
+
const held = other.fields.get(field);
|
|
103
|
+
if (!held || !typesEqual(type, held))
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
case "union": {
|
|
109
|
+
const other = right;
|
|
110
|
+
return (left.members.length === other.members.length &&
|
|
111
|
+
left.members.every((member, at) => typesEqual(member, other.members[at])));
|
|
112
|
+
}
|
|
113
|
+
case "nominal": {
|
|
114
|
+
const other = right;
|
|
115
|
+
return (left.name === other.name &&
|
|
116
|
+
left.args.length === other.args.length &&
|
|
117
|
+
left.args.every((argument, at) => typesEqual(argument, other.args[at])));
|
|
118
|
+
}
|
|
119
|
+
case "parameter":
|
|
120
|
+
return left.name === right.name;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* How a type is written. `top` collapses a list or map of `dyn` to its bare name,
|
|
125
|
+
* which is how the whole type of an expression is reported.
|
|
126
|
+
*/
|
|
127
|
+
export function formatType(type, top = false) {
|
|
128
|
+
switch (type.kind) {
|
|
129
|
+
case "dyn":
|
|
130
|
+
return "dyn";
|
|
131
|
+
case "primitive":
|
|
132
|
+
return PRIMITIVE_PRINTED[type.name];
|
|
133
|
+
case "list":
|
|
134
|
+
return top && isDyn(type.element) ? "list" : `list<${formatType(type.element)}>`;
|
|
135
|
+
case "map":
|
|
136
|
+
return top && isDyn(type.key) && isDyn(type.value)
|
|
137
|
+
? "map"
|
|
138
|
+
: `map<${formatType(type.key)}, ${formatType(type.value)}>`;
|
|
139
|
+
case "optional":
|
|
140
|
+
return `optional<${formatType(type.value)}>`;
|
|
141
|
+
case "record":
|
|
142
|
+
// An unnamed record is the shape a map has at runtime, and that is how a
|
|
143
|
+
// message names it; its fields are what a diagnostic lists, not its type.
|
|
144
|
+
return type.name ?? "map";
|
|
145
|
+
case "union":
|
|
146
|
+
return type.members.map((member) => formatType(member)).join("|");
|
|
147
|
+
case "nominal":
|
|
148
|
+
return type.args.length === 0
|
|
149
|
+
? type.name
|
|
150
|
+
: `${type.name}<${type.args.map((argument) => formatType(argument)).join(", ")}>`;
|
|
151
|
+
case "parameter":
|
|
152
|
+
return type.name;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** The numeric types, over which CEL compares and converts across type. */
|
|
156
|
+
const NUMERIC = new Set(["int", "uint", "double"]);
|
|
157
|
+
export function isNumeric(type) {
|
|
158
|
+
return type.kind === "primitive" && NUMERIC.has(type.name);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The type with every unresolved type parameter replaced by `dyn` — the last step before a
|
|
162
|
+
* type is REPORTED.
|
|
163
|
+
*
|
|
164
|
+
* cel-spec's rule is that an unresolved parameter behaves as `dyn` wherever it is used, and
|
|
165
|
+
* the type handed out is a use like any other: a consumer that reads `list<T>` has to know
|
|
166
|
+
* what `T` means to this engine, and the answer is "nothing — it was never resolved". A
|
|
167
|
+
* parameter survives only where it is DECLARED: a signature's text, a nominal type's
|
|
168
|
+
* parameter list.
|
|
169
|
+
*/
|
|
170
|
+
export function withoutParameters(type) {
|
|
171
|
+
switch (type.kind) {
|
|
172
|
+
case "parameter":
|
|
173
|
+
return DYN;
|
|
174
|
+
case "list": {
|
|
175
|
+
const element = withoutParameters(type.element);
|
|
176
|
+
return element === type.element ? type : listOf(element);
|
|
177
|
+
}
|
|
178
|
+
case "map": {
|
|
179
|
+
const key = withoutParameters(type.key);
|
|
180
|
+
const value = withoutParameters(type.value);
|
|
181
|
+
return key === type.key && value === type.value ? type : mapOf(key, value);
|
|
182
|
+
}
|
|
183
|
+
case "optional": {
|
|
184
|
+
const value = withoutParameters(type.value);
|
|
185
|
+
return value === type.value ? type : optionalOf(value);
|
|
186
|
+
}
|
|
187
|
+
case "union":
|
|
188
|
+
return unionOf(type.members.map(withoutParameters));
|
|
189
|
+
case "nominal": {
|
|
190
|
+
const args = type.args.map(withoutParameters);
|
|
191
|
+
return args.every((argument, at) => argument === type.args[at]) ? type : { ...type, args };
|
|
192
|
+
}
|
|
193
|
+
case "record": {
|
|
194
|
+
let moved = false;
|
|
195
|
+
const fields = new Map();
|
|
196
|
+
for (const [name, held] of type.fields) {
|
|
197
|
+
const replaced = withoutParameters(held);
|
|
198
|
+
if (replaced !== held)
|
|
199
|
+
moved = true;
|
|
200
|
+
fields.set(name, replaced);
|
|
201
|
+
}
|
|
202
|
+
return moved ? { ...type, fields } : type;
|
|
203
|
+
}
|
|
204
|
+
default:
|
|
205
|
+
return type;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** Whether `type` admits a null value — a null, or a union holding one. */
|
|
209
|
+
export function admitsNull(type) {
|
|
210
|
+
if (type.kind === "primitive")
|
|
211
|
+
return type.name === "null";
|
|
212
|
+
if (type.kind === "union")
|
|
213
|
+
return type.members.some(admitsNull);
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
/** The type with every null taken out of it; `dyn` and a bare null are unchanged. */
|
|
217
|
+
export function withoutNull(type) {
|
|
218
|
+
if (type.kind !== "union")
|
|
219
|
+
return type;
|
|
220
|
+
const members = type.members.filter((member) => !admitsNull(member));
|
|
221
|
+
return members.length === 0 ? type : unionOf(members);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Whether a value of `from` may stand where `to` is wanted.
|
|
225
|
+
*
|
|
226
|
+
* `dyn` passes both ways; a nominal type accepts only itself (its base is a
|
|
227
|
+
* different type); a union passes where every member does, and accepts a value any
|
|
228
|
+
* member accepts. Numeric types do **not** convert implicitly — CEL's cross-type
|
|
229
|
+
* arithmetic and comparison are declared overloads, not coercions.
|
|
230
|
+
*/
|
|
231
|
+
export function assignable(from, to) {
|
|
232
|
+
if (isDyn(from) || isDyn(to))
|
|
233
|
+
return true;
|
|
234
|
+
// An unresolved parameter is an unknown type: it stands where anything is wanted and
|
|
235
|
+
// accepts anything, exactly as `dyn` does. What it does NOT have is members — asking
|
|
236
|
+
// for one has no answer, and the checker refuses there rather than here.
|
|
237
|
+
if (to.kind === "parameter" || from.kind === "parameter")
|
|
238
|
+
return true;
|
|
239
|
+
if (from.kind === "union")
|
|
240
|
+
return from.members.every((member) => assignable(member, to));
|
|
241
|
+
if (to.kind === "union")
|
|
242
|
+
return to.members.some((member) => assignable(from, member));
|
|
243
|
+
if (from.kind === "nominal" || to.kind === "nominal")
|
|
244
|
+
return typesEqual(from, to);
|
|
245
|
+
switch (to.kind) {
|
|
246
|
+
case "list":
|
|
247
|
+
return from.kind === "list" && assignable(from.element, to.element);
|
|
248
|
+
case "map":
|
|
249
|
+
return ((from.kind === "map" && assignable(from.key, to.key) && assignable(from.value, to.value)) ||
|
|
250
|
+
// A record is a map with named keys, so it stands where a string-keyed map does.
|
|
251
|
+
(from.kind === "record" && assignable(STRING, to.key) && recordValuesAssignable(from, to.value)));
|
|
252
|
+
case "optional":
|
|
253
|
+
return from.kind === "optional" && assignable(from.value, to.value);
|
|
254
|
+
case "record":
|
|
255
|
+
return from.kind === "record" && typesEqual(from, to);
|
|
256
|
+
default:
|
|
257
|
+
return typesEqual(from, to);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function recordValuesAssignable(record, to) {
|
|
261
|
+
if (isDyn(to))
|
|
262
|
+
return true;
|
|
263
|
+
if (record.open)
|
|
264
|
+
return false;
|
|
265
|
+
return [...record.fields.values()].every((type) => assignable(type, to));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* The one type both arms can be. Unlike assignability this is symmetric, and it is
|
|
269
|
+
* what an aggregate literal's elements and a ternary's branches are reduced through:
|
|
270
|
+
* nothing in common is `dyn`, which is CEL's own reading of a heterogeneous literal.
|
|
271
|
+
*
|
|
272
|
+
* **An unresolved parameter yields to the other side**, so the element type of
|
|
273
|
+
* `[[[[]]]], [], [[[]]]]` is the deepest list rather than `dyn`: an empty aggregate
|
|
274
|
+
* says nothing about its elements and must not erase what a sibling does say.
|
|
275
|
+
*/
|
|
276
|
+
export function unify(left, right) {
|
|
277
|
+
if (typesEqual(left, right))
|
|
278
|
+
return left;
|
|
279
|
+
if (left.kind === "parameter")
|
|
280
|
+
return right;
|
|
281
|
+
if (right.kind === "parameter")
|
|
282
|
+
return left;
|
|
283
|
+
if (isDyn(left) || isDyn(right))
|
|
284
|
+
return DYN;
|
|
285
|
+
if (left.kind === "list" && right.kind === "list")
|
|
286
|
+
return listOf(unify(left.element, right.element));
|
|
287
|
+
if (left.kind === "map" && right.kind === "map") {
|
|
288
|
+
return mapOf(unify(left.key, right.key), unify(left.value, right.value));
|
|
289
|
+
}
|
|
290
|
+
if (left.kind === "optional" && right.kind === "optional")
|
|
291
|
+
return optionalOf(unify(left.value, right.value));
|
|
292
|
+
return DYN;
|
|
293
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CEL value domain, and how a value says what it is.
|
|
3
|
+
*
|
|
4
|
+
* **Identity is a string type key under `Symbol.for("telo.cel.value")`, never
|
|
5
|
+
* `instanceof`.** Two copies of this engine loaded independently are two sets of
|
|
6
|
+
* classes, so a constructor check would make a `uint` built by one copy not a uint to
|
|
7
|
+
* the other — `+`, `type()` and every overload would refuse it. A symbol from the
|
|
8
|
+
* global registry is the same symbol in both, so the key is readable across copies,
|
|
9
|
+
* and because a symbol-keyed member cannot appear in parsed JSON an inbound request
|
|
10
|
+
* body cannot forge a duration. A plain object carrying a *string*-keyed look-alike
|
|
11
|
+
* (`{"telo.cel.value": "uint"}`) is therefore data: it reads as a map, as it must.
|
|
12
|
+
*
|
|
13
|
+
* What is **plain** carries no key, because the host platform already represents it
|
|
14
|
+
* one way and only one: `null`, a boolean, a string, a double (`number`), an int
|
|
15
|
+
* (`bigint`), bytes (`Uint8Array`), a list (an array) and a map whose keys are all
|
|
16
|
+
* strings (a plain object, which is how a host hands one over). What has no faithful
|
|
17
|
+
* plain form carries the key: a `uint` (a `bigint` is already an int), a timestamp and
|
|
18
|
+
* a duration (both nanosecond-precise, which no host date type holds), a type value,
|
|
19
|
+
* an optional, a map with typed keys, and a CEL error. A host's own named type
|
|
20
|
+
* registers its own key, checked against this set at registration.
|
|
21
|
+
*
|
|
22
|
+
* The keys are a **closed set** (`CEL_VALUE_KEYS`); a new one is a change here.
|
|
23
|
+
*/
|
|
24
|
+
import type { CelLiteral, SourceRange } from "./syntax-tree.js";
|
|
25
|
+
export declare const CEL_VALUE_TYPE: unique symbol;
|
|
26
|
+
/** The type keys this engine owns. A host-registered type may not reuse one. */
|
|
27
|
+
export declare const CEL_VALUE_KEYS: readonly ["uint", "google.protobuf.Timestamp", "google.protobuf.Duration", "type", "optional", "map", "error"];
|
|
28
|
+
export type CelValueKey = (typeof CEL_VALUE_KEYS)[number];
|
|
29
|
+
interface Branded<Key extends string> {
|
|
30
|
+
readonly [CEL_VALUE_TYPE]: Key;
|
|
31
|
+
}
|
|
32
|
+
/** An unsigned 64-bit integer. A `bigint` alone is already CEL's `int`. */
|
|
33
|
+
export interface CelUint extends Branded<"uint"> {
|
|
34
|
+
readonly value: bigint;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* An instant: whole seconds since the epoch plus nanoseconds in `[0, 1e9)`, so a
|
|
38
|
+
* negative instant is still `seconds` floored and `nanos` non-negative. Nanosecond
|
|
39
|
+
* precision is required of the domain — `string(timestamp('…999999999Z'))` is a row.
|
|
40
|
+
*/
|
|
41
|
+
export interface CelTimestamp extends Branded<"google.protobuf.Timestamp"> {
|
|
42
|
+
readonly seconds: bigint;
|
|
43
|
+
readonly nanos: number;
|
|
44
|
+
}
|
|
45
|
+
/** A span: seconds and nanoseconds of the **same sign**, `|nanos| < 1e9`. */
|
|
46
|
+
export interface CelDuration extends Branded<"google.protobuf.Duration"> {
|
|
47
|
+
readonly seconds: bigint;
|
|
48
|
+
readonly nanos: number;
|
|
49
|
+
}
|
|
50
|
+
/** A type as a value — what `type(x)` answers and what `int` denotes. */
|
|
51
|
+
export interface CelTypeValue extends Branded<"type"> {
|
|
52
|
+
readonly name: string;
|
|
53
|
+
}
|
|
54
|
+
/** `optional.of(v)` and `optional.none()`. */
|
|
55
|
+
export interface CelOptional extends Branded<"optional"> {
|
|
56
|
+
readonly present: boolean;
|
|
57
|
+
readonly held?: CelValue;
|
|
58
|
+
}
|
|
59
|
+
/** One entry of a map, keyed by the canonical text of its key (`cel-map-value.ts`). */
|
|
60
|
+
export interface CelMapValueEntry {
|
|
61
|
+
readonly key: CelValue;
|
|
62
|
+
readonly value: CelValue;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* What identifies a key inside a map's entries. A `Map` distinguishes its own keys **by
|
|
66
|
+
* type**, so the four CEL key types collapse onto three JS ones with no namespace to
|
|
67
|
+
* separate by hand: a string key is itself, a bool is itself, and an int, a uint and a
|
|
68
|
+
* whole double are all the `bigint` CEL equality makes them.
|
|
69
|
+
*/
|
|
70
|
+
export type CelMapKey = string | bigint | boolean;
|
|
71
|
+
/**
|
|
72
|
+
* A map. Entries live in a `Map` keyed by each key's own `CelMapKey`, so the map holds
|
|
73
|
+
* int, uint, bool and string keys alike and **no key is ever a property name**:
|
|
74
|
+
* `__proto__`, `constructor` and `prototype` are data here, as they are in any map.
|
|
75
|
+
*/
|
|
76
|
+
export interface CelMap extends Branded<"map"> {
|
|
77
|
+
readonly entries: ReadonlyMap<CelMapKey, CelMapValueEntry>;
|
|
78
|
+
}
|
|
79
|
+
/** Every evaluation failure this engine names. A code is never derived from a message. */
|
|
80
|
+
export declare const CEL_EVALUATION_CODES: readonly ["no_such_key", "no_such_variable", "index_out_of_range", "no_matching_overload", "unsupported_container", "unsupported_key_type", "duplicate_map_key", "numeric_overflow", "division_by_zero", "modulo_by_zero", "invalid_conversion", "invalid_argument", "invalid_regular_expression", "optional_value_missing", "unbound_function", "async_value_unsupported"];
|
|
81
|
+
export type CelEvaluationCode = (typeof CEL_EVALUATION_CODES)[number];
|
|
82
|
+
/**
|
|
83
|
+
* A failure as a **value**. It is not thrown: `false && <error>` is `false`, so every
|
|
84
|
+
* operator, comprehension step and conditional carries an error-valued operand
|
|
85
|
+
* through, and only the top of an evaluation turns a surviving one into a throw
|
|
86
|
+
* (`cel-program.ts`). Throwing from the operator that found it would make the
|
|
87
|
+
* short-circuit rules unimplementable.
|
|
88
|
+
*/
|
|
89
|
+
export interface CelError extends Branded<"error"> {
|
|
90
|
+
readonly code: CelEvaluationCode;
|
|
91
|
+
readonly message: string;
|
|
92
|
+
readonly range?: SourceRange;
|
|
93
|
+
}
|
|
94
|
+
/** A value of a host-registered named type: its own key, outside `CEL_VALUE_KEYS`. */
|
|
95
|
+
export interface CelHostValue {
|
|
96
|
+
readonly [CEL_VALUE_TYPE]: string;
|
|
97
|
+
}
|
|
98
|
+
/** A map whose keys are all strings, as a host hands one over. */
|
|
99
|
+
export interface CelRecord {
|
|
100
|
+
readonly [key: string]: CelValue;
|
|
101
|
+
}
|
|
102
|
+
export type CelValue = null | boolean | string | number | bigint | Uint8Array | readonly CelValue[] | CelUint | CelTimestamp | CelDuration | CelTypeValue | CelOptional | CelMap | CelError | CelHostValue | CelRecord;
|
|
103
|
+
export declare function celUint(value: bigint): CelUint;
|
|
104
|
+
export declare function celTypeValue(name: string): CelTypeValue;
|
|
105
|
+
export declare function celNone(): CelOptional;
|
|
106
|
+
export declare function celSome(held: CelValue): CelOptional;
|
|
107
|
+
export declare function celError(code: CelEvaluationCode, message: string, range?: SourceRange): CelError;
|
|
108
|
+
export declare function isCelError(value: unknown): value is CelError;
|
|
109
|
+
export declare function isCelOptional(value: unknown): value is CelOptional;
|
|
110
|
+
export declare function isCelUint(value: unknown): value is CelUint;
|
|
111
|
+
export declare function isCelMap(value: unknown): value is CelMap;
|
|
112
|
+
export declare function isCelTimestamp(value: unknown): value is CelTimestamp;
|
|
113
|
+
export declare function isCelDuration(value: unknown): value is CelDuration;
|
|
114
|
+
export declare function isCelTypeValue(value: unknown): value is CelTypeValue;
|
|
115
|
+
/**
|
|
116
|
+
* Whether a value is bytes. `Object.prototype.toString` rather than `instanceof`, so a
|
|
117
|
+
* buffer built in another realm is still bytes — the same reason the brand is a
|
|
118
|
+
* registered symbol.
|
|
119
|
+
*/
|
|
120
|
+
export declare function isCelBytes(value: unknown): value is Uint8Array;
|
|
121
|
+
/**
|
|
122
|
+
* Whether a value is a map a host handed over: a plain object, not a branded one.
|
|
123
|
+
*
|
|
124
|
+
* The prototype decides, which is why nothing else needs checking: an array, a buffer and
|
|
125
|
+
* a class instance all have a prototype of their own, so none of them is a record. It is
|
|
126
|
+
* also the cheapest test there is, and this runs on every member read.
|
|
127
|
+
*/
|
|
128
|
+
export declare function isCelRecord(value: unknown): value is CelRecord;
|
|
129
|
+
/**
|
|
130
|
+
* The name of a value's CEL type, or nothing when the value is of no CEL type. It is
|
|
131
|
+
* what `type()` answers and what an overload is dispatched on, so it must answer for
|
|
132
|
+
* **any** value — `type()` has no `dyn` overload to fall back on.
|
|
133
|
+
*/
|
|
134
|
+
export declare function celTypeNameOf(value: unknown): string | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* A thenable reaching evaluation is refused, never passed along: evaluation is
|
|
137
|
+
* synchronous, and a promise flowing through an expression would be an invocation in
|
|
138
|
+
* disguise — invisible to a journal, absent from a trace, and unrepresentable as a
|
|
139
|
+
* step.
|
|
140
|
+
*
|
|
141
|
+
* The check is made at every **door** a host value comes through — an activation read, a
|
|
142
|
+
* registered implementation's result, a member read, an element entering a comprehension
|
|
143
|
+
* body, the value a name is bound to — and the list of them is in the package guide, which
|
|
144
|
+
* is where completeness is argued. `asyncValueRefused` is the one error they all answer
|
|
145
|
+
* with, so the code and the wording cannot drift between doors.
|
|
146
|
+
*/
|
|
147
|
+
export declare function isThenable(value: unknown): boolean;
|
|
148
|
+
/**
|
|
149
|
+
* The refusal a value that must be awaited becomes, or nothing where it is an ordinary
|
|
150
|
+
* value.
|
|
151
|
+
*
|
|
152
|
+
* **A container is NOT walked**, and that is deliberate rather than a gap: a thenable inside
|
|
153
|
+
* a host list or map is refused when it becomes a value the engine reasons about — read by
|
|
154
|
+
* index, read as a member, or bound into a body — so every element costs one `typeof` when it
|
|
155
|
+
* is actually used, instead of every read costing a walk of what it returned.
|
|
156
|
+
*/
|
|
157
|
+
export declare function asyncValueRefused(value: unknown, range?: SourceRange): CelError | undefined;
|
|
158
|
+
/**
|
|
159
|
+
* The value a literal node denotes. A tagged literal is not a bare host value — `1` and
|
|
160
|
+
* `1u` are different expressions — so the one reading of a tag lives here, where both
|
|
161
|
+
* backends and the checker's literal-argument guard reach it rather than each keeping a
|
|
162
|
+
* switch of its own.
|
|
163
|
+
*/
|
|
164
|
+
export declare function literalValue(literal: CelLiteral): CelValue;
|
|
165
|
+
export {};
|
|
166
|
+
//# sourceMappingURL=cel-value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cel-value.d.ts","sourceRoot":"","sources":["../src/cel-value.ts"],"names":[],"mappings":"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"}
|