@telorun/cel 0.0.0-stage → 0.107.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 +146 -0
- package/dist/backend-runtime.d.ts.map +1 -0
- package/dist/backend-runtime.js +322 -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 +785 -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 +34 -0
- package/dist/cel-map-value.d.ts.map +1 -0
- package/dist/cel-map-value.js +74 -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 +159 -0
- package/dist/cel-value.d.ts.map +1 -0
- package/dist/cel-value.js +225 -0
- package/dist/check-diagnostic.d.ts +53 -0
- package/dist/check-diagnostic.d.ts.map +1 -0
- package/dist/check-diagnostic.js +66 -0
- package/dist/checker.d.ts +77 -0
- package/dist/checker.d.ts.map +1 -0
- package/dist/checker.js +721 -0
- package/dist/closure-backend.d.ts +21 -0
- package/dist/closure-backend.d.ts.map +1 -0
- package/dist/closure-backend.js +436 -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 +59 -0
- package/dist/duration-value.d.ts.map +1 -0
- package/dist/duration-value.js +135 -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 +283 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +459 -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 +78 -0
- package/dist/function-registry.d.ts.map +1 -0
- package/dist/function-registry.js +189 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -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 +132 -0
- package/dist/js-emitter.d.ts.map +1 -0
- package/dist/js-emitter.js +562 -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 +33 -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 +52 -0
- package/dist/member-read.d.ts.map +1 -0
- package/dist/member-read.js +125 -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 +33 -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 +56 -0
- package/dist/runtime-library.d.ts.map +1 -0
- package/dist/runtime-library.js +545 -0
- package/dist/serializer.d.ts +24 -0
- package/dist/serializer.d.ts.map +1 -0
- package/dist/serializer.js +240 -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 +53 -0
- package/dist/timestamp-value.d.ts.map +1 -0
- package/dist/timestamp-value.js +223 -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 +26 -0
- package/dist/type-expression.d.ts.map +1 -0
- package/dist/type-expression.js +134 -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 +454 -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 +86 -0
- package/src/cel-program.ts +103 -0
- package/src/cel-type.ts +359 -0
- package/src/cel-value.ts +353 -0
- package/src/check-diagnostic.ts +102 -0
- package/src/checker.ts +932 -0
- package/src/closure-backend.ts +502 -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 +145 -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 +740 -0
- package/src/function-catalog.ts +140 -0
- package/src/function-registry.ts +229 -0
- package/src/index.ts +386 -0
- package/src/integer-arithmetic.ts +64 -0
- package/src/js-emitter.ts +713 -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 +191 -0
- package/src/macro-shape.ts +66 -0
- package/src/member-read.ts +126 -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 +34 -0
- package/src/root-references.ts +126 -0
- package/src/runtime-library.ts +615 -0
- package/src/serializer.ts +246 -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 +294 -0
- package/src/tree-equality.ts +130 -0
- package/src/type-expression.ts +160 -0
- package/src/value-equality.ts +201 -0
- package/src/value-text.ts +45 -0
- package/src/zoned-calendar.ts +178 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `matches` — and it is RE2, not the host's regular expressions.
|
|
3
|
+
*
|
|
4
|
+
* CEL's pattern language is RE2: linear-time matching with no backreferences and no
|
|
5
|
+
* lookaround. The host's own engine accepts patterns RE2 refuses and is exponential on
|
|
6
|
+
* some of them, so an expression that matches here would behave differently on another
|
|
7
|
+
* runtime and a hostile pattern in a manifest would be a denial of service. A pattern
|
|
8
|
+
* RE2 cannot parse is `invalid_regular_expression`, never a silent `false`.
|
|
9
|
+
*
|
|
10
|
+
* Compilation is memoized, bounded, because a pattern is almost always a literal
|
|
11
|
+
* evaluated many times. **One compile serves every caller** — the language's `matches`
|
|
12
|
+
* and the catalog's regex family alike — so a pattern is read one way and the cache is
|
|
13
|
+
* not duplicated; what differs is only how each words its refusal, which is why a refusal
|
|
14
|
+
* answers RE2's parse-error KIND beside the library's whole message.
|
|
15
|
+
*/
|
|
16
|
+
import { RE2JS, RE2JSSyntaxException } from "re2js";
|
|
17
|
+
import { BoundedCache } from "./bounded-cache.js";
|
|
18
|
+
import { celError } from "./cel-value.js";
|
|
19
|
+
/** How many compiled patterns one process keeps. */
|
|
20
|
+
export const PATTERN_CACHE_CAPACITY = 128;
|
|
21
|
+
/** The flag letters a caller may map onto RE2's own flags. */
|
|
22
|
+
export const RE2_FLAG_LETTERS = {
|
|
23
|
+
i: RE2JS.CASE_INSENSITIVE,
|
|
24
|
+
m: RE2JS.MULTILINE,
|
|
25
|
+
s: RE2JS.DOTALL,
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* RE2's parse-error kinds, in RE2's own words — the closed vocabulary an invalid-pattern
|
|
29
|
+
* refusal ends with, so every engine words one identically. The last two are RE2's parser
|
|
30
|
+
* limits: a nesting height above 1000, and a parsed size above 3,355,443.
|
|
31
|
+
*/
|
|
32
|
+
export const RE2_PATTERN_ERROR_KINDS = [
|
|
33
|
+
"missing closing )",
|
|
34
|
+
"missing closing ]",
|
|
35
|
+
"unexpected )",
|
|
36
|
+
"trailing backslash at end of expression",
|
|
37
|
+
"invalid escape sequence",
|
|
38
|
+
"invalid character class range",
|
|
39
|
+
"invalid named capture",
|
|
40
|
+
"duplicate capture group name",
|
|
41
|
+
"invalid or unsupported Perl syntax",
|
|
42
|
+
"missing argument to repetition operator",
|
|
43
|
+
"invalid nested repetition operator",
|
|
44
|
+
"invalid repeat count",
|
|
45
|
+
"expression nests too deeply",
|
|
46
|
+
"expression too large",
|
|
47
|
+
];
|
|
48
|
+
const compiled = new BoundedCache(PATTERN_CACHE_CAPACITY);
|
|
49
|
+
/** A compiled pattern, or why RE2 refused it. One compile and one cache for every caller. */
|
|
50
|
+
export function re2Pattern(pattern, flags = 0) {
|
|
51
|
+
const key = `${flags}\u0000${pattern}`;
|
|
52
|
+
let held = compiled.get(key);
|
|
53
|
+
if (held === undefined) {
|
|
54
|
+
try {
|
|
55
|
+
held = { pattern: RE2JS.compile(pattern, flags) };
|
|
56
|
+
}
|
|
57
|
+
catch (cause) {
|
|
58
|
+
const kind = cause instanceof RE2JSSyntaxException ? cause.error : undefined;
|
|
59
|
+
held = {
|
|
60
|
+
refused: {
|
|
61
|
+
...(kind !== undefined && RE2_PATTERN_ERROR_KINDS.includes(kind) ? { kind } : {}),
|
|
62
|
+
message: cause.message,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
compiled.set(key, held);
|
|
67
|
+
}
|
|
68
|
+
return held;
|
|
69
|
+
}
|
|
70
|
+
/** Whether the pattern matches anywhere in the text, or why the pattern is not one. */
|
|
71
|
+
export function celMatches(text, pattern, range) {
|
|
72
|
+
const held = re2Pattern(pattern);
|
|
73
|
+
if ("refused" in held) {
|
|
74
|
+
return celError("invalid_regular_expression", `${JSON.stringify(pattern)} is not an RE2 pattern: ${held.refused.message}`, range);
|
|
75
|
+
}
|
|
76
|
+
return held.pattern.matcher(text).find();
|
|
77
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words no CEL identifier may be: cel-spec's `RESERVED` production, which its
|
|
3
|
+
* `IDENT` production excludes. All 21 of them.
|
|
4
|
+
*
|
|
5
|
+
* The set is frozen deliberately: a word added here stops a manifest that uses it as
|
|
6
|
+
* a variable or a function name from parsing, so it is widened only with a
|
|
7
|
+
* deprecation behind it.
|
|
8
|
+
*
|
|
9
|
+
* **Three of the 21 are refused by being read as something else**, and the
|
|
10
|
+
* distinction is the lexer's whole policy about words, so it lives here rather than
|
|
11
|
+
* there. `true`, `false` and `null` are literals; `in` is the membership operator.
|
|
12
|
+
* Neither reading can be reached from a name position, which is why cel-spec needs
|
|
13
|
+
* them in `RESERVED` and why an engine must not quietly accept one as a name — doing
|
|
14
|
+
* so breaks the premise every consumer of the set is written against.
|
|
15
|
+
*
|
|
16
|
+
* **A reserved word is refused as an IDENTIFIER, not as a member name.** CEL's own
|
|
17
|
+
* conformance suite reads `{'let': 1}.let` and `a.while()`; `a.in` and `a.true` are
|
|
18
|
+
* the same position, and read for the same reason. A member name is a name of a
|
|
19
|
+
* value's entry, not a name in the expression's scope.
|
|
20
|
+
*
|
|
21
|
+
* **No host's property names are here.** A member *name* is written by the author; a
|
|
22
|
+
* member *key* can come from a request (`a[request.query.k]`), so a word list cannot
|
|
23
|
+
* be what keeps a host's property out of a CEL value — it does not touch the computed
|
|
24
|
+
* form at all. That guarantee belongs to the member-read operation, which resolves
|
|
25
|
+
* every form against the value's own entries and never performs a host property read.
|
|
26
|
+
* `constructor` never being on any such list is the same point made by its absence.
|
|
27
|
+
*
|
|
28
|
+
* `cel` and `optional` are legal identifiers, reserved only against being registered
|
|
29
|
+
* as a namespace (`namespace-resolution.ts`), because the standard macros are written
|
|
30
|
+
* on them (`cel.bind`, `optional.of`).
|
|
31
|
+
*/
|
|
32
|
+
export declare const RESERVED_WORDS: readonly string[];
|
|
33
|
+
/** The reserved words that are a literal where they stand. */
|
|
34
|
+
export declare const LITERAL_WORDS: readonly string[];
|
|
35
|
+
/** The reserved words that are an operator where they stand. */
|
|
36
|
+
export declare const OPERATOR_WORDS: readonly string[];
|
|
37
|
+
/** How a word is read where an expression begins. */
|
|
38
|
+
export type WordReading =
|
|
39
|
+
/** An ordinary identifier. */
|
|
40
|
+
"name"
|
|
41
|
+
/** A literal value: `true`, `false`, `null`. */
|
|
42
|
+
| "literal"
|
|
43
|
+
/** An operator written as a word: `in`. */
|
|
44
|
+
| "operator"
|
|
45
|
+
/** Reserved, with no other reading — refused wherever a name is read. */
|
|
46
|
+
| "refused";
|
|
47
|
+
export declare function wordReading(text: string): WordReading;
|
|
48
|
+
/** Whether the word is one cel-spec reserves, however it is read. */
|
|
49
|
+
export declare function isReservedWord(name: string): boolean;
|
|
50
|
+
/** Whether the text is spelled as a CEL identifier, reserved or not. */
|
|
51
|
+
export declare function isIdentifierSpelling(text: string): boolean;
|
|
52
|
+
//# sourceMappingURL=reserved-words.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reserved-words.d.ts","sourceRoot":"","sources":["../src/reserved-words.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAsB3C,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAA8B,CAAC;AAE1E,gEAAgE;AAChE,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAAW,CAAC;AAMxD,qDAAqD;AACrD,MAAM,MAAM,WAAW;AACrB,8BAA8B;AAC5B,MAAM;AACR,gDAAgD;GAC9C,SAAS;AACX,2CAA2C;GACzC,UAAU;AACZ,yEAAyE;GACvE,SAAS,CAAC;AAEd,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAIrD;AAED,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAID,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words no CEL identifier may be: cel-spec's `RESERVED` production, which its
|
|
3
|
+
* `IDENT` production excludes. All 21 of them.
|
|
4
|
+
*
|
|
5
|
+
* The set is frozen deliberately: a word added here stops a manifest that uses it as
|
|
6
|
+
* a variable or a function name from parsing, so it is widened only with a
|
|
7
|
+
* deprecation behind it.
|
|
8
|
+
*
|
|
9
|
+
* **Three of the 21 are refused by being read as something else**, and the
|
|
10
|
+
* distinction is the lexer's whole policy about words, so it lives here rather than
|
|
11
|
+
* there. `true`, `false` and `null` are literals; `in` is the membership operator.
|
|
12
|
+
* Neither reading can be reached from a name position, which is why cel-spec needs
|
|
13
|
+
* them in `RESERVED` and why an engine must not quietly accept one as a name — doing
|
|
14
|
+
* so breaks the premise every consumer of the set is written against.
|
|
15
|
+
*
|
|
16
|
+
* **A reserved word is refused as an IDENTIFIER, not as a member name.** CEL's own
|
|
17
|
+
* conformance suite reads `{'let': 1}.let` and `a.while()`; `a.in` and `a.true` are
|
|
18
|
+
* the same position, and read for the same reason. A member name is a name of a
|
|
19
|
+
* value's entry, not a name in the expression's scope.
|
|
20
|
+
*
|
|
21
|
+
* **No host's property names are here.** A member *name* is written by the author; a
|
|
22
|
+
* member *key* can come from a request (`a[request.query.k]`), so a word list cannot
|
|
23
|
+
* be what keeps a host's property out of a CEL value — it does not touch the computed
|
|
24
|
+
* form at all. That guarantee belongs to the member-read operation, which resolves
|
|
25
|
+
* every form against the value's own entries and never performs a host property read.
|
|
26
|
+
* `constructor` never being on any such list is the same point made by its absence.
|
|
27
|
+
*
|
|
28
|
+
* `cel` and `optional` are legal identifiers, reserved only against being registered
|
|
29
|
+
* as a namespace (`namespace-resolution.ts`), because the standard macros are written
|
|
30
|
+
* on them (`cel.bind`, `optional.of`).
|
|
31
|
+
*/
|
|
32
|
+
export const RESERVED_WORDS = [
|
|
33
|
+
"as",
|
|
34
|
+
"break",
|
|
35
|
+
"const",
|
|
36
|
+
"continue",
|
|
37
|
+
"else",
|
|
38
|
+
"false",
|
|
39
|
+
"for",
|
|
40
|
+
"function",
|
|
41
|
+
"if",
|
|
42
|
+
"import",
|
|
43
|
+
"in",
|
|
44
|
+
"let",
|
|
45
|
+
"loop",
|
|
46
|
+
"namespace",
|
|
47
|
+
"null",
|
|
48
|
+
"package",
|
|
49
|
+
"return",
|
|
50
|
+
"true",
|
|
51
|
+
"var",
|
|
52
|
+
"void",
|
|
53
|
+
"while",
|
|
54
|
+
];
|
|
55
|
+
/** The reserved words that are a literal where they stand. */
|
|
56
|
+
export const LITERAL_WORDS = ["true", "false", "null"];
|
|
57
|
+
/** The reserved words that are an operator where they stand. */
|
|
58
|
+
export const OPERATOR_WORDS = ["in"];
|
|
59
|
+
const RESERVED = new Set(RESERVED_WORDS);
|
|
60
|
+
const LITERALS = new Set(LITERAL_WORDS);
|
|
61
|
+
const OPERATORS = new Set(OPERATOR_WORDS);
|
|
62
|
+
export function wordReading(text) {
|
|
63
|
+
if (LITERALS.has(text))
|
|
64
|
+
return "literal";
|
|
65
|
+
if (OPERATORS.has(text))
|
|
66
|
+
return "operator";
|
|
67
|
+
return RESERVED.has(text) ? "refused" : "name";
|
|
68
|
+
}
|
|
69
|
+
/** Whether the word is one cel-spec reserves, however it is read. */
|
|
70
|
+
export function isReservedWord(name) {
|
|
71
|
+
return RESERVED.has(name);
|
|
72
|
+
}
|
|
73
|
+
const IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
74
|
+
/** Whether the text is spelled as a CEL identifier, reserved or not. */
|
|
75
|
+
export function isIdentifierSpelling(text) {
|
|
76
|
+
return IDENTIFIER.test(text);
|
|
77
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which function each call in an expression resolved to.
|
|
3
|
+
*
|
|
4
|
+
* A host needs this for policy the engine cannot know: whether a non-deterministic call
|
|
5
|
+
* sits in a field evaluated once at startup, whether a call reaches the host at all,
|
|
6
|
+
* which error codes a call can fail with. All three are properties of the **resolved**
|
|
7
|
+
* signature, not of the name written — two overloads of one name can differ in every
|
|
8
|
+
* one of them — so the answer has to come from the checker, which is what resolved it.
|
|
9
|
+
*
|
|
10
|
+
* **It is the checker's lowering, not the tree.** A macro is not a dispatch and is not
|
|
11
|
+
* listed: `xs.map(i, i)` becomes a comprehension and reaches no function, while the
|
|
12
|
+
* calls written inside it are listed where they are written. A list read off the tree
|
|
13
|
+
* would instead report whatever the reader's parser happened to expand.
|
|
14
|
+
*/
|
|
15
|
+
import type { CallForm } from "./signature.js";
|
|
16
|
+
import type { SourceRange } from "./syntax-tree.js";
|
|
17
|
+
export interface ResolvedCall {
|
|
18
|
+
/** The name as written — `<namespace>.<name>` for a namespaced call. */
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly form: CallForm;
|
|
21
|
+
/** Set only for a namespaced call. */
|
|
22
|
+
readonly namespace?: string;
|
|
23
|
+
readonly arity: number;
|
|
24
|
+
readonly range: SourceRange;
|
|
25
|
+
/** The signature it resolved to, absent where nothing resolved. */
|
|
26
|
+
readonly signature?: string;
|
|
27
|
+
/** The type the call answers here, with type parameters substituted. */
|
|
28
|
+
readonly returns?: string;
|
|
29
|
+
readonly deterministic?: boolean;
|
|
30
|
+
readonly hostBacked?: boolean;
|
|
31
|
+
readonly throws?: readonly string[];
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=resolved-call.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolved-call.d.ts","sourceRoot":"","sources":["../src/resolved-call.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,sCAAsC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,mEAAmE;IACnE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which function each call in an expression resolved to.
|
|
3
|
+
*
|
|
4
|
+
* A host needs this for policy the engine cannot know: whether a non-deterministic call
|
|
5
|
+
* sits in a field evaluated once at startup, whether a call reaches the host at all,
|
|
6
|
+
* which error codes a call can fail with. All three are properties of the **resolved**
|
|
7
|
+
* signature, not of the name written — two overloads of one name can differ in every
|
|
8
|
+
* one of them — so the answer has to come from the checker, which is what resolved it.
|
|
9
|
+
*
|
|
10
|
+
* **It is the checker's lowering, not the tree.** A macro is not a dispatch and is not
|
|
11
|
+
* listed: `xs.map(i, i)` becomes a comprehension and reaches no function, while the
|
|
12
|
+
* calls written inside it are listed where they are written. A list read off the tree
|
|
13
|
+
* would instead report whatever the reader's parser happened to expand.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an expression reads from its environment.
|
|
3
|
+
*
|
|
4
|
+
* The answer is the first identifier of every access chain — `request` in
|
|
5
|
+
* `request.query.limit`, `xs` in `xs[0].id` — with three exclusions, each of which
|
|
6
|
+
* would otherwise invent a dependency the expression does not have:
|
|
7
|
+
*
|
|
8
|
+
* - a name a comprehension or `cel.bind` binds, which the expression supplies itself;
|
|
9
|
+
* - the namespace of a qualified call, which names a module rather than a value;
|
|
10
|
+
* - the receiver of a call on a reserved namespace (`cel.bind(…)`, `optional.of(…)`),
|
|
11
|
+
* for the same reason.
|
|
12
|
+
*
|
|
13
|
+
* A function name is not an identifier node at all, so no call name can be mistaken
|
|
14
|
+
* for a read. Field names are not nodes either, which is why only the root of a
|
|
15
|
+
* chain is answered.
|
|
16
|
+
*
|
|
17
|
+
* The result is sorted and deduplicated: it is a set of names, and a consumer that
|
|
18
|
+
* compares two expressions' reads must not see an ordering difference.
|
|
19
|
+
*/
|
|
20
|
+
import type { CelNode } from "./syntax-tree.js";
|
|
21
|
+
/** Every name the expression reads from its environment, sorted. */
|
|
22
|
+
export declare function rootReferences(root: CelNode): readonly string[];
|
|
23
|
+
//# sourceMappingURL=root-references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-references.d.ts","sourceRoot":"","sources":["../src/root-references.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAoBhD,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAI/D"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an expression reads from its environment.
|
|
3
|
+
*
|
|
4
|
+
* The answer is the first identifier of every access chain — `request` in
|
|
5
|
+
* `request.query.limit`, `xs` in `xs[0].id` — with three exclusions, each of which
|
|
6
|
+
* would otherwise invent a dependency the expression does not have:
|
|
7
|
+
*
|
|
8
|
+
* - a name a comprehension or `cel.bind` binds, which the expression supplies itself;
|
|
9
|
+
* - the namespace of a qualified call, which names a module rather than a value;
|
|
10
|
+
* - the receiver of a call on a reserved namespace (`cel.bind(…)`, `optional.of(…)`),
|
|
11
|
+
* for the same reason.
|
|
12
|
+
*
|
|
13
|
+
* A function name is not an identifier node at all, so no call name can be mistaken
|
|
14
|
+
* for a read. Field names are not nodes either, which is why only the root of a
|
|
15
|
+
* chain is answered.
|
|
16
|
+
*
|
|
17
|
+
* The result is sorted and deduplicated: it is a set of names, and a consumer that
|
|
18
|
+
* compares two expressions' reads must not see an ordering difference.
|
|
19
|
+
*/
|
|
20
|
+
import { namespaceMacroBinding, receiverMacroBinding } from "./comprehension-bindings.js";
|
|
21
|
+
import { RESERVED_NAMESPACES } from "./namespace-resolution.js";
|
|
22
|
+
class BoundNames {
|
|
23
|
+
depth = new Map();
|
|
24
|
+
bind(name) {
|
|
25
|
+
this.depth.set(name, (this.depth.get(name) ?? 0) + 1);
|
|
26
|
+
}
|
|
27
|
+
unbind(name) {
|
|
28
|
+
const held = this.depth.get(name);
|
|
29
|
+
if (held === 1)
|
|
30
|
+
this.depth.delete(name);
|
|
31
|
+
else
|
|
32
|
+
this.depth.set(name, held - 1);
|
|
33
|
+
}
|
|
34
|
+
has(name) {
|
|
35
|
+
return this.depth.has(name);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Every name the expression reads from its environment, sorted. */
|
|
39
|
+
export function rootReferences(root) {
|
|
40
|
+
const found = new Set();
|
|
41
|
+
collect(root, new BoundNames(), found);
|
|
42
|
+
return [...found].sort();
|
|
43
|
+
}
|
|
44
|
+
function collect(node, bound, found) {
|
|
45
|
+
switch (node.kind) {
|
|
46
|
+
case "ident":
|
|
47
|
+
// An absolute name reads past every binding by construction, so a binding of the
|
|
48
|
+
// same name says nothing about it.
|
|
49
|
+
if (node.absolute || !bound.has(node.name))
|
|
50
|
+
found.add(node.name);
|
|
51
|
+
return;
|
|
52
|
+
case "literal":
|
|
53
|
+
case "unparsed":
|
|
54
|
+
return;
|
|
55
|
+
case "receiverCall":
|
|
56
|
+
collectCall(node, bound, found);
|
|
57
|
+
return;
|
|
58
|
+
case "list":
|
|
59
|
+
for (const element of node.elements)
|
|
60
|
+
collect(element.value, bound, found);
|
|
61
|
+
return;
|
|
62
|
+
case "map":
|
|
63
|
+
for (const entry of node.entries) {
|
|
64
|
+
collect(entry.key, bound, found);
|
|
65
|
+
collect(entry.value, bound, found);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
case "select":
|
|
69
|
+
collect(node.operand, bound, found);
|
|
70
|
+
return;
|
|
71
|
+
case "index":
|
|
72
|
+
collect(node.operand, bound, found);
|
|
73
|
+
collect(node.index, bound, found);
|
|
74
|
+
return;
|
|
75
|
+
case "call":
|
|
76
|
+
case "qcall":
|
|
77
|
+
for (const argument of node.args)
|
|
78
|
+
collect(argument, bound, found);
|
|
79
|
+
return;
|
|
80
|
+
case "unary":
|
|
81
|
+
collect(node.operand, bound, found);
|
|
82
|
+
return;
|
|
83
|
+
case "binary":
|
|
84
|
+
collect(node.left, bound, found);
|
|
85
|
+
collect(node.right, bound, found);
|
|
86
|
+
return;
|
|
87
|
+
case "conditional":
|
|
88
|
+
collect(node.condition, bound, found);
|
|
89
|
+
collect(node.whenTrue, bound, found);
|
|
90
|
+
collect(node.whenFalse, bound, found);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function collectCall(node, bound, found) {
|
|
95
|
+
const receiver = node.receiver;
|
|
96
|
+
const onNamespace = receiver.kind === "ident" && RESERVED_NAMESPACES.includes(receiver.name);
|
|
97
|
+
const binding = onNamespace
|
|
98
|
+
? namespaceMacroBinding(receiver.name, node.name, node.args.length)
|
|
99
|
+
: receiverMacroBinding(node.name, node.args.length);
|
|
100
|
+
if (!onNamespace)
|
|
101
|
+
collect(receiver, bound, found);
|
|
102
|
+
const variable = binding ? node.args[binding.variableArgument] : undefined;
|
|
103
|
+
if (!binding || variable?.kind !== "ident") {
|
|
104
|
+
for (const argument of node.args)
|
|
105
|
+
collect(argument, bound, found);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
for (const [at, argument] of node.args.entries()) {
|
|
109
|
+
if (at === binding.variableArgument || binding.scopedArguments.includes(at))
|
|
110
|
+
continue;
|
|
111
|
+
collect(argument, bound, found);
|
|
112
|
+
}
|
|
113
|
+
bound.bind(variable.name);
|
|
114
|
+
for (const at of binding.scopedArguments) {
|
|
115
|
+
const argument = node.args[at];
|
|
116
|
+
if (argument)
|
|
117
|
+
collect(argument, bound, found);
|
|
118
|
+
}
|
|
119
|
+
bound.unbind(variable.name);
|
|
120
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every operator and standard function **does** — once, for both backends.
|
|
3
|
+
*
|
|
4
|
+
* The declarations are data (`signatures/standard-library.json`); this is the behaviour
|
|
5
|
+
* behind them, keyed by the same dispatch key the registry resolves on. The closure
|
|
6
|
+
* backend calls through here and the emitter will too, so there is exactly one answer
|
|
7
|
+
* per operation and no second copy to drift: a semantics written inside a backend is a
|
|
8
|
+
* semantics each backend gets slightly wrong in its own way.
|
|
9
|
+
*
|
|
10
|
+
* An implementation takes its arguments **already evaluated and already free of
|
|
11
|
+
* errors** — the caller carries an error-valued operand through for the short-circuit
|
|
12
|
+
* rules — and returns a value, which may itself be an error value (an overflow, a
|
|
13
|
+
* missing key, a pattern RE2 refuses). Its return type is not thenable, so an
|
|
14
|
+
* implementation that answers asynchronously does not compile.
|
|
15
|
+
*/
|
|
16
|
+
import type { CelOptional, CelValue } from "./cel-value.js";
|
|
17
|
+
import { type CelError, type CelTypeValue } from "./cel-value.js";
|
|
18
|
+
import type { CelSignature } from "./signature.js";
|
|
19
|
+
import type { SourceRange } from "./syntax-tree.js";
|
|
20
|
+
/** What an implementation knows about the call it is answering. */
|
|
21
|
+
export interface CelCallContext {
|
|
22
|
+
/** The span of the call, carried into any error value it produces. */
|
|
23
|
+
readonly range?: SourceRange;
|
|
24
|
+
}
|
|
25
|
+
export type CelImplementation = (args: readonly CelValue[], ctx: CelCallContext) => CelValue;
|
|
26
|
+
/** The name a type value carries. A null's type and an optional's are named apart. */
|
|
27
|
+
export declare function typeValueName(typeName: string): string;
|
|
28
|
+
/** The type value of any value — `type()` must answer for anything, including `dyn`. */
|
|
29
|
+
export declare function celTypeValueOf(value: CelValue, range?: SourceRange): CelTypeValue | CelError;
|
|
30
|
+
/** Bytes as base64 with the standard alphabet and padding. */
|
|
31
|
+
export declare function base64Text(input: Uint8Array): string;
|
|
32
|
+
/**
|
|
33
|
+
* JSON as CEL values: an object is a map, an array a list, a number a double. Exported
|
|
34
|
+
* because the function catalog's `parseJson` answers the same question, and two readings
|
|
35
|
+
* of what JSON becomes would be two value domains.
|
|
36
|
+
*/
|
|
37
|
+
export declare function jsonAsCelValue(parsed: unknown): CelValue;
|
|
38
|
+
/**
|
|
39
|
+
* The implementation of a registered signature, or nothing where the registration has
|
|
40
|
+
* none — a host's own function, which the host supplies itself.
|
|
41
|
+
*/
|
|
42
|
+
export declare function implementationOf(signature: CelSignature): CelImplementation | undefined;
|
|
43
|
+
/** Every dispatch key this file answers for, for a completeness check. */
|
|
44
|
+
export declare function implementedKeys(): readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* The values the library's own constants read as: each type name as a type value, and
|
|
47
|
+
* `google`, through which the two well-known type names are reached — the only spelling
|
|
48
|
+
* in which an expression can name the timestamp or duration type.
|
|
49
|
+
*/
|
|
50
|
+
export declare function standardConstantValues(optionalTypes: boolean): ReadonlyMap<string, CelValue>;
|
|
51
|
+
/**
|
|
52
|
+
* `optional.ofNonZeroValue(v)`: present unless the value is its type's zero — which is
|
|
53
|
+
* what makes it different from `optional.of`, and what three of the vectors' rows read.
|
|
54
|
+
*/
|
|
55
|
+
export declare function optionalOfNonZero(value: CelValue): CelOptional;
|
|
56
|
+
//# sourceMappingURL=runtime-library.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-library.d.ts","sourceRoot":"","sources":["../src/runtime-library.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAGV,WAAW,EAEX,QAAQ,EACT,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAaL,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAqBxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAYpD,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,EAAE,GAAG,EAAE,cAAc,KAAK,QAAQ,CAAC;AA6E7F,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,QAAQ,CAM5F;AAMD,8DAA8D;AAC9D,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAYpD;AAQD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,CAQxD;AAwVD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,YAAY,GAAG,iBAAiB,GAAG,SAAS,CAEvF;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,IAAI,SAAS,MAAM,EAAE,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,aAAa,EAAE,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAc5F;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,GAAG,WAAW,CAE9D"}
|