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/docs/engine-notes.md
CHANGED
|
@@ -18,6 +18,9 @@ allocation sites, branch behavior, and validation contracts visible in code.
|
|
|
18
18
|
- For all-required strict objects, reject extras by counting own string names
|
|
19
19
|
and own symbols after field validation. Optional strict objects keep the full
|
|
20
20
|
key membership scan.
|
|
21
|
+
- Keep `compile()` and `emitAotModule()` safe by default. Unsafe mode is an
|
|
22
|
+
explicit opt-in that may use direct property/index loads and own-enumerable
|
|
23
|
+
strict-key loops after the caller accepts getter/prototype/symbol-extra risk.
|
|
21
24
|
- Mark constructed guards out-of-band so normal receivers avoid repeated schema
|
|
22
25
|
validation while forged receivers still fall back to structural checks.
|
|
23
26
|
- Use `Readonly<Record<string, unknown>>` after object guards.
|
|
@@ -91,14 +94,51 @@ descriptor-based element access, and dynamic edges use the same IR-backed
|
|
|
91
94
|
runtime fallback as ordinary guard execution, preserving behavior for `lazy` and
|
|
92
95
|
`refine`.
|
|
93
96
|
|
|
94
|
-
Strict object IR emits two shapes. When every declared key is required
|
|
95
|
-
|
|
96
|
-
`Object.getOwnPropertyNames(value).length` with the declared key
|
|
97
|
-
require `Object.getOwnPropertySymbols(value).length === 0`.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
emit the full own-key membership scan because a
|
|
101
|
-
distinguished by the final key count alone.
|
|
97
|
+
Strict object IR emits two shapes. When every declared key is required,
|
|
98
|
+
generated validators run the strict-key count before field descriptor reads:
|
|
99
|
+
they compare `Object.getOwnPropertyNames(value).length` with the declared key
|
|
100
|
+
count and require `Object.getOwnPropertySymbols(value).length === 0`. V8
|
|
101
|
+
optimizes this count-only path better than a generic `Reflect.ownKeys` count,
|
|
102
|
+
and it rejects obvious extra-key objects before touching field descriptors.
|
|
103
|
+
Optional strict objects still emit the full own-key membership scan because a
|
|
104
|
+
missing optional key cannot be distinguished by the final key count alone.
|
|
105
|
+
|
|
106
|
+
`compile(..., { mode: "unsafe" })` and
|
|
107
|
+
`emitAotModule(..., { mode: "unsafe" })` switch generated predicates to a
|
|
108
|
+
trusted-data code shape. Required object fields whose schemas reject
|
|
109
|
+
`undefined` use direct `value[key]` loads without descriptor or own-key checks.
|
|
110
|
+
Required fields that can accept `undefined` retain an own-key presence guard so
|
|
111
|
+
missing required keys do not collapse into valid `undefined` values. Optional
|
|
112
|
+
fields take the direct-load fast path for present non-`undefined` values and
|
|
113
|
+
fall back to an own-key check only for the ambiguous `undefined` case.
|
|
114
|
+
|
|
115
|
+
Unsafe array, tuple, record, and discriminant paths also prefer direct loads.
|
|
116
|
+
Strict objects use a `for...in` own-enumerable key loop instead of allocating
|
|
117
|
+
own-key arrays.
|
|
118
|
+
Object keys that are ASCII identifier names emit as dot-property loads such as
|
|
119
|
+
`value.id`; other keys emit as escaped string-literal bracket loads. That is
|
|
120
|
+
intentionally not hostile-input equivalent: getters can execute,
|
|
121
|
+
prototype-backed values can be accepted, symbol or non-enumerable strict extras
|
|
122
|
+
are not rejected, and static property names may appear in unsafe generated
|
|
123
|
+
predicate source.
|
|
124
|
+
|
|
125
|
+
`mode: "unchecked"` keeps the unsafe direct-read shape and removes strict
|
|
126
|
+
extra-key loops. It is a trusted-shape path for objects already normalized by
|
|
127
|
+
the caller; strict objects no longer reject any extra keys there.
|
|
128
|
+
|
|
129
|
+
Fast modes also remove `Object.freeze()` from successful compiled `check()`
|
|
130
|
+
results. The returned object keeps the same `{ ok: true, value }` shape, but it
|
|
131
|
+
is intentionally not frozen. Failed diagnostics stay frozen because those
|
|
132
|
+
objects are off the success hot path and are often retained for reporting.
|
|
133
|
+
Object diagnostics in fast modes are generated from the same direct-read
|
|
134
|
+
contract as predicates. Required fields load through `value.key`, optional
|
|
135
|
+
fields use direct load plus an own-key fallback for `undefined`, unsafe strict
|
|
136
|
+
objects scan own enumerable string keys, and unchecked strict objects skip the
|
|
137
|
+
strict-key diagnostic scan. Array and tuple diagnostics in fast modes read
|
|
138
|
+
items through direct indexes instead of descriptor probes. Record diagnostics
|
|
139
|
+
read through `record[key]`; unchecked mode intentionally keeps inherited
|
|
140
|
+
enumerable keys visible. Discriminant diagnostics read the tag directly and
|
|
141
|
+
compare literal string cases with strict equality.
|
|
102
142
|
|
|
103
143
|
## Recursion
|
|
104
144
|
|
|
@@ -141,13 +181,16 @@ Zod, Valibot, and Ajv are dev dependencies for measurement only. They are not
|
|
|
141
181
|
imported by `src`, and package policy rejects runtime, peer, optional, or
|
|
142
182
|
bundled dependency fields before release.
|
|
143
183
|
|
|
144
|
-
Last local
|
|
145
|
-
|
|
184
|
+
Last local benchmark on 2026-07-04 KST reported these ecosystem paths over the
|
|
185
|
+
JSON-compatible strict-object benchmark:
|
|
146
186
|
|
|
147
|
-
| Case | TypeSea runtime plan | TypeSea compiled | Ajv compiled |
|
|
148
|
-
| --- | ---: | ---: | ---: |
|
|
149
|
-
| Valid
|
|
150
|
-
|
|
|
187
|
+
| Case | TypeSea runtime plan | TypeSea compiled safe | TypeSea compiled unsafe | TypeSea compiled unchecked | Ajv compiled |
|
|
188
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
189
|
+
| Valid `is()` | 513,701 hz | 4,297,306 hz | 36,297,653 hz | 42,581,174 hz | 4,275,389 hz |
|
|
190
|
+
| Valid `check()` | 503,232 hz | 3,903,929 hz | 35,568,425 hz | 40,084,605 hz | 4,278,587 hz |
|
|
191
|
+
| Invalid `is()` | 3,636,369 hz | 42,080,241 hz | 49,654,076 hz | 50,482,732 hz | 27,820,643 hz |
|
|
192
|
+
| Invalid `check()` | 420,446 hz | 2,086,129 hz | 3,077,367 hz | 3,673,508 hz | 28,713,035 hz |
|
|
151
193
|
|
|
152
194
|
Benchmark numbers are machine-local telemetry. They are useful for catching
|
|
153
|
-
regressions, not for promising a fixed throughput floor.
|
|
195
|
+
regressions, not for promising a fixed throughput floor. Unsafe and unchecked
|
|
196
|
+
numbers are not hostile-input equivalent to safe mode.
|
package/docs/index.html
CHANGED
|
@@ -159,31 +159,6 @@
|
|
|
159
159
|
line-height: 1.5;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
.search {
|
|
163
|
-
padding: 16px 16px 8px;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.search input {
|
|
167
|
-
width: 100%;
|
|
168
|
-
min-height: 36px;
|
|
169
|
-
border: 1px solid var(--sidebar-line);
|
|
170
|
-
border-radius: 8px;
|
|
171
|
-
padding: 0 12px;
|
|
172
|
-
background: rgba(255, 255, 255, 0.06);
|
|
173
|
-
color: var(--sidebar-ink);
|
|
174
|
-
font: inherit;
|
|
175
|
-
font-size: 13px;
|
|
176
|
-
outline: none;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
.search input:focus {
|
|
180
|
-
border-color: #46b48f;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
.search input::placeholder {
|
|
184
|
-
color: var(--sidebar-muted);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
162
|
.nav {
|
|
188
163
|
flex: 1;
|
|
189
164
|
padding: 6px 12px 18px;
|
|
@@ -687,15 +662,12 @@
|
|
|
687
662
|
<aside class="sidebar" aria-label="Documentation navigation">
|
|
688
663
|
<div class="brand">
|
|
689
664
|
<h1>TypeSea</h1>
|
|
690
|
-
<span class="version">v0.
|
|
665
|
+
<span class="version">v0.2.0</span>
|
|
691
666
|
</div>
|
|
692
667
|
<p class="brand-tagline">
|
|
693
668
|
Zero-dependency runtime narrowing for TypeScript.
|
|
694
669
|
ESM-only · Node ≥ 20.19 · MIT
|
|
695
670
|
</p>
|
|
696
|
-
<div class="search">
|
|
697
|
-
<input data-search type="search" placeholder="Filter sections…" aria-label="Filter documentation sections">
|
|
698
|
-
</div>
|
|
699
671
|
<nav class="nav">
|
|
700
672
|
<p class="nav-group">Guide</p>
|
|
701
673
|
<a href="#overview">Overview</a>
|
|
@@ -813,6 +785,22 @@ const schema = toJsonSchema(User);</code></pre>
|
|
|
813
785
|
environments, emit validator source ahead of time with <code>emitAotModule()</code>.
|
|
814
786
|
</p>
|
|
815
787
|
</div>
|
|
788
|
+
<div class="callout warn">
|
|
789
|
+
<span class="icon">⚠</span>
|
|
790
|
+
<p>
|
|
791
|
+
<strong>Unsafe FastMode:</strong> <code>compile(User, { mode: "unsafe" })</code>
|
|
792
|
+
and <code>emitAotModule(User, { mode: "unsafe" })</code> emit direct
|
|
793
|
+
property and index reads plus an allocation-free strict-key loop for trusted
|
|
794
|
+
normalized data. They may execute getters, may accept prototype-backed values,
|
|
795
|
+
strict objects do not reject symbol or non-enumerable extras, and escaped
|
|
796
|
+
static property keys may appear directly in unsafe predicate source.
|
|
797
|
+
<code>mode: "unchecked"</code> also skips strict extra-key loops for
|
|
798
|
+
already-trusted object shapes. Unsafe and unchecked successful
|
|
799
|
+
<code>check()</code> results are raw <code>{ ok: true, value }</code>
|
|
800
|
+
objects; failed diagnostics remain frozen and use the same direct-read
|
|
801
|
+
FastMode object/array/record/discriminant contract where possible.
|
|
802
|
+
</p>
|
|
803
|
+
</div>
|
|
816
804
|
</section>
|
|
817
805
|
|
|
818
806
|
<section id="semantics" data-doc-section data-title="semantics presence optional undefinedable nullable edge nan proto uuid strict">
|
|
@@ -1068,23 +1056,71 @@ const schema = toJsonSchema(User);</code></pre>
|
|
|
1068
1056
|
<tbody>
|
|
1069
1057
|
<tr>
|
|
1070
1058
|
<td>TypeSea runtime plan <code>is()</code></td>
|
|
1071
|
-
<td class="num">
|
|
1059
|
+
<td class="num">513,701</td>
|
|
1060
|
+
</tr>
|
|
1061
|
+
<tr>
|
|
1062
|
+
<td>TypeSea compiled safe <code>is()</code></td>
|
|
1063
|
+
<td class="num">4,297,306</td>
|
|
1064
|
+
</tr>
|
|
1065
|
+
<tr>
|
|
1066
|
+
<td>TypeSea compiled unsafe <code>is()</code></td>
|
|
1067
|
+
<td class="num">36,297,653</td>
|
|
1068
|
+
</tr>
|
|
1069
|
+
<tr>
|
|
1070
|
+
<td>TypeSea compiled unchecked <code>is()</code></td>
|
|
1071
|
+
<td class="num"><span class="best">42,581,174</span></td>
|
|
1072
|
+
</tr>
|
|
1073
|
+
<tr>
|
|
1074
|
+
<td>Zod <code>safeParse</code></td>
|
|
1075
|
+
<td class="num">1,343,756</td>
|
|
1076
|
+
</tr>
|
|
1077
|
+
<tr>
|
|
1078
|
+
<td>Valibot <code>safeParse</code></td>
|
|
1079
|
+
<td class="num">1,406,528</td>
|
|
1080
|
+
</tr>
|
|
1081
|
+
<tr>
|
|
1082
|
+
<td>Ajv compiled</td>
|
|
1083
|
+
<td class="num">4,275,389</td>
|
|
1084
|
+
</tr>
|
|
1085
|
+
</tbody>
|
|
1086
|
+
</table>
|
|
1087
|
+
</div>
|
|
1088
|
+
<div class="table-wrap">
|
|
1089
|
+
<table>
|
|
1090
|
+
<thead>
|
|
1091
|
+
<tr>
|
|
1092
|
+
<th>Valid diagnostic path</th>
|
|
1093
|
+
<th class="num">ops/sec</th>
|
|
1094
|
+
</tr>
|
|
1095
|
+
</thead>
|
|
1096
|
+
<tbody>
|
|
1097
|
+
<tr>
|
|
1098
|
+
<td>TypeSea runtime plan <code>check()</code></td>
|
|
1099
|
+
<td class="num">503,232</td>
|
|
1072
1100
|
</tr>
|
|
1073
1101
|
<tr>
|
|
1074
|
-
<td>TypeSea compiled <code>
|
|
1075
|
-
<td class="num"
|
|
1102
|
+
<td>TypeSea compiled safe <code>check()</code></td>
|
|
1103
|
+
<td class="num">3,903,929</td>
|
|
1104
|
+
</tr>
|
|
1105
|
+
<tr>
|
|
1106
|
+
<td>TypeSea compiled unsafe <code>check()</code></td>
|
|
1107
|
+
<td class="num">35,568,425</td>
|
|
1108
|
+
</tr>
|
|
1109
|
+
<tr>
|
|
1110
|
+
<td>TypeSea compiled unchecked <code>check()</code></td>
|
|
1111
|
+
<td class="num"><span class="best">40,084,605</span></td>
|
|
1076
1112
|
</tr>
|
|
1077
1113
|
<tr>
|
|
1078
1114
|
<td>Zod <code>safeParse</code></td>
|
|
1079
|
-
<td class="num">1,
|
|
1115
|
+
<td class="num">1,355,014</td>
|
|
1080
1116
|
</tr>
|
|
1081
1117
|
<tr>
|
|
1082
1118
|
<td>Valibot <code>safeParse</code></td>
|
|
1083
|
-
<td class="num">1,
|
|
1119
|
+
<td class="num">1,378,266</td>
|
|
1084
1120
|
</tr>
|
|
1085
1121
|
<tr>
|
|
1086
1122
|
<td>Ajv compiled</td>
|
|
1087
|
-
<td class="num">4,
|
|
1123
|
+
<td class="num">4,278,587</td>
|
|
1088
1124
|
</tr>
|
|
1089
1125
|
</tbody>
|
|
1090
1126
|
</table>
|
|
@@ -1100,35 +1136,83 @@ const schema = toJsonSchema(User);</code></pre>
|
|
|
1100
1136
|
<tbody>
|
|
1101
1137
|
<tr>
|
|
1102
1138
|
<td>TypeSea runtime plan <code>is()</code></td>
|
|
1103
|
-
<td class="num">3,
|
|
1139
|
+
<td class="num">3,636,369</td>
|
|
1140
|
+
</tr>
|
|
1141
|
+
<tr>
|
|
1142
|
+
<td>TypeSea compiled safe <code>is()</code></td>
|
|
1143
|
+
<td class="num">42,080,241</td>
|
|
1104
1144
|
</tr>
|
|
1105
1145
|
<tr>
|
|
1106
|
-
<td>TypeSea compiled <code>is()</code></td>
|
|
1107
|
-
<td class="num"
|
|
1146
|
+
<td>TypeSea compiled unsafe <code>is()</code></td>
|
|
1147
|
+
<td class="num">49,654,076</td>
|
|
1148
|
+
</tr>
|
|
1149
|
+
<tr>
|
|
1150
|
+
<td>TypeSea compiled unchecked <code>is()</code></td>
|
|
1151
|
+
<td class="num"><span class="best">50,482,732</span></td>
|
|
1108
1152
|
</tr>
|
|
1109
1153
|
<tr>
|
|
1110
1154
|
<td>Zod <code>safeParse</code></td>
|
|
1111
|
-
<td class="num">
|
|
1155
|
+
<td class="num">84,272</td>
|
|
1112
1156
|
</tr>
|
|
1113
1157
|
<tr>
|
|
1114
1158
|
<td>Valibot <code>safeParse</code></td>
|
|
1115
|
-
<td class="num">
|
|
1159
|
+
<td class="num">878,521</td>
|
|
1116
1160
|
</tr>
|
|
1117
1161
|
<tr>
|
|
1118
1162
|
<td>Ajv compiled</td>
|
|
1119
|
-
<td class="num">
|
|
1163
|
+
<td class="num">27,820,643</td>
|
|
1164
|
+
</tr>
|
|
1165
|
+
</tbody>
|
|
1166
|
+
</table>
|
|
1167
|
+
</div>
|
|
1168
|
+
<div class="table-wrap">
|
|
1169
|
+
<table>
|
|
1170
|
+
<thead>
|
|
1171
|
+
<tr>
|
|
1172
|
+
<th>Invalid diagnostic path</th>
|
|
1173
|
+
<th class="num">ops/sec</th>
|
|
1174
|
+
</tr>
|
|
1175
|
+
</thead>
|
|
1176
|
+
<tbody>
|
|
1177
|
+
<tr>
|
|
1178
|
+
<td>TypeSea runtime plan <code>check()</code></td>
|
|
1179
|
+
<td class="num">420,446</td>
|
|
1180
|
+
</tr>
|
|
1181
|
+
<tr>
|
|
1182
|
+
<td>TypeSea compiled safe <code>check()</code></td>
|
|
1183
|
+
<td class="num">2,086,129</td>
|
|
1184
|
+
</tr>
|
|
1185
|
+
<tr>
|
|
1186
|
+
<td>TypeSea compiled unsafe <code>check()</code></td>
|
|
1187
|
+
<td class="num">3,077,367</td>
|
|
1188
|
+
</tr>
|
|
1189
|
+
<tr>
|
|
1190
|
+
<td>TypeSea compiled unchecked <code>check()</code></td>
|
|
1191
|
+
<td class="num">3,673,508</td>
|
|
1192
|
+
</tr>
|
|
1193
|
+
<tr>
|
|
1194
|
+
<td>Zod <code>safeParse</code></td>
|
|
1195
|
+
<td class="num">79,613</td>
|
|
1196
|
+
</tr>
|
|
1197
|
+
<tr>
|
|
1198
|
+
<td>Valibot <code>safeParse</code></td>
|
|
1199
|
+
<td class="num">887,991</td>
|
|
1200
|
+
</tr>
|
|
1201
|
+
<tr>
|
|
1202
|
+
<td>Ajv compiled</td>
|
|
1203
|
+
<td class="num"><span class="best">28,713,035</span></td>
|
|
1120
1204
|
</tr>
|
|
1121
1205
|
</tbody>
|
|
1122
1206
|
</table>
|
|
1123
1207
|
</div>
|
|
1124
1208
|
<p class="footnote">
|
|
1125
|
-
Local
|
|
1126
|
-
not throughput guarantees.
|
|
1127
|
-
|
|
1128
|
-
|
|
1209
|
+
Local benchmark, 2026-07-04 KST, single machine — regression telemetry,
|
|
1210
|
+
not throughput guarantees. Safe compiled mode keeps descriptor-based reads,
|
|
1211
|
+
strict symbol/non-enumerable key rejection, and immutable diagnostics. Unsafe
|
|
1212
|
+
and unchecked modes are faster because they are only for trusted normalized data.
|
|
1129
1213
|
</p>
|
|
1130
1214
|
<div class="code-block">
|
|
1131
|
-
<pre><code>npm run bench -- --run</code></pre>
|
|
1215
|
+
<pre><code>npm run bench -- bench/ecosystem.bench.ts --run</code></pre>
|
|
1132
1216
|
</div>
|
|
1133
1217
|
</section>
|
|
1134
1218
|
|
|
@@ -1174,69 +1258,5 @@ const schema = toJsonSchema(User);</code></pre>
|
|
|
1174
1258
|
</div>
|
|
1175
1259
|
</div>
|
|
1176
1260
|
|
|
1177
|
-
<script>
|
|
1178
|
-
const search = document.querySelector("[data-search]");
|
|
1179
|
-
const sections = Array.from(document.querySelectorAll("[data-doc-section]"));
|
|
1180
|
-
const links = Array.from(document.querySelectorAll(".nav a"));
|
|
1181
|
-
const groups = Array.from(document.querySelectorAll(".nav-group"));
|
|
1182
|
-
|
|
1183
|
-
if (search instanceof HTMLInputElement) {
|
|
1184
|
-
search.addEventListener("input", () => {
|
|
1185
|
-
const query = search.value.trim().toLowerCase();
|
|
1186
|
-
for (const section of sections) {
|
|
1187
|
-
const title = section.getAttribute("data-title") ?? "";
|
|
1188
|
-
const text = section.textContent?.toLowerCase() ?? "";
|
|
1189
|
-
const visible = query === "" || title.includes(query) || text.includes(query);
|
|
1190
|
-
section.classList.toggle("hidden", !visible);
|
|
1191
|
-
}
|
|
1192
|
-
for (const link of links) {
|
|
1193
|
-
const target = link.getAttribute("href") ?? "";
|
|
1194
|
-
const section = target.startsWith("#")
|
|
1195
|
-
? document.getElementById(target.slice(1))
|
|
1196
|
-
: null;
|
|
1197
|
-
const visible = section === null || !section.classList.contains("hidden");
|
|
1198
|
-
link.classList.toggle("hidden", !visible);
|
|
1199
|
-
}
|
|
1200
|
-
for (const group of groups) {
|
|
1201
|
-
let sibling = group.nextElementSibling;
|
|
1202
|
-
let anyVisible = false;
|
|
1203
|
-
while (sibling !== null && !sibling.classList.contains("nav-group")) {
|
|
1204
|
-
if (sibling.matches("a") && !sibling.classList.contains("hidden")) {
|
|
1205
|
-
anyVisible = true;
|
|
1206
|
-
}
|
|
1207
|
-
sibling = sibling.nextElementSibling;
|
|
1208
|
-
}
|
|
1209
|
-
group.classList.toggle("hidden", !anyVisible);
|
|
1210
|
-
}
|
|
1211
|
-
});
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
const linkById = new Map(
|
|
1215
|
-
links
|
|
1216
|
-
.map((link) => [link.getAttribute("href")?.slice(1) ?? "", link])
|
|
1217
|
-
.filter(([id]) => id !== "")
|
|
1218
|
-
);
|
|
1219
|
-
|
|
1220
|
-
if ("IntersectionObserver" in window) {
|
|
1221
|
-
const observer = new IntersectionObserver(
|
|
1222
|
-
(entries) => {
|
|
1223
|
-
for (const entry of entries) {
|
|
1224
|
-
if (entry.isIntersecting) {
|
|
1225
|
-
for (const link of links) {
|
|
1226
|
-
link.classList.toggle(
|
|
1227
|
-
"active",
|
|
1228
|
-
link === linkById.get(entry.target.id)
|
|
1229
|
-
);
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
},
|
|
1234
|
-
{ rootMargin: "-20% 0px -70% 0px" }
|
|
1235
|
-
);
|
|
1236
|
-
for (const section of sections) {
|
|
1237
|
-
observer.observe(section);
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
</script>
|
|
1241
1261
|
</body>
|
|
1242
1262
|
</html>
|
package/package.json
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
"name": "typesea",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "V8-friendly runtime narrowing for TypeScript with Sea-of-Nodes graph introspection.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "feral",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Feralthedogg/TypeSea.git"
|
|
10
|
+
},
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"typescript",
|
|
23
|
+
"typeguard",
|
|
24
|
+
"type-guard",
|
|
25
|
+
"runtime-validation",
|
|
26
|
+
"schema",
|
|
27
|
+
"narrowing",
|
|
28
|
+
"v8"
|
|
29
|
+
],
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"CHANGELOG.md",
|
|
34
|
+
"docs"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
|
|
38
|
+
"bench": "vitest bench",
|
|
39
|
+
"check": "npm run policy && npm run check:docs && npm run typecheck && npm run lint && npm run test && npm run build && npm run check:dist && npm run check:api && npm run check:pack",
|
|
40
|
+
"check:api": "node scripts/public-api-surface.mjs",
|
|
41
|
+
"check:consumer": "node scripts/consumer-smoke.mjs",
|
|
42
|
+
"check:docs": "node scripts/docs-site-check.mjs",
|
|
43
|
+
"check:dist": "node scripts/dist-policy.mjs",
|
|
44
|
+
"check:pack": "node scripts/package-contents.mjs",
|
|
45
|
+
"lint": "eslint .",
|
|
46
|
+
"pack:dry": "npm pack --dry-run --ignore-scripts",
|
|
47
|
+
"policy": "node scripts/source-policy.mjs",
|
|
48
|
+
"prepack": "npm run check",
|
|
49
|
+
"release:check": "node scripts/release-gate.mjs",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=20.19"
|
|
55
|
+
},
|
|
56
|
+
"license": "MIT",
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@eslint/js": "^10.0.1",
|
|
59
|
+
"@types/node": "^26.1.0",
|
|
60
|
+
"ajv": "^8.20.0",
|
|
61
|
+
"eslint": "^10.6.0",
|
|
62
|
+
"typescript": "^6.0.3",
|
|
63
|
+
"typescript-eslint": "^8.62.1",
|
|
64
|
+
"valibot": "^1.4.2",
|
|
65
|
+
"vitest": "^4.1.9",
|
|
66
|
+
"zod": "^4.4.3"
|
|
19
67
|
}
|
|
20
|
-
},
|
|
21
|
-
"keywords": [
|
|
22
|
-
"typescript",
|
|
23
|
-
"typeguard",
|
|
24
|
-
"type-guard",
|
|
25
|
-
"runtime-validation",
|
|
26
|
-
"schema",
|
|
27
|
-
"narrowing",
|
|
28
|
-
"v8"
|
|
29
|
-
],
|
|
30
|
-
"files": [
|
|
31
|
-
"dist",
|
|
32
|
-
"README.md",
|
|
33
|
-
"CHANGELOG.md",
|
|
34
|
-
"docs"
|
|
35
|
-
],
|
|
36
|
-
"scripts": {
|
|
37
|
-
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
|
|
38
|
-
"bench": "vitest bench",
|
|
39
|
-
"check": "npm run policy && npm run check:docs && npm run typecheck && npm run lint && npm run test && npm run build && npm run check:dist && npm run check:api && npm run check:pack",
|
|
40
|
-
"check:api": "node scripts/public-api-surface.mjs",
|
|
41
|
-
"check:consumer": "node scripts/consumer-smoke.mjs",
|
|
42
|
-
"check:docs": "node scripts/docs-site-check.mjs",
|
|
43
|
-
"check:dist": "node scripts/dist-policy.mjs",
|
|
44
|
-
"check:pack": "node scripts/package-contents.mjs",
|
|
45
|
-
"lint": "eslint .",
|
|
46
|
-
"pack:dry": "npm pack --dry-run --ignore-scripts",
|
|
47
|
-
"policy": "node scripts/source-policy.mjs",
|
|
48
|
-
"prepack": "npm run check",
|
|
49
|
-
"release:check": "node scripts/release-gate.mjs",
|
|
50
|
-
"test": "vitest run",
|
|
51
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
52
|
-
},
|
|
53
|
-
"engines": {
|
|
54
|
-
"node": ">=20.19"
|
|
55
|
-
},
|
|
56
|
-
"license": "MIT",
|
|
57
|
-
"devDependencies": {
|
|
58
|
-
"@eslint/js": "^10.0.1",
|
|
59
|
-
"@types/node": "^26.1.0",
|
|
60
|
-
"ajv": "^8.20.0",
|
|
61
|
-
"eslint": "^10.6.0",
|
|
62
|
-
"typescript": "^6.0.3",
|
|
63
|
-
"typescript-eslint": "^8.62.1",
|
|
64
|
-
"valibot": "^1.4.2",
|
|
65
|
-
"vitest": "^4.1.9",
|
|
66
|
-
"zod": "^4.4.3"
|
|
67
|
-
}
|
|
68
68
|
}
|