@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.
Files changed (223) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +281 -2
  3. package/dist/activation.d.ts +27 -0
  4. package/dist/activation.d.ts.map +1 -0
  5. package/dist/activation.js +24 -0
  6. package/dist/backend-runtime.d.ts +146 -0
  7. package/dist/backend-runtime.d.ts.map +1 -0
  8. package/dist/backend-runtime.js +322 -0
  9. package/dist/bounded-cache.d.ts +21 -0
  10. package/dist/bounded-cache.d.ts.map +1 -0
  11. package/dist/bounded-cache.js +42 -0
  12. package/dist/catalog-runtime.d.ts +59 -0
  13. package/dist/catalog-runtime.d.ts.map +1 -0
  14. package/dist/catalog-runtime.js +785 -0
  15. package/dist/cel-expression.d.ts +32 -0
  16. package/dist/cel-expression.d.ts.map +1 -0
  17. package/dist/cel-expression.js +29 -0
  18. package/dist/cel-map-value.d.ts +34 -0
  19. package/dist/cel-map-value.d.ts.map +1 -0
  20. package/dist/cel-map-value.js +74 -0
  21. package/dist/cel-program.d.ts +44 -0
  22. package/dist/cel-program.d.ts.map +1 -0
  23. package/dist/cel-program.js +72 -0
  24. package/dist/cel-type.d.ts +131 -0
  25. package/dist/cel-type.d.ts.map +1 -0
  26. package/dist/cel-type.js +293 -0
  27. package/dist/cel-value.d.ts +159 -0
  28. package/dist/cel-value.d.ts.map +1 -0
  29. package/dist/cel-value.js +225 -0
  30. package/dist/check-diagnostic.d.ts +53 -0
  31. package/dist/check-diagnostic.d.ts.map +1 -0
  32. package/dist/check-diagnostic.js +66 -0
  33. package/dist/checker.d.ts +77 -0
  34. package/dist/checker.d.ts.map +1 -0
  35. package/dist/checker.js +721 -0
  36. package/dist/closure-backend.d.ts +21 -0
  37. package/dist/closure-backend.d.ts.map +1 -0
  38. package/dist/closure-backend.js +436 -0
  39. package/dist/comprehension-bindings.d.ts +33 -0
  40. package/dist/comprehension-bindings.d.ts.map +1 -0
  41. package/dist/comprehension-bindings.js +50 -0
  42. package/dist/comprehension-runtime.d.ts +44 -0
  43. package/dist/comprehension-runtime.d.ts.map +1 -0
  44. package/dist/comprehension-runtime.js +137 -0
  45. package/dist/declared-chain.d.ts +35 -0
  46. package/dist/declared-chain.d.ts.map +1 -0
  47. package/dist/declared-chain.js +36 -0
  48. package/dist/duration-value.d.ts +59 -0
  49. package/dist/duration-value.d.ts.map +1 -0
  50. package/dist/duration-value.js +135 -0
  51. package/dist/emitted-module.d.ts +207 -0
  52. package/dist/emitted-module.d.ts.map +1 -0
  53. package/dist/emitted-module.js +359 -0
  54. package/dist/engine-version.d.ts +3 -0
  55. package/dist/engine-version.d.ts.map +1 -0
  56. package/dist/engine-version.js +8 -0
  57. package/dist/environment-digest.d.ts +44 -0
  58. package/dist/environment-digest.d.ts.map +1 -0
  59. package/dist/environment-digest.js +98 -0
  60. package/dist/environment.d.ts +283 -0
  61. package/dist/environment.d.ts.map +1 -0
  62. package/dist/environment.js +459 -0
  63. package/dist/function-catalog.d.ts +66 -0
  64. package/dist/function-catalog.d.ts.map +1 -0
  65. package/dist/function-catalog.js +77 -0
  66. package/dist/function-registry.d.ts +78 -0
  67. package/dist/function-registry.d.ts.map +1 -0
  68. package/dist/function-registry.js +189 -0
  69. package/dist/index.d.ts +91 -0
  70. package/dist/index.d.ts.map +1 -0
  71. package/dist/index.js +59 -0
  72. package/dist/integer-arithmetic.d.ts +27 -0
  73. package/dist/integer-arithmetic.d.ts.map +1 -0
  74. package/dist/integer-arithmetic.js +58 -0
  75. package/dist/js-emitter.d.ts +132 -0
  76. package/dist/js-emitter.d.ts.map +1 -0
  77. package/dist/js-emitter.js +562 -0
  78. package/dist/json-schema-type.d.ts +182 -0
  79. package/dist/json-schema-type.d.ts.map +1 -0
  80. package/dist/json-schema-type.js +487 -0
  81. package/dist/json-text-scan.d.ts +28 -0
  82. package/dist/json-text-scan.d.ts.map +1 -0
  83. package/dist/json-text-scan.js +159 -0
  84. package/dist/lexer.d.ts +103 -0
  85. package/dist/lexer.d.ts.map +1 -0
  86. package/dist/lexer.js +458 -0
  87. package/dist/macro-check.d.ts +33 -0
  88. package/dist/macro-check.d.ts.map +1 -0
  89. package/dist/macro-check.js +162 -0
  90. package/dist/macro-shape.d.ts +24 -0
  91. package/dist/macro-shape.d.ts.map +1 -0
  92. package/dist/macro-shape.js +55 -0
  93. package/dist/member-read.d.ts +52 -0
  94. package/dist/member-read.d.ts.map +1 -0
  95. package/dist/member-read.js +125 -0
  96. package/dist/namespace-resolution.d.ts +35 -0
  97. package/dist/namespace-resolution.d.ts.map +1 -0
  98. package/dist/namespace-resolution.js +160 -0
  99. package/dist/nominal-type.d.ts +63 -0
  100. package/dist/nominal-type.d.ts.map +1 -0
  101. package/dist/nominal-type.js +98 -0
  102. package/dist/nullable-access.d.ts +38 -0
  103. package/dist/nullable-access.d.ts.map +1 -0
  104. package/dist/nullable-access.js +93 -0
  105. package/dist/parse-limits.d.ts +26 -0
  106. package/dist/parse-limits.d.ts.map +1 -0
  107. package/dist/parse-limits.js +21 -0
  108. package/dist/parser.d.ts +48 -0
  109. package/dist/parser.d.ts.map +1 -0
  110. package/dist/parser.js +503 -0
  111. package/dist/qualified-calls.d.ts +22 -0
  112. package/dist/qualified-calls.d.ts.map +1 -0
  113. package/dist/qualified-calls.js +27 -0
  114. package/dist/regular-expression.d.ts +48 -0
  115. package/dist/regular-expression.d.ts.map +1 -0
  116. package/dist/regular-expression.js +77 -0
  117. package/dist/reserved-words.d.ts +52 -0
  118. package/dist/reserved-words.d.ts.map +1 -0
  119. package/dist/reserved-words.js +77 -0
  120. package/dist/resolved-call.d.ts +33 -0
  121. package/dist/resolved-call.d.ts.map +1 -0
  122. package/dist/resolved-call.js +15 -0
  123. package/dist/root-references.d.ts +23 -0
  124. package/dist/root-references.d.ts.map +1 -0
  125. package/dist/root-references.js +120 -0
  126. package/dist/runtime-library.d.ts +56 -0
  127. package/dist/runtime-library.d.ts.map +1 -0
  128. package/dist/runtime-library.js +545 -0
  129. package/dist/serializer.d.ts +24 -0
  130. package/dist/serializer.d.ts.map +1 -0
  131. package/dist/serializer.js +240 -0
  132. package/dist/sha256.d.ts +20 -0
  133. package/dist/sha256.d.ts.map +1 -0
  134. package/dist/sha256.js +103 -0
  135. package/dist/signature.d.ts +72 -0
  136. package/dist/signature.d.ts.map +1 -0
  137. package/dist/signature.js +61 -0
  138. package/dist/signatures/function-catalog.json +788 -0
  139. package/dist/signatures/standard-library.json +229 -0
  140. package/dist/standard-library.d.ts +41 -0
  141. package/dist/standard-library.d.ts.map +1 -0
  142. package/dist/standard-library.js +85 -0
  143. package/dist/syntax-diagnostic.d.ts +61 -0
  144. package/dist/syntax-diagnostic.d.ts.map +1 -0
  145. package/dist/syntax-diagnostic.js +28 -0
  146. package/dist/syntax-tree.d.ts +160 -0
  147. package/dist/syntax-tree.d.ts.map +1 -0
  148. package/dist/syntax-tree.js +58 -0
  149. package/dist/timestamp-value.d.ts +53 -0
  150. package/dist/timestamp-value.d.ts.map +1 -0
  151. package/dist/timestamp-value.js +223 -0
  152. package/dist/tree-equality.d.ts +15 -0
  153. package/dist/tree-equality.d.ts.map +1 -0
  154. package/dist/tree-equality.js +105 -0
  155. package/dist/type-expression.d.ts +26 -0
  156. package/dist/type-expression.d.ts.map +1 -0
  157. package/dist/type-expression.js +134 -0
  158. package/dist/value-equality.d.ts +38 -0
  159. package/dist/value-equality.d.ts.map +1 -0
  160. package/dist/value-equality.js +196 -0
  161. package/dist/value-text.d.ts +25 -0
  162. package/dist/value-text.d.ts.map +1 -0
  163. package/dist/value-text.js +44 -0
  164. package/dist/zoned-calendar.d.ts +61 -0
  165. package/dist/zoned-calendar.d.ts.map +1 -0
  166. package/dist/zoned-calendar.js +143 -0
  167. package/package.json +56 -3
  168. package/src/activation.ts +32 -0
  169. package/src/backend-runtime.ts +454 -0
  170. package/src/bounded-cache.ts +45 -0
  171. package/src/catalog-runtime.ts +921 -0
  172. package/src/cel-expression.ts +53 -0
  173. package/src/cel-map-value.ts +86 -0
  174. package/src/cel-program.ts +103 -0
  175. package/src/cel-type.ts +359 -0
  176. package/src/cel-value.ts +353 -0
  177. package/src/check-diagnostic.ts +102 -0
  178. package/src/checker.ts +932 -0
  179. package/src/closure-backend.ts +502 -0
  180. package/src/comprehension-bindings.ts +66 -0
  181. package/src/comprehension-runtime.ts +157 -0
  182. package/src/declared-chain.ts +45 -0
  183. package/src/duration-value.ts +145 -0
  184. package/src/emitted-module.ts +494 -0
  185. package/src/engine-version.ts +9 -0
  186. package/src/environment-digest.ts +111 -0
  187. package/src/environment.ts +740 -0
  188. package/src/function-catalog.ts +140 -0
  189. package/src/function-registry.ts +229 -0
  190. package/src/index.ts +386 -0
  191. package/src/integer-arithmetic.ts +64 -0
  192. package/src/js-emitter.ts +713 -0
  193. package/src/json-schema-type.ts +664 -0
  194. package/src/json-text-scan.ts +163 -0
  195. package/src/lexer.ts +562 -0
  196. package/src/macro-check.ts +191 -0
  197. package/src/macro-shape.ts +66 -0
  198. package/src/member-read.ts +126 -0
  199. package/src/namespace-resolution.ts +167 -0
  200. package/src/nominal-type.ts +149 -0
  201. package/src/nullable-access.ts +95 -0
  202. package/src/parse-limits.ts +36 -0
  203. package/src/parser.ts +554 -0
  204. package/src/qualified-calls.ts +39 -0
  205. package/src/regular-expression.ts +101 -0
  206. package/src/reserved-words.ts +94 -0
  207. package/src/resolved-call.ts +34 -0
  208. package/src/root-references.ts +126 -0
  209. package/src/runtime-library.ts +615 -0
  210. package/src/serializer.ts +246 -0
  211. package/src/sha256.ts +112 -0
  212. package/src/signature.ts +127 -0
  213. package/src/signatures/function-catalog.json +788 -0
  214. package/src/signatures/standard-library.json +235 -0
  215. package/src/standard-library.ts +149 -0
  216. package/src/syntax-diagnostic.ts +72 -0
  217. package/src/syntax-tree.ts +229 -0
  218. package/src/timestamp-value.ts +294 -0
  219. package/src/tree-equality.ts +130 -0
  220. package/src/type-expression.ts +160 -0
  221. package/src/value-equality.ts +201 -0
  222. package/src/value-text.ts +45 -0
  223. package/src/zoned-calendar.ts +178 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"macro-shape.d.ts","sourceRoot":"","sources":["../src/macro-shape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG7D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;CAC7B;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,iBAAiB,EAAE,CAI9E"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Whether each macro call is shaped like one at all, judged before any type is read.
3
+ *
4
+ * A macro's own arguments are not values: `xs.map(i, …)` declares the name `i`, and
5
+ * `has(a.b)` asks about the member `b` of a chain of names. Neither is something a type
6
+ * can be wrong about — they are either written in the shape the macro takes, or the call
7
+ * is not that macro. So this is a **structural** pass over the whole tree, and it runs
8
+ * first: a macro written wrongly is reported before anything inside it is typed, because
9
+ * the typing of its body depends on a name the call failed to declare.
10
+ *
11
+ * The walk is **post-order**, so the innermost mistake is the one reported first. Nesting
12
+ * macros is how a generated expression goes wrong, and the inner call is the one a reader
13
+ * has to fix.
14
+ */
15
+ import { namespaceMacroBinding, receiverMacroBinding } from "./comprehension-bindings.js";
16
+ import { childNodes } from "./syntax-tree.js";
17
+ /** Every macro call whose own arguments are not the shape it takes, innermost first. */
18
+ export function macroShapeFindings(root) {
19
+ const findings = [];
20
+ collect(root, findings);
21
+ return findings;
22
+ }
23
+ function collect(node, findings) {
24
+ for (const child of childNodes(node))
25
+ collect(child, findings);
26
+ const finding = shapeOf(node);
27
+ if (finding)
28
+ findings.push(finding);
29
+ }
30
+ function shapeOf(node) {
31
+ if (node.kind === "call" && node.name === "has" && node.args.length === 1) {
32
+ const argument = node.args[0];
33
+ if (argument.kind === "select" && argument.field !== "")
34
+ return undefined;
35
+ return {
36
+ code: "CEL_INVALID_ARGUMENT",
37
+ message: "has() asks whether a member is there, so it takes a member read: write has(a.b)",
38
+ range: argument.range,
39
+ };
40
+ }
41
+ if (node.kind !== "receiverCall")
42
+ return undefined;
43
+ const binding = receiverMacroBinding(node.name, node.args.length) ??
44
+ namespaceMacroBinding(node.receiver.kind === "ident" ? node.receiver.name : "", node.name, node.args.length);
45
+ if (!binding)
46
+ return undefined;
47
+ const variable = node.args[binding.variableArgument];
48
+ if (variable.kind === "ident")
49
+ return undefined;
50
+ return {
51
+ code: "CEL_INVALID_ARGUMENT",
52
+ message: `${node.name} binds a name here, and this is not a name`,
53
+ range: variable.range,
54
+ };
55
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The member-read seam: **one** lookup, for every form a read is written in.
3
+ *
4
+ * `a.b`, `a['b']`, `a[expr]`, `a.?b`, `a[?expr]`, a macro's field read and the presence
5
+ * question `has()` all resolve here, through a single lookup over the value's **own**
6
+ * entries. Neither backend ever performs a host property read, so no key — however it
7
+ * was computed — can reach a prototype, a method or a function property: `a['length']`
8
+ * on a map is a missing key, not `0`, and `a[request.query.k]` cannot reach
9
+ * `constructor`.
10
+ *
11
+ * That is why the reserved-word set holds CEL's own words and nothing else. A word list
12
+ * is the wrong instrument: a member *name* is written by the author, while a member
13
+ * *key* can come from a request, so no list at any position touches the form an
14
+ * attacker can actually reach — and refusing `__proto__` as a name would make a
15
+ * resource that may legally be called that unreadable through CEL.
16
+ *
17
+ * A key the value does not hold is the `no_such_key` **error value**, which
18
+ * participates in short-circuit. Never `undefined` passed along.
19
+ */
20
+ import type { CelValue } from "./cel-value.js";
21
+ import { type CelError } from "./cel-value.js";
22
+ import type { SourceRange } from "./syntax-tree.js";
23
+ /**
24
+ * What one lookup found. The four refusals are **symbols**, not objects: a lookup happens
25
+ * on nearly every evaluation, and a wrapper object per read is an allocation per read.
26
+ * `MISSING` is a key the container does not hold — which `has()` answers `false` for and a
27
+ * read turns into `no_such_key`; the other three are mistakes in the read itself.
28
+ */
29
+ export declare const MISSING: unique symbol;
30
+ export declare const OUT_OF_RANGE: unique symbol;
31
+ export declare const UNSUPPORTED_CONTAINER: unique symbol;
32
+ export declare const UNSUPPORTED_KEY: unique symbol;
33
+ export type Lookup = CelValue | typeof MISSING | typeof OUT_OF_RANGE | typeof UNSUPPORTED_CONTAINER | typeof UNSUPPORTED_KEY;
34
+ /**
35
+ * The single lookup. It is total over the value domain: a container that holds no members
36
+ * at all answers `UNSUPPORTED_CONTAINER` rather than falling back to a property read that
37
+ * might find `length`, `name`, `call` or `apply`.
38
+ */
39
+ export declare function celLookup(container: CelValue, key: CelValue): Lookup;
40
+ /** The value at a key, or the error a failed lookup is. */
41
+ export declare function celRead(container: CelValue, key: CelValue, range?: SourceRange): CelValue | CelError;
42
+ /** The error a refused lookup is. */
43
+ export declare function lookupError(found: symbol, key: CelValue, range?: SourceRange): CelError;
44
+ /**
45
+ * Whether a key is there — `has(a.b)`. It asks about presence, so a missing key is
46
+ * `false` rather than the error a read would be; a container that holds no members at
47
+ * all is still a mistake in the question.
48
+ */
49
+ export declare function celHas(container: CelValue, key: CelValue, range?: SourceRange): boolean | CelError;
50
+ /** The elements a comprehension ranges over: a list's items, a map's keys. */
51
+ export declare function celIterable(container: CelValue, range?: SourceRange): CelValue[] | CelError;
52
+ //# sourceMappingURL=member-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"member-read.d.ts","sourceRoot":"","sources":["../src/member-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAA8C,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;GAKG;AACH,eAAO,MAAM,OAAO,eAA+B,CAAC;AACpD,eAAO,MAAM,YAAY,eAAkC,CAAC;AAC5D,eAAO,MAAM,qBAAqB,eAA4C,CAAC;AAC/E,eAAO,MAAM,eAAe,eAAsC,CAAC;AAEnE,MAAM,MAAM,MAAM,GACd,QAAQ,GACR,OAAO,OAAO,GACd,OAAO,YAAY,GACnB,OAAO,qBAAqB,GAC5B,OAAO,eAAe,CAAC;AAY3B;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,GAAG,MAAM,CAqBpE;AAED,2DAA2D;AAC3D,wBAAgB,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAIpG;AAED,qCAAqC;AACrC,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,CASvF;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,QAAQ,CAKlG;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,QAAQ,EAAE,GAAG,QAAQ,CAK3F"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * The member-read seam: **one** lookup, for every form a read is written in.
3
+ *
4
+ * `a.b`, `a['b']`, `a[expr]`, `a.?b`, `a[?expr]`, a macro's field read and the presence
5
+ * question `has()` all resolve here, through a single lookup over the value's **own**
6
+ * entries. Neither backend ever performs a host property read, so no key — however it
7
+ * was computed — can reach a prototype, a method or a function property: `a['length']`
8
+ * on a map is a missing key, not `0`, and `a[request.query.k]` cannot reach
9
+ * `constructor`.
10
+ *
11
+ * That is why the reserved-word set holds CEL's own words and nothing else. A word list
12
+ * is the wrong instrument: a member *name* is written by the author, while a member
13
+ * *key* can come from a request, so no list at any position touches the form an
14
+ * attacker can actually reach — and refusing `__proto__` as a name would make a
15
+ * resource that may legally be called that unreadable through CEL.
16
+ *
17
+ * A key the value does not hold is the `no_such_key` **error value**, which
18
+ * participates in short-circuit. Never `undefined` passed along.
19
+ */
20
+ import { celMapKeys, mapKeyIdentity } from "./cel-map-value.js";
21
+ import { celError, isCelMap, isCelRecord, isCelUint } from "./cel-value.js";
22
+ /**
23
+ * What one lookup found. The four refusals are **symbols**, not objects: a lookup happens
24
+ * on nearly every evaluation, and a wrapper object per read is an allocation per read.
25
+ * `MISSING` is a key the container does not hold — which `has()` answers `false` for and a
26
+ * read turns into `no_such_key`; the other three are mistakes in the read itself.
27
+ */
28
+ export const MISSING = Symbol("cel.lookup.missing");
29
+ export const OUT_OF_RANGE = Symbol("cel.lookup.outOfRange");
30
+ export const UNSUPPORTED_CONTAINER = Symbol("cel.lookup.unsupportedContainer");
31
+ export const UNSUPPORTED_KEY = Symbol("cel.lookup.unsupportedKey");
32
+ /** An int-valued index, or nothing when the value is of no index type. */
33
+ function indexOf(key) {
34
+ if (typeof key === "bigint")
35
+ return key;
36
+ if (isCelUint(key))
37
+ return key.value;
38
+ // A double that holds a whole number indexes a list: a `dyn` arithmetic result is a
39
+ // double, and cel-spec indexes with it where it is integral.
40
+ if (typeof key === "number" && Number.isInteger(key))
41
+ return BigInt(key);
42
+ return undefined;
43
+ }
44
+ /**
45
+ * The single lookup. It is total over the value domain: a container that holds no members
46
+ * at all answers `UNSUPPORTED_CONTAINER` rather than falling back to a property read that
47
+ * might find `length`, `name`, `call` or `apply`.
48
+ */
49
+ export function celLookup(container, key) {
50
+ if (typeof key === "string" && isCelRecord(container)) {
51
+ // An OWN entry, never an inherited one: a host's object is data here.
52
+ return Object.prototype.hasOwnProperty.call(container, key)
53
+ ? container[key]
54
+ : MISSING;
55
+ }
56
+ if (isCelMap(container)) {
57
+ const identity = mapKeyIdentity(key);
58
+ if (identity === undefined)
59
+ return UNSUPPORTED_KEY;
60
+ const entry = container.entries.get(identity);
61
+ return entry ? entry.value : MISSING;
62
+ }
63
+ if (Array.isArray(container)) {
64
+ const at = indexOf(key);
65
+ if (at === undefined)
66
+ return UNSUPPORTED_KEY;
67
+ if (at < 0n || at >= BigInt(container.length))
68
+ return OUT_OF_RANGE;
69
+ return container[Number(at)];
70
+ }
71
+ if (isCelRecord(container))
72
+ return UNSUPPORTED_KEY;
73
+ return UNSUPPORTED_CONTAINER;
74
+ }
75
+ /** The value at a key, or the error a failed lookup is. */
76
+ export function celRead(container, key, range) {
77
+ const found = celLookup(container, key);
78
+ if (typeof found !== "symbol")
79
+ return found;
80
+ return lookupError(found, key, range);
81
+ }
82
+ /** The error a refused lookup is. */
83
+ export function lookupError(found, key, range) {
84
+ if (found === MISSING)
85
+ return celError("no_such_key", `no such key: ${describe(key)}`, range);
86
+ if (found === OUT_OF_RANGE) {
87
+ return celError("index_out_of_range", `index out of range: ${describe(key)}`, range);
88
+ }
89
+ if (found === UNSUPPORTED_KEY) {
90
+ return celError("unsupported_key_type", `${describe(key)} cannot name an entry of this value`, range);
91
+ }
92
+ return celError("unsupported_container", "this value holds no members", range);
93
+ }
94
+ /**
95
+ * Whether a key is there — `has(a.b)`. It asks about presence, so a missing key is
96
+ * `false` rather than the error a read would be; a container that holds no members at
97
+ * all is still a mistake in the question.
98
+ */
99
+ export function celHas(container, key, range) {
100
+ const found = celLookup(container, key);
101
+ if (typeof found !== "symbol")
102
+ return true;
103
+ if (found === MISSING || found === OUT_OF_RANGE)
104
+ return false;
105
+ return lookupError(found, key, range);
106
+ }
107
+ /** The elements a comprehension ranges over: a list's items, a map's keys. */
108
+ export function celIterable(container, range) {
109
+ if (Array.isArray(container))
110
+ return [...container];
111
+ if (isCelMap(container))
112
+ return celMapKeys(container);
113
+ if (isCelRecord(container))
114
+ return Object.keys(container);
115
+ return celError("unsupported_container", "a comprehension reads a list or a map", range);
116
+ }
117
+ function describe(key) {
118
+ if (typeof key === "string")
119
+ return JSON.stringify(key);
120
+ if (isCelUint(key))
121
+ return `${key.value}`;
122
+ if (typeof key === "bigint")
123
+ return `${key}`;
124
+ return String(key);
125
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Turning `Alias.fn(x)` into a qualified call.
3
+ *
4
+ * `Alias.fn(x)` and `obj.method(x)` are **the same syntax** — a call written on a
5
+ * receiver — so no parser can tell them apart, and only a set of names that denote
6
+ * namespaces rather than values can. That set comes from the host, which is why
7
+ * this is a separate total tree-to-tree pass rather than a parser rule: the parser
8
+ * has one input and this has two.
9
+ *
10
+ * The pass is total — it visits every node and rewrites every receiver call whose
11
+ * receiver is a bare identifier in the set, wherever it sits. It is also the only
12
+ * producer of `qcall`, and `cel` and `optional` can never be in the set, because
13
+ * the standard macros are written on them (`cel.bind(…)`, `optional.of(…)`) and a
14
+ * namespace would capture those calls instead.
15
+ *
16
+ * A resolved tree records the set it was resolved under, so a consumer given a tree
17
+ * can tell whether it was resolved under the set it is about to check it against —
18
+ * the alternative is a tree that looks resolved and silently is not.
19
+ */
20
+ import type { CelNode } from "./syntax-tree.js";
21
+ /** Names that can never be registered as a namespace. */
22
+ export declare const RESERVED_NAMESPACES: readonly string[];
23
+ /** A namespace set a host cannot have: the name is not a name, or is reserved. */
24
+ export declare class CelNamespaceError extends Error {
25
+ constructor(message: string);
26
+ }
27
+ /**
28
+ * Validates a namespace set and puts it in a canonical order, so that two sets with
29
+ * the same names compare equal however the host listed them.
30
+ */
31
+ export declare function normalizeNamespaces(names: Iterable<string>): readonly string[];
32
+ export declare function namespaceSetsEqual(left: readonly string[], right: readonly string[]): boolean;
33
+ /** Rewrites every call on a name of the set into a `qcall`. Total; shares what it does not change. */
34
+ export declare function resolveNamespaces(root: CelNode, namespaces: readonly string[]): CelNode;
35
+ //# sourceMappingURL=namespace-resolution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace-resolution.d.ts","sourceRoot":"","sources":["../src/namespace-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAe,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE7D,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAwB,CAAC;AAE1E,kFAAkF;AAClF,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,SAAS,MAAM,EAAE,CAiB9E;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAE7F;AAED,sGAAsG;AACtG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAsBvF"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Turning `Alias.fn(x)` into a qualified call.
3
+ *
4
+ * `Alias.fn(x)` and `obj.method(x)` are **the same syntax** — a call written on a
5
+ * receiver — so no parser can tell them apart, and only a set of names that denote
6
+ * namespaces rather than values can. That set comes from the host, which is why
7
+ * this is a separate total tree-to-tree pass rather than a parser rule: the parser
8
+ * has one input and this has two.
9
+ *
10
+ * The pass is total — it visits every node and rewrites every receiver call whose
11
+ * receiver is a bare identifier in the set, wherever it sits. It is also the only
12
+ * producer of `qcall`, and `cel` and `optional` can never be in the set, because
13
+ * the standard macros are written on them (`cel.bind(…)`, `optional.of(…)`) and a
14
+ * namespace would capture those calls instead.
15
+ *
16
+ * A resolved tree records the set it was resolved under, so a consumer given a tree
17
+ * can tell whether it was resolved under the set it is about to check it against —
18
+ * the alternative is a tree that looks resolved and silently is not.
19
+ */
20
+ import { isIdentifierSpelling, isReservedWord } from "./reserved-words.js";
21
+ /** Names that can never be registered as a namespace. */
22
+ export const RESERVED_NAMESPACES = ["cel", "optional"];
23
+ /** A namespace set a host cannot have: the name is not a name, or is reserved. */
24
+ export class CelNamespaceError extends Error {
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = "CelNamespaceError";
28
+ }
29
+ }
30
+ /**
31
+ * Validates a namespace set and puts it in a canonical order, so that two sets with
32
+ * the same names compare equal however the host listed them.
33
+ */
34
+ export function normalizeNamespaces(names) {
35
+ const normalized = [];
36
+ for (const name of names) {
37
+ if (!isIdentifierSpelling(name)) {
38
+ throw new CelNamespaceError(`${JSON.stringify(name)} is not spelled as a name, so it names no namespace`);
39
+ }
40
+ if (isReservedWord(name)) {
41
+ throw new CelNamespaceError(`${JSON.stringify(name)} is a reserved word, so it names no namespace`);
42
+ }
43
+ if (RESERVED_NAMESPACES.includes(name)) {
44
+ throw new CelNamespaceError(`${JSON.stringify(name)} is reserved: the standard macros are written on it, and a namespace would capture them`);
45
+ }
46
+ if (!normalized.includes(name))
47
+ normalized.push(name);
48
+ }
49
+ return normalized.sort();
50
+ }
51
+ export function namespaceSetsEqual(left, right) {
52
+ return left.length === right.length && left.every((name, at) => name === right[at]);
53
+ }
54
+ /** Rewrites every call on a name of the set into a `qcall`. Total; shares what it does not change. */
55
+ export function resolveNamespaces(root, namespaces) {
56
+ // With no namespaces the pass is the identity — nothing can match an empty set — so it
57
+ // answers without walking. Every site with no module names takes this path, which is why
58
+ // it is worth stating rather than leaving to the structural sharing below.
59
+ if (namespaces.length === 0)
60
+ return root;
61
+ const resolved = mapChildren(root, (child) => resolveNamespaces(child, namespaces));
62
+ if (resolved.kind !== "receiverCall")
63
+ return resolved;
64
+ const receiver = resolved.receiver;
65
+ // An absolute name denotes a value the environment declares, never a namespace: a
66
+ // namespaced call has exactly one spelling, and `.Alias.fn(x)` is not it.
67
+ if (receiver.kind !== "ident" || receiver.absolute || !namespaces.includes(receiver.name)) {
68
+ return resolved;
69
+ }
70
+ return {
71
+ kind: "qcall",
72
+ namespace: receiver.name,
73
+ namespaceRange: receiver.range,
74
+ name: resolved.name,
75
+ nameRange: resolved.nameRange,
76
+ args: resolved.args,
77
+ range: resolved.range,
78
+ };
79
+ }
80
+ /** Rebuilds a node from its mapped children, returning the original when none moved. */
81
+ function mapChildren(node, map) {
82
+ switch (node.kind) {
83
+ case "literal":
84
+ case "ident":
85
+ case "unparsed":
86
+ return node;
87
+ case "list": {
88
+ let moved = false;
89
+ const elements = node.elements.map((element) => {
90
+ const value = map(element.value);
91
+ if (value === element.value)
92
+ return element;
93
+ moved = true;
94
+ return { ...element, value };
95
+ });
96
+ return moved ? { ...node, elements } : node;
97
+ }
98
+ case "map": {
99
+ let moved = false;
100
+ const entries = node.entries.map((entry) => {
101
+ const key = map(entry.key);
102
+ const value = map(entry.value);
103
+ if (key === entry.key && value === entry.value)
104
+ return entry;
105
+ moved = true;
106
+ return { ...entry, key, value };
107
+ });
108
+ return moved ? { ...node, entries } : node;
109
+ }
110
+ case "select": {
111
+ const operand = map(node.operand);
112
+ return operand === node.operand ? node : { ...node, operand };
113
+ }
114
+ case "index": {
115
+ const operand = map(node.operand);
116
+ const index = map(node.index);
117
+ return operand === node.operand && index === node.index ? node : { ...node, operand, index };
118
+ }
119
+ case "call":
120
+ case "qcall": {
121
+ const args = mapList(node.args, map);
122
+ return args ? { ...node, args } : node;
123
+ }
124
+ case "receiverCall": {
125
+ const receiver = map(node.receiver);
126
+ const args = mapList(node.args, map);
127
+ if (receiver === node.receiver && !args)
128
+ return node;
129
+ return { ...node, receiver, args: args ?? node.args };
130
+ }
131
+ case "unary": {
132
+ const operand = map(node.operand);
133
+ return operand === node.operand ? node : { ...node, operand };
134
+ }
135
+ case "binary": {
136
+ const left = map(node.left);
137
+ const right = map(node.right);
138
+ return left === node.left && right === node.right ? node : { ...node, left, right };
139
+ }
140
+ case "conditional": {
141
+ const condition = map(node.condition);
142
+ const whenTrue = map(node.whenTrue);
143
+ const whenFalse = map(node.whenFalse);
144
+ return condition === node.condition && whenTrue === node.whenTrue && whenFalse === node.whenFalse
145
+ ? node
146
+ : { ...node, condition, whenTrue, whenFalse };
147
+ }
148
+ }
149
+ }
150
+ /** The mapped list, or nothing when every element is the one it started as. */
151
+ function mapList(nodes, map) {
152
+ let moved = false;
153
+ const mapped = nodes.map((node) => {
154
+ const next = map(node);
155
+ if (next !== node)
156
+ moved = true;
157
+ return next;
158
+ });
159
+ return moved ? mapped : undefined;
160
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Named types a host registers — the one mechanism, with none of the vocabulary.
3
+ *
4
+ * A nominal type is a name over a base type, with its own operators, comparisons,
5
+ * conversions and member functions, and with named **invariant** type parameters. It
6
+ * is not its base: a value of the base does not stand where the named type is wanted,
7
+ * and only what the definition declares applies to it. That is what makes a named type
8
+ * worth having — a slot that wants one refuses a plain value of the base, which is
9
+ * exactly what an engine typing by wrapper class cannot express.
10
+ *
11
+ * Invariance is deliberate: `Holder<string>` and `Holder<int>` are unrelated, so a
12
+ * type argument that differs is a mistake with its own diagnostic rather than a silent
13
+ * widening to the base.
14
+ *
15
+ * `Self` inside a definition names the type being defined, with its own parameters
16
+ * applied, so a member can answer its own type without repeating it.
17
+ */
18
+ import type { CelType, NominalType } from "./cel-type.js";
19
+ import type { NominalResolver } from "./type-expression.js";
20
+ export interface NominalOperatorDeclaration {
21
+ readonly operator: string;
22
+ /** Type expressions; `Self` names the type being defined. */
23
+ readonly parameters: readonly string[];
24
+ readonly returns: string;
25
+ }
26
+ export interface NominalTypeDefinition {
27
+ readonly name: string;
28
+ /** The type expression a value of this type is, underneath. */
29
+ readonly base: string;
30
+ /** Invariant type parameter names, each a single capital letter. */
31
+ readonly parameters?: readonly string[];
32
+ /** Operators over the type, written with `Self`. */
33
+ readonly operators?: readonly NominalOperatorDeclaration[];
34
+ /** Operator symbols to register as `(Self, Self): bool`. */
35
+ readonly comparisons?: readonly string[];
36
+ /** Conversion signatures, e.g. `string(Self): string`. */
37
+ readonly conversions?: readonly string[];
38
+ /** Member signatures, e.g. `Self.scaled(int): Self`. */
39
+ readonly members?: readonly string[];
40
+ readonly description?: string;
41
+ }
42
+ export declare class CelTypeRegistrationError extends Error {
43
+ constructor(message: string);
44
+ }
45
+ /** A registered nominal type: its definition, its base, and the type `Self` names. */
46
+ export interface RegisteredType {
47
+ readonly definition: NominalTypeDefinition;
48
+ readonly base: CelType;
49
+ readonly parameters: readonly string[];
50
+ /** The type with its own parameters applied — what `Self` resolves to. */
51
+ readonly self: NominalType;
52
+ }
53
+ export declare function validateTypeName(name: string): void;
54
+ /**
55
+ * Builds the registered form of a definition. `resolveNominal` resolves names the
56
+ * definition's own base or members mention, including itself through `Self`.
57
+ */
58
+ export declare function buildRegisteredType(definition: NominalTypeDefinition, resolveNominal: NominalResolver): RegisteredType;
59
+ /** The signatures a definition declares, as text, in registration order. */
60
+ export declare function nominalSignatures(definition: NominalTypeDefinition): readonly string[];
61
+ /** The operator declarations a definition implies, its comparisons expanded. */
62
+ export declare function nominalOperators(definition: NominalTypeDefinition): readonly NominalOperatorDeclaration[];
63
+ //# sourceMappingURL=nominal-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nominal-type.d.ts","sourceRoot":"","sources":["../src/nominal-type.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC3D,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAsBD,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,EAAE,MAAM;CAI5B;AAED,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAYnD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,qBAAqB,EACjC,cAAc,EAAE,eAAe,GAC9B,cAAc,CA6BhB;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,qBAAqB,GAAG,SAAS,MAAM,EAAE,CAEtF;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,qBAAqB,GAAG,SAAS,0BAA0B,EAAE,CAOzG"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Named types a host registers — the one mechanism, with none of the vocabulary.
3
+ *
4
+ * A nominal type is a name over a base type, with its own operators, comparisons,
5
+ * conversions and member functions, and with named **invariant** type parameters. It
6
+ * is not its base: a value of the base does not stand where the named type is wanted,
7
+ * and only what the definition declares applies to it. That is what makes a named type
8
+ * worth having — a slot that wants one refuses a plain value of the base, which is
9
+ * exactly what an engine typing by wrapper class cannot express.
10
+ *
11
+ * Invariance is deliberate: `Holder<string>` and `Holder<int>` are unrelated, so a
12
+ * type argument that differs is a mistake with its own diagnostic rather than a silent
13
+ * widening to the base.
14
+ *
15
+ * `Self` inside a definition names the type being defined, with its own parameters
16
+ * applied, so a member can answer its own type without repeating it.
17
+ */
18
+ import { parameterOf } from "./cel-type.js";
19
+ import { parseTypeExpression } from "./type-expression.js";
20
+ const NAME = /^[A-Za-z_][A-Za-z0-9_.]*$/;
21
+ const PARAMETER = /^[A-Z]$/;
22
+ const LANGUAGE_NAMES = new Set([
23
+ "dyn",
24
+ "int",
25
+ "uint",
26
+ "double",
27
+ "bool",
28
+ "string",
29
+ "bytes",
30
+ "null",
31
+ "null_type",
32
+ "type",
33
+ "list",
34
+ "map",
35
+ "optional",
36
+ "timestamp",
37
+ "duration",
38
+ ]);
39
+ export class CelTypeRegistrationError extends Error {
40
+ constructor(message) {
41
+ super(message);
42
+ this.name = "CelTypeRegistrationError";
43
+ }
44
+ }
45
+ export function validateTypeName(name) {
46
+ if (!NAME.test(name)) {
47
+ throw new CelTypeRegistrationError(`${JSON.stringify(name)} is not spelled as a type name`);
48
+ }
49
+ if (LANGUAGE_NAMES.has(name)) {
50
+ throw new CelTypeRegistrationError(`${JSON.stringify(name)} is a type of the language and cannot be redefined`);
51
+ }
52
+ if (PARAMETER.test(name)) {
53
+ throw new CelTypeRegistrationError(`${JSON.stringify(name)} is a single capital letter, which a signature reads as a type parameter`);
54
+ }
55
+ }
56
+ /**
57
+ * Builds the registered form of a definition. `resolveNominal` resolves names the
58
+ * definition's own base or members mention, including itself through `Self`.
59
+ */
60
+ export function buildRegisteredType(definition, resolveNominal) {
61
+ validateTypeName(definition.name);
62
+ const parameters = definition.parameters ?? [];
63
+ for (const parameter of parameters) {
64
+ if (!PARAMETER.test(parameter)) {
65
+ throw new CelTypeRegistrationError(`type parameter ${JSON.stringify(parameter)} of ${definition.name} must be a single capital letter`);
66
+ }
67
+ }
68
+ const self = {
69
+ kind: "nominal",
70
+ name: definition.name,
71
+ base: { kind: "dyn" },
72
+ args: parameters.map(parameterOf),
73
+ };
74
+ const withSelf = (name, args) => name === "Self" || name === definition.name
75
+ ? { ...self, args: args.length > 0 ? args : self.args }
76
+ : resolveNominal(name, args);
77
+ let base;
78
+ try {
79
+ base = parseTypeExpression(definition.base, withSelf);
80
+ }
81
+ catch (cause) {
82
+ throw new CelTypeRegistrationError(`the base of ${definition.name} does not read as a type: ${cause.message}`);
83
+ }
84
+ return { definition, base, parameters, self: { ...self, base } };
85
+ }
86
+ /** The signatures a definition declares, as text, in registration order. */
87
+ export function nominalSignatures(definition) {
88
+ return [...(definition.conversions ?? []), ...(definition.members ?? [])];
89
+ }
90
+ /** The operator declarations a definition implies, its comparisons expanded. */
91
+ export function nominalOperators(definition) {
92
+ const comparisons = (definition.comparisons ?? []).map((operator) => ({
93
+ operator,
94
+ parameters: ["Self", "Self"],
95
+ returns: "bool",
96
+ }));
97
+ return [...(definition.operators ?? []), ...comparisons];
98
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Which dereferences a guard has proven safe.
3
+ *
4
+ * A value whose declared type admits null is only safely dereferenced where something
5
+ * has proven it is not null, and **what counts as proof is exactly three constructs**:
6
+ * a ternary, `&&` and `||`. Not more, not less. That bound is not a simplification — a
7
+ * consumer switching engines must not newly accept an expression (which recognising
8
+ * another construct would do) nor newly reject one (which recognising fewer would do),
9
+ * and a guard written as a function call is deliberately not proof.
10
+ *
11
+ * The rules, over a condition `c`:
12
+ *
13
+ * - `chain != null` proves `chain` where `c` holds; `chain == null` proves it where `c`
14
+ * fails. `null` may stand on either side of the comparison.
15
+ * - `!c` swaps the two.
16
+ * - `a && b` proves, where it holds, everything `a` and `b` prove; where it fails,
17
+ * nothing, since either arm may be the one that failed.
18
+ * - `a || b` is the mirror: where it fails, both arms failed, so both their negative
19
+ * proofs hold.
20
+ *
21
+ * A chain is a plain path of named members (`error.code`), which is what a proof can
22
+ * name: nothing proves anything about `xs[i].code`, because the index is not part of a
23
+ * name.
24
+ */
25
+ import type { CelNode } from "./syntax-tree.js";
26
+ /** The dotted path a node spells, if it is a plain chain of named members. */
27
+ export declare function chainText(node: CelNode): string | undefined;
28
+ /**
29
+ * The name a chain is rooted at, or nothing when it is not a chain of plain members over a
30
+ * name. It is what says whether the chain's subject is a name the EXPRESSION bound — a
31
+ * comprehension variable, a `cel.bind` name — rather than one the host declared.
32
+ */
33
+ export declare function chainRoot(node: CelNode): string | undefined;
34
+ /** The chains proven non-null where the condition holds. */
35
+ export declare function provenWhereTrue(condition: CelNode): readonly string[];
36
+ /** The chains proven non-null where the condition fails. */
37
+ export declare function provenWhereFalse(condition: CelNode): readonly string[];
38
+ //# sourceMappingURL=nullable-access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nullable-access.d.ts","sourceRoot":"","sources":["../src/nullable-access.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK3D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAI3D;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAarE;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAatE"}