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
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file compile/check-scalar.ts
|
|
3
3
|
* @brief Scalar 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
|
-
import { NumberCheckTag, SchemaTag, StringCheckTag } from "../kind/index.js";
|
|
6
|
-
import { UUID_PATTERN } from "../schema/index.js";
|
|
7
|
+
import { DateCheckTag, NumberCheckTag, SchemaTag, StringCheckTag } from "../kind/index.js";
|
|
8
|
+
import { EMAIL_PATTERN, IPV4_PATTERN, IPV6_PATTERN, ISO_DATETIME_PATTERN, ISO_DATE_PATTERN, ULID_PATTERN, URL_PATTERN, UUID_PATTERN } from "../schema/index.js";
|
|
7
9
|
import { pushLiteral } from "./context.js";
|
|
8
|
-
import { emitIssue, emitIssueExpr, emitPatternIssue } from "./issue.js";
|
|
10
|
+
import { emitIssue, emitIssueAtSegment, emitIssueAtTwoSegments, emitIssueExpr, emitIssueExprAtSegment, emitIssueExprAtTwoSegments, emitPatternIssueAtSegment, emitPatternIssueAtTwoSegments, emitPatternIssue } from "./issue.js";
|
|
9
11
|
import { stringLiteral } from "./names.js";
|
|
12
|
+
import { emitUnion } from "./predicate.js";
|
|
10
13
|
/**
|
|
11
14
|
* @brief emit string check.
|
|
15
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
16
|
+
* stable across runtime and AOT emission.
|
|
17
|
+
* @param schema String schema with scalar checks.
|
|
18
|
+
* @param value Generated expression for the candidate value.
|
|
19
|
+
* @param path Generated expression for the current diagnostic path.
|
|
20
|
+
* @param issues Generated expression for the issue buffer.
|
|
21
|
+
* @param context Shared code-generation context.
|
|
22
|
+
* @returns JavaScript source for root string diagnostics.
|
|
12
23
|
*/
|
|
13
24
|
export function emitStringCheck(schema, value, path, issues, context) {
|
|
14
25
|
const parts = [
|
|
15
26
|
`if(typeof ${value}!=="string"){${emitIssue(issues, path, "expected_string", "string", `a(${value})`)}return;}`
|
|
16
27
|
];
|
|
17
28
|
const checks = schema.checks;
|
|
29
|
+
/*
|
|
30
|
+
* Constraint diagnostics run only after the type guard returns. This avoids
|
|
31
|
+
* meaningless length or pattern reads on non-string values.
|
|
32
|
+
*/
|
|
18
33
|
for (let index = 0; index < checks.length; index += 1) {
|
|
19
34
|
const check = checks[index];
|
|
20
35
|
if (check === undefined) {
|
|
@@ -33,18 +48,374 @@ export function emitStringCheck(schema, value, path, issues, context) {
|
|
|
33
48
|
case StringCheckTag.Uuid:
|
|
34
49
|
parts.push(emitPatternIssue(value, path, issues, UUID_PATTERN, "uuid", context));
|
|
35
50
|
break;
|
|
51
|
+
case StringCheckTag.Email:
|
|
52
|
+
parts.push(emitPatternIssue(value, path, issues, EMAIL_PATTERN, "email", context));
|
|
53
|
+
break;
|
|
54
|
+
case StringCheckTag.Url:
|
|
55
|
+
parts.push(emitPatternIssue(value, path, issues, URL_PATTERN, "url", context));
|
|
56
|
+
break;
|
|
57
|
+
case StringCheckTag.IsoDate:
|
|
58
|
+
parts.push(emitPatternIssue(value, path, issues, ISO_DATE_PATTERN, "iso_date", context));
|
|
59
|
+
break;
|
|
60
|
+
case StringCheckTag.IsoDateTime:
|
|
61
|
+
parts.push(emitPatternIssue(value, path, issues, ISO_DATETIME_PATTERN, "iso_datetime", context));
|
|
62
|
+
break;
|
|
63
|
+
case StringCheckTag.Ulid:
|
|
64
|
+
parts.push(emitPatternIssue(value, path, issues, ULID_PATTERN, "ulid", context));
|
|
65
|
+
break;
|
|
66
|
+
case StringCheckTag.Ipv4:
|
|
67
|
+
parts.push(emitPatternIssue(value, path, issues, IPV4_PATTERN, "ipv4", context));
|
|
68
|
+
break;
|
|
69
|
+
case StringCheckTag.Ipv6:
|
|
70
|
+
parts.push(emitPatternIssue(value, path, issues, IPV6_PATTERN, "ipv6", context));
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return parts.join("");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* @brief Emit Date diagnostics.
|
|
78
|
+
* @param value Generated expression for the candidate value.
|
|
79
|
+
* @param path Generated expression for the current diagnostic path.
|
|
80
|
+
* @param issues Generated expression for the issue buffer.
|
|
81
|
+
* @returns JavaScript source for root Date diagnostics.
|
|
82
|
+
*/
|
|
83
|
+
export function emitDateCheck(schema, value, path, issues) {
|
|
84
|
+
const invalid = `!dg(${value})`;
|
|
85
|
+
const checks = schema.checks;
|
|
86
|
+
if (checks.length === 0) {
|
|
87
|
+
return `if(${invalid}){${emitIssue(issues, path, "expected_date", "valid Date", `a(${value})`)}}`;
|
|
88
|
+
}
|
|
89
|
+
const parts = [`if(${invalid}){${emitIssue(issues, path, "expected_date", "valid Date", `a(${value})`)}}else{`];
|
|
90
|
+
for (let index = 0; index < checks.length; index += 1) {
|
|
91
|
+
const check = checks[index];
|
|
92
|
+
if (check === undefined) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const actual = `new Date(dt(${value})).toISOString()`;
|
|
96
|
+
switch (check.tag) {
|
|
97
|
+
case DateCheckTag.Min:
|
|
98
|
+
parts.push(`if(dt(${value})<${String(check.value)}){${emitIssue(issues, path, "expected_gte", `>= ${new Date(check.value).toISOString()}`, actual)}}`);
|
|
99
|
+
break;
|
|
100
|
+
case DateCheckTag.Max:
|
|
101
|
+
parts.push(`if(dt(${value})>${String(check.value)}){${emitIssue(issues, path, "expected_lte", `<= ${new Date(check.value).toISOString()}`, actual)}}`);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
parts.push("}");
|
|
106
|
+
return parts.join("");
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* @brief emit leaf check at one appended path segment.
|
|
110
|
+
* @details This path is used by object-field diagnostics to avoid building a
|
|
111
|
+
* mutable path frame and calling a child collector for scalar schemas.
|
|
112
|
+
* @param schema Candidate leaf schema.
|
|
113
|
+
* @param value Generated expression for the candidate value.
|
|
114
|
+
* @param path Generated expression for the current diagnostic path.
|
|
115
|
+
* @param segmentExpression Generated expression for the appended path segment.
|
|
116
|
+
* @param issues Generated expression for the issue buffer.
|
|
117
|
+
* @param context Shared code-generation context.
|
|
118
|
+
* @returns Inline diagnostic source, or undefined when a full child collector is required.
|
|
119
|
+
*/
|
|
120
|
+
export function emitLeafCheckAtSegment(schema, value, path, segmentExpression, issues, context) {
|
|
121
|
+
switch (schema.tag) {
|
|
122
|
+
case SchemaTag.Unknown:
|
|
123
|
+
return "";
|
|
124
|
+
case SchemaTag.Never:
|
|
125
|
+
return emitIssueAtSegment(issues, path, segmentExpression, "expected_never", "never", `a(${value})`);
|
|
126
|
+
case SchemaTag.String:
|
|
127
|
+
return emitStringCheckAtSegment(schema, value, path, segmentExpression, issues, context);
|
|
128
|
+
case SchemaTag.Number:
|
|
129
|
+
return emitNumberCheckAtSegment(schema, value, path, segmentExpression, issues);
|
|
130
|
+
case SchemaTag.Date:
|
|
131
|
+
if (schema.checks.length !== 0) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
return `if(!dg(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_date", "valid Date", `a(${value})`)}}`;
|
|
135
|
+
case SchemaTag.BigInt:
|
|
136
|
+
return `if(typeof ${value}!=="bigint"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_bigint", "bigint", `a(${value})`)}}`;
|
|
137
|
+
case SchemaTag.Symbol:
|
|
138
|
+
return `if(typeof ${value}!=="symbol"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_symbol", "symbol", `a(${value})`)}}`;
|
|
139
|
+
case SchemaTag.Boolean:
|
|
140
|
+
return `if(typeof ${value}!=="boolean"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_boolean", "boolean", `a(${value})`)}}`;
|
|
141
|
+
case SchemaTag.Literal:
|
|
142
|
+
return emitLiteralCheckAtSegment(schema.value, value, path, segmentExpression, issues, context);
|
|
143
|
+
case SchemaTag.Union:
|
|
144
|
+
/*
|
|
145
|
+
* Primitive unions are cheap enough to inline. Complex union branches
|
|
146
|
+
* already delegate through emitUnion and child predicate helpers.
|
|
147
|
+
*/
|
|
148
|
+
return `if(!${emitUnion(schema.options, value, context)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_union", "union", `a(${value})`)}}`;
|
|
149
|
+
default:
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* @brief emit leaf check for a proven undefined value at one path segment.
|
|
155
|
+
* @details Array and tuple holes are known to be undefined. Emitting only the
|
|
156
|
+
* reachable type or literal issue keeps generated collectors smaller and avoids
|
|
157
|
+
* cold constraint branches that V8 still has to parse.
|
|
158
|
+
* @param schema Candidate leaf schema.
|
|
159
|
+
* @param path Generated expression for the current diagnostic path.
|
|
160
|
+
* @param segmentExpression Generated expression for the appended path segment.
|
|
161
|
+
* @param issues Generated expression for the issue buffer.
|
|
162
|
+
* @param context Shared code-generation context.
|
|
163
|
+
* @returns Inline diagnostic source, or undefined when a full child collector is required.
|
|
164
|
+
*/
|
|
165
|
+
export function emitUndefinedLeafCheckAtSegment(schema, path, segmentExpression, issues, context) {
|
|
166
|
+
switch (schema.tag) {
|
|
167
|
+
case SchemaTag.Unknown:
|
|
168
|
+
return "";
|
|
169
|
+
case SchemaTag.Never:
|
|
170
|
+
return emitIssueAtSegment(issues, path, segmentExpression, "expected_never", "never", stringLiteral("undefined"));
|
|
171
|
+
case SchemaTag.String:
|
|
172
|
+
return emitIssueAtSegment(issues, path, segmentExpression, "expected_string", "string", stringLiteral("undefined"));
|
|
173
|
+
case SchemaTag.Number:
|
|
174
|
+
return emitIssueAtSegment(issues, path, segmentExpression, "expected_number", "number", stringLiteral("undefined"));
|
|
175
|
+
case SchemaTag.Date:
|
|
176
|
+
return emitIssueAtSegment(issues, path, segmentExpression, "expected_date", "valid Date", stringLiteral("undefined"));
|
|
177
|
+
case SchemaTag.BigInt:
|
|
178
|
+
return emitIssueAtSegment(issues, path, segmentExpression, "expected_bigint", "bigint", stringLiteral("undefined"));
|
|
179
|
+
case SchemaTag.Symbol:
|
|
180
|
+
return emitIssueAtSegment(issues, path, segmentExpression, "expected_symbol", "symbol", stringLiteral("undefined"));
|
|
181
|
+
case SchemaTag.Boolean:
|
|
182
|
+
return emitIssueAtSegment(issues, path, segmentExpression, "expected_boolean", "boolean", stringLiteral("undefined"));
|
|
183
|
+
case SchemaTag.Literal:
|
|
184
|
+
return emitUndefinedLiteralCheckAtSegment(schema.value, path, segmentExpression, issues, context);
|
|
185
|
+
default:
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* @brief emit leaf check at two appended path segments.
|
|
191
|
+
* @details Used by object-field array/record diagnostics to avoid push/pop path
|
|
192
|
+
* mutation when both parent key and child key are known in generated source.
|
|
193
|
+
* @param schema Candidate leaf schema.
|
|
194
|
+
* @param value Generated expression for the candidate value.
|
|
195
|
+
* @param path Generated expression for the current diagnostic path.
|
|
196
|
+
* @param firstSegmentExpression Generated expression for the parent segment.
|
|
197
|
+
* @param secondSegmentExpression Generated expression for the child segment.
|
|
198
|
+
* @param issues Generated expression for the issue buffer.
|
|
199
|
+
* @param context Shared code-generation context.
|
|
200
|
+
* @returns Inline diagnostic source, or undefined when a full child collector is required.
|
|
201
|
+
*/
|
|
202
|
+
export function emitLeafCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
|
|
203
|
+
switch (schema.tag) {
|
|
204
|
+
case SchemaTag.Unknown:
|
|
205
|
+
return "";
|
|
206
|
+
case SchemaTag.Never:
|
|
207
|
+
return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_never", "never", `a(${value})`);
|
|
208
|
+
case SchemaTag.String:
|
|
209
|
+
return emitStringCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues, context);
|
|
210
|
+
case SchemaTag.Number:
|
|
211
|
+
return emitNumberCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues);
|
|
212
|
+
case SchemaTag.Date:
|
|
213
|
+
if (schema.checks.length !== 0) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
return `if(!dg(${value})){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_date", "valid Date", `a(${value})`)}}`;
|
|
217
|
+
case SchemaTag.BigInt:
|
|
218
|
+
return `if(typeof ${value}!=="bigint"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_bigint", "bigint", `a(${value})`)}}`;
|
|
219
|
+
case SchemaTag.Symbol:
|
|
220
|
+
return `if(typeof ${value}!=="symbol"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_symbol", "symbol", `a(${value})`)}}`;
|
|
221
|
+
case SchemaTag.Boolean:
|
|
222
|
+
return `if(typeof ${value}!=="boolean"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_boolean", "boolean", `a(${value})`)}}`;
|
|
223
|
+
case SchemaTag.Literal:
|
|
224
|
+
return emitLiteralCheckAtTwoSegments(schema.value, value, path, firstSegmentExpression, secondSegmentExpression, issues, context);
|
|
225
|
+
case SchemaTag.Union:
|
|
226
|
+
return `if(!${emitUnion(schema.options, value, context)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_union", "union", `a(${value})`)}}`;
|
|
227
|
+
default:
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* @brief emit leaf check for a proven undefined value at two path segments.
|
|
233
|
+
* @details Array and tuple holes under object fields are known to be undefined,
|
|
234
|
+
* so the emitter can skip value reads and emit only reachable leaf issues.
|
|
235
|
+
* @param schema Candidate leaf schema.
|
|
236
|
+
* @param path Generated expression for the current diagnostic path.
|
|
237
|
+
* @param firstSegmentExpression Generated expression for the parent segment.
|
|
238
|
+
* @param secondSegmentExpression Generated expression for the child segment.
|
|
239
|
+
* @param issues Generated expression for the issue buffer.
|
|
240
|
+
* @param context Shared code-generation context.
|
|
241
|
+
* @returns Inline diagnostic source, or undefined when a full child collector is required.
|
|
242
|
+
*/
|
|
243
|
+
export function emitUndefinedLeafCheckAtTwoSegments(schema, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
|
|
244
|
+
switch (schema.tag) {
|
|
245
|
+
case SchemaTag.Unknown:
|
|
246
|
+
return "";
|
|
247
|
+
case SchemaTag.Never:
|
|
248
|
+
return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_never", "never", stringLiteral("undefined"));
|
|
249
|
+
case SchemaTag.String:
|
|
250
|
+
return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_string", "string", stringLiteral("undefined"));
|
|
251
|
+
case SchemaTag.Number:
|
|
252
|
+
return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_number", "number", stringLiteral("undefined"));
|
|
253
|
+
case SchemaTag.Date:
|
|
254
|
+
return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_date", "valid Date", stringLiteral("undefined"));
|
|
255
|
+
case SchemaTag.BigInt:
|
|
256
|
+
return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_bigint", "bigint", stringLiteral("undefined"));
|
|
257
|
+
case SchemaTag.Symbol:
|
|
258
|
+
return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_symbol", "symbol", stringLiteral("undefined"));
|
|
259
|
+
case SchemaTag.Boolean:
|
|
260
|
+
return emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_boolean", "boolean", stringLiteral("undefined"));
|
|
261
|
+
case SchemaTag.Literal:
|
|
262
|
+
return emitUndefinedLiteralCheckAtTwoSegments(schema.value, path, firstSegmentExpression, secondSegmentExpression, issues, context);
|
|
263
|
+
default:
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* @brief emit string check at one appended path segment.
|
|
269
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
270
|
+
* stable across runtime and AOT emission.
|
|
271
|
+
* @param schema String schema with scalar checks.
|
|
272
|
+
* @param value Generated expression for the candidate value.
|
|
273
|
+
* @param path Generated expression for the current diagnostic path.
|
|
274
|
+
* @param segmentExpression Generated expression for the appended path segment.
|
|
275
|
+
* @param issues Generated expression for the issue buffer.
|
|
276
|
+
* @param context Shared code-generation context.
|
|
277
|
+
* @returns JavaScript source for one-segment string diagnostics.
|
|
278
|
+
*/
|
|
279
|
+
function emitStringCheckAtSegment(schema, value, path, segmentExpression, issues, context) {
|
|
280
|
+
const checks = schema.checks;
|
|
281
|
+
if (checks.length === 0) {
|
|
282
|
+
/*
|
|
283
|
+
* No constraints means no else block is needed. The generated collector
|
|
284
|
+
* stays as a single type branch.
|
|
285
|
+
*/
|
|
286
|
+
return `if(typeof ${value}!=="string"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_string", "string", `a(${value})`)}}`;
|
|
287
|
+
}
|
|
288
|
+
const parts = [
|
|
289
|
+
`if(typeof ${value}!=="string"){${emitIssueAtSegment(issues, path, segmentExpression, "expected_string", "string", `a(${value})`)}}else{`
|
|
290
|
+
];
|
|
291
|
+
for (let index = 0; index < checks.length; index += 1) {
|
|
292
|
+
const check = checks[index];
|
|
293
|
+
if (check === undefined) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
switch (check.tag) {
|
|
297
|
+
case StringCheckTag.Min:
|
|
298
|
+
parts.push(`if(${value}.length<${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_min_length", `length >= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
|
|
299
|
+
break;
|
|
300
|
+
case StringCheckTag.Max:
|
|
301
|
+
parts.push(`if(${value}.length>${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_max_length", `length <= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
|
|
302
|
+
break;
|
|
303
|
+
case StringCheckTag.Regex:
|
|
304
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, check.regex, check.name, context));
|
|
305
|
+
break;
|
|
306
|
+
case StringCheckTag.Uuid:
|
|
307
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, UUID_PATTERN, "uuid", context));
|
|
308
|
+
break;
|
|
309
|
+
case StringCheckTag.Email:
|
|
310
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, EMAIL_PATTERN, "email", context));
|
|
311
|
+
break;
|
|
312
|
+
case StringCheckTag.Url:
|
|
313
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, URL_PATTERN, "url", context));
|
|
314
|
+
break;
|
|
315
|
+
case StringCheckTag.IsoDate:
|
|
316
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, ISO_DATE_PATTERN, "iso_date", context));
|
|
317
|
+
break;
|
|
318
|
+
case StringCheckTag.IsoDateTime:
|
|
319
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, ISO_DATETIME_PATTERN, "iso_datetime", context));
|
|
320
|
+
break;
|
|
321
|
+
case StringCheckTag.Ulid:
|
|
322
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, ULID_PATTERN, "ulid", context));
|
|
323
|
+
break;
|
|
324
|
+
case StringCheckTag.Ipv4:
|
|
325
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, IPV4_PATTERN, "ipv4", context));
|
|
326
|
+
break;
|
|
327
|
+
case StringCheckTag.Ipv6:
|
|
328
|
+
parts.push(emitPatternIssueAtSegment(value, path, segmentExpression, issues, IPV6_PATTERN, "ipv6", context));
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
parts.push("}");
|
|
333
|
+
return parts.join("");
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* @brief emit string check at two appended path segments.
|
|
337
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
338
|
+
* stable across runtime and AOT emission.
|
|
339
|
+
* @param schema String schema with scalar checks.
|
|
340
|
+
* @param value Generated expression for the candidate value.
|
|
341
|
+
* @param path Generated expression for the current diagnostic path.
|
|
342
|
+
* @param firstSegmentExpression Generated expression for the parent segment.
|
|
343
|
+
* @param secondSegmentExpression Generated expression for the child segment.
|
|
344
|
+
* @param issues Generated expression for the issue buffer.
|
|
345
|
+
* @param context Shared code-generation context.
|
|
346
|
+
* @returns JavaScript source for two-segment string diagnostics.
|
|
347
|
+
*/
|
|
348
|
+
function emitStringCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
|
|
349
|
+
const checks = schema.checks;
|
|
350
|
+
if (checks.length === 0) {
|
|
351
|
+
return `if(typeof ${value}!=="string"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_string", "string", `a(${value})`)}}`;
|
|
352
|
+
}
|
|
353
|
+
const parts = [
|
|
354
|
+
`if(typeof ${value}!=="string"){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_string", "string", `a(${value})`)}}else{`
|
|
355
|
+
];
|
|
356
|
+
for (let index = 0; index < checks.length; index += 1) {
|
|
357
|
+
const check = checks[index];
|
|
358
|
+
if (check === undefined) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
switch (check.tag) {
|
|
362
|
+
case StringCheckTag.Min:
|
|
363
|
+
parts.push(`if(${value}.length<${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_min_length", `length >= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
|
|
364
|
+
break;
|
|
365
|
+
case StringCheckTag.Max:
|
|
366
|
+
parts.push(`if(${value}.length>${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_max_length", `length <= ${String(check.value)}`, `"length "+String(${value}.length)`)}}`);
|
|
367
|
+
break;
|
|
368
|
+
case StringCheckTag.Regex:
|
|
369
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, check.regex, check.name, context));
|
|
370
|
+
break;
|
|
371
|
+
case StringCheckTag.Uuid:
|
|
372
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, UUID_PATTERN, "uuid", context));
|
|
373
|
+
break;
|
|
374
|
+
case StringCheckTag.Email:
|
|
375
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, EMAIL_PATTERN, "email", context));
|
|
376
|
+
break;
|
|
377
|
+
case StringCheckTag.Url:
|
|
378
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, URL_PATTERN, "url", context));
|
|
379
|
+
break;
|
|
380
|
+
case StringCheckTag.IsoDate:
|
|
381
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, ISO_DATE_PATTERN, "iso_date", context));
|
|
382
|
+
break;
|
|
383
|
+
case StringCheckTag.IsoDateTime:
|
|
384
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, ISO_DATETIME_PATTERN, "iso_datetime", context));
|
|
385
|
+
break;
|
|
386
|
+
case StringCheckTag.Ulid:
|
|
387
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, ULID_PATTERN, "ulid", context));
|
|
388
|
+
break;
|
|
389
|
+
case StringCheckTag.Ipv4:
|
|
390
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, IPV4_PATTERN, "ipv4", context));
|
|
391
|
+
break;
|
|
392
|
+
case StringCheckTag.Ipv6:
|
|
393
|
+
parts.push(emitPatternIssueAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, IPV6_PATTERN, "ipv6", context));
|
|
394
|
+
break;
|
|
36
395
|
}
|
|
37
396
|
}
|
|
397
|
+
parts.push("}");
|
|
38
398
|
return parts.join("");
|
|
39
399
|
}
|
|
40
400
|
/**
|
|
41
401
|
* @brief emit number check.
|
|
402
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
403
|
+
* stable across runtime and AOT emission.
|
|
404
|
+
* @param schema Number schema with scalar checks.
|
|
405
|
+
* @param value Generated expression for the candidate value.
|
|
406
|
+
* @param path Generated expression for the current diagnostic path.
|
|
407
|
+
* @param issues Generated expression for the issue buffer.
|
|
408
|
+
* @returns JavaScript source for root number diagnostics.
|
|
42
409
|
*/
|
|
43
410
|
export function emitNumberCheck(schema, value, path, issues) {
|
|
44
411
|
const parts = [
|
|
45
412
|
`if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssue(issues, path, "expected_number", "number", `a(${value})`)}return;}`
|
|
46
413
|
];
|
|
47
414
|
const checks = schema.checks;
|
|
415
|
+
/*
|
|
416
|
+
* Bounds and integer diagnostics are emitted only after the finite-number
|
|
417
|
+
* guard, so generated code never compares non-number values to bounds.
|
|
418
|
+
*/
|
|
48
419
|
for (let index = 0; index < checks.length; index += 1) {
|
|
49
420
|
const check = checks[index];
|
|
50
421
|
if (check === undefined) {
|
|
@@ -60,14 +431,210 @@ export function emitNumberCheck(schema, value, path, issues) {
|
|
|
60
431
|
case NumberCheckTag.Lte:
|
|
61
432
|
parts.push(`if(${value}>${String(check.value)}){${emitIssue(issues, path, "expected_lte", `<= ${String(check.value)}`, `String(${value})`)}}`);
|
|
62
433
|
break;
|
|
434
|
+
case NumberCheckTag.Gt:
|
|
435
|
+
parts.push(`if(${value}<=${String(check.value)}){${emitIssue(issues, path, "expected_gt", `> ${String(check.value)}`, `String(${value})`)}}`);
|
|
436
|
+
break;
|
|
437
|
+
case NumberCheckTag.Lt:
|
|
438
|
+
parts.push(`if(${value}>=${String(check.value)}){${emitIssue(issues, path, "expected_lt", `< ${String(check.value)}`, `String(${value})`)}}`);
|
|
439
|
+
break;
|
|
440
|
+
case NumberCheckTag.MultipleOf:
|
|
441
|
+
parts.push(`if(${value}%${String(check.value)}!==0){${emitIssue(issues, path, "expected_multiple_of", `multiple of ${String(check.value)}`, `String(${value})`)}}`);
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return parts.join("");
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* @brief emit number check at one appended path segment.
|
|
449
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
450
|
+
* stable across runtime and AOT emission.
|
|
451
|
+
* @param schema Number schema with scalar checks.
|
|
452
|
+
* @param value Generated expression for the candidate value.
|
|
453
|
+
* @param path Generated expression for the current diagnostic path.
|
|
454
|
+
* @param segmentExpression Generated expression for the appended path segment.
|
|
455
|
+
* @param issues Generated expression for the issue buffer.
|
|
456
|
+
* @returns JavaScript source for one-segment number diagnostics.
|
|
457
|
+
*/
|
|
458
|
+
function emitNumberCheckAtSegment(schema, value, path, segmentExpression, issues) {
|
|
459
|
+
const checks = schema.checks;
|
|
460
|
+
if (checks.length === 0) {
|
|
461
|
+
/*
|
|
462
|
+
* Plain number schemas need only the finite-number guard. Emitting an
|
|
463
|
+
* else block would add cold code with no diagnostic work.
|
|
464
|
+
*/
|
|
465
|
+
return `if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_number", "number", `a(${value})`)}}`;
|
|
466
|
+
}
|
|
467
|
+
const parts = [
|
|
468
|
+
`if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssueAtSegment(issues, path, segmentExpression, "expected_number", "number", `a(${value})`)}}else{`
|
|
469
|
+
];
|
|
470
|
+
for (let index = 0; index < checks.length; index += 1) {
|
|
471
|
+
const check = checks[index];
|
|
472
|
+
if (check === undefined) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
switch (check.tag) {
|
|
476
|
+
case NumberCheckTag.Integer:
|
|
477
|
+
parts.push(`if(!Number.isInteger(${value})){${emitIssueExprAtSegment(issues, path, segmentExpression, "expected_integer", stringLiteral("integer"), stringLiteral("number"))}}`);
|
|
478
|
+
break;
|
|
479
|
+
case NumberCheckTag.Gte:
|
|
480
|
+
parts.push(`if(${value}<${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_gte", `>= ${String(check.value)}`, `String(${value})`)}}`);
|
|
481
|
+
break;
|
|
482
|
+
case NumberCheckTag.Lte:
|
|
483
|
+
parts.push(`if(${value}>${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_lte", `<= ${String(check.value)}`, `String(${value})`)}}`);
|
|
484
|
+
break;
|
|
485
|
+
case NumberCheckTag.Gt:
|
|
486
|
+
parts.push(`if(${value}<=${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_gt", `> ${String(check.value)}`, `String(${value})`)}}`);
|
|
487
|
+
break;
|
|
488
|
+
case NumberCheckTag.Lt:
|
|
489
|
+
parts.push(`if(${value}>=${String(check.value)}){${emitIssueAtSegment(issues, path, segmentExpression, "expected_lt", `< ${String(check.value)}`, `String(${value})`)}}`);
|
|
490
|
+
break;
|
|
491
|
+
case NumberCheckTag.MultipleOf:
|
|
492
|
+
parts.push(`if(${value}%${String(check.value)}!==0){${emitIssueAtSegment(issues, path, segmentExpression, "expected_multiple_of", `multiple of ${String(check.value)}`, `String(${value})`)}}`);
|
|
493
|
+
break;
|
|
63
494
|
}
|
|
64
495
|
}
|
|
496
|
+
parts.push("}");
|
|
497
|
+
return parts.join("");
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* @brief emit number check at two appended path segments.
|
|
501
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
502
|
+
* stable across runtime and AOT emission.
|
|
503
|
+
* @param schema Number schema with scalar checks.
|
|
504
|
+
* @param value Generated expression for the candidate value.
|
|
505
|
+
* @param path Generated expression for the current diagnostic path.
|
|
506
|
+
* @param firstSegmentExpression Generated expression for the parent segment.
|
|
507
|
+
* @param secondSegmentExpression Generated expression for the child segment.
|
|
508
|
+
* @param issues Generated expression for the issue buffer.
|
|
509
|
+
* @returns JavaScript source for two-segment number diagnostics.
|
|
510
|
+
*/
|
|
511
|
+
function emitNumberCheckAtTwoSegments(schema, value, path, firstSegmentExpression, secondSegmentExpression, issues) {
|
|
512
|
+
const checks = schema.checks;
|
|
513
|
+
if (checks.length === 0) {
|
|
514
|
+
return `if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_number", "number", `a(${value})`)}}`;
|
|
515
|
+
}
|
|
516
|
+
const parts = [
|
|
517
|
+
`if(typeof ${value}!=="number"||!Number.isFinite(${value})){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_number", "number", `a(${value})`)}}else{`
|
|
518
|
+
];
|
|
519
|
+
for (let index = 0; index < checks.length; index += 1) {
|
|
520
|
+
const check = checks[index];
|
|
521
|
+
if (check === undefined) {
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
switch (check.tag) {
|
|
525
|
+
case NumberCheckTag.Integer:
|
|
526
|
+
parts.push(`if(!Number.isInteger(${value})){${emitIssueExprAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_integer", stringLiteral("integer"), stringLiteral("number"))}}`);
|
|
527
|
+
break;
|
|
528
|
+
case NumberCheckTag.Gte:
|
|
529
|
+
parts.push(`if(${value}<${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_gte", `>= ${String(check.value)}`, `String(${value})`)}}`);
|
|
530
|
+
break;
|
|
531
|
+
case NumberCheckTag.Lte:
|
|
532
|
+
parts.push(`if(${value}>${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_lte", `<= ${String(check.value)}`, `String(${value})`)}}`);
|
|
533
|
+
break;
|
|
534
|
+
case NumberCheckTag.Gt:
|
|
535
|
+
parts.push(`if(${value}<=${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_gt", `> ${String(check.value)}`, `String(${value})`)}}`);
|
|
536
|
+
break;
|
|
537
|
+
case NumberCheckTag.Lt:
|
|
538
|
+
parts.push(`if(${value}>=${String(check.value)}){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_lt", `< ${String(check.value)}`, `String(${value})`)}}`);
|
|
539
|
+
break;
|
|
540
|
+
case NumberCheckTag.MultipleOf:
|
|
541
|
+
parts.push(`if(${value}%${String(check.value)}!==0){${emitIssueAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_multiple_of", `multiple of ${String(check.value)}`, `String(${value})`)}}`);
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
parts.push("}");
|
|
65
546
|
return parts.join("");
|
|
66
547
|
}
|
|
67
548
|
/**
|
|
68
549
|
* @brief emit literal check.
|
|
550
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
551
|
+
* stable across runtime and AOT emission.
|
|
552
|
+
* @param value Literal expected by the schema.
|
|
553
|
+
* @param checked Generated expression for the candidate value.
|
|
554
|
+
* @param path Generated expression for the current diagnostic path.
|
|
555
|
+
* @param issues Generated expression for the issue buffer.
|
|
556
|
+
* @param context Shared code-generation context.
|
|
557
|
+
* @returns JavaScript source for root literal diagnostics.
|
|
69
558
|
*/
|
|
70
559
|
export function emitLiteralCheck(value, checked, path, issues, context) {
|
|
71
560
|
const index = pushLiteral(context, value);
|
|
561
|
+
/*
|
|
562
|
+
* Object.is preserves JavaScript literal edge cases such as NaN and -0.
|
|
563
|
+
* The expected value stays in the literal side table rather than source text.
|
|
564
|
+
*/
|
|
72
565
|
return `if(!Object.is(${checked},l[${String(index)}])){${emitIssueExpr(issues, path, "expected_literal", `le(l[${String(index)}])`, `a(${checked})`)}}`;
|
|
73
566
|
}
|
|
567
|
+
/**
|
|
568
|
+
* @brief emit literal check at one appended path segment.
|
|
569
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
570
|
+
* stable across runtime and AOT emission.
|
|
571
|
+
* @param value Literal expected by the schema.
|
|
572
|
+
* @param checked Generated expression for the candidate value.
|
|
573
|
+
* @param path Generated expression for the current diagnostic path.
|
|
574
|
+
* @param segmentExpression Generated expression for the appended path segment.
|
|
575
|
+
* @param issues Generated expression for the issue buffer.
|
|
576
|
+
* @param context Shared code-generation context.
|
|
577
|
+
* @returns JavaScript source for one-segment literal diagnostics.
|
|
578
|
+
*/
|
|
579
|
+
function emitLiteralCheckAtSegment(value, checked, path, segmentExpression, issues, context) {
|
|
580
|
+
const index = pushLiteral(context, value);
|
|
581
|
+
return `if(!Object.is(${checked},l[${String(index)}])){${emitIssueExprAtSegment(issues, path, segmentExpression, "expected_literal", `le(l[${String(index)}])`, `a(${checked})`)}}`;
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* @brief emit literal check at two appended path segments.
|
|
585
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
586
|
+
* stable across runtime and AOT emission.
|
|
587
|
+
* @param value Literal expected by the schema.
|
|
588
|
+
* @param checked Generated expression for the candidate value.
|
|
589
|
+
* @param path Generated expression for the current diagnostic path.
|
|
590
|
+
* @param firstSegmentExpression Generated expression for the parent segment.
|
|
591
|
+
* @param secondSegmentExpression Generated expression for the child segment.
|
|
592
|
+
* @param issues Generated expression for the issue buffer.
|
|
593
|
+
* @param context Shared code-generation context.
|
|
594
|
+
* @returns JavaScript source for two-segment literal diagnostics.
|
|
595
|
+
*/
|
|
596
|
+
function emitLiteralCheckAtTwoSegments(value, checked, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
|
|
597
|
+
const index = pushLiteral(context, value);
|
|
598
|
+
return `if(!Object.is(${checked},l[${String(index)}])){${emitIssueExprAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_literal", `le(l[${String(index)}])`, `a(${checked})`)}}`;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* @brief emit undefined literal check at one appended path segment.
|
|
602
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
603
|
+
* stable across runtime and AOT emission.
|
|
604
|
+
* @param value Literal expected by the schema.
|
|
605
|
+
* @param path Generated expression for the current diagnostic path.
|
|
606
|
+
* @param segmentExpression Generated expression for the appended path segment.
|
|
607
|
+
* @param issues Generated expression for the issue buffer.
|
|
608
|
+
* @param context Shared code-generation context.
|
|
609
|
+
* @returns Empty source when undefined is the expected literal, otherwise an issue.
|
|
610
|
+
*/
|
|
611
|
+
function emitUndefinedLiteralCheckAtSegment(value, path, segmentExpression, issues, context) {
|
|
612
|
+
if (value === undefined) {
|
|
613
|
+
/*
|
|
614
|
+
* A sparse hole has already produced the exact expected literal. There is
|
|
615
|
+
* no diagnostic work left to emit.
|
|
616
|
+
*/
|
|
617
|
+
return "";
|
|
618
|
+
}
|
|
619
|
+
const index = pushLiteral(context, value);
|
|
620
|
+
return emitIssueExprAtSegment(issues, path, segmentExpression, "expected_literal", `le(l[${String(index)}])`, stringLiteral("undefined"));
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* @brief emit undefined literal check at two appended path segments.
|
|
624
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
625
|
+
* stable across runtime and AOT emission.
|
|
626
|
+
* @param value Literal expected by the schema.
|
|
627
|
+
* @param path Generated expression for the current diagnostic path.
|
|
628
|
+
* @param firstSegmentExpression Generated expression for the parent segment.
|
|
629
|
+
* @param secondSegmentExpression Generated expression for the child segment.
|
|
630
|
+
* @param issues Generated expression for the issue buffer.
|
|
631
|
+
* @param context Shared code-generation context.
|
|
632
|
+
* @returns Empty source when undefined is the expected literal, otherwise an issue.
|
|
633
|
+
*/
|
|
634
|
+
function emitUndefinedLiteralCheckAtTwoSegments(value, path, firstSegmentExpression, secondSegmentExpression, issues, context) {
|
|
635
|
+
if (value === undefined) {
|
|
636
|
+
return "";
|
|
637
|
+
}
|
|
638
|
+
const index = pushLiteral(context, value);
|
|
639
|
+
return emitIssueExprAtTwoSegments(issues, path, firstSegmentExpression, secondSegmentExpression, "expected_literal", `le(l[${String(index)}])`, stringLiteral("undefined"));
|
|
640
|
+
}
|
package/dist/compile/check.d.ts
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file compile/check.ts
|
|
3
3
|
* @brief Diagnostic validator function table emitter.
|
|
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 type { Schema } from "../schema/index.js";
|
|
6
8
|
import type { EmitContext } from "./types.js";
|
|
7
9
|
/**
|
|
8
10
|
* @brief emit check function.
|
|
11
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
12
|
+
* stable across runtime and AOT emission.
|
|
13
|
+
* @param schema Schema whose diagnostics should be emitted.
|
|
14
|
+
* @param context Shared code-generation context.
|
|
15
|
+
* @returns Generated diagnostic function name.
|
|
16
|
+
* @invariant The same schema object maps to one diagnostic function per bundle.
|
|
9
17
|
*/
|
|
10
18
|
export declare function emitCheckFunction(schema: Schema, context: EmitContext): string;
|
|
11
19
|
/**
|
|
12
20
|
* @brief emit check functions.
|
|
21
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
22
|
+
* stable across runtime and AOT emission.
|
|
23
|
+
* @param context Shared code-generation context with accumulated check sources.
|
|
24
|
+
* @returns Concatenated JavaScript function declarations.
|
|
13
25
|
*/
|
|
14
26
|
export declare function emitCheckFunctions(context: EmitContext): string;
|
|
15
27
|
//# sourceMappingURL=check.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/compile/check.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/compile/check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAiBjD,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AAE9D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,MAAM,CAkB9E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAU/D"}
|