typesea 0.1.0 → 0.2.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 +67 -6
- package/README.md +98 -17
- 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 +18 -2
- package/dist/aot/index.d.ts.map +1 -1
- package/dist/aot/index.js +93 -14
- 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 +37 -6
- package/dist/builders/composite.d.ts.map +1 -1
- package/dist/builders/composite.js +84 -10
- package/dist/builders/index.d.ts +2 -0
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +2 -0
- package/dist/builders/modifier.d.ts +30 -5
- package/dist/builders/modifier.d.ts.map +1 -1
- package/dist/builders/modifier.js +38 -5
- package/dist/builders/object/guard.d.ts +18 -22
- package/dist/builders/object/guard.d.ts.map +1 -1
- package/dist/builders/object/guard.js +26 -26
- package/dist/builders/object/index.d.ts +2 -0
- package/dist/builders/object/index.d.ts.map +1 -1
- package/dist/builders/object/index.js +2 -0
- package/dist/builders/object/schema.d.ts +55 -9
- package/dist/builders/object/schema.d.ts.map +1 -1
- package/dist/builders/object/schema.js +92 -15
- package/dist/builders/object/types.d.ts +5 -31
- package/dist/builders/object/types.d.ts.map +1 -1
- package/dist/builders/object/types.js +2 -0
- package/dist/builders/scalar.d.ts +29 -8
- package/dist/builders/scalar.d.ts.map +1 -1
- package/dist/builders/scalar.js +33 -8
- package/dist/builders/table.d.ts +4 -0
- package/dist/builders/table.d.ts.map +1 -1
- package/dist/builders/table.js +4 -0
- package/dist/builders/types.d.ts +14 -4
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/builders/types.js +2 -0
- package/dist/compile/check-composite.d.ts +22 -1
- package/dist/compile/check-composite.d.ts.map +1 -1
- package/dist/compile/check-composite.js +564 -24
- package/dist/compile/check-scalar.d.ts +78 -0
- package/dist/compile/check-scalar.d.ts.map +1 -1
- package/dist/compile/check-scalar.js +432 -1
- package/dist/compile/check.d.ts +12 -0
- package/dist/compile/check.d.ts.map +1 -1
- package/dist/compile/check.js +37 -0
- package/dist/compile/context.d.ts +47 -9
- package/dist/compile/context.d.ts.map +1 -1
- package/dist/compile/context.js +51 -8
- 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 +1907 -171
- package/dist/compile/guard.d.ts +15 -24
- package/dist/compile/guard.d.ts.map +1 -1
- package/dist/compile/guard.js +158 -74
- 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 +131 -5
- package/dist/compile/runtime.d.ts +80 -12
- package/dist/compile/runtime.d.ts.map +1 -1
- package/dist/compile/runtime.js +25 -6
- package/dist/compile/source.d.ts +10 -2
- package/dist/compile/source.d.ts.map +1 -1
- package/dist/compile/source.js +361 -26
- package/dist/compile/types.d.ts +20 -0
- package/dist/compile/types.d.ts.map +1 -1
- package/dist/compile/types.js +2 -0
- package/dist/decoder/index.d.ts +32 -46
- package/dist/decoder/index.d.ts.map +1 -1
- package/dist/decoder/index.js +102 -38
- package/dist/evaluate/check-composite.d.ts +59 -0
- package/dist/evaluate/check-composite.d.ts.map +1 -1
- package/dist/evaluate/check-composite.js +151 -3
- package/dist/evaluate/check-scalar.d.ts +16 -0
- package/dist/evaluate/check-scalar.d.ts.map +1 -1
- package/dist/evaluate/check-scalar.js +32 -0
- package/dist/evaluate/check.d.ts +7 -0
- package/dist/evaluate/check.d.ts.map +1 -1
- package/dist/evaluate/check.js +43 -0
- 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 +59 -13
- package/dist/evaluate/shared.d.ts.map +1 -1
- package/dist/evaluate/shared.js +66 -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/base.d.ts +79 -29
- package/dist/guard/base.d.ts.map +1 -1
- package/dist/guard/base.js +91 -29
- 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 +2 -0
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +2 -0
- package/dist/guard/number.d.ts +26 -11
- package/dist/guard/number.d.ts.map +1 -1
- package/dist/guard/number.js +30 -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 +62 -9
- package/dist/guard/read.d.ts.map +1 -1
- package/dist/guard/read.js +83 -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 +33 -13
- package/dist/guard/string.d.ts.map +1 -1
- package/dist/guard/string.js +37 -13
- package/dist/guard/types.d.ts +92 -40
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/guard/types.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- 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 +16 -126
- package/dist/ir/builder.d.ts.map +1 -1
- package/dist/ir/builder.js +77 -137
- package/dist/ir/freeze.d.ts +4 -0
- package/dist/ir/freeze.d.ts.map +1 -1
- package/dist/ir/freeze.js +59 -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 +90 -55
- 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 +477 -61
- package/dist/issue/index.d.ts +41 -9
- package/dist/issue/index.d.ts.map +1 -1
- package/dist/issue/index.js +61 -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 +10 -0
- package/dist/json-schema/emit-composite.d.ts.map +1 -1
- package/dist/json-schema/emit-composite.js +15 -1
- 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 +70 -9
- 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 +12 -1
- 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 +38 -15
- package/dist/json-schema/types.d.ts.map +1 -1
- package/dist/json-schema/types.js +2 -0
- package/dist/kind/index.d.ts +15 -28
- package/dist/kind/index.d.ts.map +1 -1
- package/dist/kind/index.js +15 -10
- package/dist/lower/index.d.ts +6 -1
- package/dist/lower/index.d.ts.map +1 -1
- package/dist/lower/index.js +411 -44
- package/dist/message/index.d.ts +46 -10
- package/dist/message/index.d.ts.map +1 -1
- package/dist/message/index.js +88 -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 +615 -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 +45 -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 +21 -5
- 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 +268 -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 +117 -13
- 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 +18 -0
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +3 -0
- 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 +20 -96
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +5 -1
- package/dist/schema/undefined.d.ts +17 -0
- package/dist/schema/undefined.d.ts.map +1 -0
- package/dist/schema/undefined.js +72 -0
- package/dist/schema/validate.d.ts +8 -1
- package/dist/schema/validate.d.ts.map +1 -1
- package/dist/schema/validate.js +146 -55
- package/docs/api.md +57 -0
- package/docs/assets/benchmark-headline.svg +163 -0
- package/docs/engine-notes.md +58 -15
- package/docs/index.html +130 -110
- package/package.json +65 -65
|
@@ -1,30 +1,85 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file compile/check-composite.ts
|
|
3
3
|
* @brief Composite diagnostic validator snippets.
|
|
4
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
5
|
+
* stable across runtime and AOT emission.
|
|
4
6
|
*/
|
|
5
7
|
import { ObjectModeTag, PresenceTag, SchemaTag } from "../kind/index.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
+
import { schemaCanAcceptUndefined } from "../schema/index.js";
|
|
9
|
+
import { pushLiteral, stringRef } from "./context.js";
|
|
10
|
+
import { emitIssue, emitIssueAtSegment, emitIssueAtTwoSegments, emitIssueExprAtSegment } from "./issue.js";
|
|
11
|
+
import { emitLeafCheckAtSegment, emitLeafCheckAtTwoSegments, emitUndefinedLeafCheckAtTwoSegments, emitUndefinedLeafCheckAtSegment } from "./check-scalar.js";
|
|
8
12
|
import { stringLiteral } from "./names.js";
|
|
9
13
|
/**
|
|
10
14
|
* @brief emit array check.
|
|
15
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
16
|
+
* stable across runtime and AOT emission.
|
|
17
|
+
* @param item Schema applied to each logical array slot.
|
|
18
|
+
* @param value Generated expression for the candidate value.
|
|
19
|
+
* @param path Generated expression for the mutable diagnostic path.
|
|
20
|
+
* @param issues Generated expression for the diagnostic buffer.
|
|
21
|
+
* @param context Shared code-generation context.
|
|
22
|
+
* @param emitChild Fallback emitter for non-leaf child validators.
|
|
23
|
+
* @returns JavaScript source for array diagnostics.
|
|
11
24
|
*/
|
|
12
25
|
export function emitArrayCheck(item, value, path, issues, context, emitChild) {
|
|
13
|
-
|
|
26
|
+
if (isUnsafeMode(context)) {
|
|
27
|
+
return emitUnsafeArrayCheck(item, value, path, issues, context, emitChild);
|
|
28
|
+
}
|
|
29
|
+
const itemValue = "av";
|
|
30
|
+
const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, "i", issues, context);
|
|
31
|
+
const missingLeaf = itemLeaf === undefined
|
|
32
|
+
? undefined
|
|
33
|
+
: emitUndefinedLeafCheckAtSegment(item, path, "i", issues, context);
|
|
34
|
+
let missingCheck;
|
|
35
|
+
let itemCheck;
|
|
36
|
+
if (itemLeaf === undefined || missingLeaf === undefined) {
|
|
37
|
+
const itemFunction = emitChild(item, context);
|
|
38
|
+
missingCheck = `${path}.push(i);${itemFunction}(undefined,${path},${issues});${path}.pop();`;
|
|
39
|
+
itemCheck = `${path}.push(i);${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
missingCheck = missingLeaf;
|
|
43
|
+
itemCheck = itemLeaf;
|
|
44
|
+
}
|
|
45
|
+
const presentCheck = itemCheck === ""
|
|
46
|
+
? ""
|
|
47
|
+
: `const ${itemValue}=d.value;${itemCheck}`;
|
|
48
|
+
if (schemaCanAcceptUndefined(item)) {
|
|
49
|
+
/*
|
|
50
|
+
* Generated diagnostics mirror the interpreter: holes are valid only
|
|
51
|
+
* after the item schema admits undefined, while present accessors still
|
|
52
|
+
* produce a data-property issue instead of executing.
|
|
53
|
+
*/
|
|
54
|
+
return [
|
|
55
|
+
`if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_array", "array", `a(${value})`)}return;}`,
|
|
56
|
+
`const xs=Object.getOwnPropertyNames(${value});`,
|
|
57
|
+
"for(let xi=0;xi<xs.length;xi+=1){",
|
|
58
|
+
"const key=xs[xi];",
|
|
59
|
+
`if(!ai(key,${value}.length))continue;`,
|
|
60
|
+
"const i=Number(key);",
|
|
61
|
+
`const d=gp(${value},key);`,
|
|
62
|
+
`if(d!==undefined&&!h.call(d,"value")){${emitIssueAtSegment(issues, path, "i", "expected_array", "data property", stringLiteral("accessor"))}}else if(d!==undefined){${presentCheck}}`,
|
|
63
|
+
"}"
|
|
64
|
+
].join("");
|
|
65
|
+
}
|
|
14
66
|
return [
|
|
15
67
|
`if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_array", "array", `a(${value})`)}return;}`,
|
|
16
68
|
`for(let i=0;i<${value}.length;i+=1){`,
|
|
17
69
|
`const d=gp(${value},i);`,
|
|
18
|
-
|
|
19
|
-
`if(d!==undefined&&!h.call(d,"value")){${emitIssue(issues, path, "expected_array", "data property", stringLiteral("accessor"))}}else{${itemFunction}(d===undefined?undefined:d.value,${path},${issues});}`,
|
|
20
|
-
`${path}.pop();`,
|
|
70
|
+
`if(d===undefined){${missingCheck}}else if(!h.call(d,"value")){${emitIssueAtSegment(issues, path, "i", "expected_array", "data property", stringLiteral("accessor"))}}else{${presentCheck}}`,
|
|
21
71
|
"}"
|
|
22
72
|
].join("");
|
|
23
73
|
}
|
|
24
74
|
/**
|
|
25
75
|
* @brief emit tuple check.
|
|
76
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
77
|
+
* stable across runtime and AOT emission.
|
|
26
78
|
*/
|
|
27
79
|
export function emitTupleCheck(items, value, path, issues, context, emitChild) {
|
|
80
|
+
if (isUnsafeMode(context)) {
|
|
81
|
+
return emitUnsafeTupleCheck(items, value, path, issues, context, emitChild);
|
|
82
|
+
}
|
|
28
83
|
const parts = [
|
|
29
84
|
`if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_tuple", "tuple", `a(${value})`)}return;}`,
|
|
30
85
|
`if(${value}.length!==${String(items.length)}){${emitIssue(issues, path, "expected_tuple_length", `length ${String(items.length)}`, `"length "+String(${value}.length)`)}}`,
|
|
@@ -35,48 +90,392 @@ export function emitTupleCheck(items, value, path, issues, context, emitChild) {
|
|
|
35
90
|
if (item === undefined) {
|
|
36
91
|
continue;
|
|
37
92
|
}
|
|
93
|
+
const indexExpression = String(index);
|
|
94
|
+
const itemValue = `tv${indexExpression}`;
|
|
95
|
+
const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, indexExpression, issues, context);
|
|
96
|
+
const missingLeaf = itemLeaf === undefined
|
|
97
|
+
? undefined
|
|
98
|
+
: emitUndefinedLeafCheckAtSegment(item, path, indexExpression, issues, context);
|
|
99
|
+
let missingCheck;
|
|
100
|
+
let itemCheck;
|
|
101
|
+
if (itemLeaf === undefined || missingLeaf === undefined) {
|
|
102
|
+
const itemFunction = emitChild(item, context);
|
|
103
|
+
missingCheck = `${path}.push(${indexExpression});${itemFunction}(undefined,${path},${issues});${path}.pop();`;
|
|
104
|
+
itemCheck = `${path}.push(${indexExpression});${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
missingCheck = missingLeaf;
|
|
108
|
+
itemCheck = itemLeaf;
|
|
109
|
+
}
|
|
110
|
+
const presentCheck = itemCheck === ""
|
|
111
|
+
? ""
|
|
112
|
+
: `const ${itemValue}=d.value;${itemCheck}`;
|
|
113
|
+
parts.push(`if(${indexExpression}<n){const d=gp(${value},${indexExpression});if(d===undefined){${missingCheck}}else if(!h.call(d,"value")){${emitIssueAtSegment(issues, path, indexExpression, "expected_tuple", "data property", stringLiteral("accessor"))}}else{${presentCheck}}}`);
|
|
114
|
+
}
|
|
115
|
+
return parts.join("");
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* @brief Execute emit unsafe array check.
|
|
119
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
120
|
+
*/
|
|
121
|
+
function emitUnsafeArrayCheck(item, value, path, issues, context, emitChild) {
|
|
122
|
+
const itemValue = "av";
|
|
123
|
+
const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, "i", issues, context);
|
|
124
|
+
let itemCheck;
|
|
125
|
+
if (itemLeaf === undefined) {
|
|
38
126
|
const itemFunction = emitChild(item, context);
|
|
39
|
-
|
|
127
|
+
itemCheck = `${path}.push(i);${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
itemCheck = itemLeaf;
|
|
131
|
+
}
|
|
132
|
+
const parts = [
|
|
133
|
+
`if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_array", "array", `a(${value})`)}return;}`
|
|
134
|
+
];
|
|
135
|
+
if (itemCheck !== "") {
|
|
136
|
+
parts.push(`for(let i=0;i<${value}.length;i+=1){`, `const ${itemValue}=${value}[i];`, itemCheck, "}");
|
|
137
|
+
}
|
|
138
|
+
return parts.join("");
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* @brief Execute emit unsafe tuple check.
|
|
142
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
143
|
+
*/
|
|
144
|
+
function emitUnsafeTupleCheck(items, value, path, issues, context, emitChild) {
|
|
145
|
+
const parts = [
|
|
146
|
+
`if(!Array.isArray(${value})){${emitIssue(issues, path, "expected_tuple", "tuple", `a(${value})`)}return;}`,
|
|
147
|
+
`if(${value}.length!==${String(items.length)}){${emitIssue(issues, path, "expected_tuple_length", `length ${String(items.length)}`, `"length "+String(${value}.length)`)}}`,
|
|
148
|
+
`const n=${value}.length<${String(items.length)}?${value}.length:${String(items.length)};`
|
|
149
|
+
];
|
|
150
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
151
|
+
const item = items[index];
|
|
152
|
+
if (item === undefined) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const indexExpression = String(index);
|
|
156
|
+
const itemValue = `tv${indexExpression}`;
|
|
157
|
+
const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, indexExpression, issues, context);
|
|
158
|
+
let itemCheck;
|
|
159
|
+
if (itemLeaf === undefined) {
|
|
160
|
+
const itemFunction = emitChild(item, context);
|
|
161
|
+
itemCheck = `${path}.push(${indexExpression});${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
itemCheck = itemLeaf;
|
|
165
|
+
}
|
|
166
|
+
if (itemCheck !== "") {
|
|
167
|
+
parts.push(`if(${indexExpression}<n){const ${itemValue}=${value}[${indexExpression}];${itemCheck}}`);
|
|
168
|
+
}
|
|
40
169
|
}
|
|
41
170
|
return parts.join("");
|
|
42
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* @brief emit array check at one appended object-field segment.
|
|
174
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
175
|
+
* stable across runtime and AOT emission.
|
|
176
|
+
* @param item Schema applied to each logical array slot.
|
|
177
|
+
* @param value Generated expression for the candidate value.
|
|
178
|
+
* @param path Generated expression for the mutable diagnostic path.
|
|
179
|
+
* @param segmentExpression Generated parent path segment.
|
|
180
|
+
* @param issues Generated expression for the diagnostic buffer.
|
|
181
|
+
* @param context Shared code-generation context.
|
|
182
|
+
* @returns JavaScript source, or undefined when the caller must fall back.
|
|
183
|
+
*/
|
|
184
|
+
function emitArrayCheckAtSegment(item, value, path, segmentExpression, issues, context) {
|
|
185
|
+
if (isUnsafeMode(context)) {
|
|
186
|
+
return emitUnsafeArrayCheckAtSegment(item, value, path, segmentExpression, issues, context);
|
|
187
|
+
}
|
|
188
|
+
const itemValue = "av";
|
|
189
|
+
const itemLeaf = emitLeafCheckAtTwoSegments(item, itemValue, path, segmentExpression, "i", issues, context);
|
|
190
|
+
const missingLeaf = itemLeaf === undefined
|
|
191
|
+
? undefined
|
|
192
|
+
: emitUndefinedLeafCheckAtTwoSegments(item, path, segmentExpression, "i", issues, context);
|
|
193
|
+
if (itemLeaf === undefined || missingLeaf === undefined) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
const presentCheck = itemLeaf === ""
|
|
197
|
+
? ""
|
|
198
|
+
: `const ${itemValue}=vd.value;${itemLeaf}`;
|
|
199
|
+
if (schemaCanAcceptUndefined(item)) {
|
|
200
|
+
/*
|
|
201
|
+
* The two-segment variant is used inside object fields. It keeps the
|
|
202
|
+
* parent key and array index inline so diagnostics avoid path-stack churn.
|
|
203
|
+
*/
|
|
204
|
+
return [
|
|
205
|
+
`if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_array", "array", `a(${value})`)}}else{`,
|
|
206
|
+
`const xs=Object.getOwnPropertyNames(${value});`,
|
|
207
|
+
"for(let xi=0;xi<xs.length;xi+=1){",
|
|
208
|
+
"const key=xs[xi];",
|
|
209
|
+
`if(!ai(key,${value}.length))continue;`,
|
|
210
|
+
"const i=Number(key);",
|
|
211
|
+
`const vd=gp(${value},key);`,
|
|
212
|
+
`if(vd!==undefined&&!h.call(vd,"value")){${emitIssueAtTwoSegments(issues, path, segmentExpression, "i", "expected_array", "data property", stringLiteral("accessor"))}}else if(vd!==undefined){${presentCheck}}`,
|
|
213
|
+
"}",
|
|
214
|
+
"}"
|
|
215
|
+
].join("");
|
|
216
|
+
}
|
|
217
|
+
return [
|
|
218
|
+
`if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_array", "array", `a(${value})`)}}else{`,
|
|
219
|
+
`for(let i=0;i<${value}.length;i+=1){`,
|
|
220
|
+
`const vd=gp(${value},i);`,
|
|
221
|
+
`if(vd===undefined){${missingLeaf}}else if(!h.call(vd,"value")){${emitIssueAtTwoSegments(issues, path, segmentExpression, "i", "expected_array", "data property", stringLiteral("accessor"))}}else{${presentCheck}}`,
|
|
222
|
+
"}",
|
|
223
|
+
"}"
|
|
224
|
+
].join("");
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* @brief emit tuple check at one appended object-field segment.
|
|
228
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
229
|
+
* stable across runtime and AOT emission.
|
|
230
|
+
*/
|
|
231
|
+
function emitTupleCheckAtSegment(items, value, path, segmentExpression, issues, context) {
|
|
232
|
+
if (isUnsafeMode(context)) {
|
|
233
|
+
return emitUnsafeTupleCheckAtSegment(items, value, path, segmentExpression, issues, context);
|
|
234
|
+
}
|
|
235
|
+
const parts = [
|
|
236
|
+
`if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_tuple", "tuple", `a(${value})`)}}else{`,
|
|
237
|
+
`if(${value}.length!==${String(items.length)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_tuple_length", `length ${String(items.length)}`, `"length "+String(${value}.length)`)}}`,
|
|
238
|
+
`const n=${value}.length<${String(items.length)}?${value}.length:${String(items.length)};`
|
|
239
|
+
];
|
|
240
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
241
|
+
const item = items[index];
|
|
242
|
+
if (item === undefined) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const indexExpression = String(index);
|
|
246
|
+
const itemValue = `tv${indexExpression}`;
|
|
247
|
+
const itemLeaf = emitLeafCheckAtTwoSegments(item, itemValue, path, segmentExpression, indexExpression, issues, context);
|
|
248
|
+
const missingLeaf = itemLeaf === undefined
|
|
249
|
+
? undefined
|
|
250
|
+
: emitUndefinedLeafCheckAtTwoSegments(item, path, segmentExpression, indexExpression, issues, context);
|
|
251
|
+
if (itemLeaf === undefined || missingLeaf === undefined) {
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
const presentCheck = itemLeaf === ""
|
|
255
|
+
? ""
|
|
256
|
+
: `const ${itemValue}=td.value;${itemLeaf}`;
|
|
257
|
+
parts.push(`if(${indexExpression}<n){const td=gp(${value},${indexExpression});if(td===undefined){${missingLeaf}}else if(!h.call(td,"value")){${emitIssueAtTwoSegments(issues, path, segmentExpression, indexExpression, "expected_tuple", "data property", stringLiteral("accessor"))}}else{${presentCheck}}}`);
|
|
258
|
+
}
|
|
259
|
+
parts.push("}");
|
|
260
|
+
return parts.join("");
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* @brief Execute emit unsafe array check at segment.
|
|
264
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
265
|
+
*/
|
|
266
|
+
function emitUnsafeArrayCheckAtSegment(item, value, path, segmentExpression, issues, context) {
|
|
267
|
+
const itemLeaf = emitLeafCheckAtTwoSegments(item, "av", path, segmentExpression, "i", issues, context);
|
|
268
|
+
if (itemLeaf === undefined) {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
const parts = [
|
|
272
|
+
`if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_array", "array", `a(${value})`)}}`
|
|
273
|
+
];
|
|
274
|
+
if (itemLeaf !== "") {
|
|
275
|
+
parts.push("else{", `for(let i=0;i<${value}.length;i+=1){`, `const av=${value}[i];`, itemLeaf, "}", "}");
|
|
276
|
+
}
|
|
277
|
+
return parts.join("");
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* @brief Execute emit unsafe tuple check at segment.
|
|
281
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
282
|
+
*/
|
|
283
|
+
function emitUnsafeTupleCheckAtSegment(items, value, path, segmentExpression, issues, context) {
|
|
284
|
+
const parts = [
|
|
285
|
+
`if(!Array.isArray(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_tuple", "tuple", `a(${value})`)}}else{`,
|
|
286
|
+
`if(${value}.length!==${String(items.length)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_tuple_length", `length ${String(items.length)}`, `"length "+String(${value}.length)`)}}`,
|
|
287
|
+
`const n=${value}.length<${String(items.length)}?${value}.length:${String(items.length)};`
|
|
288
|
+
];
|
|
289
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
290
|
+
const item = items[index];
|
|
291
|
+
if (item === undefined) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const indexExpression = String(index);
|
|
295
|
+
const itemValue = `tv${indexExpression}`;
|
|
296
|
+
const itemLeaf = emitLeafCheckAtTwoSegments(item, itemValue, path, segmentExpression, indexExpression, issues, context);
|
|
297
|
+
if (itemLeaf === undefined) {
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
300
|
+
if (itemLeaf !== "") {
|
|
301
|
+
parts.push(`if(${indexExpression}<n){const ${itemValue}=${value}[${indexExpression}];${itemLeaf}}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
parts.push("}");
|
|
305
|
+
return parts.join("");
|
|
306
|
+
}
|
|
43
307
|
/**
|
|
44
308
|
* @brief emit record check.
|
|
309
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
310
|
+
* stable across runtime and AOT emission.
|
|
45
311
|
*/
|
|
46
312
|
export function emitRecordCheck(item, value, path, issues, context, emitChild) {
|
|
47
|
-
|
|
313
|
+
if (isUnsafeMode(context)) {
|
|
314
|
+
return emitUnsafeRecordCheck(item, value, path, issues, context, emitChild);
|
|
315
|
+
}
|
|
316
|
+
const itemValue = "rv";
|
|
317
|
+
const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, "key", issues, context);
|
|
318
|
+
let itemCheck;
|
|
319
|
+
if (itemLeaf === undefined) {
|
|
320
|
+
const itemFunction = emitChild(item, context);
|
|
321
|
+
itemCheck = `${path}.push(key);${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
itemCheck = itemLeaf;
|
|
325
|
+
}
|
|
326
|
+
const presentCheck = itemCheck === ""
|
|
327
|
+
? ""
|
|
328
|
+
: `const ${itemValue}=d.value;${itemCheck}`;
|
|
48
329
|
return [
|
|
49
|
-
`if(
|
|
50
|
-
`const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
`if(key!==undefined){const d=g(${value},key);${path}.push(key);if(d===undefined){${emitIssue(issues, path, "expected_record", "data property", stringLiteral("accessor or missing"))}}else{${itemFunction}(d.value,${path},${issues});}${path}.pop();}`,
|
|
330
|
+
`if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_record", "record", `a(${value})`)}return;}`,
|
|
331
|
+
`for(const key in ${value}){`,
|
|
332
|
+
`if(!h.call(${value},key))continue;`,
|
|
333
|
+
`const d=gp(${value},key);if(d===undefined||!h.call(d,"value")){${emitIssueAtSegment(issues, path, "key", "expected_record", "data property", stringLiteral("accessor or missing"))}}else{${presentCheck}}`,
|
|
54
334
|
"}"
|
|
55
335
|
].join("");
|
|
56
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* @brief emit record check at one appended object-field segment.
|
|
339
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
340
|
+
* stable across runtime and AOT emission.
|
|
341
|
+
*/
|
|
342
|
+
function emitRecordCheckAtSegment(item, value, path, segmentExpression, issues, context) {
|
|
343
|
+
if (isUnsafeMode(context)) {
|
|
344
|
+
return emitUnsafeRecordCheckAtSegment(item, value, path, segmentExpression, issues, context);
|
|
345
|
+
}
|
|
346
|
+
const itemValue = "rv";
|
|
347
|
+
const itemLeaf = emitLeafCheckAtTwoSegments(item, itemValue, path, segmentExpression, "key", issues, context);
|
|
348
|
+
if (itemLeaf === undefined) {
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
const presentCheck = itemLeaf === ""
|
|
352
|
+
? ""
|
|
353
|
+
: `const ${itemValue}=rd.value;${itemLeaf}`;
|
|
354
|
+
return [
|
|
355
|
+
`if(${objectRejectExpression(value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_record", "record", `a(${value})`)}}else{`,
|
|
356
|
+
`for(const key in ${value}){`,
|
|
357
|
+
`if(!h.call(${value},key))continue;`,
|
|
358
|
+
`const rd=gp(${value},key);if(rd===undefined||!h.call(rd,"value")){${emitIssueAtTwoSegments(issues, path, segmentExpression, "key", "expected_record", "data property", stringLiteral("accessor or missing"))}}else{${presentCheck}}`,
|
|
359
|
+
"}",
|
|
360
|
+
"}"
|
|
361
|
+
].join("");
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* @brief Execute emit unsafe record check.
|
|
365
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
366
|
+
*/
|
|
367
|
+
function emitUnsafeRecordCheck(item, value, path, issues, context, emitChild) {
|
|
368
|
+
const itemValue = "rv";
|
|
369
|
+
const itemLeaf = emitLeafCheckAtSegment(item, itemValue, path, "key", issues, context);
|
|
370
|
+
let itemCheck;
|
|
371
|
+
if (itemLeaf === undefined) {
|
|
372
|
+
const itemFunction = emitChild(item, context);
|
|
373
|
+
itemCheck = `${path}.push(key);${itemFunction}(${itemValue},${path},${issues});${path}.pop();`;
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
itemCheck = itemLeaf;
|
|
377
|
+
}
|
|
378
|
+
const parts = [
|
|
379
|
+
`if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_record", "record", `a(${value})`)}return;}`
|
|
380
|
+
];
|
|
381
|
+
if (itemCheck !== "") {
|
|
382
|
+
parts.push(`for(const key in ${value}){`, isUncheckedMode(context) ? "" : `if(!h.call(${value},key))continue;`, `const ${itemValue}=${value}[key];`, itemCheck, "}");
|
|
383
|
+
}
|
|
384
|
+
return parts.join("");
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* @brief Execute emit unsafe record check at segment.
|
|
388
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
389
|
+
*/
|
|
390
|
+
function emitUnsafeRecordCheckAtSegment(item, value, path, segmentExpression, issues, context) {
|
|
391
|
+
const itemLeaf = emitLeafCheckAtTwoSegments(item, "rv", path, segmentExpression, "key", issues, context);
|
|
392
|
+
if (itemLeaf === undefined) {
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
const parts = [
|
|
396
|
+
`if(${objectRejectExpression(value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_record", "record", `a(${value})`)}}`
|
|
397
|
+
];
|
|
398
|
+
if (itemLeaf !== "") {
|
|
399
|
+
parts.push("else{", `for(const key in ${value}){`, isUncheckedMode(context) ? "" : `if(!h.call(${value},key))continue;`, `const rv=${value}[key];`, itemLeaf, "}", "}");
|
|
400
|
+
}
|
|
401
|
+
return parts.join("");
|
|
402
|
+
}
|
|
57
403
|
/**
|
|
58
404
|
* @brief emit object check.
|
|
405
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
406
|
+
* stable across runtime and AOT emission.
|
|
59
407
|
*/
|
|
60
408
|
export function emitObjectCheck(schema, value, path, issues, context, emitChild) {
|
|
409
|
+
if (isUnsafeMode(context)) {
|
|
410
|
+
return emitUnsafeObjectCheck(schema, value, path, issues, context, emitChild);
|
|
411
|
+
}
|
|
61
412
|
const parts = [
|
|
62
|
-
`if(
|
|
413
|
+
`if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`
|
|
63
414
|
];
|
|
64
415
|
const entries = schema.entries;
|
|
416
|
+
const keyExpressions = [];
|
|
65
417
|
for (let index = 0; index < entries.length; index += 1) {
|
|
66
418
|
const entry = entries[index];
|
|
67
419
|
if (entry === undefined) {
|
|
68
420
|
continue;
|
|
69
421
|
}
|
|
70
422
|
const key = stringRef(context, entry.key);
|
|
71
|
-
|
|
423
|
+
keyExpressions.push(key);
|
|
424
|
+
const itemValue = `v${String(index)}`;
|
|
425
|
+
const leaf = emitLeafCheckAtSegment(entry.schema, itemValue, path, key, issues, context);
|
|
426
|
+
const composite = leaf === undefined
|
|
427
|
+
? emitCompositeCheckAtSegment(entry.schema, itemValue, path, key, issues, context)
|
|
428
|
+
: undefined;
|
|
429
|
+
let childCheck = leaf ?? composite;
|
|
430
|
+
if (childCheck === undefined) {
|
|
431
|
+
const child = emitChild(entry.schema, context);
|
|
432
|
+
childCheck = `${path}.push(${key});${child}(${itemValue},${path},${issues});${path}.pop();`;
|
|
433
|
+
}
|
|
434
|
+
const presentCheck = childCheck === ""
|
|
435
|
+
? ""
|
|
436
|
+
: `const ${itemValue}=d.value;${childCheck}`;
|
|
72
437
|
if (entry.presence === PresenceTag.Required) {
|
|
73
|
-
parts.push(`{const d=
|
|
438
|
+
parts.push(`{const d=gp(${value},${key});if(d===undefined||!h.call(d,"value")){${emitIssueAtSegment(issues, path, key, "expected_required_key", "present key", stringLiteral("missing"))}}else{${presentCheck}}}`);
|
|
74
439
|
}
|
|
75
440
|
else {
|
|
76
|
-
parts.push(`if(h.call(${value},${key})){const d=
|
|
441
|
+
parts.push(`if(h.call(${value},${key})){const d=gp(${value},${key});if(d===undefined||!h.call(d,"value")){${emitIssueAtSegment(issues, path, key, "expected_object", "data property", stringLiteral("accessor"))}}else{${presentCheck}}}`);
|
|
77
442
|
}
|
|
78
443
|
}
|
|
79
444
|
if (schema.mode === ObjectModeTag.Strict) {
|
|
445
|
+
parts.push(`const xs=Object.getOwnPropertyNames(${value});const xn=xs.length;for(let i=0;i<xn;i+=1){const key=xs[i];if(!(${safeKeyMembershipExpression("key", keyExpressions)})){${emitIssueAtSegment(issues, path, "key", "unrecognized_key", "known key", stringLiteral("extra key"))}}}const ys=Object.getOwnPropertySymbols(${value});const yn=ys.length;for(let i=0;i<yn;i+=1){const key=ys[i];if(key!==undefined){${emitIssueAtSegment(issues, path, "String(key)", "unrecognized_key", "known key", stringLiteral("extra key"))}}}`);
|
|
446
|
+
}
|
|
447
|
+
return parts.join("");
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* @brief Execute emit unsafe object check.
|
|
451
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
452
|
+
*/
|
|
453
|
+
function emitUnsafeObjectCheck(schema, value, path, issues, context, emitChild) {
|
|
454
|
+
const parts = [
|
|
455
|
+
`if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`
|
|
456
|
+
];
|
|
457
|
+
const entries = schema.entries;
|
|
458
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
459
|
+
const entry = entries[index];
|
|
460
|
+
if (entry === undefined) {
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
const key = unsafeStringLiteralExpression(entry.key);
|
|
464
|
+
const itemValue = `v${String(index)}`;
|
|
465
|
+
const childCheck = emitObjectFieldCheck(entry.schema, itemValue, path, key, issues, context, emitChild);
|
|
466
|
+
parts.push(`{const ${itemValue}=${unsafePropertyReadExpression(value, entry.key)};`);
|
|
467
|
+
if (entry.presence === PresenceTag.Optional) {
|
|
468
|
+
parts.push(`if(${itemValue}!==undefined){${childCheck}}else if(h.call(${value},${key})){${childCheck}}`);
|
|
469
|
+
}
|
|
470
|
+
else if (schemaCanAcceptUndefined(entry.schema)) {
|
|
471
|
+
parts.push(`if(${itemValue}===undefined&&!h.call(${value},${key})){${emitIssueAtSegment(issues, path, key, "expected_required_key", "present key", stringLiteral("missing"))}}else{${childCheck}}`);
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
parts.push(childCheck);
|
|
475
|
+
}
|
|
476
|
+
parts.push("}");
|
|
477
|
+
}
|
|
478
|
+
if (schema.mode === ObjectModeTag.Strict && !isUncheckedMode(context)) {
|
|
80
479
|
const keys = new Array(schema.entries.length);
|
|
81
480
|
for (let index = 0; index < schema.entries.length; index += 1) {
|
|
82
481
|
const entry = schema.entries[index];
|
|
@@ -84,22 +483,58 @@ export function emitObjectCheck(schema, value, path, issues, context, emitChild)
|
|
|
84
483
|
keys[index] = entry.key;
|
|
85
484
|
}
|
|
86
485
|
}
|
|
87
|
-
parts.push(`const
|
|
486
|
+
parts.push(`for(const key in ${value}){if(h.call(${value},key)&&!(${unsafeKeyMembershipExpression("key", keys)})){${emitIssueAtSegment(issues, path, "key", "unrecognized_key", "known key", stringLiteral("extra key"))}}}`);
|
|
88
487
|
}
|
|
89
488
|
return parts.join("");
|
|
90
489
|
}
|
|
490
|
+
/**
|
|
491
|
+
* @brief Execute emit object field check.
|
|
492
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
493
|
+
*/
|
|
494
|
+
function emitObjectFieldCheck(schema, value, path, segmentExpression, issues, context, emitChild) {
|
|
495
|
+
const leaf = emitLeafCheckAtSegment(schema, value, path, segmentExpression, issues, context);
|
|
496
|
+
if (leaf !== undefined) {
|
|
497
|
+
return leaf;
|
|
498
|
+
}
|
|
499
|
+
const composite = emitCompositeCheckAtSegment(schema, value, path, segmentExpression, issues, context);
|
|
500
|
+
if (composite !== undefined) {
|
|
501
|
+
return composite;
|
|
502
|
+
}
|
|
503
|
+
const child = emitChild(schema, context);
|
|
504
|
+
return `${path}.push(${segmentExpression});${child}(${value},${path},${issues});${path}.pop();`;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* @brief Execute emit composite check at segment.
|
|
508
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
509
|
+
*/
|
|
510
|
+
function emitCompositeCheckAtSegment(schema, value, path, segmentExpression, issues, context) {
|
|
511
|
+
switch (schema.tag) {
|
|
512
|
+
case SchemaTag.Array:
|
|
513
|
+
return emitArrayCheckAtSegment(schema.item, value, path, segmentExpression, issues, context);
|
|
514
|
+
case SchemaTag.Tuple:
|
|
515
|
+
return emitTupleCheckAtSegment(schema.items, value, path, segmentExpression, issues, context);
|
|
516
|
+
case SchemaTag.Record:
|
|
517
|
+
return emitRecordCheckAtSegment(schema.value, value, path, segmentExpression, issues, context);
|
|
518
|
+
default:
|
|
519
|
+
return undefined;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
91
522
|
/**
|
|
92
523
|
* @brief emit discriminated union check.
|
|
524
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
525
|
+
* stable across runtime and AOT emission.
|
|
93
526
|
*/
|
|
94
527
|
export function emitDiscriminatedUnionCheck(key, cases, value, path, issues, context, emitChild) {
|
|
528
|
+
if (isUnsafeMode(context)) {
|
|
529
|
+
return emitUnsafeDiscriminatedUnionCheck(key, cases, value, path, issues, context, emitChild);
|
|
530
|
+
}
|
|
95
531
|
const keyRef = stringRef(context, key);
|
|
96
|
-
const descriptor = `g(${value},${keyRef})`;
|
|
97
532
|
const parts = [
|
|
98
|
-
`if(
|
|
99
|
-
`const dd
|
|
100
|
-
`if(dd===undefined){${
|
|
533
|
+
`if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`,
|
|
534
|
+
`const dd=gp(${value},${keyRef});`,
|
|
535
|
+
`if(dd===undefined||!h.call(dd,"value")){${emitIssueAtSegment(issues, path, keyRef, "expected_discriminant", "data property", stringLiteral("missing or accessor"))}return;}`,
|
|
101
536
|
"const dv=dd.value;",
|
|
102
|
-
`if(typeof dv!=="string"){${
|
|
537
|
+
`if(typeof dv!=="string"){${emitIssueAtSegment(issues, path, keyRef, "expected_discriminant", "string discriminant", "a(dv)")}return;}`
|
|
103
538
|
];
|
|
104
539
|
for (let index = 0; index < cases.length; index += 1) {
|
|
105
540
|
const unionCase = cases[index];
|
|
@@ -112,6 +547,111 @@ export function emitDiscriminatedUnionCheck(key, cases, value, path, issues, con
|
|
|
112
547
|
const check = emitChild(schema, context);
|
|
113
548
|
parts.push(`if(Object.is(dv,l[${String(literalIndex)}])){${check}(${value},${path},${issues});return;}`);
|
|
114
549
|
}
|
|
115
|
-
parts.push(
|
|
550
|
+
parts.push(emitIssueExprAtSegment(issues, path, keyRef, "expected_discriminant", stringLiteral("known discriminant"), "le(dv)"));
|
|
551
|
+
return parts.join("");
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* @brief Execute emit unsafe discriminated union check.
|
|
555
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
556
|
+
*/
|
|
557
|
+
function emitUnsafeDiscriminatedUnionCheck(key, cases, value, path, issues, context, emitChild) {
|
|
558
|
+
const keyRef = unsafeStringLiteralExpression(key);
|
|
559
|
+
const parts = [
|
|
560
|
+
`if(${objectRejectExpression(value)}){${emitIssue(issues, path, "expected_object", "object", `a(${value})`)}return;}`,
|
|
561
|
+
`const dv=${unsafePropertyReadExpression(value, key)};`,
|
|
562
|
+
`if(typeof dv!=="string"){${emitIssueAtSegment(issues, path, keyRef, "expected_discriminant", "string discriminant", "a(dv)")}return;}`
|
|
563
|
+
];
|
|
564
|
+
for (let index = 0; index < cases.length; index += 1) {
|
|
565
|
+
const unionCase = cases[index];
|
|
566
|
+
if (unionCase === undefined) {
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
const literal = unionCase.literal;
|
|
570
|
+
const schema = unionCase.schema;
|
|
571
|
+
const check = emitChild(schema, context);
|
|
572
|
+
parts.push(`if(dv===${unsafeStringLiteralExpression(literal)}){${check}(${value},${path},${issues});return;}`);
|
|
573
|
+
}
|
|
574
|
+
parts.push(emitIssueExprAtSegment(issues, path, keyRef, "expected_discriminant", stringLiteral("known discriminant"), "le(dv)"));
|
|
116
575
|
return parts.join("");
|
|
117
576
|
}
|
|
577
|
+
/**
|
|
578
|
+
* @brief Execute object reject expression.
|
|
579
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
580
|
+
*/
|
|
581
|
+
function objectRejectExpression(value) {
|
|
582
|
+
return `typeof ${value}!=="object"||${value}===null||Array.isArray(${value})`;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* @brief Check unsafe mode.
|
|
586
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
587
|
+
*/
|
|
588
|
+
function isUnsafeMode(context) {
|
|
589
|
+
return context.mode !== "safe";
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* @brief Check unchecked mode.
|
|
593
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
594
|
+
*/
|
|
595
|
+
function isUncheckedMode(context) {
|
|
596
|
+
return context.mode === "unchecked";
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* @brief Execute unsafe property read expression.
|
|
600
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
601
|
+
*/
|
|
602
|
+
function unsafePropertyReadExpression(objectExpression, key) {
|
|
603
|
+
if (isAsciiIdentifierName(key)) {
|
|
604
|
+
return `${objectExpression}.${key}`;
|
|
605
|
+
}
|
|
606
|
+
return `${objectExpression}[${unsafeStringLiteralExpression(key)}]`;
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* @brief Execute unsafe key membership expression.
|
|
610
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
611
|
+
*/
|
|
612
|
+
function unsafeKeyMembershipExpression(key, keys) {
|
|
613
|
+
if (keys.length === 0) {
|
|
614
|
+
return "false";
|
|
615
|
+
}
|
|
616
|
+
const parts = new Array(keys.length);
|
|
617
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
618
|
+
const value = keys[index];
|
|
619
|
+
parts[index] = value === undefined
|
|
620
|
+
? "false"
|
|
621
|
+
: `${key}===${unsafeStringLiteralExpression(value)}`;
|
|
622
|
+
}
|
|
623
|
+
return parts.join("||");
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* @brief Execute safe key membership expression.
|
|
627
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
628
|
+
*/
|
|
629
|
+
function safeKeyMembershipExpression(key, keyExpressions) {
|
|
630
|
+
if (keyExpressions.length === 0) {
|
|
631
|
+
return "false";
|
|
632
|
+
}
|
|
633
|
+
const parts = new Array(keyExpressions.length);
|
|
634
|
+
for (let index = 0; index < keyExpressions.length; index += 1) {
|
|
635
|
+
const expression = keyExpressions[index];
|
|
636
|
+
parts[index] = expression === undefined
|
|
637
|
+
? "false"
|
|
638
|
+
: `${key}===${expression}`;
|
|
639
|
+
}
|
|
640
|
+
return parts.join("||");
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* @brief Check ascii identifier name.
|
|
644
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
645
|
+
*/
|
|
646
|
+
function isAsciiIdentifierName(value) {
|
|
647
|
+
return /^[A-Za-z_$][0-9A-Za-z_$]*$/u.test(value);
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* @brief Execute unsafe string literal expression.
|
|
651
|
+
* @details Code generation helpers keep emitted JavaScript shape stable across runtime and AOT paths.
|
|
652
|
+
*/
|
|
653
|
+
function unsafeStringLiteralExpression(value) {
|
|
654
|
+
return JSON.stringify(value)
|
|
655
|
+
.replace(/\u2028/gu, "\\u2028")
|
|
656
|
+
.replace(/\u2029/gu, "\\u2029");
|
|
657
|
+
}
|