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,55 +1,123 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file compile-runtime.ts
|
|
3
3
|
* @brief Runtime support passed into generated validator factories.
|
|
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
|
* @section side_tables Side-table ABI
|
|
6
8
|
* Generated validators receive literals, regexps, keysets, strings, and
|
|
7
9
|
* dynamic schema fallbacks as indexed tables. The emitted source contains only
|
|
8
10
|
* numeric table slots and compact helper names.
|
|
9
11
|
*/
|
|
10
|
-
import type { Issue, PathSegment } from "../issue/index.js";
|
|
12
|
+
import type { CheckResult, Issue, PathSegment } from "../issue/index.js";
|
|
11
13
|
import type { LiteralValue, Schema } from "../schema/index.js";
|
|
12
14
|
/**
|
|
13
|
-
* @brief
|
|
15
|
+
* @brief Allocation-lean validator root generated for `is` calls.
|
|
16
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
17
|
+
* stable across runtime and AOT emission.
|
|
18
|
+
* @param value Candidate runtime value.
|
|
19
|
+
* @returns True when the generated predicate accepts the value.
|
|
14
20
|
*/
|
|
15
21
|
export type BooleanPredicate = (value: unknown) => boolean;
|
|
16
22
|
/**
|
|
17
|
-
* @brief
|
|
23
|
+
* @brief Diagnostic collector generated for `check` calls.
|
|
24
|
+
* @details Generated collectors return undefined for the successful fast path.
|
|
25
|
+
* Hand-written collectors still have to return an issue array and are validated
|
|
26
|
+
* before publication.
|
|
27
|
+
* @param value Candidate runtime value.
|
|
28
|
+
* @returns Undefined on success, otherwise the collected validation issues.
|
|
18
29
|
*/
|
|
19
|
-
export type IssueCollectorRoot = (value: unknown) => readonly Issue[];
|
|
30
|
+
export type IssueCollectorRoot = (value: unknown) => readonly Issue[] | undefined;
|
|
20
31
|
/**
|
|
21
|
-
* @brief
|
|
32
|
+
* @brief Result-producing wrapper generated beside every compiled predicate.
|
|
33
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
34
|
+
* stable across runtime and AOT emission.
|
|
35
|
+
* @param value Candidate runtime value.
|
|
36
|
+
* @returns TypeSea check result carrying the accepted value or issue list.
|
|
37
|
+
*/
|
|
38
|
+
export type CheckResultRoot = (value: unknown) => CheckResult<unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* @brief Boolean fallback for schemas that cannot be fully lowered.
|
|
41
|
+
* @details Generated code stores only a schema table index. The helper keeps
|
|
42
|
+
* recursive and user-refined branches out of the emitted source while retaining
|
|
43
|
+
* the same boolean contract as the interpreter.
|
|
44
|
+
* @param schemaIndex Slot in the side table supplied to the factory.
|
|
45
|
+
* @param value Candidate value for that schema.
|
|
46
|
+
* @returns True when the fallback schema accepts the value.
|
|
22
47
|
*/
|
|
23
48
|
export type DynamicCheck = (schemaIndex: number, value: unknown) => boolean;
|
|
24
49
|
/**
|
|
25
|
-
* @brief
|
|
50
|
+
* @brief Diagnostic fallback for non-lowered schema fragments.
|
|
51
|
+
* @details The generated collector delegates here only at opaque graph leaves.
|
|
52
|
+
* Nested issues are copied into the caller-owned buffer so the outer generated
|
|
53
|
+
* path prefix remains in control.
|
|
54
|
+
* @param schemaIndex Slot in the side table supplied to the factory.
|
|
55
|
+
* @param value Candidate value for that schema.
|
|
56
|
+
* @param path Path prefix owned by the generated collector.
|
|
57
|
+
* @param issues Mutable issue buffer owned by the caller.
|
|
26
58
|
*/
|
|
27
59
|
export type DynamicIssueCheck = (schemaIndex: number, value: unknown, path: readonly PathSegment[], issues: Issue[]) => void;
|
|
28
60
|
/**
|
|
29
|
-
* @brief strict
|
|
61
|
+
* @brief Runtime helper for strict-object excess key validation.
|
|
62
|
+
* @details Code generation can choose safe or fast property access strategies,
|
|
63
|
+
* but strict key counting remains centralized so the emitted source uses a
|
|
64
|
+
* compact ABI.
|
|
65
|
+
* @param value Candidate object.
|
|
66
|
+
* @param keys Allowed string keys for the strict schema.
|
|
67
|
+
* @returns True when no extra own string key is present.
|
|
30
68
|
*/
|
|
31
69
|
export type StrictKeysCheck = (value: unknown, keys: readonly string[]) => boolean;
|
|
32
70
|
/**
|
|
33
|
-
* @brief
|
|
71
|
+
* @brief Published validator entry points returned by a compiled factory.
|
|
72
|
+
* @details The three functions share side tables and generated helper code but
|
|
73
|
+
* expose the distinct public contracts used by Guard methods.
|
|
34
74
|
*/
|
|
35
75
|
export interface RuntimeBundle {
|
|
36
76
|
readonly is: BooleanPredicate;
|
|
37
77
|
readonly check: IssueCollectorRoot;
|
|
78
|
+
readonly result: CheckResultRoot;
|
|
38
79
|
}
|
|
39
80
|
/**
|
|
40
|
-
* @brief
|
|
81
|
+
* @brief Factory signature consumed by `new Function` compiled modules.
|
|
82
|
+
* @details Generated source is pure JavaScript text. All runtime objects that
|
|
83
|
+
* should not be serialized into source travel through these side tables, which
|
|
84
|
+
* keeps emitted code small and friendly to V8 inline caches.
|
|
85
|
+
* @param literals Literal constants referenced by emitted predicates.
|
|
86
|
+
* @param regexps Precompiled regular expressions for string constraints.
|
|
87
|
+
* @param keysets Strict-object key tables.
|
|
88
|
+
* @param strings Shared string constants used by generated diagnostics.
|
|
89
|
+
* @param dynamicCheck Boolean fallback for opaque schema fragments.
|
|
90
|
+
* @param dynamicIssueCheck Diagnostic fallback for opaque schema fragments.
|
|
91
|
+
* @param strictKeys Shared strict-object excess key helper.
|
|
92
|
+
* @returns Runtime bundle exposed by the compiled guard.
|
|
41
93
|
*/
|
|
42
94
|
export type IsFactory = (literals: readonly LiteralValue[], regexps: readonly RegExp[], keysets: readonly (readonly string[])[], strings: readonly string[], dynamicCheck: DynamicCheck, dynamicIssueCheck: DynamicIssueCheck, strictKeys: StrictKeysCheck) => RuntimeBundle;
|
|
43
95
|
/**
|
|
44
|
-
* @brief
|
|
96
|
+
* @brief Build the boolean fallback table reader for generated validators.
|
|
97
|
+
* @details Missing table slots fail closed. That preserves the security
|
|
98
|
+
* invariant that malformed generated code cannot accidentally accept a value by
|
|
99
|
+
* indexing outside the schema side table.
|
|
100
|
+
* @param schemas Schema side table captured by the compiled guard.
|
|
101
|
+
* @returns Boolean fallback callback used by emitted predicates.
|
|
45
102
|
*/
|
|
46
103
|
export declare function makeDynamicCheck(schemas: readonly Schema[]): DynamicCheck;
|
|
47
104
|
/**
|
|
48
|
-
* @brief
|
|
105
|
+
* @brief Build the diagnostic fallback table reader for generated validators.
|
|
106
|
+
* @details Nested interpreter issues are re-rooted under the path supplied by
|
|
107
|
+
* generated code. This lets compiled object and array checks delegate complex
|
|
108
|
+
* children without losing exact issue locations.
|
|
109
|
+
* @param schemas Schema side table captured by the compiled guard.
|
|
110
|
+
* @returns Issue fallback callback used by emitted collectors.
|
|
49
111
|
*/
|
|
50
112
|
export declare function makeDynamicIssueCheck(schemas: readonly Schema[]): DynamicIssueCheck;
|
|
51
113
|
/**
|
|
52
|
-
* @brief strict
|
|
114
|
+
* @brief Safe strict-object key membership helper for generated validators.
|
|
115
|
+
* @details The default compiled mode uses Reflect.ownKeys so symbol and
|
|
116
|
+
* non-enumerable extras are rejected as strictly as the interpreter. Unsafe
|
|
117
|
+
* modes may emit a cheaper loop, but this helper remains the conservative ABI.
|
|
118
|
+
* @param value Candidate object value.
|
|
119
|
+
* @param keys Allowed string keys for the strict object schema.
|
|
120
|
+
* @returns True when every own key belongs to the schema key set.
|
|
53
121
|
*/
|
|
54
122
|
export declare function strictKeys(value: unknown, keys: readonly string[]): boolean;
|
|
55
123
|
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/compile/runtime.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/compile/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;AAElF;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,WAAW,CAAC,OAAO,CAAC,CAAC;AAEvE;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAE5E;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC5B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,MAAM,EAAE,KAAK,EAAE,KACd,IAAI,CAAC;AAEV;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,CAC1B,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,MAAM,EAAE,KACtB,OAAO,CAAC;AAEb;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,EAAE,EAAE,gBAAgB,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,SAAS,GAAG,CACpB,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EACvC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,YAAY,EAAE,YAAY,EAC1B,iBAAiB,EAAE,iBAAiB,EACpC,UAAU,EAAE,eAAe,KAC1B,aAAa,CAAC;AAEnB;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAKzE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACjC,OAAO,EAAE,SAAS,MAAM,EAAE,GAC3B,iBAAiB,CA8BnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACtB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,SAAS,MAAM,EAAE,GACxB,OAAO,CAYT"}
|
package/dist/compile/runtime.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file compile-runtime.ts
|
|
3
3
|
* @brief Runtime support passed into generated validator factories.
|
|
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
|
* @section side_tables Side-table ABI
|
|
6
8
|
* Generated validators receive literals, regexps, keysets, strings, and
|
|
@@ -9,7 +11,12 @@
|
|
|
9
11
|
*/
|
|
10
12
|
import { checkSchema, isSchema } from "../evaluate/index.js";
|
|
11
13
|
/**
|
|
12
|
-
* @brief
|
|
14
|
+
* @brief Build the boolean fallback table reader for generated validators.
|
|
15
|
+
* @details Missing table slots fail closed. That preserves the security
|
|
16
|
+
* invariant that malformed generated code cannot accidentally accept a value by
|
|
17
|
+
* indexing outside the schema side table.
|
|
18
|
+
* @param schemas Schema side table captured by the compiled guard.
|
|
19
|
+
* @returns Boolean fallback callback used by emitted predicates.
|
|
13
20
|
*/
|
|
14
21
|
export function makeDynamicCheck(schemas) {
|
|
15
22
|
return (schemaIndex, value) => {
|
|
@@ -18,7 +25,12 @@ export function makeDynamicCheck(schemas) {
|
|
|
18
25
|
};
|
|
19
26
|
}
|
|
20
27
|
/**
|
|
21
|
-
* @brief
|
|
28
|
+
* @brief Build the diagnostic fallback table reader for generated validators.
|
|
29
|
+
* @details Nested interpreter issues are re-rooted under the path supplied by
|
|
30
|
+
* generated code. This lets compiled object and array checks delegate complex
|
|
31
|
+
* children without losing exact issue locations.
|
|
32
|
+
* @param schemas Schema side table captured by the compiled guard.
|
|
33
|
+
* @returns Issue fallback callback used by emitted collectors.
|
|
22
34
|
*/
|
|
23
35
|
export function makeDynamicIssueCheck(schemas) {
|
|
24
36
|
return (schemaIndex, value, path, issues) => {
|
|
@@ -34,19 +46,26 @@ export function makeDynamicIssueCheck(schemas) {
|
|
|
34
46
|
for (let index = 0; index < nested.length; index += 1) {
|
|
35
47
|
const issue = nested[index];
|
|
36
48
|
if (issue !== undefined) {
|
|
37
|
-
|
|
38
|
-
|
|
49
|
+
const nestedPath = Object.freeze(path.concat(issue.path));
|
|
50
|
+
issues.push(Object.freeze({
|
|
51
|
+
path: nestedPath,
|
|
39
52
|
code: issue.code,
|
|
40
53
|
expected: issue.expected,
|
|
41
54
|
actual: issue.actual,
|
|
42
55
|
message: issue.message
|
|
43
|
-
});
|
|
56
|
+
}));
|
|
44
57
|
}
|
|
45
58
|
}
|
|
46
59
|
};
|
|
47
60
|
}
|
|
48
61
|
/**
|
|
49
|
-
* @brief strict
|
|
62
|
+
* @brief Safe strict-object key membership helper for generated validators.
|
|
63
|
+
* @details The default compiled mode uses Reflect.ownKeys so symbol and
|
|
64
|
+
* non-enumerable extras are rejected as strictly as the interpreter. Unsafe
|
|
65
|
+
* modes may emit a cheaper loop, but this helper remains the conservative ABI.
|
|
66
|
+
* @param value Candidate object value.
|
|
67
|
+
* @param keys Allowed string keys for the strict object schema.
|
|
68
|
+
* @returns True when every own key belongs to the schema key set.
|
|
50
69
|
*/
|
|
51
70
|
export function strictKeys(value, keys) {
|
|
52
71
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
package/dist/compile/source.d.ts
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file compile/source.ts
|
|
3
3
|
* @brief Generated validator source bundle assembly.
|
|
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
|
-
import type { CompiledSourceBundle } from "./types.js";
|
|
8
|
+
import type { CompileMode, CompiledSourceBundle } from "./types.js";
|
|
7
9
|
/**
|
|
8
10
|
* @brief emit compiled source bundle.
|
|
11
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
12
|
+
* stable across runtime and AOT emission.
|
|
13
|
+
* @param schema Root schema to compile.
|
|
14
|
+
* @param name Requested public function name.
|
|
15
|
+
* @param mode Compile mode controlling safety and allocation tradeoffs.
|
|
16
|
+
* @returns Generated source plus side tables consumed by the runtime factory.
|
|
9
17
|
*/
|
|
10
|
-
export declare function emitCompiledSourceBundle(schema: Schema, name: string): CompiledSourceBundle;
|
|
18
|
+
export declare function emitCompiledSourceBundle(schema: Schema, name: string, mode?: CompileMode): CompiledSourceBundle;
|
|
11
19
|
//# sourceMappingURL=source.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/compile/source.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/compile/source.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAKjD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,WAAoB,GAC3B,oBAAoB,CA+CtB"}
|
package/dist/compile/source.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file compile/source.ts
|
|
3
3
|
* @brief Generated validator source bundle assembly.
|
|
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 { emitCheckFunction, emitCheckFunctions } from "./check.js";
|
|
6
8
|
import { createEmitContext } from "./context.js";
|
|
@@ -8,37 +10,47 @@ import { emitGraphFunction, emitGraphFunctions } from "./graph-predicate.js";
|
|
|
8
10
|
import { safeFunctionName } from "./names.js";
|
|
9
11
|
/**
|
|
10
12
|
* @brief emit compiled source bundle.
|
|
13
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
14
|
+
* stable across runtime and AOT emission.
|
|
15
|
+
* @param schema Root schema to compile.
|
|
16
|
+
* @param name Requested public function name.
|
|
17
|
+
* @param mode Compile mode controlling safety and allocation tradeoffs.
|
|
18
|
+
* @returns Generated source plus side tables consumed by the runtime factory.
|
|
11
19
|
*/
|
|
12
|
-
export function emitCompiledSourceBundle(schema, name) {
|
|
13
|
-
const context = createEmitContext();
|
|
14
|
-
const root = emitGraphFunction(schema, context);
|
|
15
|
-
const checkRoot = emitCheckFunction(schema, context);
|
|
20
|
+
export function emitCompiledSourceBundle(schema, name, mode = "safe") {
|
|
21
|
+
const context = createEmitContext(mode);
|
|
16
22
|
const functionName = safeFunctionName(name);
|
|
23
|
+
const directRoot = canUseDirectRootFunctionName(functionName);
|
|
24
|
+
/*
|
|
25
|
+
* A direct root function gives V8 a stable, named hot predicate. Names that
|
|
26
|
+
* collide with helper or generated ids are wrapped to avoid shadowing.
|
|
27
|
+
*/
|
|
28
|
+
const root = emitGraphFunction(schema, context, directRoot ? functionName : undefined);
|
|
29
|
+
const checkRoot = emitCheckFunction(schema, context);
|
|
17
30
|
const checkFunctionName = `${functionName}_check`;
|
|
31
|
+
const resultFunctionName = `${functionName}_result`;
|
|
32
|
+
const isProperty = directRoot
|
|
33
|
+
? `is:${root}`
|
|
34
|
+
: `is:function ${functionName}(x){return ${root}(x);}`;
|
|
35
|
+
const graphFunctions = emitGraphFunctions(context);
|
|
36
|
+
const checkFunctions = emitCheckFunctions(context);
|
|
37
|
+
const rootPathIsFrozen = canReuseFrozenRootPath(checkFunctions);
|
|
38
|
+
const rootPath = rootPathIsFrozen ? "z" : "[]";
|
|
39
|
+
/*
|
|
40
|
+
* Boolean is() owns the hot path; check()/result() first reuse it so valid
|
|
41
|
+
* data avoids diagnostic allocation. Only failing inputs enter the check tree.
|
|
42
|
+
*/
|
|
43
|
+
const issueCollector = `check:function ${checkFunctionName}(x){if(${root}(x))return;const s=[];${checkRoot}(x,${rootPath},s);return s;}`;
|
|
44
|
+
const resultCollector = `result:function ${resultFunctionName}(x){if(${root}(x))return ${emitSuccessResult(mode, "x")};const s=[];${checkRoot}(x,${rootPath},s);return Object.freeze({ok:false,error:Object.freeze(s)});}`;
|
|
45
|
+
const body = [
|
|
46
|
+
graphFunctions,
|
|
47
|
+
checkFunctions,
|
|
48
|
+
`return {${isProperty},${issueCollector},${resultCollector}};`
|
|
49
|
+
].join("");
|
|
18
50
|
const source = [
|
|
19
51
|
"\"use strict\";",
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"const o=function(v){return typeof v===\"object\"&&v!==null&&!Array.isArray(v);};",
|
|
23
|
-
"const ph=function(v){return (typeof v===\"object\"&&v!==null)||typeof v===\"function\";};",
|
|
24
|
-
"const g=function(v,k){const d=gp(v,k);return d!==undefined&&h.call(d,\"value\")?d:undefined;};",
|
|
25
|
-
"const gv=function(v,k){if(!ph(v))return undefined;const d=gp(v,k);return d!==undefined&&h.call(d,\"value\")?d.value:undefined;};",
|
|
26
|
-
"const ho=function(v,k){return ph(v)&&h.call(v,k);};",
|
|
27
|
-
"const hd=function(v,k){if(!ph(v))return false;const d=gp(v,k);return d!==undefined&&h.call(d,\"value\");};",
|
|
28
|
-
"const fn=function(v){return typeof v===\"number\"&&Number.isFinite(v);};",
|
|
29
|
-
"const nc=function(x,y,gte){return typeof x===\"number\"&&typeof y===\"number\"&&(gte?x>=y:x<=y);};",
|
|
30
|
-
"const sb=function(v,b,min){return typeof v===\"string\"&&(min?v.length>=b:v.length<=b);};",
|
|
31
|
-
"const rx=function(v,re){if(typeof v!==\"string\")return false;re.lastIndex=0;const ok=re.test(v);re.lastIndex=0;return ok;};",
|
|
32
|
-
"const ea=function(v,f){if(!Array.isArray(v))return false;for(let i=0;i<v.length;i+=1){const d=gp(v,i);if(d!==undefined&&!h.call(d,\"value\"))return false;if(!f(d===undefined?undefined:d.value))return false;}return true;};",
|
|
33
|
-
"const ev=function(v,i,f){const d=gp(v,i);if(d!==undefined&&!h.call(d,\"value\"))return false;return f(d===undefined?undefined:d.value);};",
|
|
34
|
-
"const er=function(v,f){if(!o(v))return false;const ks=Object.keys(v);for(let i=0;i<ks.length;i+=1){const key=ks[i];if(key===undefined)return false;const d=gp(v,key);if(d===undefined||!h.call(d,\"value\")||!f(d.value))return false;}return true;};",
|
|
35
|
-
"const dj=function(v,key,ks){if(!o(v))return false;const d=g(v,key);if(d===undefined||typeof d.value!==\"string\")return false;const i=ks.indexOf(d.value);return i>=0&&arguments[i+3](v);};",
|
|
36
|
-
"const a=function(v){if(v===null)return \"null\";if(Array.isArray(v))return \"array\";if(typeof v===\"bigint\")return \"bigint\";if(typeof v===\"symbol\")return \"symbol\";if(typeof v===\"number\"&&Number.isNaN(v))return \"nan\";return typeof v;};",
|
|
37
|
-
"const le=function(v){if(v===null)return \"null\";if(v===undefined)return \"undefined\";if(typeof v===\"string\")return JSON.stringify(v);if(typeof v===\"number\"&&Object.is(v,-0))return \"-0\";if(typeof v===\"symbol\")return String(v);return String(v);};",
|
|
38
|
-
"const q=function(s,p,c,e,x){s.push({path:p.slice(),code:c,expected:e,actual:x,message:undefined});};",
|
|
39
|
-
emitGraphFunctions(context),
|
|
40
|
-
emitCheckFunctions(context),
|
|
41
|
-
`return {is:function ${functionName}(x){return ${root}(x);},check:function ${checkFunctionName}(x){const s=[];if(${root}(x))return s;${checkRoot}(x,[],s);return s;}};`
|
|
52
|
+
emitHelperPrelude(body, rootPathIsFrozen),
|
|
53
|
+
body
|
|
42
54
|
].join("");
|
|
43
55
|
return {
|
|
44
56
|
source,
|
|
@@ -49,3 +61,326 @@ export function emitCompiledSourceBundle(schema, name) {
|
|
|
49
61
|
dynamicSchemas: context.schemas
|
|
50
62
|
};
|
|
51
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* @brief Emit the success Result expression for compiled result().
|
|
66
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
67
|
+
* stable across runtime and AOT emission.
|
|
68
|
+
* @param mode Compile mode controlling object freezing.
|
|
69
|
+
* @param value Generated expression for the accepted runtime value.
|
|
70
|
+
* @returns JavaScript source for the success branch.
|
|
71
|
+
*/
|
|
72
|
+
function emitSuccessResult(mode, value) {
|
|
73
|
+
if (mode === "safe") {
|
|
74
|
+
return `Object.freeze({ok:true,value:${value}})`;
|
|
75
|
+
}
|
|
76
|
+
return `{ok:true,value:${value}}`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @brief Decide whether the root predicate can use the public function name.
|
|
80
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
81
|
+
* stable across runtime and AOT emission.
|
|
82
|
+
* @param name Sanitized generated function name.
|
|
83
|
+
* @returns True when the name cannot shadow helpers or generated child ids.
|
|
84
|
+
*/
|
|
85
|
+
function canUseDirectRootFunctionName(name) {
|
|
86
|
+
return !isRuntimeHelperName(name) &&
|
|
87
|
+
!isFactoryParameterName(name) &&
|
|
88
|
+
!isGeneratedFunctionName(name);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* @brief Decide whether the generated check tree mutates the path stack.
|
|
92
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
93
|
+
* stable across runtime and AOT emission.
|
|
94
|
+
* @param checkFunctions Generated diagnostic function source.
|
|
95
|
+
* @returns True when the frozen empty path singleton can be reused.
|
|
96
|
+
*/
|
|
97
|
+
function canReuseFrozenRootPath(checkFunctions) {
|
|
98
|
+
return !checkFunctions.includes("p.push(");
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* @brief Test whether a name is a generated factory parameter.
|
|
102
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
103
|
+
* stable across runtime and AOT emission.
|
|
104
|
+
* @param name Candidate identifier.
|
|
105
|
+
* @returns True when the name would shadow a factory side table.
|
|
106
|
+
*/
|
|
107
|
+
function isFactoryParameterName(name) {
|
|
108
|
+
switch (name) {
|
|
109
|
+
case "l":
|
|
110
|
+
case "r":
|
|
111
|
+
case "k":
|
|
112
|
+
case "u":
|
|
113
|
+
case "d":
|
|
114
|
+
case "m":
|
|
115
|
+
case "sk":
|
|
116
|
+
case "w":
|
|
117
|
+
return true;
|
|
118
|
+
default:
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* @brief Test whether a name matches TypeSea child function naming.
|
|
124
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
125
|
+
* stable across runtime and AOT emission.
|
|
126
|
+
* @param name Candidate identifier.
|
|
127
|
+
* @returns True for generated predicate/check names such as `p0` or `c12`.
|
|
128
|
+
*/
|
|
129
|
+
function isGeneratedFunctionName(name) {
|
|
130
|
+
if (name.length < 2) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
const first = name.charCodeAt(0);
|
|
134
|
+
if (first !== 99 && first !== 112) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
for (let index = 1; index < name.length; index += 1) {
|
|
138
|
+
const code = name.charCodeAt(index);
|
|
139
|
+
if (code < 48 || code > 57) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* @brief emit helper prelude.
|
|
147
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
148
|
+
* stable across runtime and AOT emission.
|
|
149
|
+
* @param body Generated factory body without helper definitions.
|
|
150
|
+
* @param rootPathIsFrozen True when path helpers may use the frozen empty path.
|
|
151
|
+
* @returns JavaScript source for only the helpers referenced by `body`.
|
|
152
|
+
*/
|
|
153
|
+
function emitHelperPrelude(body, rootPathIsFrozen) {
|
|
154
|
+
const needed = readNeededHelpers(body);
|
|
155
|
+
const chunks = [];
|
|
156
|
+
pushHelper(chunks, needed, "z", "const z=Object.freeze([]);");
|
|
157
|
+
pushHelper(chunks, needed, "h", "const h=Object.prototype.hasOwnProperty;");
|
|
158
|
+
pushHelper(chunks, needed, "gp", "const gp=Object.getOwnPropertyDescriptor;");
|
|
159
|
+
pushHelper(chunks, needed, "o", "const o=function(v){return typeof v===\"object\"&&v!==null&&!Array.isArray(v);};");
|
|
160
|
+
pushHelper(chunks, needed, "ph", "const ph=function(v){return (typeof v===\"object\"&&v!==null)||typeof v===\"function\";};");
|
|
161
|
+
pushHelper(chunks, needed, "g", "const g=function(v,k){const d=gp(v,k);return d!==undefined&&h.call(d,\"value\")?d:undefined;};");
|
|
162
|
+
pushHelper(chunks, needed, "gv", "const gv=function(v,k){if(!ph(v))return undefined;const d=gp(v,k);return d!==undefined&&h.call(d,\"value\")?d.value:undefined;};");
|
|
163
|
+
pushHelper(chunks, needed, "ho", "const ho=function(v,k){return ph(v)&&h.call(v,k);};");
|
|
164
|
+
pushHelper(chunks, needed, "hd", "const hd=function(v,k){if(!ph(v))return false;const d=gp(v,k);return d!==undefined&&h.call(d,\"value\");};");
|
|
165
|
+
pushHelper(chunks, needed, "fn", "const fn=function(v){return typeof v===\"number\"&&Number.isFinite(v);};");
|
|
166
|
+
pushHelper(chunks, needed, "nc", "const nc=function(x,y,gte){return typeof x===\"number\"&&typeof y===\"number\"&&(gte?x>=y:x<=y);};");
|
|
167
|
+
pushHelper(chunks, needed, "sb", "const sb=function(v,b,min){return typeof v===\"string\"&&(min?v.length>=b:v.length<=b);};");
|
|
168
|
+
pushHelper(chunks, needed, "rx", "const rx=function(v,re){if(typeof v!==\"string\")return false;re.lastIndex=0;const ok=re.test(v);re.lastIndex=0;return ok;};");
|
|
169
|
+
pushHelper(chunks, needed, "ai", "const ai=function(k,n){if(k.length===0||k===\"length\")return false;const i=Number(k);return Number.isInteger(i)&&i>=0&&i<=4294967294&&i<n&&String(i)===k;};");
|
|
170
|
+
pushHelper(chunks, needed, "ea", "const ea=function(v,f){if(!Array.isArray(v))return false;for(let i=0;i<v.length;i+=1){const d=gp(v,i);if(d!==undefined&&!h.call(d,\"value\"))return false;if(!f(d===undefined?undefined:d.value))return false;}return true;};");
|
|
171
|
+
pushHelper(chunks, needed, "eu", "const eu=function(v,f){if(!Array.isArray(v))return false;const xs=Object.getOwnPropertyNames(v);for(let i=0;i<xs.length;i+=1){const k=xs[i];if(!ai(k,v.length))continue;const d=gp(v,k);if(d!==undefined&&!h.call(d,\"value\"))return false;if(d!==undefined&&!f(d.value))return false;}return true;};");
|
|
172
|
+
pushHelper(chunks, needed, "ev", "const ev=function(v,i,f){const d=gp(v,i);if(d!==undefined&&!h.call(d,\"value\"))return false;return f(d===undefined?undefined:d.value);};");
|
|
173
|
+
pushHelper(chunks, needed, "er", "const er=function(v,f){if(!o(v))return false;for(const key in v){if(!h.call(v,key))continue;const d=gp(v,key);if(d===undefined||!h.call(d,\"value\")||!f(d.value))return false;}return true;};");
|
|
174
|
+
pushHelper(chunks, needed, "dj", "const dj=function(v,key,ks){if(!o(v))return false;const d=g(v,key);if(d===undefined||typeof d.value!==\"string\")return false;const i=ks.indexOf(d.value);return i>=0&&arguments[i+3](v);};");
|
|
175
|
+
pushHelper(chunks, needed, "a", "const a=function(v){if(v===null)return \"null\";if(Array.isArray(v))return \"array\";if(typeof v===\"bigint\")return \"bigint\";if(typeof v===\"symbol\")return \"symbol\";if(typeof v===\"number\"&&Number.isNaN(v))return \"nan\";return typeof v;};");
|
|
176
|
+
pushHelper(chunks, needed, "le", "const le=function(v){if(v===null)return \"null\";if(v===undefined)return \"undefined\";if(typeof v===\"string\")return JSON.stringify(v);if(typeof v===\"number\"&&Object.is(v,-0))return \"-0\";if(typeof v===\"symbol\")return String(v);return String(v);};");
|
|
177
|
+
pushHelper(chunks, needed, "w", "const w=function(){const x=new Array(u.length);for(let i=0;i<u.length;i+=1)x[i]=Object.freeze([u[i]]);return x;}();");
|
|
178
|
+
pushHelper(chunks, needed, "q", rootPathIsFrozen
|
|
179
|
+
? "const q=function(s,p,c,e,x){s.push(Object.freeze({path:z,code:c,expected:e,actual:x,message:undefined}));};"
|
|
180
|
+
: "const q=function(s,p,c,e,x){const y=p.length===0?z:Object.freeze(p.slice());s.push(Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined}));};");
|
|
181
|
+
pushHelper(chunks, needed, "q1", rootPathIsFrozen
|
|
182
|
+
? "const q1=function(s,p,k,c,e,x){s.push(Object.freeze({path:Object.freeze([k]),code:c,expected:e,actual:x,message:undefined}));};"
|
|
183
|
+
: "const q1=function(s,p,k,c,e,x){const n=p.length;const y=n===0?[k]:p.slice();if(n!==0)y.push(k);Object.freeze(y);s.push(Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined}));};");
|
|
184
|
+
pushHelper(chunks, needed, "q1s", rootPathIsFrozen
|
|
185
|
+
? "const q1s=function(s,p,i,c,e,x){s.push(Object.freeze({path:w[i],code:c,expected:e,actual:x,message:undefined}));};"
|
|
186
|
+
: "const q1s=function(s,p,i,c,e,x){const n=p.length;if(n===0){s.push(Object.freeze({path:w[i],code:c,expected:e,actual:x,message:undefined}));return;}const y=p.slice();y.push(u[i]);Object.freeze(y);s.push(Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined}));};");
|
|
187
|
+
pushHelper(chunks, needed, "q2", rootPathIsFrozen
|
|
188
|
+
? "const q2=function(s,p,a,b,c,e,x){s.push(Object.freeze({path:Object.freeze([a,b]),code:c,expected:e,actual:x,message:undefined}));};"
|
|
189
|
+
: "const q2=function(s,p,a,b,c,e,x){const n=p.length;const y=n===0?[a,b]:p.slice();if(n!==0){y.push(a);y.push(b);}Object.freeze(y);s.push(Object.freeze({path:y,code:c,expected:e,actual:x,message:undefined}));};");
|
|
190
|
+
return chunks.join("");
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* @brief Append one helper definition when referenced by generated code.
|
|
194
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
195
|
+
* stable across runtime and AOT emission.
|
|
196
|
+
* @param chunks Mutable helper source list.
|
|
197
|
+
* @param needed Helper names discovered in generated function bodies.
|
|
198
|
+
* @param name Helper identifier.
|
|
199
|
+
* @param source Helper source text.
|
|
200
|
+
*/
|
|
201
|
+
function pushHelper(chunks, needed, name, source) {
|
|
202
|
+
if (needed.has(name)) {
|
|
203
|
+
chunks.push(source);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* @brief Discover runtime helpers referenced by generated validator bodies.
|
|
208
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
209
|
+
* stable across runtime and AOT emission.
|
|
210
|
+
* @param body Generated factory body without helper definitions.
|
|
211
|
+
* @returns Closed helper-name set including transitive helper dependencies.
|
|
212
|
+
*/
|
|
213
|
+
function readNeededHelpers(body) {
|
|
214
|
+
const needed = new Set();
|
|
215
|
+
markCalledHelpers(body, needed);
|
|
216
|
+
closeHelperDependencies(needed);
|
|
217
|
+
return needed;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* @brief Scan generated source for helper calls without allocating RegExp objects.
|
|
221
|
+
* @details Helper names are intentionally short. Scanning by identifier prevents
|
|
222
|
+
* false positives such as the `o(` suffix in a user function named `foo`.
|
|
223
|
+
* @param body Generated factory body without helper definitions.
|
|
224
|
+
* @param needed Mutable helper-name set.
|
|
225
|
+
*/
|
|
226
|
+
function markCalledHelpers(body, needed) {
|
|
227
|
+
let index = 0;
|
|
228
|
+
while (index < body.length) {
|
|
229
|
+
const code = body.charCodeAt(index);
|
|
230
|
+
if (!isIdentifierStartCode(code)) {
|
|
231
|
+
index += 1;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const start = index;
|
|
235
|
+
index += 1;
|
|
236
|
+
while (index < body.length && isIdentifierPartCode(body.charCodeAt(index))) {
|
|
237
|
+
index += 1;
|
|
238
|
+
}
|
|
239
|
+
const name = body.slice(start, index);
|
|
240
|
+
if (name === "z") {
|
|
241
|
+
/*
|
|
242
|
+
* The frozen empty path is referenced as a value, not a call. It gets
|
|
243
|
+
* special handling because the call scanner would otherwise miss it.
|
|
244
|
+
*/
|
|
245
|
+
needed.add("z");
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (!isRuntimeHelperName(name) || isFunctionNamePosition(body, start)) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (body.charCodeAt(index) === 40) {
|
|
252
|
+
needed.add(name);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (name === "h" && body.startsWith(".call(", index)) {
|
|
256
|
+
/*
|
|
257
|
+
* hasOwnProperty is used through h.call(...). This is still a helper
|
|
258
|
+
* dependency even though it is not written as h(...).
|
|
259
|
+
*/
|
|
260
|
+
needed.add("h");
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* @brief close helper dependencies.
|
|
266
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
267
|
+
* stable across runtime and AOT emission.
|
|
268
|
+
* @param needed Mutable helper-name set.
|
|
269
|
+
* @post Every helper required by another helper has been inserted.
|
|
270
|
+
*/
|
|
271
|
+
function closeHelperDependencies(needed) {
|
|
272
|
+
let changed = true;
|
|
273
|
+
while (changed) {
|
|
274
|
+
changed = false;
|
|
275
|
+
changed = addDependencies(needed, "g", ["gp", "h"]) || changed;
|
|
276
|
+
changed = addDependencies(needed, "gv", ["ph", "gp", "h"]) || changed;
|
|
277
|
+
changed = addDependencies(needed, "ho", ["ph", "h"]) || changed;
|
|
278
|
+
changed = addDependencies(needed, "hd", ["ph", "gp", "h"]) || changed;
|
|
279
|
+
changed = addDependencies(needed, "ea", ["gp", "h"]) || changed;
|
|
280
|
+
changed = addDependencies(needed, "eu", ["ai", "gp", "h"]) || changed;
|
|
281
|
+
changed = addDependencies(needed, "ev", ["gp", "h"]) || changed;
|
|
282
|
+
changed = addDependencies(needed, "er", ["o", "gp", "h"]) || changed;
|
|
283
|
+
changed = addDependencies(needed, "dj", ["o", "g"]) || changed;
|
|
284
|
+
changed = addDependencies(needed, "q", ["z"]) || changed;
|
|
285
|
+
changed = addDependencies(needed, "q1s", ["w"]) || changed;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* @brief add dependencies.
|
|
290
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
291
|
+
* stable across runtime and AOT emission.
|
|
292
|
+
* @param needed Mutable helper-name set.
|
|
293
|
+
* @param name Helper whose dependencies should be inserted.
|
|
294
|
+
* @param dependencies Helper names required by `name`.
|
|
295
|
+
* @returns True when the set changed.
|
|
296
|
+
*/
|
|
297
|
+
function addDependencies(needed, name, dependencies) {
|
|
298
|
+
if (!needed.has(name)) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
let changed = false;
|
|
302
|
+
for (let index = 0; index < dependencies.length; index += 1) {
|
|
303
|
+
const dependency = dependencies[index];
|
|
304
|
+
if (dependency !== undefined && !needed.has(dependency)) {
|
|
305
|
+
needed.add(dependency);
|
|
306
|
+
changed = true;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return changed;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* @brief Test whether an identifier is a generated runtime helper.
|
|
313
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
314
|
+
* stable across runtime and AOT emission.
|
|
315
|
+
* @param name Candidate identifier.
|
|
316
|
+
* @returns True when `name` is reserved for helper prelude emission.
|
|
317
|
+
*/
|
|
318
|
+
function isRuntimeHelperName(name) {
|
|
319
|
+
switch (name) {
|
|
320
|
+
case "h":
|
|
321
|
+
case "z":
|
|
322
|
+
case "gp":
|
|
323
|
+
case "o":
|
|
324
|
+
case "ph":
|
|
325
|
+
case "g":
|
|
326
|
+
case "gv":
|
|
327
|
+
case "ho":
|
|
328
|
+
case "hd":
|
|
329
|
+
case "fn":
|
|
330
|
+
case "nc":
|
|
331
|
+
case "sb":
|
|
332
|
+
case "rx":
|
|
333
|
+
case "ai":
|
|
334
|
+
case "ea":
|
|
335
|
+
case "eu":
|
|
336
|
+
case "ev":
|
|
337
|
+
case "er":
|
|
338
|
+
case "dj":
|
|
339
|
+
case "a":
|
|
340
|
+
case "le":
|
|
341
|
+
case "w":
|
|
342
|
+
case "q":
|
|
343
|
+
case "q1":
|
|
344
|
+
case "q1s":
|
|
345
|
+
case "q2":
|
|
346
|
+
return true;
|
|
347
|
+
default:
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* @brief Test whether an identifier occurrence is a function declaration name.
|
|
353
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
354
|
+
* stable across runtime and AOT emission.
|
|
355
|
+
* @param source Full generated source being scanned.
|
|
356
|
+
* @param start Start offset of the identifier.
|
|
357
|
+
* @returns True when the identifier follows `function `.
|
|
358
|
+
*/
|
|
359
|
+
function isFunctionNamePosition(source, start) {
|
|
360
|
+
const prefix = "function ";
|
|
361
|
+
return start >= prefix.length &&
|
|
362
|
+
source.slice(start - prefix.length, start) === prefix;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* @brief Test ASCII identifier-start characters used by generated code.
|
|
366
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
367
|
+
* stable across runtime and AOT emission.
|
|
368
|
+
* @param code Character code under inspection.
|
|
369
|
+
* @returns True for `$`, `_`, and ASCII letters.
|
|
370
|
+
*/
|
|
371
|
+
function isIdentifierStartCode(code) {
|
|
372
|
+
return code === 36 ||
|
|
373
|
+
code === 95 ||
|
|
374
|
+
(code >= 65 && code <= 90) ||
|
|
375
|
+
(code >= 97 && code <= 122);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* @brief Test ASCII identifier-part characters used by generated code.
|
|
379
|
+
* @details Generated-source helpers keep the side-table ABI and JavaScript source shape
|
|
380
|
+
* stable across runtime and AOT emission.
|
|
381
|
+
* @param code Character code under inspection.
|
|
382
|
+
* @returns True for identifier-start characters and digits.
|
|
383
|
+
*/
|
|
384
|
+
function isIdentifierPartCode(code) {
|
|
385
|
+
return isIdentifierStartCode(code) || (code >= 48 && code <= 57);
|
|
386
|
+
}
|