@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,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a comprehension macro **does**, as a function of its range and its body.
|
|
3
|
+
*
|
|
4
|
+
* The macros are lowered by each backend — there is no comprehension node in the tree,
|
|
5
|
+
* because expanding one at read time would make the source unwritable from the tree —
|
|
6
|
+
* but what the lowering *means* lives here, once. The closure backend passes a closure
|
|
7
|
+
* as the body and the emitter will pass an emitted function, and both get the same
|
|
8
|
+
* answers, including the error rules.
|
|
9
|
+
*
|
|
10
|
+
* **An error does not win over a decided answer**, with the one exception named below: `all`
|
|
11
|
+
* is `false` as soon as one element is false even if another errors, and `exists` is `true` as
|
|
12
|
+
* soon as one is true. That is the same rule `&&` and `||` follow, and it is what makes a
|
|
13
|
+
* comprehension over partly-unreadable data usable at all.
|
|
14
|
+
*
|
|
15
|
+
* **An element entering a body is a door a host value comes through**, and it is checked for a
|
|
16
|
+
* thenable here — in the one place a comprehension's meaning lives, so both backends inherit it
|
|
17
|
+
* rather than each remembering to. It is not the leak it looks like: `xs.all(e, true)` over a
|
|
18
|
+
* host list holding a promise used to answer **`true`**, having decided something about a value
|
|
19
|
+
* it never touched, which is the worse half of the failure class. The cost is one `typeof` per
|
|
20
|
+
* element, the same check the member read already makes, on a loop that already calls a closure
|
|
21
|
+
* per element.
|
|
22
|
+
*
|
|
23
|
+
* **That refusal is TERMINAL, and it is the one error here that does not short-circuit.** It is
|
|
24
|
+
* checked where the element is BOUND, before the body runs, and it ends the comprehension
|
|
25
|
+
* whatever a later element would have decided — so `xs.all(e, false)` and `xs.exists(e, true)`
|
|
26
|
+
* refuse rather than answering `false` and `true` off the one element that is readable. The
|
|
27
|
+
* distinction is what the error is ABOUT: `no_such_key` is a fact about one datum, so a decided
|
|
28
|
+
* answer may legitimately outrank it, while a value that must be awaited says the host handed
|
|
29
|
+
* this engine something it cannot evaluate at all. Carrying that past a convenient element makes
|
|
30
|
+
* the answer depend on how many elements happen to be readable and in what order — and the rule
|
|
31
|
+
* is subtle enough that two readers in a row took the discardable refusal for a leak instead.
|
|
32
|
+
*/
|
|
33
|
+
import { asyncValueRefused, celError, isCelError } from "./cel-value.js";
|
|
34
|
+
function notBool(value, range) {
|
|
35
|
+
return celError("no_matching_overload", `a comprehension's test must answer a bool, and it answered ${typeof value}`, range);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Whether an element entering a body is one that must be awaited.
|
|
39
|
+
*
|
|
40
|
+
* The `typeof` is inlined here rather than left to the call, because this runs once per element
|
|
41
|
+
* on the engine's hottest loop and only an OBJECT can be a thenable. Measured on a
|
|
42
|
+
* 100k-element `map` over integers — a body that does almost nothing, so the check is as
|
|
43
|
+
* visible as it ever gets: calling unconditionally cost about 4 ms, and with the `typeof`
|
|
44
|
+
* guarding the call the difference sits at this machine's noise floor.
|
|
45
|
+
*/
|
|
46
|
+
function awaited(element, range) {
|
|
47
|
+
if (typeof element !== "object" || element === null)
|
|
48
|
+
return undefined;
|
|
49
|
+
return asyncValueRefused(element, range);
|
|
50
|
+
}
|
|
51
|
+
/** A predicate's answer for one element: `true`, `false`, or the error it is. */
|
|
52
|
+
function test(body, element, range) {
|
|
53
|
+
const answered = body(element);
|
|
54
|
+
if (isCelError(answered))
|
|
55
|
+
return answered;
|
|
56
|
+
if (typeof answered !== "boolean")
|
|
57
|
+
return notBool(answered, range);
|
|
58
|
+
return answered;
|
|
59
|
+
}
|
|
60
|
+
export function celAll(elements, body, range) {
|
|
61
|
+
let failure;
|
|
62
|
+
for (const element of elements) {
|
|
63
|
+
const refused = awaited(element, range);
|
|
64
|
+
if (refused)
|
|
65
|
+
return refused;
|
|
66
|
+
const answered = test(body, element, range);
|
|
67
|
+
if (answered === false)
|
|
68
|
+
return false;
|
|
69
|
+
if (answered !== true && !failure)
|
|
70
|
+
failure = answered;
|
|
71
|
+
}
|
|
72
|
+
return failure ?? true;
|
|
73
|
+
}
|
|
74
|
+
export function celExists(elements, body, range) {
|
|
75
|
+
let failure;
|
|
76
|
+
for (const element of elements) {
|
|
77
|
+
const refused = awaited(element, range);
|
|
78
|
+
if (refused)
|
|
79
|
+
return refused;
|
|
80
|
+
const answered = test(body, element, range);
|
|
81
|
+
if (answered === true)
|
|
82
|
+
return true;
|
|
83
|
+
if (answered !== false && !failure)
|
|
84
|
+
failure = answered;
|
|
85
|
+
}
|
|
86
|
+
return failure ?? false;
|
|
87
|
+
}
|
|
88
|
+
/** Exactly one element satisfies the test. An error anywhere leaves no count to trust. */
|
|
89
|
+
export function celExistsOne(elements, body, range) {
|
|
90
|
+
let found = 0;
|
|
91
|
+
for (const element of elements) {
|
|
92
|
+
const refused = awaited(element, range);
|
|
93
|
+
if (refused)
|
|
94
|
+
return refused;
|
|
95
|
+
const answered = test(body, element, range);
|
|
96
|
+
if (isCelError(answered))
|
|
97
|
+
return answered;
|
|
98
|
+
if (answered)
|
|
99
|
+
found += 1;
|
|
100
|
+
}
|
|
101
|
+
return found === 1;
|
|
102
|
+
}
|
|
103
|
+
export function celFilter(elements, body, range) {
|
|
104
|
+
const kept = [];
|
|
105
|
+
for (const element of elements) {
|
|
106
|
+
const refused = awaited(element, range);
|
|
107
|
+
if (refused)
|
|
108
|
+
return refused;
|
|
109
|
+
const answered = test(body, element, range);
|
|
110
|
+
if (isCelError(answered))
|
|
111
|
+
return answered;
|
|
112
|
+
if (answered)
|
|
113
|
+
kept.push(element);
|
|
114
|
+
}
|
|
115
|
+
return kept;
|
|
116
|
+
}
|
|
117
|
+
/** `map` in both arities: with a filter, an element the filter drops is not transformed. */
|
|
118
|
+
export function celMapComprehension(elements, transform, filter, range) {
|
|
119
|
+
const out = [];
|
|
120
|
+
for (const element of elements) {
|
|
121
|
+
const refused = awaited(element, range);
|
|
122
|
+
if (refused)
|
|
123
|
+
return refused;
|
|
124
|
+
if (filter) {
|
|
125
|
+
const answered = test(filter, element, range);
|
|
126
|
+
if (isCelError(answered))
|
|
127
|
+
return answered;
|
|
128
|
+
if (!answered)
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const value = transform(element);
|
|
132
|
+
if (isCelError(value))
|
|
133
|
+
return value;
|
|
134
|
+
out.push(value);
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splitting a dotted chain over the names a host DECLARED — once, for both halves.
|
|
3
|
+
*
|
|
4
|
+
* A host may declare `a.b.c`, or `a.b` holding a map, or both. `a.b.c` then reads the
|
|
5
|
+
* variable of that name where it is declared and the map's entry where only `a.b` is, so the
|
|
6
|
+
* host's own naming decides rather than the shape of the expression: the **longest declared
|
|
7
|
+
* prefix wins**.
|
|
8
|
+
*
|
|
9
|
+
* The checker and the backend ask the same question of the same declarations, so they ask it
|
|
10
|
+
* here. Two readers would be two answers to "which name is this chain", and the pair that
|
|
11
|
+
* disagrees is the worst kind: `telo check` types one name while evaluation reads another, and
|
|
12
|
+
* nothing says so. Splitting at compile time also means a declared chain costs **one**
|
|
13
|
+
* activation read at evaluation rather than a search over its prefixes.
|
|
14
|
+
*
|
|
15
|
+
* A chain **no prefix of which** is declared — the root included — is left alone: there is
|
|
16
|
+
* nothing to split it on, and the checker has no opinion about it either. The backend then
|
|
17
|
+
* searches the activation at evaluation, which is what every conformance row binding a dotted
|
|
18
|
+
* key relies on. Where any prefix IS declared the search never runs, so a key the host did not
|
|
19
|
+
* declare can never win over a name it did.
|
|
20
|
+
*/
|
|
21
|
+
/** Where a chain splits: the declared name, and the members read off its value. */
|
|
22
|
+
export interface DeclaredChain {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly rest: readonly string[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The longest declared prefix of a chain, or nothing when no declaration covers one.
|
|
28
|
+
*
|
|
29
|
+
* **The root counts as a prefix**, and leaving it out was the disagreement this function
|
|
30
|
+
* exists to prevent: with a chain whose root alone is declared treated as undeclared, the
|
|
31
|
+
* backend fell into the activation prefix search, and an activation holding both `a` and the
|
|
32
|
+
* key `"a.b"` answered the undeclared key where the checker had typed the declared name.
|
|
33
|
+
*/
|
|
34
|
+
export declare function splitDeclaredChain(segments: readonly string[], declared: (name: string) => boolean): DeclaredChain | undefined;
|
|
35
|
+
//# sourceMappingURL=declared-chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declared-chain.d.ts","sourceRoot":"","sources":["../src/declared-chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,mFAAmF;AACnF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAClC,aAAa,GAAG,SAAS,CAM3B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splitting a dotted chain over the names a host DECLARED — once, for both halves.
|
|
3
|
+
*
|
|
4
|
+
* A host may declare `a.b.c`, or `a.b` holding a map, or both. `a.b.c` then reads the
|
|
5
|
+
* variable of that name where it is declared and the map's entry where only `a.b` is, so the
|
|
6
|
+
* host's own naming decides rather than the shape of the expression: the **longest declared
|
|
7
|
+
* prefix wins**.
|
|
8
|
+
*
|
|
9
|
+
* The checker and the backend ask the same question of the same declarations, so they ask it
|
|
10
|
+
* here. Two readers would be two answers to "which name is this chain", and the pair that
|
|
11
|
+
* disagrees is the worst kind: `telo check` types one name while evaluation reads another, and
|
|
12
|
+
* nothing says so. Splitting at compile time also means a declared chain costs **one**
|
|
13
|
+
* activation read at evaluation rather than a search over its prefixes.
|
|
14
|
+
*
|
|
15
|
+
* A chain **no prefix of which** is declared — the root included — is left alone: there is
|
|
16
|
+
* nothing to split it on, and the checker has no opinion about it either. The backend then
|
|
17
|
+
* searches the activation at evaluation, which is what every conformance row binding a dotted
|
|
18
|
+
* key relies on. Where any prefix IS declared the search never runs, so a key the host did not
|
|
19
|
+
* declare can never win over a name it did.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* The longest declared prefix of a chain, or nothing when no declaration covers one.
|
|
23
|
+
*
|
|
24
|
+
* **The root counts as a prefix**, and leaving it out was the disagreement this function
|
|
25
|
+
* exists to prevent: with a chain whose root alone is declared treated as undeclared, the
|
|
26
|
+
* backend fell into the activation prefix search, and an activation holding both `a` and the
|
|
27
|
+
* key `"a.b"` answered the undeclared key where the checker had typed the declared name.
|
|
28
|
+
*/
|
|
29
|
+
export function splitDeclaredChain(segments, declared) {
|
|
30
|
+
for (let length = segments.length; length >= 1; length -= 1) {
|
|
31
|
+
const name = segments.slice(0, length).join(".");
|
|
32
|
+
if (declared(name))
|
|
33
|
+
return { name, rest: segments.slice(length) };
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durations: reading one, writing one, and the fields of one.
|
|
3
|
+
*
|
|
4
|
+
* **CEL's duration is the signed 64-bit range of its total NANOSECONDS** —
|
|
5
|
+
* `-9223372036.854775808s … 9223372036.854775807s`, roughly ±292 years. That is cel-spec's
|
|
6
|
+
* own rule, stated under *Overflow* in its language definition ("Duration values are
|
|
7
|
+
* limited to a single int64 value, or roughly +-290 years"), and all six of the vectors'
|
|
8
|
+
* `timestamps/duration_range` rows read it: each uses an operand of 200,000,000,000s or
|
|
9
|
+
* 320,000,000,000s and each expects `duration out of range`.
|
|
10
|
+
*
|
|
11
|
+
* **It is a subrange of the typed frame's, deliberately.** The frame carries protobuf's
|
|
12
|
+
* `google.protobuf.Duration` range — ±315,576,000,000s, ±10,000 years — because a duration
|
|
13
|
+
* arriving from a transport, a journal or a controller must always be representable, and
|
|
14
|
+
* narrowing the frame to CEL's range would make such a value unwritable. So CEL ⊂ frame:
|
|
15
|
+
* `duration('200000000000s')` is a value the frame carries and CEL cannot construct, which
|
|
16
|
+
* is the correct answer rather than a cost. Nothing about the frame changes here.
|
|
17
|
+
*
|
|
18
|
+
* The range is an invariant, not a storage format: a duration is still seconds and
|
|
19
|
+
* nanoseconds of the same sign, with `|nanos| < 1e9`, and nanosecond-precise. A computation
|
|
20
|
+
* that leaves the range is an error, never a value outside it.
|
|
21
|
+
*
|
|
22
|
+
* It is written as seconds with an `s` suffix (`1000000s`, `-1.5s`), which is cel-spec's
|
|
23
|
+
* own spelling, and the one plain encoding a duration has wherever it is written down.
|
|
24
|
+
*/
|
|
25
|
+
import { type CelDuration, type CelError } from "./cel-value.js";
|
|
26
|
+
import type { SourceRange } from "./syntax-tree.js";
|
|
27
|
+
/** The widest and narrowest total a duration holds, in nanoseconds: int64. */
|
|
28
|
+
export declare const MAX_DURATION_NANOS = 9223372036854775807n;
|
|
29
|
+
export declare const MIN_DURATION_NANOS = -9223372036854775808n;
|
|
30
|
+
/** A duration from a total in nanoseconds, or the range error. */
|
|
31
|
+
export declare function celDurationFromNanos(total: bigint, range?: SourceRange): CelDuration | CelError;
|
|
32
|
+
/**
|
|
33
|
+
* The error a duration **this engine did not build** is outside CEL's range: one from a
|
|
34
|
+
* host, which the frame's wider range admits. Checked where such a duration is used, not
|
|
35
|
+
* where it arrives, so a value merely passing through is not judged.
|
|
36
|
+
*/
|
|
37
|
+
export declare function durationOutOfRange(value: CelDuration, range?: SourceRange): CelError | undefined;
|
|
38
|
+
/** The duration's total nanoseconds — what arithmetic and ordering compare. */
|
|
39
|
+
export declare function durationNanos(value: CelDuration): bigint;
|
|
40
|
+
/**
|
|
41
|
+
* A duration from CEL's own text: a sign, then one or more number-and-unit parts over
|
|
42
|
+
* `ns`, `us`, `ms`, `s`, `m` and `h` (`1h30m`, `1.5s`, `-10m`).
|
|
43
|
+
*/
|
|
44
|
+
export declare function parseDuration(text: string, range?: SourceRange): CelDuration | CelError;
|
|
45
|
+
/** Seconds with an `s` suffix, the fraction trimmed to what it carries. */
|
|
46
|
+
export declare function formatDuration(value: CelDuration): string;
|
|
47
|
+
/** Which field of a duration a getter answers. */
|
|
48
|
+
export type DurationField = "getHours" | "getMinutes" | "getSeconds" | "getMilliseconds";
|
|
49
|
+
/**
|
|
50
|
+
* A field of a duration. `getHours`, `getMinutes` and `getSeconds` answer the **whole span**
|
|
51
|
+
* in that unit, truncated toward zero; `getMilliseconds` answers the **component** — the
|
|
52
|
+
* milliseconds inside the second, so `duration('123.321456789s').getMilliseconds()` is 321
|
|
53
|
+
* and not 123,321.
|
|
54
|
+
*
|
|
55
|
+
* That split is cel-spec's, and it is also the only reading under which the engine does not
|
|
56
|
+
* contradict itself: a timestamp's `getMilliseconds()` has always answered the component.
|
|
57
|
+
*/
|
|
58
|
+
export declare function durationField(value: CelDuration, field: DurationField): bigint;
|
|
59
|
+
//# sourceMappingURL=duration-value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duration-value.d.ts","sourceRoot":"","sources":["../src/duration-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAA4B,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,uBAA6B,CAAC;AAC7D,eAAO,MAAM,kBAAkB,wBAA8B,CAAC;AAI9D,kEAAkE;AAClE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CAS/F;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAIhG;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAExD;AAeD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,QAAQ,CA4BvF;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAQzD;AAED,kDAAkD;AAClD,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,CAAC;AAEzF;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAY9E"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durations: reading one, writing one, and the fields of one.
|
|
3
|
+
*
|
|
4
|
+
* **CEL's duration is the signed 64-bit range of its total NANOSECONDS** —
|
|
5
|
+
* `-9223372036.854775808s … 9223372036.854775807s`, roughly ±292 years. That is cel-spec's
|
|
6
|
+
* own rule, stated under *Overflow* in its language definition ("Duration values are
|
|
7
|
+
* limited to a single int64 value, or roughly +-290 years"), and all six of the vectors'
|
|
8
|
+
* `timestamps/duration_range` rows read it: each uses an operand of 200,000,000,000s or
|
|
9
|
+
* 320,000,000,000s and each expects `duration out of range`.
|
|
10
|
+
*
|
|
11
|
+
* **It is a subrange of the typed frame's, deliberately.** The frame carries protobuf's
|
|
12
|
+
* `google.protobuf.Duration` range — ±315,576,000,000s, ±10,000 years — because a duration
|
|
13
|
+
* arriving from a transport, a journal or a controller must always be representable, and
|
|
14
|
+
* narrowing the frame to CEL's range would make such a value unwritable. So CEL ⊂ frame:
|
|
15
|
+
* `duration('200000000000s')` is a value the frame carries and CEL cannot construct, which
|
|
16
|
+
* is the correct answer rather than a cost. Nothing about the frame changes here.
|
|
17
|
+
*
|
|
18
|
+
* The range is an invariant, not a storage format: a duration is still seconds and
|
|
19
|
+
* nanoseconds of the same sign, with `|nanos| < 1e9`, and nanosecond-precise. A computation
|
|
20
|
+
* that leaves the range is an error, never a value outside it.
|
|
21
|
+
*
|
|
22
|
+
* It is written as seconds with an `s` suffix (`1000000s`, `-1.5s`), which is cel-spec's
|
|
23
|
+
* own spelling, and the one plain encoding a duration has wherever it is written down.
|
|
24
|
+
*/
|
|
25
|
+
import { celError, CEL_VALUE_TYPE } from "./cel-value.js";
|
|
26
|
+
/** The widest and narrowest total a duration holds, in nanoseconds: int64. */
|
|
27
|
+
export const MAX_DURATION_NANOS = 9223372036854775807n;
|
|
28
|
+
export const MIN_DURATION_NANOS = -9223372036854775808n;
|
|
29
|
+
const NANOS_PER_SECOND = 1000000000n;
|
|
30
|
+
/** A duration from a total in nanoseconds, or the range error. */
|
|
31
|
+
export function celDurationFromNanos(total, range) {
|
|
32
|
+
if (total > MAX_DURATION_NANOS || total < MIN_DURATION_NANOS) {
|
|
33
|
+
return celError("invalid_conversion", "duration out of range", range);
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
[CEL_VALUE_TYPE]: "google.protobuf.Duration",
|
|
37
|
+
seconds: total / NANOS_PER_SECOND,
|
|
38
|
+
nanos: Number(total % NANOS_PER_SECOND),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The error a duration **this engine did not build** is outside CEL's range: one from a
|
|
43
|
+
* host, which the frame's wider range admits. Checked where such a duration is used, not
|
|
44
|
+
* where it arrives, so a value merely passing through is not judged.
|
|
45
|
+
*/
|
|
46
|
+
export function durationOutOfRange(value, range) {
|
|
47
|
+
const total = durationNanos(value);
|
|
48
|
+
if (total <= MAX_DURATION_NANOS && total >= MIN_DURATION_NANOS)
|
|
49
|
+
return undefined;
|
|
50
|
+
return celError("invalid_conversion", "duration out of range", range);
|
|
51
|
+
}
|
|
52
|
+
/** The duration's total nanoseconds — what arithmetic and ordering compare. */
|
|
53
|
+
export function durationNanos(value) {
|
|
54
|
+
return value.seconds * NANOS_PER_SECOND + BigInt(value.nanos);
|
|
55
|
+
}
|
|
56
|
+
const UNIT_NANOS = {
|
|
57
|
+
ns: 1n,
|
|
58
|
+
us: 1000n,
|
|
59
|
+
"µs": 1000n,
|
|
60
|
+
"μs": 1000n,
|
|
61
|
+
ms: 1000000n,
|
|
62
|
+
s: 1000000000n,
|
|
63
|
+
m: 60000000000n,
|
|
64
|
+
h: 3600000000000n,
|
|
65
|
+
};
|
|
66
|
+
const PART = /([0-9]*)(?:\.([0-9]*))?(ns|us|µs|μs|ms|s|m|h)/g;
|
|
67
|
+
/**
|
|
68
|
+
* A duration from CEL's own text: a sign, then one or more number-and-unit parts over
|
|
69
|
+
* `ns`, `us`, `ms`, `s`, `m` and `h` (`1h30m`, `1.5s`, `-10m`).
|
|
70
|
+
*/
|
|
71
|
+
export function parseDuration(text, range) {
|
|
72
|
+
const refuse = () => celError("invalid_conversion", `${JSON.stringify(text)} is not a duration`, range);
|
|
73
|
+
let body = text;
|
|
74
|
+
let negative = false;
|
|
75
|
+
if (body.startsWith("+") || body.startsWith("-")) {
|
|
76
|
+
negative = body.startsWith("-");
|
|
77
|
+
body = body.slice(1);
|
|
78
|
+
}
|
|
79
|
+
if (body === "0")
|
|
80
|
+
return celDurationFromNanos(0n, range);
|
|
81
|
+
if (body === "")
|
|
82
|
+
return refuse();
|
|
83
|
+
PART.lastIndex = 0;
|
|
84
|
+
let total = 0n;
|
|
85
|
+
let at = 0;
|
|
86
|
+
for (let found = PART.exec(body); found; found = PART.exec(body)) {
|
|
87
|
+
if (found.index !== at)
|
|
88
|
+
return refuse();
|
|
89
|
+
const [whole, digits, fraction, unit] = found;
|
|
90
|
+
if (!digits && !fraction)
|
|
91
|
+
return refuse();
|
|
92
|
+
const scale = UNIT_NANOS[unit];
|
|
93
|
+
total += BigInt(digits || "0") * scale;
|
|
94
|
+
if (fraction) {
|
|
95
|
+
const padded = `${fraction}000000000`.slice(0, 9);
|
|
96
|
+
total += (BigInt(padded) * scale) / NANOS_PER_SECOND;
|
|
97
|
+
}
|
|
98
|
+
at += whole.length;
|
|
99
|
+
}
|
|
100
|
+
if (at !== body.length)
|
|
101
|
+
return refuse();
|
|
102
|
+
return celDurationFromNanos(negative ? -total : total, range);
|
|
103
|
+
}
|
|
104
|
+
/** Seconds with an `s` suffix, the fraction trimmed to what it carries. */
|
|
105
|
+
export function formatDuration(value) {
|
|
106
|
+
const total = durationNanos(value);
|
|
107
|
+
const negative = total < 0n;
|
|
108
|
+
const magnitude = negative ? -total : total;
|
|
109
|
+
const seconds = magnitude / NANOS_PER_SECOND;
|
|
110
|
+
const nanos = magnitude % NANOS_PER_SECOND;
|
|
111
|
+
const fraction = nanos === 0n ? "" : `.${String(nanos).padStart(9, "0").replace(/0+$/, "")}`;
|
|
112
|
+
return `${negative ? "-" : ""}${seconds}${fraction}s`;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A field of a duration. `getHours`, `getMinutes` and `getSeconds` answer the **whole span**
|
|
116
|
+
* in that unit, truncated toward zero; `getMilliseconds` answers the **component** — the
|
|
117
|
+
* milliseconds inside the second, so `duration('123.321456789s').getMilliseconds()` is 321
|
|
118
|
+
* and not 123,321.
|
|
119
|
+
*
|
|
120
|
+
* That split is cel-spec's, and it is also the only reading under which the engine does not
|
|
121
|
+
* contradict itself: a timestamp's `getMilliseconds()` has always answered the component.
|
|
122
|
+
*/
|
|
123
|
+
export function durationField(value, field) {
|
|
124
|
+
const total = durationNanos(value);
|
|
125
|
+
switch (field) {
|
|
126
|
+
case "getHours":
|
|
127
|
+
return total / 3600000000000n;
|
|
128
|
+
case "getMinutes":
|
|
129
|
+
return total / 60000000000n;
|
|
130
|
+
case "getSeconds":
|
|
131
|
+
return total / NANOS_PER_SECOND;
|
|
132
|
+
case "getMilliseconds":
|
|
133
|
+
return BigInt(Math.trunc(value.nanos / 1_000_000));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An emitted module: its text, its key, its integrity header, and the one seam a host
|
|
3
|
+
* stores it through.
|
|
4
|
+
*
|
|
5
|
+
* **The runtime is injected, never imported.** The module's default export is a factory
|
|
6
|
+
* taking the runtime support library and answering one synchronous function per
|
|
7
|
+
* expression, and the text names no specifier of any kind. An emitted module that imported
|
|
8
|
+
* `@telorun/cel` would be loadable only where that specifier resolves — which rules out a
|
|
9
|
+
* `data:` URL, a cache directory mounted somewhere else, and a host whose resolver is not
|
|
10
|
+
* Node's — and, worse, it would silently accept a runtime of another version, which is
|
|
11
|
+
* precisely what the key cannot see from the outside.
|
|
12
|
+
*
|
|
13
|
+
* **The key is wider than the source text, and the header is wider than the key.** The key
|
|
14
|
+
* is a hash over the emitter's format generation, the engine version, the environment
|
|
15
|
+
* digest and the canonical ordered list of expression sources. A key is a claim about a
|
|
16
|
+
* *name*; the header is a fact about the *bytes*, and it carries five fields because the
|
|
17
|
+
* provenance three answer only part of the question:
|
|
18
|
+
*
|
|
19
|
+
* - `format`, `engine`, `environment` — **provenance**. These are identical for every module
|
|
20
|
+
* one engine writes against one environment, so they catch a cache root shared by two
|
|
21
|
+
* engines and a stale environment, and **nothing else**. Two different modules of one
|
|
22
|
+
* engine carry byte-identical provenance.
|
|
23
|
+
* - `key` — the module's **identity**: the key this text was written for. It catches a store
|
|
24
|
+
* that answered one key's lookup with another key's text, which the provenance fields
|
|
25
|
+
* cannot see at all and which an expression count can only catch by luck.
|
|
26
|
+
* - `body` — the digest of the text **following the header line**, which covers every byte
|
|
27
|
+
* that is or could be read as code, the `integrity` export included. It catches a text
|
|
28
|
+
* truncated after its header and a text edited after it was written — and the banner says
|
|
29
|
+
* *edit the expression, not this*, which is evidence that someone will edit one. A text with
|
|
30
|
+
* an intact header, an exported factory and a matching function count **runs**, whatever its
|
|
31
|
+
* body says; that is the one failure here no retry undoes.
|
|
32
|
+
*
|
|
33
|
+
* `body` cannot live in the `integrity` export, because it covers that export: a digest in the
|
|
34
|
+
* bytes it digests has no fixed point. So the header LINE carries all five and the export
|
|
35
|
+
* carries the four that are checkable without the text — which is also the split between the
|
|
36
|
+
* two paths. **Every mismatch on the store-read path is a recompile** that names itself in
|
|
37
|
+
* `refused`; the load path, which has an object and not the bytes, refuses with
|
|
38
|
+
* `emitted_module_rejected`.
|
|
39
|
+
*
|
|
40
|
+
* **There is no loader, and there is no filesystem.** A loader would have to reach a
|
|
41
|
+
* filesystem (which this package may not), or be `eval` (which the closure backend exists
|
|
42
|
+
* to avoid), or be a `data:` URL import (fine under Node, refused under a browser's content
|
|
43
|
+
* security policy). Loading is the host's half; the engine writes the text, verifies what
|
|
44
|
+
* comes back, and wires the loaded factory to the runtime.
|
|
45
|
+
*/
|
|
46
|
+
import type { CelProgram } from "./cel-program.js";
|
|
47
|
+
import { type CelStep, type CompileTarget } from "./backend-runtime.js";
|
|
48
|
+
import { type RuntimeBinding } from "./js-emitter.js";
|
|
49
|
+
import type { CelNode } from "./syntax-tree.js";
|
|
50
|
+
/**
|
|
51
|
+
* **Bumped on any change to the text the emitter writes for any tree** — not only when the
|
|
52
|
+
* module's shape changes. It is the first component of the key and the first field of the
|
|
53
|
+
* header, so a module written under one generation is never handed to an engine expecting
|
|
54
|
+
* another.
|
|
55
|
+
*
|
|
56
|
+
* The wider rule is the one that holds, because the narrower one asks whoever makes the
|
|
57
|
+
* change to decide that a text difference is semantically neutral — and that judgement is
|
|
58
|
+
* exactly what produces the unrecoverable failure. The case in point is this emitter's own
|
|
59
|
+
* first defect: temporaries numbered per function let a comprehension body's `let t0` shadow
|
|
60
|
+
* the `t0` its caller held a bound value in, so `cel.bind(n, 2, xs.map(e, e + n))` answered
|
|
61
|
+
* `[2, 4, 6]` for `[3, 4, 5]`. No signature moved, no library entry moved, no shape changed —
|
|
62
|
+
* and a module cached before the fix would have gone on answering `[2, 4, 6]` forever.
|
|
63
|
+
*
|
|
64
|
+
* `tests/emitter-text.test.ts` is what makes the rule checkable: it pins the digest of the
|
|
65
|
+
* code the emitter writes for a corpus drawn from the package's own total enumerations, beside
|
|
66
|
+
* this number, so a change to that text fails naming the bump it owes.
|
|
67
|
+
*/
|
|
68
|
+
export declare const EMITTER_FORMAT_GENERATION = 1;
|
|
69
|
+
/**
|
|
70
|
+
* What an emitted module declares about itself in its `integrity` export: its provenance and
|
|
71
|
+
* its own key. These are the four a loaded module can be held to, because checking them needs
|
|
72
|
+
* nothing but the object the host imported.
|
|
73
|
+
*/
|
|
74
|
+
export interface EmittedIdentity {
|
|
75
|
+
readonly format: number;
|
|
76
|
+
readonly engine: string;
|
|
77
|
+
readonly environment: string;
|
|
78
|
+
/** The cache key this text was written for. */
|
|
79
|
+
readonly key: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* What the header LINE declares: the identity, plus the digest of the body it precedes. The
|
|
83
|
+
* body digest is here and nowhere else — a digest cannot live in the bytes it covers — so it
|
|
84
|
+
* is verified on the one path that has the bytes in hand.
|
|
85
|
+
*/
|
|
86
|
+
export interface EmittedHeader extends EmittedIdentity {
|
|
87
|
+
/** The digest of every byte after the header line. */
|
|
88
|
+
readonly body: string;
|
|
89
|
+
}
|
|
90
|
+
/** One expression to emit: its source text, and the tree it read into. */
|
|
91
|
+
export interface EmittedExpression {
|
|
92
|
+
readonly source: string;
|
|
93
|
+
readonly root: CelNode;
|
|
94
|
+
}
|
|
95
|
+
export interface EmittedModule {
|
|
96
|
+
/** The cache key: 64 hexadecimal characters a host names its stored copy by. */
|
|
97
|
+
readonly key: string;
|
|
98
|
+
readonly header: EmittedHeader;
|
|
99
|
+
readonly text: string;
|
|
100
|
+
/** The expression sources, in the order the factory answers functions for them. */
|
|
101
|
+
readonly sources: readonly string[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Where a host keeps emitted module text, keyed by the key the engine computed. It is the
|
|
105
|
+
* engine's only seam to a store, and the engine touches no filesystem itself.
|
|
106
|
+
*
|
|
107
|
+
* **A write is atomic** — written elsewhere and renamed into place — and that is the store's
|
|
108
|
+
* contract rather than a suggestion: several hosts share one cache root. It is still how a
|
|
109
|
+
* half-written entry is *avoided*, and avoiding one is better than detecting it. But the
|
|
110
|
+
* guarantee no longer rests on it: the header's `body` digest **detects** a truncated or
|
|
111
|
+
* edited text, so a host that gets the write wrong costs a recompile rather than running
|
|
112
|
+
* whatever the bytes happen to say.
|
|
113
|
+
*
|
|
114
|
+
* It is **synchronous**, because emission is: a store over a filesystem writes and renames
|
|
115
|
+
* synchronously, and a store over anything slower is a map the host filled before it asked.
|
|
116
|
+
*/
|
|
117
|
+
export interface EmittedModuleStore {
|
|
118
|
+
read(key: string): string | undefined;
|
|
119
|
+
write(key: string, text: string): void;
|
|
120
|
+
}
|
|
121
|
+
/** A module taken from the store, or emitted because the store had nothing usable. */
|
|
122
|
+
export interface StoredEmittedModule extends EmittedModule {
|
|
123
|
+
/** Why the stored copy was not used, where there was one and it was refused. */
|
|
124
|
+
readonly refused?: string;
|
|
125
|
+
/** Whether the text was emitted now rather than read from the store. */
|
|
126
|
+
readonly emitted: boolean;
|
|
127
|
+
}
|
|
128
|
+
/** The runtime object an emitted module's factory is handed. */
|
|
129
|
+
export type EmittedRuntime = Readonly<Record<RuntimeBinding, unknown>>;
|
|
130
|
+
/** What an emitted module's default export is. */
|
|
131
|
+
export type EmittedFactory = (runtime: EmittedRuntime) => readonly CelStep[];
|
|
132
|
+
/**
|
|
133
|
+
* The key for a set of expressions against an environment.
|
|
134
|
+
*
|
|
135
|
+
* The four components are hashed in one order, each on its own line with its source
|
|
136
|
+
* escaped, so no expression's text can be read as another component. Source alone would
|
|
137
|
+
* serve the wrong module for exactly the capability this package exists for — a host that
|
|
138
|
+
* replaced a standard function has the same text and a different environment.
|
|
139
|
+
*/
|
|
140
|
+
export declare function emittedModuleKey(environmentDigest: string, sources: readonly string[]): string;
|
|
141
|
+
/** What an emission against this environment, for these sources, declares about itself. */
|
|
142
|
+
export declare function emittedModuleIdentity(environmentDigest: string, sources: readonly string[]): EmittedIdentity;
|
|
143
|
+
/**
|
|
144
|
+
* The header a stored text declares, or nothing where it declares none.
|
|
145
|
+
*
|
|
146
|
+
* It is read from the **text**, before anything is loaded: a text whose header is wrong is
|
|
147
|
+
* never handed to a loader at all, which is the cheapest place to refuse and the only place
|
|
148
|
+
* that works for a text that would not even parse.
|
|
149
|
+
*/
|
|
150
|
+
export declare function readEmittedHeader(text: string): EmittedHeader | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* Why a stored text is not the module that was asked for, or nothing where it is.
|
|
153
|
+
*
|
|
154
|
+
* This is the **store-read path**, the one that has the bytes, so it is where the body digest
|
|
155
|
+
* is verified as well as the identity — and every answer is a recompile, never a refusal the
|
|
156
|
+
* caller has to handle. Each names what differed, because a host that logs a recompile wants
|
|
157
|
+
* to know whether it was a stale cache, two engines sharing a root, a store that answered the
|
|
158
|
+
* wrong lookup, or a text somebody edited.
|
|
159
|
+
*/
|
|
160
|
+
export declare function emittedModuleRefusal(text: string, expected: EmittedIdentity): string | undefined;
|
|
161
|
+
/**
|
|
162
|
+
* One module for a set of expressions. Byte-identical for the same expressions in the same
|
|
163
|
+
* order against the same environment: nothing here reads a clock, a counter outside the
|
|
164
|
+
* emission, or the iteration order of anything the caller did not order.
|
|
165
|
+
*/
|
|
166
|
+
export declare function emitModule(target: CompileTarget, environmentDigest: string, expressions: readonly EmittedExpression[]): EmittedModule;
|
|
167
|
+
/**
|
|
168
|
+
* The module for a set of expressions, from the store where it holds a copy whose header
|
|
169
|
+
* matches, and emitted and written where it does not.
|
|
170
|
+
*
|
|
171
|
+
* The header check is what makes this safe to call on a shared cache root: a stored text
|
|
172
|
+
* that does not prove it was emitted by this engine, in this format, against this
|
|
173
|
+
* environment is replaced rather than run.
|
|
174
|
+
*/
|
|
175
|
+
export declare function storedEmittedModule(target: CompileTarget, environmentDigest: string, sources: readonly string[],
|
|
176
|
+
/** The trees, read only where there is something to emit — a hit parses nothing. */
|
|
177
|
+
expressions: () => readonly EmittedExpression[], store: EmittedModuleStore): StoredEmittedModule;
|
|
178
|
+
/**
|
|
179
|
+
* The runtime support library an emitted module's factory takes: every operation the
|
|
180
|
+
* emitted code calls, bound to this environment.
|
|
181
|
+
*
|
|
182
|
+
* Each entry is the function the **closure backend** calls for the same operation —
|
|
183
|
+
* literally the same reference — which is what makes "the two backends answer identically"
|
|
184
|
+
* a property of the wiring rather than a hope the tests confirm.
|
|
185
|
+
*/
|
|
186
|
+
export declare function emitterRuntime(target: CompileTarget): EmittedRuntime;
|
|
187
|
+
/**
|
|
188
|
+
* The programs a loaded emitted module answers, after its header is verified.
|
|
189
|
+
*
|
|
190
|
+
* This is the **load path**: it has an object the host imported and not the bytes, so it
|
|
191
|
+
* checks the four fields the `integrity` export carries. A module that declares no header,
|
|
192
|
+
* declares another format, engine or environment, declares **another key** — which is a host
|
|
193
|
+
* that imported bytes this engine never hashed — exports no factory, or answers a different
|
|
194
|
+
* number of functions than the expressions asked for is refused with
|
|
195
|
+
* `emitted_module_rejected`. The function count stays as the cheap backstop; the `key` field
|
|
196
|
+
* is what actually distinguishes two modules of one engine.
|
|
197
|
+
*
|
|
198
|
+
* The body digest is **not** checked here, and cannot be: it covers the `integrity` export,
|
|
199
|
+
* so it lives only in the header line and is verified where the bytes are
|
|
200
|
+
* (`emittedModuleRefusal`, on the store-read path). Nothing here imports or evaluates
|
|
201
|
+
* anything; the module arrived already loaded, by whatever means the host loads one.
|
|
202
|
+
*/
|
|
203
|
+
export declare function programsFromEmittedModule(loaded: {
|
|
204
|
+
readonly integrity?: unknown;
|
|
205
|
+
readonly default?: unknown;
|
|
206
|
+
}, expected: EmittedModule, runtime: EmittedRuntime): readonly CelProgram[];
|
|
207
|
+
//# sourceMappingURL=emitted-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitted-module.d.ts","sourceRoot":"","sources":["../src/emitted-module.ts"],"names":[],"mappings":"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"}
|