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
package/dist/schema/validate.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file schema/validate.ts
|
|
3
3
|
* @brief Runtime validators for direct schema objects.
|
|
4
|
+
* @details Schema helpers enforce construction-time invariants before values reach
|
|
5
|
+
* validation, compilation, or export.
|
|
4
6
|
*/
|
|
5
7
|
import { NumberCheckTag, ObjectModeTag, PresenceTag, SchemaTag, StringCheckTag } from "../kind/index.js";
|
|
6
8
|
import { isLiteralValue } from "./literal.js";
|
|
7
|
-
import { includesString, isObjectKeyLookup, isPlainRegExp, isRecord, isStringArray, isUnknownArray } from "./common.js";
|
|
9
|
+
import { includesString, isMissingDataProperty, isObjectKeyLookup, isPlainRegExp, isRecord, isStringArray, isUnknownArray, readOwnDataProperty } from "./common.js";
|
|
8
10
|
/**
|
|
9
|
-
* @brief
|
|
11
|
+
* @brief Validate an unknown value as a TypeSea schema tree.
|
|
12
|
+
* @param value Candidate schema object from a public boundary.
|
|
13
|
+
* @returns True when the complete tree satisfies the internal schema layout.
|
|
14
|
+
* @details This routine is intentionally stricter than normal JavaScript object
|
|
15
|
+
* access: every record and vector must be data-only so later consumers can read
|
|
16
|
+
* fields without invoking user code.
|
|
10
17
|
*/
|
|
11
18
|
export function isSchemaValue(value) {
|
|
12
19
|
return isSchemaValueInner(value, {
|
|
@@ -15,7 +22,12 @@ export function isSchemaValue(value) {
|
|
|
15
22
|
});
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
|
-
* @brief
|
|
25
|
+
* @brief Validate one schema node with cycle protection.
|
|
26
|
+
* @details Schema helpers enforce construction-time invariants before values reach
|
|
27
|
+
* validation, compilation, or export.
|
|
28
|
+
* @param value Candidate node.
|
|
29
|
+
* @param state Recursion state shared by the root validation pass.
|
|
30
|
+
* @returns True when this node and its reachable children are well-formed.
|
|
19
31
|
*/
|
|
20
32
|
function isSchemaValueInner(value, state) {
|
|
21
33
|
if (!isRecord(value)) {
|
|
@@ -28,6 +40,10 @@ function isSchemaValueInner(value, state) {
|
|
|
28
40
|
return false;
|
|
29
41
|
}
|
|
30
42
|
state.visiting.add(value);
|
|
43
|
+
/*
|
|
44
|
+
* The node is placed in `visiting` before child traversal so recursive
|
|
45
|
+
* object graphs fail closed instead of creating an infinite walk.
|
|
46
|
+
*/
|
|
31
47
|
const valid = isSchemaRecord(value, state);
|
|
32
48
|
state.visiting.delete(value);
|
|
33
49
|
if (valid) {
|
|
@@ -36,10 +52,17 @@ function isSchemaValueInner(value, state) {
|
|
|
36
52
|
return valid;
|
|
37
53
|
}
|
|
38
54
|
/**
|
|
39
|
-
* @brief
|
|
55
|
+
* @brief Dispatch validation by schema tag.
|
|
56
|
+
* @param value Data-only record already accepted by isRecord.
|
|
57
|
+
* @param state Recursion state for child schemas.
|
|
58
|
+
* @returns True when the tag-specific payload is well-formed.
|
|
59
|
+
* @details Tag and payload fields are read through readOwnDataProperty. This
|
|
60
|
+
* preserves the rule that forged schema prototypes never participate in schema
|
|
61
|
+
* admission.
|
|
40
62
|
*/
|
|
41
63
|
function isSchemaRecord(value, state) {
|
|
42
|
-
|
|
64
|
+
const tag = readOwnDataProperty(value, "tag");
|
|
65
|
+
switch (tag) {
|
|
43
66
|
case SchemaTag.Unknown:
|
|
44
67
|
case SchemaTag.Never:
|
|
45
68
|
case SchemaTag.BigInt:
|
|
@@ -47,45 +70,55 @@ function isSchemaRecord(value, state) {
|
|
|
47
70
|
case SchemaTag.Boolean:
|
|
48
71
|
return true;
|
|
49
72
|
case SchemaTag.String:
|
|
50
|
-
return isStringChecks(value
|
|
73
|
+
return isStringChecks(readOwnDataProperty(value, "checks"));
|
|
51
74
|
case SchemaTag.Number:
|
|
52
|
-
return isNumberChecks(value
|
|
53
|
-
case SchemaTag.Literal:
|
|
54
|
-
|
|
75
|
+
return isNumberChecks(readOwnDataProperty(value, "checks"));
|
|
76
|
+
case SchemaTag.Literal: {
|
|
77
|
+
const literal = readOwnDataProperty(value, "value");
|
|
78
|
+
/*
|
|
79
|
+
* `undefined` is a legal literal payload. The sentinel distinguishes
|
|
80
|
+
* a missing `value` field from a stored undefined literal.
|
|
81
|
+
*/
|
|
82
|
+
return !isMissingDataProperty(literal) && isLiteralValue(literal);
|
|
83
|
+
}
|
|
55
84
|
case SchemaTag.Array:
|
|
56
|
-
return isSchemaValueInner(value
|
|
85
|
+
return isSchemaValueInner(readOwnDataProperty(value, "item"), state);
|
|
57
86
|
case SchemaTag.Tuple:
|
|
58
|
-
return isSchemaArray(value
|
|
87
|
+
return isSchemaArray(readOwnDataProperty(value, "items"), state);
|
|
59
88
|
case SchemaTag.Record:
|
|
60
|
-
return isSchemaValueInner(value
|
|
89
|
+
return isSchemaValueInner(readOwnDataProperty(value, "value"), state);
|
|
61
90
|
case SchemaTag.Object:
|
|
62
91
|
return isObjectSchemaValue(value, state);
|
|
63
92
|
case SchemaTag.Union:
|
|
64
|
-
return isSchemaArray(value
|
|
93
|
+
return isSchemaArray(readOwnDataProperty(value, "options"), state);
|
|
65
94
|
case SchemaTag.Intersection:
|
|
66
|
-
return isSchemaValueInner(value
|
|
67
|
-
isSchemaValueInner(value
|
|
95
|
+
return isSchemaValueInner(readOwnDataProperty(value, "left"), state) &&
|
|
96
|
+
isSchemaValueInner(readOwnDataProperty(value, "right"), state);
|
|
68
97
|
case SchemaTag.Optional:
|
|
69
98
|
case SchemaTag.Undefinedable:
|
|
70
99
|
case SchemaTag.Nullable:
|
|
71
|
-
return isSchemaValueInner(value
|
|
100
|
+
return isSchemaValueInner(readOwnDataProperty(value, "inner"), state);
|
|
72
101
|
case SchemaTag.DiscriminatedUnion:
|
|
73
102
|
return isDiscriminatedUnionSchemaValue(value, state);
|
|
74
103
|
case SchemaTag.Brand:
|
|
75
|
-
return typeof value
|
|
76
|
-
isSchemaValueInner(value
|
|
104
|
+
return typeof readOwnDataProperty(value, "brand") === "string" &&
|
|
105
|
+
isSchemaValueInner(readOwnDataProperty(value, "inner"), state);
|
|
77
106
|
case SchemaTag.Lazy:
|
|
78
|
-
return typeof value
|
|
107
|
+
return typeof readOwnDataProperty(value, "get") === "function";
|
|
79
108
|
case SchemaTag.Refine:
|
|
80
|
-
return typeof value
|
|
81
|
-
typeof value
|
|
82
|
-
isSchemaValueInner(value
|
|
109
|
+
return typeof readOwnDataProperty(value, "name") === "string" &&
|
|
110
|
+
typeof readOwnDataProperty(value, "predicate") === "function" &&
|
|
111
|
+
isSchemaValueInner(readOwnDataProperty(value, "inner"), state);
|
|
83
112
|
default:
|
|
84
113
|
return false;
|
|
85
114
|
}
|
|
86
115
|
}
|
|
87
116
|
/**
|
|
88
|
-
* @brief
|
|
117
|
+
* @brief Validate the check vector attached to a string schema.
|
|
118
|
+
* @param value Candidate check vector.
|
|
119
|
+
* @returns True when every check is data-only and semantically usable.
|
|
120
|
+
* @details Bounds are constrained at admission so interpreter and codegen do not
|
|
121
|
+
* need to repeat defensive numeric checks in their hot paths.
|
|
89
122
|
*/
|
|
90
123
|
function isStringChecks(value) {
|
|
91
124
|
if (!isUnknownArray(value)) {
|
|
@@ -96,17 +129,22 @@ function isStringChecks(value) {
|
|
|
96
129
|
if (!isRecord(check)) {
|
|
97
130
|
return false;
|
|
98
131
|
}
|
|
99
|
-
switch (check
|
|
132
|
+
switch (readOwnDataProperty(check, "tag")) {
|
|
100
133
|
case StringCheckTag.Min:
|
|
101
134
|
case StringCheckTag.Max: {
|
|
102
|
-
const bound = check
|
|
135
|
+
const bound = readOwnDataProperty(check, "value");
|
|
103
136
|
if (typeof bound !== "number" || !Number.isInteger(bound) || bound < 0) {
|
|
104
137
|
return false;
|
|
105
138
|
}
|
|
106
139
|
break;
|
|
107
140
|
}
|
|
108
141
|
case StringCheckTag.Regex:
|
|
109
|
-
|
|
142
|
+
/*
|
|
143
|
+
* Regex checks carry executable engine state. Only a plain
|
|
144
|
+
* RegExp plus a stable diagnostic name can enter the schema.
|
|
145
|
+
*/
|
|
146
|
+
if (!isPlainRegExp(readOwnDataProperty(check, "regex")) ||
|
|
147
|
+
typeof readOwnDataProperty(check, "name") !== "string") {
|
|
110
148
|
return false;
|
|
111
149
|
}
|
|
112
150
|
break;
|
|
@@ -119,7 +157,11 @@ function isStringChecks(value) {
|
|
|
119
157
|
return true;
|
|
120
158
|
}
|
|
121
159
|
/**
|
|
122
|
-
* @brief
|
|
160
|
+
* @brief Validate the check vector attached to a number schema.
|
|
161
|
+
* @details Schema helpers enforce construction-time invariants before values reach
|
|
162
|
+
* validation, compilation, or export.
|
|
163
|
+
* @param value Candidate check vector.
|
|
164
|
+
* @returns True when all numeric bounds are finite and tag-compatible.
|
|
123
165
|
*/
|
|
124
166
|
function isNumberChecks(value) {
|
|
125
167
|
if (!isUnknownArray(value)) {
|
|
@@ -130,12 +172,12 @@ function isNumberChecks(value) {
|
|
|
130
172
|
if (!isRecord(check)) {
|
|
131
173
|
return false;
|
|
132
174
|
}
|
|
133
|
-
switch (check
|
|
175
|
+
switch (readOwnDataProperty(check, "tag")) {
|
|
134
176
|
case NumberCheckTag.Integer:
|
|
135
177
|
break;
|
|
136
178
|
case NumberCheckTag.Gte:
|
|
137
179
|
case NumberCheckTag.Lte: {
|
|
138
|
-
const bound = check
|
|
180
|
+
const bound = readOwnDataProperty(check, "value");
|
|
139
181
|
if (typeof bound !== "number" || !Number.isFinite(bound)) {
|
|
140
182
|
return false;
|
|
141
183
|
}
|
|
@@ -148,7 +190,12 @@ function isNumberChecks(value) {
|
|
|
148
190
|
return true;
|
|
149
191
|
}
|
|
150
192
|
/**
|
|
151
|
-
* @brief
|
|
193
|
+
* @brief Validate a dense vector of child schemas.
|
|
194
|
+
* @details Schema helpers enforce construction-time invariants before values reach
|
|
195
|
+
* validation, compilation, or export.
|
|
196
|
+
* @param value Candidate schema vector.
|
|
197
|
+
* @param state Recursion state shared with the parent node.
|
|
198
|
+
* @returns True when every vector slot is a valid schema.
|
|
152
199
|
*/
|
|
153
200
|
function isSchemaArray(value, state) {
|
|
154
201
|
if (!isUnknownArray(value)) {
|
|
@@ -162,16 +209,23 @@ function isSchemaArray(value, state) {
|
|
|
162
209
|
return true;
|
|
163
210
|
}
|
|
164
211
|
/**
|
|
165
|
-
* @brief
|
|
212
|
+
* @brief Validate object-schema payload invariants.
|
|
213
|
+
* @param value Candidate object schema record.
|
|
214
|
+
* @param state Recursion state for property schemas.
|
|
215
|
+
* @returns True when entries, key order, lookup, and presence metadata agree.
|
|
216
|
+
* @details Object validation depends on three redundant views: ordered entries
|
|
217
|
+
* for stable codegen, ordered keys for strict key checks, and lookup for fast
|
|
218
|
+
* membership. Admission rejects drift between those views.
|
|
166
219
|
*/
|
|
167
220
|
function isObjectSchemaValue(value, state) {
|
|
168
|
-
|
|
169
|
-
|
|
221
|
+
const mode = readOwnDataProperty(value, "mode");
|
|
222
|
+
if (mode !== ObjectModeTag.Passthrough &&
|
|
223
|
+
mode !== ObjectModeTag.Strict) {
|
|
170
224
|
return false;
|
|
171
225
|
}
|
|
172
|
-
const entries = value
|
|
173
|
-
const keys = value
|
|
174
|
-
const keyLookup = value
|
|
226
|
+
const entries = readOwnDataProperty(value, "entries");
|
|
227
|
+
const keys = readOwnDataProperty(value, "keys");
|
|
228
|
+
const keyLookup = readOwnDataProperty(value, "keyLookup");
|
|
175
229
|
if (!isUnknownArray(entries) || !isStringArray(keys) ||
|
|
176
230
|
!isObjectKeyLookup(keyLookup, keys) || entries.length !== keys.length) {
|
|
177
231
|
return false;
|
|
@@ -179,43 +233,70 @@ function isObjectSchemaValue(value, state) {
|
|
|
179
233
|
const seen = [];
|
|
180
234
|
for (let index = 0; index < entries.length; index += 1) {
|
|
181
235
|
const entry = entries[index];
|
|
182
|
-
if (!isRecord(entry)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
236
|
+
if (!isRecord(entry)) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
const key = readOwnDataProperty(entry, "key");
|
|
240
|
+
const presence = readOwnDataProperty(entry, "presence");
|
|
241
|
+
const schema = readOwnDataProperty(entry, "schema");
|
|
242
|
+
/*
|
|
243
|
+
* The entry key must match the parallel `keys` slot. That keeps emitted
|
|
244
|
+
* object code deterministic and prevents a lookup table from describing
|
|
245
|
+
* a different shape than the property graph.
|
|
246
|
+
*/
|
|
247
|
+
if (typeof key !== "string" ||
|
|
248
|
+
key !== keys[index] ||
|
|
249
|
+
includesString(seen, key) ||
|
|
250
|
+
(presence !== PresenceTag.Required &&
|
|
251
|
+
presence !== PresenceTag.Optional) ||
|
|
252
|
+
!isSchemaValueInner(schema, state)) {
|
|
189
253
|
return false;
|
|
190
254
|
}
|
|
191
|
-
seen.push(
|
|
255
|
+
seen.push(key);
|
|
192
256
|
}
|
|
193
257
|
return true;
|
|
194
258
|
}
|
|
195
259
|
/**
|
|
196
|
-
* @brief
|
|
260
|
+
* @brief Validate discriminated-union dispatch metadata.
|
|
261
|
+
* @param value Candidate discriminated union record.
|
|
262
|
+
* @param state Recursion state for case schemas.
|
|
263
|
+
* @returns True when each case owns a unique literal and proves the tag field.
|
|
264
|
+
* @details The case schema must require the discriminant literal. Without that
|
|
265
|
+
* proof, dispatch could choose a branch before the branch actually validates the
|
|
266
|
+
* same discriminant field.
|
|
197
267
|
*/
|
|
198
268
|
function isDiscriminatedUnionSchemaValue(value, state) {
|
|
199
|
-
const cases = value
|
|
200
|
-
const key = value
|
|
269
|
+
const cases = readOwnDataProperty(value, "cases");
|
|
270
|
+
const key = readOwnDataProperty(value, "key");
|
|
201
271
|
if (typeof key !== "string" || !isUnknownArray(cases) || cases.length === 0) {
|
|
202
272
|
return false;
|
|
203
273
|
}
|
|
204
274
|
const literals = [];
|
|
205
275
|
for (let index = 0; index < cases.length; index += 1) {
|
|
206
276
|
const unionCase = cases[index];
|
|
207
|
-
if (!isRecord(unionCase)
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
277
|
+
if (!isRecord(unionCase)) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
const literal = readOwnDataProperty(unionCase, "literal");
|
|
281
|
+
const schema = readOwnDataProperty(unionCase, "schema");
|
|
282
|
+
if (typeof literal !== "string" ||
|
|
283
|
+
includesString(literals, literal) ||
|
|
284
|
+
!isSchemaValueInner(schema, state) ||
|
|
285
|
+
!caseRequiresDiscriminant(schema, key, literal)) {
|
|
211
286
|
return false;
|
|
212
287
|
}
|
|
213
|
-
literals.push(
|
|
288
|
+
literals.push(literal);
|
|
214
289
|
}
|
|
215
290
|
return true;
|
|
216
291
|
}
|
|
217
292
|
/**
|
|
218
|
-
* @brief case requires discriminant.
|
|
293
|
+
* @brief Prove that one case schema requires the requested discriminant value.
|
|
294
|
+
* @details Schema helpers enforce construction-time invariants before values reach
|
|
295
|
+
* validation, compilation, or export.
|
|
296
|
+
* @param schema Case schema after structural validation.
|
|
297
|
+
* @param key Discriminant property name.
|
|
298
|
+
* @param literal Required literal value for this case.
|
|
299
|
+
* @returns True when an object case contains a required matching literal field.
|
|
219
300
|
*/
|
|
220
301
|
function caseRequiresDiscriminant(schema, key, literal) {
|
|
221
302
|
const objectSchema = unwrapCaseObjectSchema(schema);
|
|
@@ -234,7 +315,12 @@ function caseRequiresDiscriminant(schema, key, literal) {
|
|
|
234
315
|
return false;
|
|
235
316
|
}
|
|
236
317
|
/**
|
|
237
|
-
* @brief
|
|
318
|
+
* @brief Peel transparent wrappers until an object case schema is reached.
|
|
319
|
+
* @param schema Case schema.
|
|
320
|
+
* @returns The object schema used for discriminant proof, or undefined.
|
|
321
|
+
* @details Intersections and transparent wrappers can carry the object branch
|
|
322
|
+
* while still adding extra validation. Lazy and union nodes are not unwrapped
|
|
323
|
+
* here because they do not give a local, branch-stable object proof.
|
|
238
324
|
*/
|
|
239
325
|
function unwrapCaseObjectSchema(schema) {
|
|
240
326
|
switch (schema.tag) {
|
|
@@ -250,7 +336,12 @@ function unwrapCaseObjectSchema(schema) {
|
|
|
250
336
|
}
|
|
251
337
|
}
|
|
252
338
|
/**
|
|
253
|
-
* @brief schema
|
|
339
|
+
* @brief Check whether a schema forces one exact string literal.
|
|
340
|
+
* @details Schema helpers enforce construction-time invariants before values reach
|
|
341
|
+
* validation, compilation, or export.
|
|
342
|
+
* @param schema Property schema.
|
|
343
|
+
* @param literal Required literal value.
|
|
344
|
+
* @returns True when the schema cannot accept a different discriminant value.
|
|
254
345
|
*/
|
|
255
346
|
function schemaRequiresLiteral(schema, literal) {
|
|
256
347
|
switch (schema.tag) {
|
package/docs/api.md
CHANGED
|
@@ -187,10 +187,67 @@ Generated source never interpolates user-controlled values directly. Literals,
|
|
|
187
187
|
regexps, property keys, keysets, and dynamic schema fallbacks are captured in
|
|
188
188
|
side tables and referenced by numeric index.
|
|
189
189
|
|
|
190
|
+
### Unsafe Compile Mode
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const FastButLooseUser = compile(User, {
|
|
194
|
+
name: "isUserFast",
|
|
195
|
+
mode: "unsafe"
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`CompileOptions["mode"]` and `AotCompileOptions["mode"]` are
|
|
200
|
+
`"safe" | "unsafe" | "unchecked" | undefined`; omitted options default to
|
|
201
|
+
`"safe"`. Safe mode keeps TypeSea's hostile-input contract: descriptor-based
|
|
202
|
+
property reads, no getter execution, and strict-object rejection for symbol and
|
|
203
|
+
non-enumerable extras.
|
|
204
|
+
|
|
205
|
+
Unsafe mode is an explicit performance escape hatch for trusted, normalized
|
|
206
|
+
plain data:
|
|
207
|
+
|
|
208
|
+
- Required object fields read with `value[key]` when the field schema rejects
|
|
209
|
+
`undefined`.
|
|
210
|
+
- Discriminant dispatch reads the tag with direct bracket access.
|
|
211
|
+
- Arrays and tuples read items with direct indexed loads.
|
|
212
|
+
- Strict-object extra-key rejection uses an allocation-free own-enumerable
|
|
213
|
+
`for...in` loop.
|
|
214
|
+
|
|
215
|
+
This may execute getters, may accept prototype-backed values, and does not
|
|
216
|
+
reject symbol or non-enumerable extras on strict objects. Because compiled
|
|
217
|
+
`check()` first trusts the generated predicate verdict, an unsafe predicate
|
|
218
|
+
that returns `true` also returns a successful `check()` result. Use unsafe mode
|
|
219
|
+
only after the input has crossed a trusted normalization boundary.
|
|
220
|
+
|
|
221
|
+
Unsafe mode may embed escaped static property keys directly into generated
|
|
222
|
+
predicate source so V8 can attach ordinary property-load inline caches. Safe
|
|
223
|
+
mode keeps property keys in side tables.
|
|
224
|
+
|
|
225
|
+
Unchecked mode uses the unsafe direct-read shape and also skips strict-object
|
|
226
|
+
extra-key loops. It is only for input whose object shape has already been
|
|
227
|
+
trusted or normalized; strict objects no longer reject extra keys in this mode.
|
|
228
|
+
Unsafe and unchecked compiled `check()` calls also return raw successful Result
|
|
229
|
+
objects without `Object.freeze()`. Failure diagnostics remain frozen. Safe mode
|
|
230
|
+
keeps frozen success and failure Result objects.
|
|
231
|
+
FastMode diagnostic collectors use direct field reads and FastMode strict-key
|
|
232
|
+
rules for object diagnostics where possible, so missing/accessor issue codes
|
|
233
|
+
are not guaranteed to match safe mode. Array and tuple diagnostics also use
|
|
234
|
+
direct indexed reads in fast modes, so sparse slots are diagnosed from the
|
|
235
|
+
loaded `undefined` value. Record diagnostics use direct `record[key]` reads;
|
|
236
|
+
unchecked mode also visits inherited enumerable keys. Discriminant diagnostics
|
|
237
|
+
read the tag directly and compare string cases with `===`.
|
|
238
|
+
|
|
190
239
|
## AOT Emit
|
|
191
240
|
|
|
192
241
|
```ts
|
|
193
242
|
const emitted = emitAotModule(User, { name: "aotUser" });
|
|
243
|
+
const unsafeEmitted = emitAotModule(User, {
|
|
244
|
+
name: "aotUserFast",
|
|
245
|
+
mode: "unsafe"
|
|
246
|
+
});
|
|
247
|
+
const uncheckedEmitted = emitAotModule(User, {
|
|
248
|
+
name: "aotUserTrustedShape",
|
|
249
|
+
mode: "unchecked"
|
|
250
|
+
});
|
|
194
251
|
```
|
|
195
252
|
|
|
196
253
|
`emitAotModule` returns `Result<AotModule, AotIssue[]>`. A successful result
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1120" height="760" viewBox="0 0 1120 760" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">TypeSea benchmark comparison</title>
|
|
3
|
+
<desc id="desc">Local strict object benchmark comparing TypeSea safe, unsafe, unchecked, Zod, Valibot, and Ajv throughput.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
6
|
+
<stop offset="0" stop-color="#071014"/>
|
|
7
|
+
<stop offset="0.58" stop-color="#0f172a"/>
|
|
8
|
+
<stop offset="1" stop-color="#13251f"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
<linearGradient id="panel" x1="0" y1="0" x2="1" y2="1">
|
|
11
|
+
<stop offset="0" stop-color="#111827"/>
|
|
12
|
+
<stop offset="1" stop-color="#0b1220"/>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
<linearGradient id="safe" x1="0" y1="0" x2="1" y2="0">
|
|
15
|
+
<stop offset="0" stop-color="#14b8a6"/>
|
|
16
|
+
<stop offset="1" stop-color="#2dd4bf"/>
|
|
17
|
+
</linearGradient>
|
|
18
|
+
<linearGradient id="unsafe" x1="0" y1="0" x2="1" y2="0">
|
|
19
|
+
<stop offset="0" stop-color="#f97316"/>
|
|
20
|
+
<stop offset="1" stop-color="#fbbf24"/>
|
|
21
|
+
</linearGradient>
|
|
22
|
+
<linearGradient id="unchecked" x1="0" y1="0" x2="1" y2="0">
|
|
23
|
+
<stop offset="0" stop-color="#22c55e"/>
|
|
24
|
+
<stop offset="1" stop-color="#a3e635"/>
|
|
25
|
+
</linearGradient>
|
|
26
|
+
<linearGradient id="ajv" x1="0" y1="0" x2="1" y2="0">
|
|
27
|
+
<stop offset="0" stop-color="#3b82f6"/>
|
|
28
|
+
<stop offset="1" stop-color="#93c5fd"/>
|
|
29
|
+
</linearGradient>
|
|
30
|
+
<linearGradient id="zod" x1="0" y1="0" x2="1" y2="0">
|
|
31
|
+
<stop offset="0" stop-color="#8b5cf6"/>
|
|
32
|
+
<stop offset="1" stop-color="#c4b5fd"/>
|
|
33
|
+
</linearGradient>
|
|
34
|
+
<linearGradient id="valibot" x1="0" y1="0" x2="1" y2="0">
|
|
35
|
+
<stop offset="0" stop-color="#ec4899"/>
|
|
36
|
+
<stop offset="1" stop-color="#f9a8d4"/>
|
|
37
|
+
</linearGradient>
|
|
38
|
+
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
39
|
+
<feDropShadow dx="0" dy="14" stdDeviation="18" flood-color="#000000" flood-opacity="0.35"/>
|
|
40
|
+
</filter>
|
|
41
|
+
<style>
|
|
42
|
+
text { font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
43
|
+
.title { fill: #f8fafc; font-size: 42px; font-weight: 800; letter-spacing: 0; }
|
|
44
|
+
.subtitle { fill: #94a3b8; font-size: 16px; font-weight: 500; }
|
|
45
|
+
.card-title { fill: #e5e7eb; font-size: 18px; font-weight: 800; }
|
|
46
|
+
.card-note { fill: #94a3b8; font-size: 12px; font-weight: 600; }
|
|
47
|
+
.metric-label { fill: #94a3b8; font-size: 12px; font-weight: 700; text-transform: uppercase; }
|
|
48
|
+
.metric-value { fill: #f8fafc; font-size: 30px; font-weight: 900; }
|
|
49
|
+
.metric-sub { fill: #cbd5e1; font-size: 13px; font-weight: 600; }
|
|
50
|
+
.bar-label { fill: #cbd5e1; font-size: 13px; font-weight: 700; }
|
|
51
|
+
.bar-value { fill: #f8fafc; font-size: 13px; font-weight: 800; }
|
|
52
|
+
.axis { stroke: #334155; stroke-width: 1; }
|
|
53
|
+
</style>
|
|
54
|
+
</defs>
|
|
55
|
+
|
|
56
|
+
<rect width="1120" height="760" rx="28" fill="url(#bg)"/>
|
|
57
|
+
<circle cx="1028" cy="82" r="180" fill="#22c55e" opacity="0.08"/>
|
|
58
|
+
<circle cx="84" cy="690" r="220" fill="#38bdf8" opacity="0.07"/>
|
|
59
|
+
|
|
60
|
+
<text id="headline" x="44" y="58" class="title">TypeSea benchmark comparison</text>
|
|
61
|
+
<text x="46" y="88" class="subtitle">Local run on 2026-07-04 KST, strict-object contract, ops/sec. Higher is better.</text>
|
|
62
|
+
|
|
63
|
+
<g filter="url(#shadow)">
|
|
64
|
+
<rect x="44" y="118" width="322" height="108" rx="18" fill="url(#panel)" stroke="#1f2937"/>
|
|
65
|
+
<text x="66" y="148" class="metric-label">Unchecked valid hot path</text>
|
|
66
|
+
<text x="66" y="188" class="metric-value">42.58M</text>
|
|
67
|
+
<text x="66" y="210" class="metric-sub">31.7x Zod, 10.0x Ajv</text>
|
|
68
|
+
|
|
69
|
+
<rect x="399" y="118" width="322" height="108" rx="18" fill="url(#panel)" stroke="#1f2937"/>
|
|
70
|
+
<text x="421" y="148" class="metric-label">Safe invalid fast-fail</text>
|
|
71
|
+
<text x="421" y="188" class="metric-value">42.08M</text>
|
|
72
|
+
<text x="421" y="210" class="metric-sub">1.51x Ajv, 499x Zod</text>
|
|
73
|
+
|
|
74
|
+
<rect x="754" y="118" width="322" height="108" rx="18" fill="url(#panel)" stroke="#1f2937"/>
|
|
75
|
+
<text x="776" y="148" class="metric-label">Safe valid path</text>
|
|
76
|
+
<text x="776" y="188" class="metric-value">4.30M</text>
|
|
77
|
+
<text x="776" y="210" class="metric-sub">Ajv-class while staying safe</text>
|
|
78
|
+
</g>
|
|
79
|
+
|
|
80
|
+
<g filter="url(#shadow)">
|
|
81
|
+
<rect x="44" y="260" width="1032" height="136" rx="18" fill="url(#panel)" stroke="#1f2937"/>
|
|
82
|
+
<text x="66" y="291" class="card-title">Valid object path</text>
|
|
83
|
+
<text x="230" y="291" class="card-note">linear scale to 42.58M</text>
|
|
84
|
+
<line x1="270" y1="318" x2="1010" y2="318" class="axis"/>
|
|
85
|
+
|
|
86
|
+
<text x="66" y="326" class="bar-label">TypeSea unchecked</text>
|
|
87
|
+
<rect x="270" y="312" width="740" height="15" rx="7.5" fill="url(#unchecked)"/>
|
|
88
|
+
<text x="1024" y="326" class="bar-value">42.58M</text>
|
|
89
|
+
|
|
90
|
+
<text x="66" y="350" class="bar-label">TypeSea unsafe</text>
|
|
91
|
+
<rect x="270" y="336" width="631" height="15" rx="7.5" fill="url(#unsafe)"/>
|
|
92
|
+
<text x="915" y="350" class="bar-value">36.30M</text>
|
|
93
|
+
|
|
94
|
+
<text x="66" y="374" class="bar-label">TypeSea safe / Ajv / Zod</text>
|
|
95
|
+
<rect x="270" y="360" width="75" height="15" rx="7.5" fill="url(#safe)"/>
|
|
96
|
+
<rect x="354" y="360" width="74" height="15" rx="7.5" fill="url(#ajv)"/>
|
|
97
|
+
<rect x="437" y="360" width="24" height="15" rx="7.5" fill="url(#valibot)"/>
|
|
98
|
+
<rect x="470" y="360" width="23" height="15" rx="7.5" fill="url(#zod)"/>
|
|
99
|
+
<text x="506" y="374" class="bar-value">safe 4.30M, Ajv 4.28M, Valibot 1.41M, Zod 1.34M</text>
|
|
100
|
+
</g>
|
|
101
|
+
|
|
102
|
+
<g filter="url(#shadow)">
|
|
103
|
+
<rect x="44" y="418" width="1032" height="150" rx="18" fill="url(#panel)" stroke="#1f2937"/>
|
|
104
|
+
<text x="66" y="449" class="card-title">Invalid object fast-fail</text>
|
|
105
|
+
<text x="268" y="449" class="card-note">linear scale to 50.48M</text>
|
|
106
|
+
<line x1="270" y1="476" x2="1010" y2="476" class="axis"/>
|
|
107
|
+
|
|
108
|
+
<text x="66" y="482" class="bar-label">TypeSea unchecked</text>
|
|
109
|
+
<rect x="270" y="468" width="740" height="15" rx="7.5" fill="url(#unchecked)"/>
|
|
110
|
+
<text x="1024" y="482" class="bar-value">50.48M</text>
|
|
111
|
+
|
|
112
|
+
<text x="66" y="506" class="bar-label">TypeSea unsafe</text>
|
|
113
|
+
<rect x="270" y="492" width="728" height="15" rx="7.5" fill="url(#unsafe)"/>
|
|
114
|
+
<text x="1024" y="506" class="bar-value">49.65M</text>
|
|
115
|
+
|
|
116
|
+
<text x="66" y="530" class="bar-label">TypeSea safe</text>
|
|
117
|
+
<rect x="270" y="516" width="617" height="15" rx="7.5" fill="url(#safe)"/>
|
|
118
|
+
<text x="902" y="530" class="bar-value">42.08M</text>
|
|
119
|
+
|
|
120
|
+
<text x="66" y="554" class="bar-label">Ajv / Valibot / Zod</text>
|
|
121
|
+
<rect x="270" y="540" width="408" height="15" rx="7.5" fill="url(#ajv)"/>
|
|
122
|
+
<rect x="690" y="540" width="13" height="15" rx="7.5" fill="url(#valibot)"/>
|
|
123
|
+
<rect x="714" y="540" width="3" height="15" rx="1.5" fill="url(#zod)"/>
|
|
124
|
+
<text x="734" y="554" class="bar-value">Ajv 27.82M, Valibot 0.88M, Zod 0.08M</text>
|
|
125
|
+
</g>
|
|
126
|
+
|
|
127
|
+
<g filter="url(#shadow)">
|
|
128
|
+
<rect x="44" y="576" width="1032" height="136" rx="18" fill="url(#panel)" stroke="#1f2937"/>
|
|
129
|
+
<text x="66" y="607" class="card-title">Invalid diagnostic path</text>
|
|
130
|
+
<text x="270" y="607" class="card-note">linear scale to 28.71M; Ajv is a boolean baseline</text>
|
|
131
|
+
<line x1="270" y1="634" x2="1010" y2="634" class="axis"/>
|
|
132
|
+
|
|
133
|
+
<text x="66" y="642" class="bar-label">Ajv compiled</text>
|
|
134
|
+
<rect x="270" y="628" width="740" height="15" rx="7.5" fill="url(#ajv)"/>
|
|
135
|
+
<text x="1024" y="642" class="bar-value">28.71M</text>
|
|
136
|
+
|
|
137
|
+
<text x="66" y="666" class="bar-label">TypeSea modes</text>
|
|
138
|
+
<rect x="270" y="652" width="95" height="15" rx="7.5" fill="url(#unchecked)"/>
|
|
139
|
+
<rect x="374" y="652" width="79" height="15" rx="7.5" fill="url(#unsafe)"/>
|
|
140
|
+
<rect x="462" y="652" width="54" height="15" rx="7.5" fill="url(#safe)"/>
|
|
141
|
+
<text x="532" y="666" class="bar-value">unchecked 3.67M, unsafe 3.08M, safe 2.09M</text>
|
|
142
|
+
|
|
143
|
+
<text x="66" y="690" class="bar-label">Valibot / Zod</text>
|
|
144
|
+
<rect x="270" y="676" width="23" height="15" rx="7.5" fill="url(#valibot)"/>
|
|
145
|
+
<rect x="302" y="676" width="3" height="15" rx="1.5" fill="url(#zod)"/>
|
|
146
|
+
<text x="322" y="690" class="bar-value">Valibot 0.89M, Zod 0.08M</text>
|
|
147
|
+
</g>
|
|
148
|
+
|
|
149
|
+
<g transform="translate(44 730)">
|
|
150
|
+
<rect x="0" y="-11" width="13" height="13" rx="3" fill="url(#safe)"/>
|
|
151
|
+
<text x="20" y="0" class="card-note">TypeSea safe</text>
|
|
152
|
+
<rect x="128" y="-11" width="13" height="13" rx="3" fill="url(#unsafe)"/>
|
|
153
|
+
<text x="148" y="0" class="card-note">unsafe</text>
|
|
154
|
+
<rect x="228" y="-11" width="13" height="13" rx="3" fill="url(#unchecked)"/>
|
|
155
|
+
<text x="248" y="0" class="card-note">unchecked</text>
|
|
156
|
+
<rect x="356" y="-11" width="13" height="13" rx="3" fill="url(#ajv)"/>
|
|
157
|
+
<text x="376" y="0" class="card-note">Ajv</text>
|
|
158
|
+
<rect x="426" y="-11" width="13" height="13" rx="3" fill="url(#valibot)"/>
|
|
159
|
+
<text x="446" y="0" class="card-note">Valibot</text>
|
|
160
|
+
<rect x="536" y="-11" width="13" height="13" rx="3" fill="url(#zod)"/>
|
|
161
|
+
<text x="556" y="0" class="card-note">Zod</text>
|
|
162
|
+
</g>
|
|
163
|
+
</svg>
|