typesea 0.1.0 → 0.3.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/CHANGELOG.md +85 -6
- package/README.md +143 -28
- package/dist/adapters/index.d.ts +50 -8
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +169 -48
- package/dist/aot/index.d.ts +19 -3
- package/dist/aot/index.d.ts.map +1 -1
- package/dist/aot/index.js +115 -17
- package/dist/async/index.d.ts +28 -56
- package/dist/async/index.d.ts.map +1 -1
- package/dist/async/index.js +94 -37
- package/dist/builders/composite.d.ts +43 -9
- package/dist/builders/composite.d.ts.map +1 -1
- package/dist/builders/composite.js +100 -17
- package/dist/builders/index.d.ts +8 -5
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +7 -4
- package/dist/builders/modifier.d.ts +36 -5
- package/dist/builders/modifier.d.ts.map +1 -1
- package/dist/builders/modifier.js +52 -5
- package/dist/builders/object/guard.d.ts +72 -24
- package/dist/builders/object/guard.d.ts.map +1 -1
- package/dist/builders/object/guard.js +139 -29
- package/dist/builders/object/index.d.ts +4 -2
- package/dist/builders/object/index.d.ts.map +1 -1
- package/dist/builders/object/index.js +3 -1
- package/dist/builders/object/schema.d.ts +88 -11
- package/dist/builders/object/schema.d.ts.map +1 -1
- package/dist/builders/object/schema.js +290 -23
- package/dist/builders/object/types.d.ts +20 -31
- package/dist/builders/object/types.d.ts.map +1 -1
- package/dist/builders/object/types.js +2 -0
- package/dist/builders/runtime.d.ts +40 -0
- package/dist/builders/runtime.d.ts.map +1 -0
- package/dist/builders/runtime.js +150 -0
- package/dist/builders/scalar.d.ts +49 -9
- package/dist/builders/scalar.d.ts.map +1 -1
- package/dist/builders/scalar.js +87 -9
- package/dist/builders/table.d.ts +35 -5
- package/dist/builders/table.d.ts.map +1 -1
- package/dist/builders/table.js +35 -5
- package/dist/builders/types.d.ts +20 -4
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/builders/types.js +2 -0
- package/dist/compile/check-composite.d.ts +25 -2
- package/dist/compile/check-composite.d.ts.map +1 -1
- package/dist/compile/check-composite.js +699 -27
- package/dist/compile/check-scalar.d.ts +88 -0
- package/dist/compile/check-scalar.d.ts.map +1 -1
- package/dist/compile/check-scalar.js +570 -3
- package/dist/compile/check.d.ts +12 -0
- package/dist/compile/check.d.ts.map +1 -1
- package/dist/compile/check.js +62 -3
- package/dist/compile/context.d.ts +47 -9
- package/dist/compile/context.d.ts.map +1 -1
- package/dist/compile/context.js +53 -8
- package/dist/compile/first.d.ts +26 -0
- package/dist/compile/first.d.ts.map +1 -0
- package/dist/compile/first.js +850 -0
- package/dist/compile/graph-predicate.d.ts +4 -2
- package/dist/compile/graph-predicate.d.ts.map +1 -1
- package/dist/compile/graph-predicate.js +2272 -165
- package/dist/compile/guard.d.ts +16 -24
- package/dist/compile/guard.d.ts.map +1 -1
- package/dist/compile/guard.js +202 -72
- package/dist/compile/index.d.ts +3 -1
- package/dist/compile/index.d.ts.map +1 -1
- package/dist/compile/index.js +2 -0
- package/dist/compile/issue.d.ts +110 -0
- package/dist/compile/issue.d.ts.map +1 -1
- package/dist/compile/issue.js +184 -1
- package/dist/compile/names.d.ts +12 -2
- package/dist/compile/names.d.ts.map +1 -1
- package/dist/compile/names.js +19 -3
- package/dist/compile/predicate.d.ts +24 -0
- package/dist/compile/predicate.d.ts.map +1 -1
- package/dist/compile/predicate.js +287 -10
- package/dist/compile/runtime.d.ts +100 -13
- package/dist/compile/runtime.d.ts.map +1 -1
- package/dist/compile/runtime.js +56 -6
- package/dist/compile/source.d.ts +10 -2
- package/dist/compile/source.d.ts.map +1 -1
- package/dist/compile/source.js +385 -26
- package/dist/compile/types.d.ts +22 -0
- package/dist/compile/types.d.ts.map +1 -1
- package/dist/compile/types.js +2 -0
- package/dist/decoder/index.d.ts +92 -46
- package/dist/decoder/index.d.ts.map +1 -1
- package/dist/decoder/index.js +266 -39
- package/dist/evaluate/check-composite.d.ts +111 -2
- package/dist/evaluate/check-composite.d.ts.map +1 -1
- package/dist/evaluate/check-composite.js +343 -8
- package/dist/evaluate/check-scalar.d.ts +25 -0
- package/dist/evaluate/check-scalar.d.ts.map +1 -1
- package/dist/evaluate/check-scalar.js +124 -3
- package/dist/evaluate/check.d.ts +7 -0
- package/dist/evaluate/check.d.ts.map +1 -1
- package/dist/evaluate/check.js +62 -4
- package/dist/evaluate/index.d.ts +2 -0
- package/dist/evaluate/index.d.ts.map +1 -1
- package/dist/evaluate/index.js +2 -0
- package/dist/evaluate/issue.d.ts +11 -1
- package/dist/evaluate/issue.d.ts.map +1 -1
- package/dist/evaluate/issue.js +15 -1
- package/dist/evaluate/predicate.d.ts +16 -5
- package/dist/evaluate/predicate.d.ts.map +1 -1
- package/dist/evaluate/predicate.js +20 -5
- package/dist/evaluate/shared.d.ts +78 -13
- package/dist/evaluate/shared.d.ts.map +1 -1
- package/dist/evaluate/shared.js +101 -8
- package/dist/evaluate/state.d.ts +35 -13
- package/dist/evaluate/state.d.ts.map +1 -1
- package/dist/evaluate/state.js +35 -2
- package/dist/guard/array.d.ts +48 -0
- package/dist/guard/array.d.ts.map +1 -0
- package/dist/guard/array.js +84 -0
- package/dist/guard/base.d.ts +111 -31
- package/dist/guard/base.d.ts.map +1 -1
- package/dist/guard/base.js +165 -32
- package/dist/guard/date.d.ts +34 -0
- package/dist/guard/date.d.ts.map +1 -0
- package/dist/guard/date.js +60 -0
- package/dist/guard/error.d.ts +10 -5
- package/dist/guard/error.d.ts.map +1 -1
- package/dist/guard/error.js +10 -5
- package/dist/guard/index.d.ts +4 -0
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +4 -0
- package/dist/guard/number.d.ts +86 -11
- package/dist/guard/number.d.ts.map +1 -1
- package/dist/guard/number.js +159 -11
- package/dist/guard/props.d.ts +27 -3
- package/dist/guard/props.d.ts.map +1 -1
- package/dist/guard/props.js +27 -3
- package/dist/guard/read.d.ts +115 -10
- package/dist/guard/read.d.ts.map +1 -1
- package/dist/guard/read.js +185 -10
- package/dist/guard/registry.d.ts +12 -2
- package/dist/guard/registry.d.ts.map +1 -1
- package/dist/guard/registry.js +15 -3
- package/dist/guard/string.d.ts +115 -13
- package/dist/guard/string.d.ts.map +1 -1
- package/dist/guard/string.js +250 -13
- package/dist/guard/types.d.ts +110 -40
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/guard/types.js +2 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/internal/index.d.ts +42 -6
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +51 -8
- package/dist/ir/builder.d.ts +17 -127
- package/dist/ir/builder.d.ts.map +1 -1
- package/dist/ir/builder.js +80 -137
- package/dist/ir/freeze.d.ts +4 -0
- package/dist/ir/freeze.d.ts.map +1 -1
- package/dist/ir/freeze.js +66 -0
- package/dist/ir/index.d.ts +3 -1
- package/dist/ir/index.d.ts.map +1 -1
- package/dist/ir/index.js +2 -0
- package/dist/ir/regexp.d.ts +2 -0
- package/dist/ir/regexp.d.ts.map +1 -1
- package/dist/ir/regexp.js +2 -0
- package/dist/ir/types.d.ts +94 -56
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/ir/types.js +2 -0
- package/dist/ir/validate.d.ts +8 -1
- package/dist/ir/validate.d.ts.map +1 -1
- package/dist/ir/validate.js +511 -61
- package/dist/issue/index.d.ts +42 -10
- package/dist/issue/index.d.ts.map +1 -1
- package/dist/issue/index.js +65 -11
- package/dist/json-schema/emit-combinator.d.ts +44 -4
- package/dist/json-schema/emit-combinator.d.ts.map +1 -1
- package/dist/json-schema/emit-combinator.js +44 -4
- package/dist/json-schema/emit-composite.d.ts +16 -2
- package/dist/json-schema/emit-composite.d.ts.map +1 -1
- package/dist/json-schema/emit-composite.js +81 -13
- package/dist/json-schema/emit-scalar.d.ts +26 -3
- package/dist/json-schema/emit-scalar.d.ts.map +1 -1
- package/dist/json-schema/emit-scalar.js +124 -10
- package/dist/json-schema/emit-types.d.ts +11 -1
- package/dist/json-schema/emit-types.d.ts.map +1 -1
- package/dist/json-schema/emit-types.js +2 -0
- package/dist/json-schema/emit.d.ts +12 -1
- package/dist/json-schema/emit.d.ts.map +1 -1
- package/dist/json-schema/emit.js +23 -3
- package/dist/json-schema/freeze.d.ts +13 -2
- package/dist/json-schema/freeze.d.ts.map +1 -1
- package/dist/json-schema/freeze.js +41 -8
- package/dist/json-schema/index.d.ts +16 -2
- package/dist/json-schema/index.d.ts.map +1 -1
- package/dist/json-schema/index.js +23 -3
- package/dist/json-schema/issue.d.ts +4 -1
- package/dist/json-schema/issue.d.ts.map +1 -1
- package/dist/json-schema/issue.js +4 -1
- package/dist/json-schema/read.d.ts +24 -3
- package/dist/json-schema/read.d.ts.map +1 -1
- package/dist/json-schema/read.js +59 -12
- package/dist/json-schema/types.d.ts +45 -16
- package/dist/json-schema/types.d.ts.map +1 -1
- package/dist/json-schema/types.js +2 -0
- package/dist/kind/index.d.ts +40 -28
- package/dist/kind/index.d.ts.map +1 -1
- package/dist/kind/index.js +41 -13
- package/dist/lower/index.d.ts +6 -1
- package/dist/lower/index.d.ts.map +1 -1
- package/dist/lower/index.js +462 -46
- package/dist/message/index.d.ts +64 -10
- package/dist/message/index.d.ts.map +1 -1
- package/dist/message/index.js +155 -17
- package/dist/optimize/algebraic.d.ts +54 -0
- package/dist/optimize/algebraic.d.ts.map +1 -0
- package/dist/optimize/algebraic.js +314 -0
- package/dist/optimize/compact.d.ts +8 -1
- package/dist/optimize/compact.d.ts.map +1 -1
- package/dist/optimize/compact.js +13 -2
- package/dist/optimize/domain.d.ts +16 -0
- package/dist/optimize/domain.d.ts.map +1 -0
- package/dist/optimize/domain.js +619 -0
- package/dist/optimize/fold-boolean.d.ts +17 -2
- package/dist/optimize/fold-boolean.d.ts.map +1 -1
- package/dist/optimize/fold-boolean.js +59 -14
- package/dist/optimize/fold-common.d.ts +43 -8
- package/dist/optimize/fold-common.d.ts.map +1 -1
- package/dist/optimize/fold-common.js +37 -6
- package/dist/optimize/fold-constraints.d.ts +33 -0
- package/dist/optimize/fold-constraints.d.ts.map +1 -0
- package/dist/optimize/fold-constraints.js +484 -0
- package/dist/optimize/fold-scalar.d.ts +98 -13
- package/dist/optimize/fold-scalar.d.ts.map +1 -1
- package/dist/optimize/fold-scalar.js +98 -13
- package/dist/optimize/fold.d.ts +8 -1
- package/dist/optimize/fold.d.ts.map +1 -1
- package/dist/optimize/fold.js +22 -2
- package/dist/optimize/index.d.ts +9 -1
- package/dist/optimize/index.d.ts.map +1 -1
- package/dist/optimize/index.js +18 -3
- package/dist/optimize/map-node.d.ts +3 -1
- package/dist/optimize/map-node.d.ts.map +1 -1
- package/dist/optimize/map-node.js +48 -3
- package/dist/optimize/peephole.d.ts +16 -0
- package/dist/optimize/peephole.d.ts.map +1 -0
- package/dist/optimize/peephole.js +254 -0
- package/dist/optimize/remap.d.ts +2 -0
- package/dist/optimize/remap.d.ts.map +1 -1
- package/dist/optimize/remap.js +2 -0
- package/dist/optimize/rewrite.d.ts +13 -8
- package/dist/optimize/rewrite.d.ts.map +1 -1
- package/dist/optimize/rewrite.js +13 -8
- package/dist/plan/cache.d.ts +9 -3
- package/dist/plan/cache.d.ts.map +1 -1
- package/dist/plan/cache.js +34 -6
- package/dist/plan/index.d.ts +2 -0
- package/dist/plan/index.d.ts.map +1 -1
- package/dist/plan/index.js +2 -0
- package/dist/plan/predicate.d.ts +2 -0
- package/dist/plan/predicate.d.ts.map +1 -1
- package/dist/plan/predicate.js +298 -29
- package/dist/plan/schema-predicate.d.ts +6 -0
- package/dist/plan/schema-predicate.d.ts.map +1 -1
- package/dist/plan/schema-predicate.js +382 -19
- package/dist/plan/types.d.ts +2 -0
- package/dist/plan/types.d.ts.map +1 -1
- package/dist/plan/types.js +2 -0
- package/dist/result/index.d.ts +19 -5
- package/dist/result/index.d.ts.map +1 -1
- package/dist/result/index.js +10 -2
- package/dist/schema/common.d.ts +69 -6
- package/dist/schema/common.d.ts.map +1 -1
- package/dist/schema/common.js +104 -10
- package/dist/schema/freeze.d.ts +4 -0
- package/dist/schema/freeze.d.ts.map +1 -1
- package/dist/schema/freeze.js +40 -0
- package/dist/schema/index.d.ts +5 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +4 -1
- package/dist/schema/lazy.d.ts +4 -0
- package/dist/schema/lazy.d.ts.map +1 -1
- package/dist/schema/lazy.js +4 -0
- package/dist/schema/literal.d.ts +7 -1
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +7 -1
- package/dist/schema/types.d.ts +109 -100
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +13 -2
- package/dist/schema/undefined.d.ts +17 -0
- package/dist/schema/undefined.d.ts.map +1 -0
- package/dist/schema/undefined.js +77 -0
- package/dist/schema/validate.d.ts +8 -1
- package/dist/schema/validate.d.ts.map +1 -1
- package/dist/schema/validate.js +255 -57
- package/docs/api.md +128 -8
- package/docs/assets/benchmark-headline.svg +163 -0
- package/docs/engine-notes.md +62 -15
- package/docs/index.html +1340 -702
- package/docs/ko/api.md +375 -0
- package/docs/ko/engine-notes.md +156 -0
- package/docs/ko/readme.md +378 -0
- package/package.json +66 -65
package/dist/lower/index.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { NumberCheckTag,
|
|
1
|
+
import { NumberCheckTag, PresenceTag, SchemaTag, StringCheckTag } from "../kind/index.js";
|
|
2
2
|
import { GraphBuilder } from "../ir/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { optimizeGraph } from "../optimize/index.js";
|
|
4
|
+
import { EMAIL_PATTERN, IPV4_PATTERN, IPV6_PATTERN, ISO_DATETIME_PATTERN, ISO_DATE_PATTERN, ULID_PATTERN, URL_PATTERN, UUID_PATTERN } from "../schema/index.js";
|
|
4
5
|
/**
|
|
5
|
-
* @brief
|
|
6
|
+
* @brief Convert one schema root into a Sea-of-Nodes predicate graph.
|
|
7
|
+
* @details The graph always starts with a single input parameter and ends in a
|
|
8
|
+
* boolean return node. Keeping that calling convention uniform lets optimizer,
|
|
9
|
+
* interpreter, compiler, and AOT code consume the same IR shape.
|
|
10
|
+
* @param schema Root schema to lower into predicate IR.
|
|
11
|
+
* @returns Graph with one parameter and one return node.
|
|
6
12
|
*/
|
|
7
13
|
export function lowerSchema(schema) {
|
|
8
14
|
const builder = new GraphBuilder();
|
|
@@ -13,7 +19,14 @@ export function lowerSchema(schema) {
|
|
|
13
19
|
return builder.finish(entry, ret);
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
|
-
* @brief
|
|
22
|
+
* @brief Lower one schema node into a boolean-producing IR node.
|
|
23
|
+
* @details Static schemas become explicit graph operations so later passes can
|
|
24
|
+
* fold, reorder, or specialize them. Dynamic schemas stay behind SchemaCheck
|
|
25
|
+
* nodes because their semantics require runtime callbacks or lazy resolution.
|
|
26
|
+
* @param builder Graph builder owning the current graph.
|
|
27
|
+
* @param schema Schema node to lower.
|
|
28
|
+
* @param value Node id that produces the candidate value.
|
|
29
|
+
* @returns Node id for the boolean predicate result.
|
|
17
30
|
*/
|
|
18
31
|
function lowerPredicate(builder, schema, value) {
|
|
19
32
|
switch (schema.tag) {
|
|
@@ -25,6 +38,8 @@ function lowerPredicate(builder, schema, value) {
|
|
|
25
38
|
return lowerString(builder, schema, value);
|
|
26
39
|
case SchemaTag.Number:
|
|
27
40
|
return lowerNumber(builder, schema, value);
|
|
41
|
+
case SchemaTag.Date:
|
|
42
|
+
return builder.schemaCheck(value, schema);
|
|
28
43
|
case SchemaTag.BigInt:
|
|
29
44
|
return builder.isBigInt(value);
|
|
30
45
|
case SchemaTag.Symbol:
|
|
@@ -34,20 +49,33 @@ function lowerPredicate(builder, schema, value) {
|
|
|
34
49
|
case SchemaTag.Literal:
|
|
35
50
|
return builder.equals(value, builder.constant(schema.value));
|
|
36
51
|
case SchemaTag.Array:
|
|
52
|
+
/*
|
|
53
|
+
* Container checks stay as explicit siblings of iteration nodes. The
|
|
54
|
+
* domain pass can later remove redundant guards when iteration already
|
|
55
|
+
* proves the same container type.
|
|
56
|
+
*/
|
|
37
57
|
return builder.and([
|
|
38
58
|
builder.isArray(value),
|
|
39
|
-
builder.arrayEvery(value, schema.item)
|
|
59
|
+
builder.arrayEvery(value, schema.item, schema.checks, lowerChildGraph(schema.item))
|
|
40
60
|
]);
|
|
41
61
|
case SchemaTag.Tuple:
|
|
62
|
+
if (schema.rest !== undefined) {
|
|
63
|
+
return builder.schemaCheck(value, schema);
|
|
64
|
+
}
|
|
42
65
|
return builder.and([
|
|
43
66
|
builder.isArray(value),
|
|
44
|
-
builder.tupleItems(value, schema.items)
|
|
67
|
+
builder.tupleItems(value, schema.items, lowerChildGraphs(schema.items))
|
|
45
68
|
]);
|
|
46
69
|
case SchemaTag.Record:
|
|
47
70
|
return builder.and([
|
|
48
71
|
builder.isObject(value),
|
|
49
|
-
builder.recordEvery(value, schema.value)
|
|
72
|
+
builder.recordEvery(value, schema.value, lowerChildGraph(schema.value))
|
|
50
73
|
]);
|
|
74
|
+
case SchemaTag.Map:
|
|
75
|
+
case SchemaTag.Set:
|
|
76
|
+
case SchemaTag.InstanceOf:
|
|
77
|
+
case SchemaTag.Property:
|
|
78
|
+
return builder.schemaCheck(value, schema);
|
|
51
79
|
case SchemaTag.Object:
|
|
52
80
|
return lowerObject(builder, schema, value);
|
|
53
81
|
case SchemaTag.Union:
|
|
@@ -74,15 +102,31 @@ function lowerPredicate(builder, schema, value) {
|
|
|
74
102
|
return lowerPredicate(builder, schema.inner, value);
|
|
75
103
|
case SchemaTag.Lazy:
|
|
76
104
|
case SchemaTag.Refine:
|
|
105
|
+
/*
|
|
106
|
+
* Lazy resolution and user predicates are represented as opaque schema
|
|
107
|
+
* checks. Lowering keeps the graph pure and lets runtime evaluation
|
|
108
|
+
* decide those dynamic cases.
|
|
109
|
+
*/
|
|
77
110
|
return builder.schemaCheck(value, schema);
|
|
78
111
|
}
|
|
79
112
|
}
|
|
80
113
|
/**
|
|
81
|
-
* @brief
|
|
114
|
+
* @brief Lower a string schema into independent scalar predicate nodes.
|
|
115
|
+
* @details The base string check and each constraint remain separate in the IR
|
|
116
|
+
* so algebraic and constraint passes can remove redundant bounds without
|
|
117
|
+
* re-parsing the source schema.
|
|
118
|
+
* @param builder Graph builder owning the current graph.
|
|
119
|
+
* @param schema String schema with scalar checks.
|
|
120
|
+
* @param value Node id that produces the candidate value.
|
|
121
|
+
* @returns Node id for the combined string predicate.
|
|
82
122
|
*/
|
|
83
123
|
function lowerString(builder, schema, value) {
|
|
84
124
|
const tests = [builder.isString(value)];
|
|
85
125
|
const checks = schema.checks;
|
|
126
|
+
/*
|
|
127
|
+
* String constraints are represented as independent nodes. Later algebraic
|
|
128
|
+
* and domain passes can fold impossible or redundant checks.
|
|
129
|
+
*/
|
|
86
130
|
for (let index = 0; index < checks.length; index += 1) {
|
|
87
131
|
const check = checks[index];
|
|
88
132
|
if (check === undefined) {
|
|
@@ -101,12 +145,40 @@ function lowerString(builder, schema, value) {
|
|
|
101
145
|
case StringCheckTag.Uuid:
|
|
102
146
|
tests.push(builder.regex(value, UUID_PATTERN, "uuid"));
|
|
103
147
|
break;
|
|
148
|
+
case StringCheckTag.Email:
|
|
149
|
+
tests.push(builder.regex(value, EMAIL_PATTERN, "email"));
|
|
150
|
+
break;
|
|
151
|
+
case StringCheckTag.Url:
|
|
152
|
+
tests.push(builder.regex(value, URL_PATTERN, "url"));
|
|
153
|
+
break;
|
|
154
|
+
case StringCheckTag.IsoDate:
|
|
155
|
+
tests.push(builder.regex(value, ISO_DATE_PATTERN, "iso_date"));
|
|
156
|
+
break;
|
|
157
|
+
case StringCheckTag.IsoDateTime:
|
|
158
|
+
tests.push(builder.regex(value, ISO_DATETIME_PATTERN, "iso_datetime"));
|
|
159
|
+
break;
|
|
160
|
+
case StringCheckTag.Ulid:
|
|
161
|
+
tests.push(builder.regex(value, ULID_PATTERN, "ulid"));
|
|
162
|
+
break;
|
|
163
|
+
case StringCheckTag.Ipv4:
|
|
164
|
+
tests.push(builder.regex(value, IPV4_PATTERN, "ipv4"));
|
|
165
|
+
break;
|
|
166
|
+
case StringCheckTag.Ipv6:
|
|
167
|
+
tests.push(builder.regex(value, IPV6_PATTERN, "ipv6"));
|
|
168
|
+
break;
|
|
104
169
|
}
|
|
105
170
|
}
|
|
106
171
|
return builder.and(tests);
|
|
107
172
|
}
|
|
108
173
|
/**
|
|
109
|
-
* @brief
|
|
174
|
+
* @brief Lower a number schema into numeric predicate nodes.
|
|
175
|
+
* @details Bounds are represented as comparisons against Const nodes. That
|
|
176
|
+
* gives constant folding one canonical place to intern literal limits and gives
|
|
177
|
+
* constraint folding clean min/max facts.
|
|
178
|
+
* @param builder Graph builder owning the current graph.
|
|
179
|
+
* @param schema Number schema with scalar checks.
|
|
180
|
+
* @param value Node id that produces the candidate value.
|
|
181
|
+
* @returns Node id for the combined number predicate.
|
|
110
182
|
*/
|
|
111
183
|
function lowerNumber(builder, schema, value) {
|
|
112
184
|
const tests = [builder.isNumber(value)];
|
|
@@ -126,64 +198,303 @@ function lowerNumber(builder, schema, value) {
|
|
|
126
198
|
case NumberCheckTag.Lte:
|
|
127
199
|
tests.push(builder.lte(value, builder.constant(check.value)));
|
|
128
200
|
break;
|
|
201
|
+
case NumberCheckTag.Gt:
|
|
202
|
+
tests.push(builder.not(builder.lte(value, builder.constant(check.value))));
|
|
203
|
+
break;
|
|
204
|
+
case NumberCheckTag.Lt:
|
|
205
|
+
tests.push(builder.not(builder.gte(value, builder.constant(check.value))));
|
|
206
|
+
break;
|
|
207
|
+
case NumberCheckTag.MultipleOf:
|
|
208
|
+
tests.push(builder.schemaCheck(value, {
|
|
209
|
+
tag: SchemaTag.Number,
|
|
210
|
+
checks: [check]
|
|
211
|
+
}));
|
|
212
|
+
break;
|
|
129
213
|
}
|
|
130
214
|
}
|
|
131
215
|
return builder.and(tests);
|
|
132
216
|
}
|
|
133
217
|
/**
|
|
134
|
-
* @brief
|
|
218
|
+
* @brief Lower an object schema into one structured shape node.
|
|
219
|
+
* @details Object validation keeps key order, strict-mode metadata, and child
|
|
220
|
+
* graphs together. Codegen can then emit one object-shaped fast path instead of
|
|
221
|
+
* rediscovering shape facts from generic boolean nodes.
|
|
222
|
+
* @param builder Graph builder owning the current graph.
|
|
223
|
+
* @param schema Object schema with shape metadata.
|
|
224
|
+
* @param value Node id that produces the candidate value.
|
|
225
|
+
* @returns Node id for the object-shape predicate.
|
|
135
226
|
*/
|
|
136
227
|
function lowerObject(builder, schema, value) {
|
|
137
|
-
|
|
138
|
-
|
|
228
|
+
return builder.objectShape(value, lowerObjectShapeEntries(schema.entries), schema.keys, schema.mode, schema.catchall, schema.catchall === undefined ? undefined : lowerChildGraph(schema.catchall));
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* @brief Lower and optimize a child schema before embedding it in a parent node.
|
|
232
|
+
* @details Composite nodes store child graphs by value. Optimizing them at
|
|
233
|
+
* construction time keeps array, tuple, record, object, and union codegen from
|
|
234
|
+
* carrying avoidable dead nodes in every embedded child.
|
|
235
|
+
* @param schema Child schema to lower.
|
|
236
|
+
* @returns Optimized child graph suitable for dispatch or iteration nodes.
|
|
237
|
+
*/
|
|
238
|
+
function lowerChildGraph(schema) {
|
|
239
|
+
/*
|
|
240
|
+
* Child graphs are optimized immediately because they are embedded into
|
|
241
|
+
* dispatch and iteration nodes. Smaller child graphs make later codegen
|
|
242
|
+
* and graph introspection cheaper.
|
|
243
|
+
*/
|
|
244
|
+
return optimizeGraph(lowerSchema(schema));
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* @brief Lower a schema vector into index-aligned child graphs.
|
|
248
|
+
* @details Undefined holes are preserved so union and tuple branch indexes
|
|
249
|
+
* remain stable for diagnostics and generated dispatch tables.
|
|
250
|
+
* @param schemas Closed schema list.
|
|
251
|
+
* @returns Child graph list preserving source indexes.
|
|
252
|
+
*/
|
|
253
|
+
function lowerChildGraphs(schemas) {
|
|
254
|
+
const graphs = new Array(schemas.length);
|
|
255
|
+
for (let index = 0; index < schemas.length; index += 1) {
|
|
256
|
+
const schema = schemas[index];
|
|
257
|
+
if (schema !== undefined) {
|
|
258
|
+
graphs[index] = lowerChildGraph(schema);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return graphs;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* @brief Lower object entries into IR entries with optimized child graphs.
|
|
265
|
+
* @details The IR keeps the original schema beside each child graph so
|
|
266
|
+
* diagnostics and dynamic fallback paths can still recover schema-level detail.
|
|
267
|
+
* @param entries Object schema entries.
|
|
268
|
+
* @returns IR object-shape entries with optimized child graphs.
|
|
269
|
+
*/
|
|
270
|
+
function lowerObjectShapeEntries(entries) {
|
|
271
|
+
const lowered = new Array(entries.length);
|
|
139
272
|
for (let index = 0; index < entries.length; index += 1) {
|
|
140
273
|
const entry = entries[index];
|
|
141
|
-
if (entry
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const hasKey = builder.hasOwn(value, entry.key);
|
|
149
|
-
tests.push(builder.or([
|
|
150
|
-
builder.not(hasKey),
|
|
151
|
-
builder.and([hasData, propTest])
|
|
152
|
-
]));
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
tests.push(hasData);
|
|
156
|
-
tests.push(propTest);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (schema.mode === ObjectModeTag.Strict) {
|
|
160
|
-
const keys = new Array(entries.length);
|
|
161
|
-
for (let index = 0; index < entries.length; index += 1) {
|
|
162
|
-
const entry = entries[index];
|
|
163
|
-
if (entry !== undefined) {
|
|
164
|
-
keys[index] = entry.key;
|
|
165
|
-
}
|
|
274
|
+
if (entry !== undefined) {
|
|
275
|
+
lowered[index] = {
|
|
276
|
+
key: entry.key,
|
|
277
|
+
schema: entry.schema,
|
|
278
|
+
graph: lowerChildGraph(entry.schema),
|
|
279
|
+
presence: entry.presence
|
|
280
|
+
};
|
|
166
281
|
}
|
|
167
|
-
tests.push(builder.strictKeys(value, keys));
|
|
168
282
|
}
|
|
169
|
-
return
|
|
283
|
+
return lowered;
|
|
170
284
|
}
|
|
171
285
|
/**
|
|
172
|
-
* @brief
|
|
286
|
+
* @brief Select the most specific IR shape for a union schema.
|
|
287
|
+
* @details The lowering order is intentional: literal object discriminants are
|
|
288
|
+
* most precise, primitive-only masks are cheapest for scalar unions, and the
|
|
289
|
+
* general dispatch node preserves behavior for mixed or opaque branches.
|
|
290
|
+
* @param builder Graph builder owning the current graph.
|
|
291
|
+
* @param options Union option schemas.
|
|
292
|
+
* @param value Node id that produces the candidate value.
|
|
293
|
+
* @returns Node id for the selected union lowering strategy.
|
|
173
294
|
*/
|
|
174
295
|
function lowerUnion(builder, options, value) {
|
|
175
|
-
const
|
|
296
|
+
const discriminant = inferObjectUnionDiscriminant(options);
|
|
297
|
+
if (discriminant !== undefined) {
|
|
298
|
+
/*
|
|
299
|
+
* Object unions with a common required string literal key can dispatch by
|
|
300
|
+
* one property read instead of probing every branch.
|
|
301
|
+
*/
|
|
302
|
+
return builder.discriminantDispatch(value, discriminant.key, discriminant.literals, options, lowerChildGraphs(options));
|
|
303
|
+
}
|
|
304
|
+
if (isPrimitiveUnionOptions(options)) {
|
|
305
|
+
/*
|
|
306
|
+
* Primitive-only unions lower to a compact mask dispatch so codegen can
|
|
307
|
+
* group arms by typeof result.
|
|
308
|
+
*/
|
|
309
|
+
return builder.primitiveUnion(value, lowerChildGraphs(options), lowerUnionMasks(options));
|
|
310
|
+
}
|
|
311
|
+
return builder.unionDispatch(value, options, lowerChildGraphs(options), lowerUnionMasks(options));
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* @brief Bit positions used to summarize possible union root domains.
|
|
315
|
+
* @details Masks let lowering and codegen skip branches whose root JavaScript
|
|
316
|
+
* kind is impossible for the candidate value.
|
|
317
|
+
*/
|
|
318
|
+
const UnionMask = {
|
|
319
|
+
None: 0,
|
|
320
|
+
String: 1 << 0,
|
|
321
|
+
Number: 1 << 1,
|
|
322
|
+
Boolean: 1 << 2,
|
|
323
|
+
BigInt: 1 << 3,
|
|
324
|
+
Symbol: 1 << 4,
|
|
325
|
+
Undefined: 1 << 5,
|
|
326
|
+
Null: 1 << 6,
|
|
327
|
+
Array: 1 << 7,
|
|
328
|
+
Object: 1 << 8,
|
|
329
|
+
Function: 1 << 9,
|
|
330
|
+
Any: (1 << 10) - 1
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* @brief Mask containing only domains accepted by primitive-union dispatch.
|
|
334
|
+
* @details Object and array domains are excluded because they need descriptor,
|
|
335
|
+
* key, or child graph handling that primitive dispatch deliberately avoids.
|
|
336
|
+
*/
|
|
337
|
+
const PrimitiveUnionMask = UnionMask.String |
|
|
338
|
+
UnionMask.Number |
|
|
339
|
+
UnionMask.Boolean |
|
|
340
|
+
UnionMask.BigInt |
|
|
341
|
+
UnionMask.Symbol |
|
|
342
|
+
UnionMask.Undefined |
|
|
343
|
+
UnionMask.Null;
|
|
344
|
+
/**
|
|
345
|
+
* @brief Decide whether a union can use primitive-domain dispatch.
|
|
346
|
+
* @details The generated graph can replace ordered branch probing with a small
|
|
347
|
+
* domain mask only when every reachable option is primitive-shaped. Empty
|
|
348
|
+
* unions are rejected here so the caller does not emit a vacuous dispatcher.
|
|
349
|
+
* @param options Union option schemas in public declaration order.
|
|
350
|
+
* @returns True when every reachable option has a primitive-only mask.
|
|
351
|
+
*/
|
|
352
|
+
function isPrimitiveUnionOptions(options) {
|
|
353
|
+
let sawReachable = false;
|
|
176
354
|
for (let index = 0; index < options.length; index += 1) {
|
|
177
355
|
const option = options[index];
|
|
178
|
-
|
|
356
|
+
const mask = option === undefined ? UnionMask.None : schemaUnionMask(option);
|
|
357
|
+
if (mask === UnionMask.None) {
|
|
179
358
|
continue;
|
|
180
359
|
}
|
|
181
|
-
|
|
360
|
+
if ((mask & ~PrimitiveUnionMask) !== 0) {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
sawReachable = true;
|
|
364
|
+
}
|
|
365
|
+
return sawReachable;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* @brief Compute root-domain masks for every union option.
|
|
369
|
+
* @details The returned array is index-aligned with the source options so
|
|
370
|
+
* generated dispatch can keep branch order while cheaply rejecting impossible
|
|
371
|
+
* arms by runtime kind.
|
|
372
|
+
* @param options Union option schemas.
|
|
373
|
+
* @returns Primitive-domain mask per union option.
|
|
374
|
+
*/
|
|
375
|
+
function lowerUnionMasks(options) {
|
|
376
|
+
const masks = new Array(options.length);
|
|
377
|
+
for (let index = 0; index < options.length; index += 1) {
|
|
378
|
+
const option = options[index];
|
|
379
|
+
masks[index] = option === undefined ? UnionMask.None : schemaUnionMask(option);
|
|
380
|
+
}
|
|
381
|
+
return masks;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* @brief Approximate the possible root runtime domains for a schema.
|
|
385
|
+
* @details The mask is intentionally conservative. Static scalar and container
|
|
386
|
+
* schemas narrow to precise domains, while lazy and refinement schemas widen to
|
|
387
|
+
* the full mask because their behavior is not known during lowering.
|
|
388
|
+
* @param schema Schema whose possible runtime domain is needed.
|
|
389
|
+
* @returns Bit mask describing the schema's possible runtime domains.
|
|
390
|
+
*/
|
|
391
|
+
function schemaUnionMask(schema) {
|
|
392
|
+
switch (schema.tag) {
|
|
393
|
+
case SchemaTag.Unknown:
|
|
394
|
+
return UnionMask.Any;
|
|
395
|
+
case SchemaTag.Never:
|
|
396
|
+
return UnionMask.None;
|
|
397
|
+
case SchemaTag.String:
|
|
398
|
+
return UnionMask.String;
|
|
399
|
+
case SchemaTag.Number:
|
|
400
|
+
return UnionMask.Number;
|
|
401
|
+
case SchemaTag.Date:
|
|
402
|
+
return UnionMask.Object;
|
|
403
|
+
case SchemaTag.BigInt:
|
|
404
|
+
return UnionMask.BigInt;
|
|
405
|
+
case SchemaTag.Symbol:
|
|
406
|
+
return UnionMask.Symbol;
|
|
407
|
+
case SchemaTag.Boolean:
|
|
408
|
+
return UnionMask.Boolean;
|
|
409
|
+
case SchemaTag.Literal:
|
|
410
|
+
return literalUnionMask(schema.value);
|
|
411
|
+
case SchemaTag.Array:
|
|
412
|
+
case SchemaTag.Tuple:
|
|
413
|
+
return UnionMask.Array;
|
|
414
|
+
case SchemaTag.Object:
|
|
415
|
+
case SchemaTag.Record:
|
|
416
|
+
case SchemaTag.Map:
|
|
417
|
+
case SchemaTag.Set:
|
|
418
|
+
case SchemaTag.InstanceOf:
|
|
419
|
+
case SchemaTag.Property:
|
|
420
|
+
case SchemaTag.DiscriminatedUnion:
|
|
421
|
+
return UnionMask.Object;
|
|
422
|
+
case SchemaTag.Optional:
|
|
423
|
+
case SchemaTag.Undefinedable:
|
|
424
|
+
return UnionMask.Undefined | schemaUnionMask(schema.inner);
|
|
425
|
+
case SchemaTag.Nullable:
|
|
426
|
+
return UnionMask.Null | schemaUnionMask(schema.inner);
|
|
427
|
+
case SchemaTag.Brand:
|
|
428
|
+
return schemaUnionMask(schema.inner);
|
|
429
|
+
case SchemaTag.Intersection:
|
|
430
|
+
/*
|
|
431
|
+
* Intersections accept values accepted by both sides, so their
|
|
432
|
+
* possible runtime domain is the bitwise intersection of both masks.
|
|
433
|
+
*/
|
|
434
|
+
return schemaUnionMask(schema.left) & schemaUnionMask(schema.right);
|
|
435
|
+
case SchemaTag.Union:
|
|
436
|
+
return unionOptionsMask(schema.options);
|
|
437
|
+
case SchemaTag.Lazy:
|
|
438
|
+
case SchemaTag.Refine:
|
|
439
|
+
return UnionMask.Any;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* @brief Merge root-domain masks for a union option vector.
|
|
444
|
+
* @details This summary feeds recursive mask analysis for nested unions without
|
|
445
|
+
* expanding branch graphs during a simple domain query.
|
|
446
|
+
* @param options Union option schemas.
|
|
447
|
+
* @returns Bitwise union of all option masks.
|
|
448
|
+
*/
|
|
449
|
+
function unionOptionsMask(options) {
|
|
450
|
+
let mask = UnionMask.None;
|
|
451
|
+
for (let index = 0; index < options.length; index += 1) {
|
|
452
|
+
const option = options[index];
|
|
453
|
+
if (option !== undefined) {
|
|
454
|
+
mask |= schemaUnionMask(option);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return mask;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* @brief Map a literal value to the matching root-domain bit.
|
|
461
|
+
* @details Literal schemas participate in union dispatch by their JavaScript
|
|
462
|
+
* runtime kind. Object literals are not supported by TypeSea literal schemas and
|
|
463
|
+
* therefore fall back to the empty mask.
|
|
464
|
+
* @param value Literal value from a literal schema.
|
|
465
|
+
* @returns Domain bit for the literal's runtime type.
|
|
466
|
+
*/
|
|
467
|
+
function literalUnionMask(value) {
|
|
468
|
+
if (value === null) {
|
|
469
|
+
return UnionMask.Null;
|
|
470
|
+
}
|
|
471
|
+
switch (typeof value) {
|
|
472
|
+
case "string":
|
|
473
|
+
return UnionMask.String;
|
|
474
|
+
case "number":
|
|
475
|
+
return UnionMask.Number;
|
|
476
|
+
case "boolean":
|
|
477
|
+
return UnionMask.Boolean;
|
|
478
|
+
case "bigint":
|
|
479
|
+
return UnionMask.BigInt;
|
|
480
|
+
case "symbol":
|
|
481
|
+
return UnionMask.Symbol;
|
|
482
|
+
case "undefined":
|
|
483
|
+
return UnionMask.Undefined;
|
|
484
|
+
default:
|
|
485
|
+
return UnionMask.None;
|
|
182
486
|
}
|
|
183
|
-
return builder.or(tests);
|
|
184
487
|
}
|
|
185
488
|
/**
|
|
186
|
-
* @brief
|
|
489
|
+
* @brief Lower an explicit discriminated union into table dispatch IR.
|
|
490
|
+
* @details Builder validation already proved that every branch requires its
|
|
491
|
+
* literal tag. Lowering can therefore store the literal table directly and let
|
|
492
|
+
* codegen emit a single property read plus branch selection.
|
|
493
|
+
* @param builder Graph builder owning the current graph.
|
|
494
|
+
* @param key Discriminant property name.
|
|
495
|
+
* @param cases Closed discriminated union cases.
|
|
496
|
+
* @param value Node id that produces the candidate value.
|
|
497
|
+
* @returns Node id for discriminant dispatch.
|
|
187
498
|
*/
|
|
188
499
|
function lowerDiscriminatedUnion(builder, key, cases, value) {
|
|
189
500
|
const literals = new Array(cases.length);
|
|
@@ -195,5 +506,110 @@ function lowerDiscriminatedUnion(builder, key, cases, value) {
|
|
|
195
506
|
schemas[index] = unionCase.schema;
|
|
196
507
|
}
|
|
197
508
|
}
|
|
198
|
-
return builder.discriminantDispatch(value, key, literals, schemas);
|
|
509
|
+
return builder.discriminantDispatch(value, key, literals, schemas, lowerChildGraphs(schemas));
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* @brief Search a plain object union for an implicit discriminant key.
|
|
513
|
+
* @details Only required string literal fields from the first branch are
|
|
514
|
+
* candidates. Every other branch must prove the same key with a unique literal
|
|
515
|
+
* before the union can use table dispatch.
|
|
516
|
+
* @param options Union option schemas.
|
|
517
|
+
* @returns Shared discriminant key and literals, or undefined when not provable.
|
|
518
|
+
*/
|
|
519
|
+
function inferObjectUnionDiscriminant(options) {
|
|
520
|
+
if (options.length < 2) {
|
|
521
|
+
return undefined;
|
|
522
|
+
}
|
|
523
|
+
const first = options[0];
|
|
524
|
+
if (first?.tag !== SchemaTag.Object) {
|
|
525
|
+
return undefined;
|
|
526
|
+
}
|
|
527
|
+
const entries = first.entries;
|
|
528
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 1) {
|
|
529
|
+
const entry = entries[entryIndex];
|
|
530
|
+
if (entry === undefined) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
const firstLiteral = readRequiredStringLiteral(entry);
|
|
534
|
+
if (firstLiteral === undefined) {
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
/*
|
|
538
|
+
* Only keys already required by the first option are candidates. Every
|
|
539
|
+
* other option must carry a unique required string literal for that key.
|
|
540
|
+
*/
|
|
541
|
+
const literals = readObjectUnionDiscriminantLiterals(options, entry.key);
|
|
542
|
+
if (literals !== undefined) {
|
|
543
|
+
return {
|
|
544
|
+
key: entry.key,
|
|
545
|
+
literals
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return undefined;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* @brief Build the literal dispatch table for an inferred object union.
|
|
553
|
+
* @details The table is usable only when each branch owns the candidate key,
|
|
554
|
+
* requires it, and binds it to a unique string literal. Repeated or missing
|
|
555
|
+
* literals make branch selection ambiguous, so this helper returns undefined
|
|
556
|
+
* and the lowerer keeps the general union path.
|
|
557
|
+
* @param options Union option schemas in branch order.
|
|
558
|
+
* @param key Candidate discriminant key shared by the branches.
|
|
559
|
+
* @returns Literal table when every option has a unique required string literal.
|
|
560
|
+
*/
|
|
561
|
+
function readObjectUnionDiscriminantLiterals(options, key) {
|
|
562
|
+
const literals = new Array(options.length);
|
|
563
|
+
const seen = new Set();
|
|
564
|
+
for (let index = 0; index < options.length; index += 1) {
|
|
565
|
+
const option = options[index];
|
|
566
|
+
if (option?.tag !== SchemaTag.Object) {
|
|
567
|
+
return undefined;
|
|
568
|
+
}
|
|
569
|
+
const literal = readObjectDiscriminantLiteral(option, key);
|
|
570
|
+
if (literal === undefined || seen.has(literal)) {
|
|
571
|
+
/*
|
|
572
|
+
* Missing or repeated literals make direct dispatch ambiguous, so the
|
|
573
|
+
* union must fall back to general branch probing.
|
|
574
|
+
*/
|
|
575
|
+
return undefined;
|
|
576
|
+
}
|
|
577
|
+
seen.add(literal);
|
|
578
|
+
literals[index] = literal;
|
|
579
|
+
}
|
|
580
|
+
return literals;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* @brief Locate the required string literal carried by one object branch.
|
|
584
|
+
* @details Optional and wrapped non-literal fields are rejected because direct
|
|
585
|
+
* dispatch must prove that accepting the branch also proves the tag value.
|
|
586
|
+
* @param schema Object schema to inspect.
|
|
587
|
+
* @param key Candidate discriminant key.
|
|
588
|
+
* @returns Required string literal value for the key, or undefined.
|
|
589
|
+
*/
|
|
590
|
+
function readObjectDiscriminantLiteral(schema, key) {
|
|
591
|
+
const entries = schema.entries;
|
|
592
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
593
|
+
const entry = entries[index];
|
|
594
|
+
if (entry?.key === key) {
|
|
595
|
+
return readRequiredStringLiteral(entry);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return undefined;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* @brief Prove that an object entry is a required string literal tag.
|
|
602
|
+
* @details The discriminant optimizer deliberately refuses optional,
|
|
603
|
+
* undefinedable, or refined tags. Those forms may still validate correctly, but
|
|
604
|
+
* they do not provide a branch-selection proof before child validation runs.
|
|
605
|
+
* @param entry Object entry to inspect.
|
|
606
|
+
* @returns Literal string when the entry is required and exactly string-literal.
|
|
607
|
+
*/
|
|
608
|
+
function readRequiredStringLiteral(entry) {
|
|
609
|
+
if (entry.presence !== PresenceTag.Required ||
|
|
610
|
+
entry.schema.tag !== SchemaTag.Literal ||
|
|
611
|
+
typeof entry.schema.value !== "string") {
|
|
612
|
+
return undefined;
|
|
613
|
+
}
|
|
614
|
+
return entry.schema.value;
|
|
199
615
|
}
|