typebox 1.1.23 → 1.1.25
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/build/schema/check.d.mts +3 -3
- package/build/schema/compile.d.mts +2 -2
- package/build/schema/engine/_stack.d.mts +4 -4
- package/build/schema/engine/_stack.mjs +52 -18
- package/build/schema/engine/dynamicRef.d.mts +6 -0
- package/build/schema/engine/dynamicRef.mjs +25 -0
- package/build/schema/engine/recursiveRef.mjs +3 -3
- package/build/schema/engine/ref.mjs +3 -3
- package/build/schema/engine/schema.mjs +9 -4
- package/build/schema/parse.d.mts +3 -3
- package/build/schema/resolve/ref.d.mts +1 -0
- package/build/schema/resolve/ref.mjs +61 -11
- package/package.json +30 -30
- package/readme.md +143 -24
package/build/schema/check.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { type Static } from '../type/types/static.mjs';
|
|
1
2
|
import * as Schema from './types/index.mjs';
|
|
2
|
-
import * as Static from './static/index.mjs';
|
|
3
3
|
/** Checks a value against the provided schema */
|
|
4
|
-
export declare function Check<const Schema extends Schema.XSchema>(schema: Schema, value: unknown): value is Static
|
|
4
|
+
export declare function Check<const Schema extends Schema.XSchema>(schema: Schema, value: unknown): value is Static<Schema>;
|
|
5
5
|
/** Checks a value against the provided schema */
|
|
6
|
-
export declare function Check<const Schema extends Schema.XSchema>(context: Record<PropertyKey, Schema.XSchema>, schema: Schema, value: unknown): value is Static
|
|
6
|
+
export declare function Check<const Schema extends Schema.XSchema>(context: Record<PropertyKey, Schema.XSchema>, schema: Schema, value: unknown): value is Static<Schema>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type TLocalizedValidationError } from '../error/index.mjs';
|
|
2
|
+
import { type Static } from '../type/types/static.mjs';
|
|
2
3
|
import * as Schema from './types/index.mjs';
|
|
3
|
-
|
|
4
|
-
export declare class Validator<Schema extends Schema.XSchema = Schema.XSchema, Value extends unknown = Static.XStatic<Schema>> {
|
|
4
|
+
export declare class Validator<const Schema extends Schema.XSchema = Schema.XSchema, Value extends unknown = Static<Schema>> {
|
|
5
5
|
private readonly build;
|
|
6
6
|
private readonly result;
|
|
7
7
|
constructor(context: Record<string, Schema.XSchema>, schema: Schema);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Schema from '../types/index.mjs';
|
|
2
2
|
export declare class Stack {
|
|
3
|
+
#private;
|
|
3
4
|
private readonly context;
|
|
4
5
|
private readonly schema;
|
|
5
6
|
private readonly ids;
|
|
@@ -11,8 +12,7 @@ export declare class Stack {
|
|
|
11
12
|
Base(): Schema.XSchemaObject;
|
|
12
13
|
Push(schema: Schema.XSchema): void;
|
|
13
14
|
Pop(schema: Schema.XSchema): void;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
RecursiveRef(recursiveRef: string): Schema.XSchema | undefined;
|
|
15
|
+
Ref(ref: Schema.XRef): Schema.XSchema | undefined;
|
|
16
|
+
RecursiveRef(recursiveRef: Schema.XRecursiveRef): Schema.XSchema | undefined;
|
|
17
|
+
DynamicRef(dynamicRef: Schema.XDynamicRef): Schema.XSchema | undefined;
|
|
18
18
|
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
|
+
};
|
|
7
|
+
var _Stack_instances, _Stack_PushResourceAnchors, _Stack_PopResourceAnchors, _Stack_FromContext, _Stack_FromRef;
|
|
2
8
|
import * as Schema from '../types/index.mjs';
|
|
3
9
|
import { Guard as G } from '../../guard/index.mjs';
|
|
4
10
|
import { Resolve } from '../resolve/index.mjs';
|
|
5
11
|
export class Stack {
|
|
6
12
|
constructor(context, schema) {
|
|
13
|
+
_Stack_instances.add(this);
|
|
7
14
|
this.context = context;
|
|
8
15
|
this.schema = schema;
|
|
9
16
|
this.ids = [];
|
|
@@ -26,8 +33,10 @@ export class Stack {
|
|
|
26
33
|
Push(schema) {
|
|
27
34
|
if (!Schema.IsSchemaObject(schema))
|
|
28
35
|
return;
|
|
29
|
-
if (Schema.IsId(schema))
|
|
36
|
+
if (Schema.IsId(schema)) {
|
|
30
37
|
this.ids.push(schema);
|
|
38
|
+
__classPrivateFieldGet(this, _Stack_instances, "m", _Stack_PushResourceAnchors).call(this, schema);
|
|
39
|
+
}
|
|
31
40
|
if (Schema.IsAnchor(schema))
|
|
32
41
|
this.anchors.push(schema);
|
|
33
42
|
if (Schema.IsRecursiveAnchorTrue(schema))
|
|
@@ -38,8 +47,10 @@ export class Stack {
|
|
|
38
47
|
Pop(schema) {
|
|
39
48
|
if (!Schema.IsSchemaObject(schema))
|
|
40
49
|
return;
|
|
41
|
-
if (Schema.IsId(schema))
|
|
50
|
+
if (Schema.IsId(schema)) {
|
|
42
51
|
this.ids.pop();
|
|
52
|
+
__classPrivateFieldGet(this, _Stack_instances, "m", _Stack_PopResourceAnchors).call(this, schema);
|
|
53
|
+
}
|
|
43
54
|
if (Schema.IsAnchor(schema))
|
|
44
55
|
this.anchors.pop();
|
|
45
56
|
if (Schema.IsRecursiveAnchorTrue(schema))
|
|
@@ -47,27 +58,50 @@ export class Stack {
|
|
|
47
58
|
if (Schema.IsDynamicAnchor(schema))
|
|
48
59
|
this.dynamicAnchors.pop();
|
|
49
60
|
}
|
|
50
|
-
// ----------------------------------------------------------------
|
|
51
|
-
// Ref
|
|
52
|
-
// ----------------------------------------------------------------
|
|
53
|
-
FromContext(ref) {
|
|
54
|
-
return G.HasPropertyKey(this.context, ref) ? this.context[ref] : undefined;
|
|
55
|
-
}
|
|
56
|
-
FromRef(ref) {
|
|
57
|
-
return !ref.startsWith('#')
|
|
58
|
-
? Resolve.Ref(this.schema, ref)
|
|
59
|
-
: Resolve.Ref(this.Base(), ref);
|
|
60
|
-
}
|
|
61
61
|
Ref(ref) {
|
|
62
|
-
return this.
|
|
62
|
+
return __classPrivateFieldGet(this, _Stack_instances, "m", _Stack_FromContext).call(this, ref) ?? __classPrivateFieldGet(this, _Stack_instances, "m", _Stack_FromRef).call(this, ref);
|
|
63
63
|
}
|
|
64
64
|
// ----------------------------------------------------------------
|
|
65
65
|
// RecursiveRef
|
|
66
66
|
// ----------------------------------------------------------------
|
|
67
67
|
RecursiveRef(recursiveRef) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
return Schema.IsRecursiveAnchorTrue(this.Base())
|
|
69
|
+
? Resolve.Ref(this.recursiveAnchors[0], recursiveRef.$recursiveRef)
|
|
70
|
+
: Resolve.Ref(this.Base(), recursiveRef.$recursiveRef);
|
|
71
|
+
}
|
|
72
|
+
// ----------------------------------------------------------------
|
|
73
|
+
// DynamicRef
|
|
74
|
+
// ----------------------------------------------------------------
|
|
75
|
+
DynamicRef(dynamicRef) {
|
|
76
|
+
const root = this.schema;
|
|
77
|
+
return Resolve.DynamicRef(root, this.Base(), dynamicRef, this.dynamicAnchors);
|
|
72
78
|
}
|
|
73
79
|
}
|
|
80
|
+
_Stack_instances = new WeakSet(), _Stack_PushResourceAnchors = function _Stack_PushResourceAnchors(schema, isRoot = true) {
|
|
81
|
+
if (!Schema.IsSchemaObject(schema))
|
|
82
|
+
return;
|
|
83
|
+
const current = schema;
|
|
84
|
+
if (!isRoot && Schema.IsId(current))
|
|
85
|
+
return;
|
|
86
|
+
if (!isRoot && Schema.IsDynamicAnchor(current))
|
|
87
|
+
this.dynamicAnchors.push(current);
|
|
88
|
+
for (const key of G.Keys(current))
|
|
89
|
+
__classPrivateFieldGet(this, _Stack_instances, "m", _Stack_PushResourceAnchors).call(this, current[key], false);
|
|
90
|
+
}, _Stack_PopResourceAnchors = function _Stack_PopResourceAnchors(schema, isRoot = true) {
|
|
91
|
+
if (!Schema.IsSchemaObject(schema))
|
|
92
|
+
return;
|
|
93
|
+
const current = schema;
|
|
94
|
+
if (!isRoot && Schema.IsId(current))
|
|
95
|
+
return;
|
|
96
|
+
if (!isRoot && Schema.IsDynamicAnchor(current))
|
|
97
|
+
this.dynamicAnchors.pop();
|
|
98
|
+
for (const key of G.Keys(current))
|
|
99
|
+
__classPrivateFieldGet(this, _Stack_instances, "m", _Stack_PopResourceAnchors).call(this, current[key], false);
|
|
100
|
+
}, _Stack_FromContext = function _Stack_FromContext(ref) {
|
|
101
|
+
return G.HasPropertyKey(this.context, ref.$ref) ? this.context[ref.$ref] : undefined;
|
|
102
|
+
}, _Stack_FromRef = function _Stack_FromRef(ref) {
|
|
103
|
+
const root = this.schema;
|
|
104
|
+
return !ref.$ref.startsWith('#')
|
|
105
|
+
? Resolve.Ref(root, ref.$ref)
|
|
106
|
+
: Resolve.Ref(this.Base(), ref.$ref);
|
|
107
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as Schema from '../types/index.mjs';
|
|
2
|
+
import { Stack } from './_stack.mjs';
|
|
3
|
+
import { BuildContext, CheckContext, ErrorContext } from './_context.mjs';
|
|
4
|
+
export declare function BuildDynamicRef(stack: Stack, context: BuildContext, schema: Schema.XDynamicRef, value: string): string;
|
|
5
|
+
export declare function CheckDynamicRef(stack: Stack, context: CheckContext, schema: Schema.XDynamicRef, value: unknown): boolean;
|
|
6
|
+
export declare function ErrorDynamicRef(stack: Stack, context: ErrorContext, _schemaPath: string, instancePath: string, schema: Schema.XDynamicRef, value: unknown): boolean;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// deno-fmt-ignore-file
|
|
2
|
+
import * as Functions from './_functions.mjs';
|
|
3
|
+
import * as Schema from '../types/index.mjs';
|
|
4
|
+
import { CheckSchema, ErrorSchema } from './schema.mjs';
|
|
5
|
+
// ------------------------------------------------------------------
|
|
6
|
+
// Build
|
|
7
|
+
// ------------------------------------------------------------------
|
|
8
|
+
export function BuildDynamicRef(stack, context, schema, value) {
|
|
9
|
+
const target = stack.DynamicRef(schema) ?? false;
|
|
10
|
+
return Functions.CreateFunction(stack, context, target, value);
|
|
11
|
+
}
|
|
12
|
+
// ------------------------------------------------------------------
|
|
13
|
+
// Check
|
|
14
|
+
// ------------------------------------------------------------------
|
|
15
|
+
export function CheckDynamicRef(stack, context, schema, value) {
|
|
16
|
+
const target = stack.DynamicRef(schema) ?? false;
|
|
17
|
+
return (Schema.IsSchema(target) && CheckSchema(stack, context, target, value));
|
|
18
|
+
}
|
|
19
|
+
// ------------------------------------------------------------------
|
|
20
|
+
// Error
|
|
21
|
+
// ------------------------------------------------------------------
|
|
22
|
+
export function ErrorDynamicRef(stack, context, _schemaPath, instancePath, schema, value) {
|
|
23
|
+
const target = stack.DynamicRef(schema) ?? false;
|
|
24
|
+
return (Schema.IsSchema(target) && ErrorSchema(stack, context, '#', instancePath, target, value));
|
|
25
|
+
}
|
|
@@ -6,20 +6,20 @@ import { CheckSchema, ErrorSchema } from './schema.mjs';
|
|
|
6
6
|
// Build
|
|
7
7
|
// ------------------------------------------------------------------
|
|
8
8
|
export function BuildRecursiveRef(stack, context, schema, value) {
|
|
9
|
-
const target = stack.RecursiveRef(schema
|
|
9
|
+
const target = stack.RecursiveRef(schema) ?? false;
|
|
10
10
|
return Functions.CreateFunction(stack, context, target, value);
|
|
11
11
|
}
|
|
12
12
|
// ------------------------------------------------------------------
|
|
13
13
|
// Check
|
|
14
14
|
// ------------------------------------------------------------------
|
|
15
15
|
export function CheckRecursiveRef(stack, context, schema, value) {
|
|
16
|
-
const target = stack.RecursiveRef(schema
|
|
16
|
+
const target = stack.RecursiveRef(schema) ?? false;
|
|
17
17
|
return (Schema.IsSchema(target) && CheckSchema(stack, context, target, value));
|
|
18
18
|
}
|
|
19
19
|
// ------------------------------------------------------------------
|
|
20
20
|
// Error
|
|
21
21
|
// ------------------------------------------------------------------
|
|
22
22
|
export function ErrorRecursiveRef(stack, context, _schemaPath, instancePath, schema, value) {
|
|
23
|
-
const target = stack.RecursiveRef(schema
|
|
23
|
+
const target = stack.RecursiveRef(schema) ?? false;
|
|
24
24
|
return (Schema.IsSchema(target) && ErrorSchema(stack, context, '#', instancePath, target, value));
|
|
25
25
|
}
|
|
@@ -27,7 +27,7 @@ function BuildRefFast(stack, context, target, value) {
|
|
|
27
27
|
// BuildRef
|
|
28
28
|
// ------------------------------------------------------------------
|
|
29
29
|
export function BuildRef(stack, context, schema, value) {
|
|
30
|
-
const target = stack.Ref(schema
|
|
30
|
+
const target = stack.Ref(schema) ?? false;
|
|
31
31
|
return context.UseUnevaluated()
|
|
32
32
|
? BuildRefStandard(stack, context, target, value)
|
|
33
33
|
: BuildRefFast(stack, context, target, value);
|
|
@@ -36,7 +36,7 @@ export function BuildRef(stack, context, schema, value) {
|
|
|
36
36
|
// Check
|
|
37
37
|
// ------------------------------------------------------------------
|
|
38
38
|
export function CheckRef(stack, context, schema, value) {
|
|
39
|
-
const target = stack.Ref(schema
|
|
39
|
+
const target = stack.Ref(schema) ?? false;
|
|
40
40
|
const nextContext = new CheckContext();
|
|
41
41
|
const result = (Schema.IsSchema(target) && CheckSchema(stack, nextContext, target, value));
|
|
42
42
|
if (result)
|
|
@@ -47,7 +47,7 @@ export function CheckRef(stack, context, schema, value) {
|
|
|
47
47
|
// Error
|
|
48
48
|
// ------------------------------------------------------------------
|
|
49
49
|
export function ErrorRef(stack, context, _schemaPath, instancePath, schema, value) {
|
|
50
|
-
const target = stack.Ref(schema
|
|
50
|
+
const target = stack.Ref(schema) ?? false;
|
|
51
51
|
const nextContext = new AccumulatedErrorContext();
|
|
52
52
|
const result = (Schema.IsSchema(target) && ErrorSchema(stack, nextContext, '#', instancePath, target, value));
|
|
53
53
|
if (result)
|
|
@@ -13,6 +13,7 @@ import { BuildContains, CheckContains, ErrorContains } from './contains.mjs';
|
|
|
13
13
|
import { BuildDependencies, CheckDependencies, ErrorDependencies } from './dependencies.mjs';
|
|
14
14
|
import { BuildDependentRequired, CheckDependentRequired, ErrorDependentRequired } from './dependentRequired.mjs';
|
|
15
15
|
import { BuildDependentSchemas, CheckDependentSchemas, ErrorDependentSchemas } from './dependentSchemas.mjs';
|
|
16
|
+
import { BuildDynamicRef, CheckDynamicRef, ErrorDynamicRef } from './dynamicRef.mjs';
|
|
16
17
|
import { BuildEnum, CheckEnum, ErrorEnum } from './enum.mjs';
|
|
17
18
|
import { BuildExclusiveMaximum, CheckExclusiveMaximum, ErrorExclusiveMaximum } from './exclusiveMaximum.mjs';
|
|
18
19
|
import { BuildExclusiveMinimum, CheckExclusiveMinimum, ErrorExclusiveMinimum } from './exclusiveMinimum.mjs';
|
|
@@ -209,10 +210,12 @@ export function BuildSchema(stack, context, schema, value) {
|
|
|
209
210
|
const guarded = E.Or(E.Not(E.Or(E.IsNumber(value), E.IsBigInt(value))), reduced);
|
|
210
211
|
conditions.push(HasNumberType(schema) ? reduced : guarded);
|
|
211
212
|
}
|
|
212
|
-
if (Schema.IsRecursiveRef(schema))
|
|
213
|
-
conditions.push(BuildRecursiveRef(stack, context, schema, value));
|
|
214
213
|
if (Schema.IsRef(schema))
|
|
215
214
|
conditions.push(BuildRef(stack, context, schema, value));
|
|
215
|
+
if (Schema.IsRecursiveRef(schema))
|
|
216
|
+
conditions.push(BuildRecursiveRef(stack, context, schema, value));
|
|
217
|
+
if (Schema.IsDynamicRef(schema))
|
|
218
|
+
conditions.push(BuildDynamicRef(stack, context, schema, value));
|
|
216
219
|
if (Schema.IsGuard(schema))
|
|
217
220
|
conditions.push(BuildGuard(stack, context, schema, value));
|
|
218
221
|
if (Schema.IsConst(schema))
|
|
@@ -276,8 +279,9 @@ export function CheckSchema(stack, context, schema, value) {
|
|
|
276
279
|
(!Schema.IsMaximum(schema) || CheckMaximum(stack, context, schema, value)) &&
|
|
277
280
|
(!Schema.IsMinimum(schema) || CheckMinimum(stack, context, schema, value)) &&
|
|
278
281
|
(!Schema.IsMultipleOf(schema) || CheckMultipleOf(stack, context, schema, value)))) &&
|
|
279
|
-
(!Schema.IsRecursiveRef(schema) || CheckRecursiveRef(stack, context, schema, value)) &&
|
|
280
282
|
(!Schema.IsRef(schema) || CheckRef(stack, context, schema, value)) &&
|
|
283
|
+
(!Schema.IsRecursiveRef(schema) || CheckRecursiveRef(stack, context, schema, value)) &&
|
|
284
|
+
(!Schema.IsDynamicRef(schema) || CheckDynamicRef(stack, context, schema, value)) &&
|
|
281
285
|
(!Schema.IsGuard(schema) || CheckGuard(stack, context, schema, value)) &&
|
|
282
286
|
(!Schema.IsConst(schema) || CheckConst(stack, context, schema, value)) &&
|
|
283
287
|
(!Schema.IsEnum(schema) || CheckEnum(stack, context, schema, value)) &&
|
|
@@ -329,8 +333,9 @@ export function ErrorSchema(stack, context, schemaPath, instancePath, schema, va
|
|
|
329
333
|
+(!Schema.IsMaximum(schema) || ErrorMaximum(stack, context, schemaPath, instancePath, schema, value)) &
|
|
330
334
|
+(!Schema.IsMinimum(schema) || ErrorMinimum(stack, context, schemaPath, instancePath, schema, value)) &
|
|
331
335
|
+(!Schema.IsMultipleOf(schema) || ErrorMultipleOf(stack, context, schemaPath, instancePath, schema, value)))) &
|
|
332
|
-
+(!Schema.IsRecursiveRef(schema) || ErrorRecursiveRef(stack, context, schemaPath, instancePath, schema, value)) &
|
|
333
336
|
+(!Schema.IsRef(schema) || ErrorRef(stack, context, schemaPath, instancePath, schema, value)) &
|
|
337
|
+
+(!Schema.IsRecursiveRef(schema) || ErrorRecursiveRef(stack, context, schemaPath, instancePath, schema, value)) &
|
|
338
|
+
+(!Schema.IsDynamicRef(schema) || ErrorDynamicRef(stack, context, schemaPath, instancePath, schema, value)) &
|
|
334
339
|
+(!Schema.IsGuard(schema) || ErrorGuard(stack, context, schemaPath, instancePath, schema, value)) &
|
|
335
340
|
+(!Schema.IsConst(schema) || ErrorConst(stack, context, schemaPath, instancePath, schema, value)) &
|
|
336
341
|
+(!Schema.IsEnum(schema) || ErrorEnum(stack, context, schemaPath, instancePath, schema, value)) &
|
package/build/schema/parse.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type TLocalizedValidationError } from '../error/index.mjs';
|
|
2
|
+
import { type Static } from '../type/types/static.mjs';
|
|
2
3
|
import * as Schema from './types/index.mjs';
|
|
3
|
-
import * as Static from './static/index.mjs';
|
|
4
4
|
export declare class ParseError {
|
|
5
5
|
schema: Schema.XSchema;
|
|
6
6
|
value: unknown;
|
|
@@ -8,6 +8,6 @@ export declare class ParseError {
|
|
|
8
8
|
constructor(schema: Schema.XSchema, value: unknown, errors: TLocalizedValidationError[]);
|
|
9
9
|
}
|
|
10
10
|
/** Parses a value against the provided schema */
|
|
11
|
-
export declare function Parse<const Schema extends Schema.XSchema>(schema: Schema, value: unknown): Static
|
|
11
|
+
export declare function Parse<const Schema extends Schema.XSchema>(schema: Schema, value: unknown): Static<Schema>;
|
|
12
12
|
/** Parses a value against the provided schema */
|
|
13
|
-
export declare function Parse<const Schema extends Schema.XSchema>(context: Record<PropertyKey, Schema.XSchema>, schema: Schema, value: unknown): Static
|
|
13
|
+
export declare function Parse<const Schema extends Schema.XSchema>(context: Record<PropertyKey, Schema.XSchema>, schema: Schema, value: unknown): Static<Schema>;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import * as Schema from '../types/index.mjs';
|
|
2
2
|
export declare function Ref(schema: Schema.XSchemaObject, ref: string): Schema.XSchema | undefined;
|
|
3
|
+
export declare function DynamicRef(root: Schema.XSchemaObject, base: Schema.XSchemaObject, dynamicRef: Schema.XDynamicRef, dynamicAnchors: Schema.XDynamicAnchor[]): Schema.XSchema | undefined;
|
|
@@ -21,19 +21,34 @@ function MatchId(schema, base, ref) {
|
|
|
21
21
|
function MatchAnchor(schema, base, ref) {
|
|
22
22
|
const absoluteAnchor = new URL(`#${schema.$anchor}`, base.href);
|
|
23
23
|
const absoluteRef = new URL(ref.href, base.href);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
return Guard.IsEqual(absoluteAnchor.href, absoluteRef.href) ? schema : undefined;
|
|
25
|
+
}
|
|
26
|
+
// ------------------------------------------------------------------
|
|
27
|
+
// Match: DynamicAnchor
|
|
28
|
+
// ------------------------------------------------------------------
|
|
29
|
+
function MatchDynamicAnchor(schema, base, ref) {
|
|
30
|
+
const absoluteAnchor = new URL(`#${schema.$dynamicAnchor}`, base.href);
|
|
31
|
+
const absoluteRef = new URL(ref.href, base.href);
|
|
32
|
+
return Guard.IsEqual(absoluteAnchor.href, absoluteRef.href) ? schema : undefined;
|
|
27
33
|
}
|
|
28
34
|
// ------------------------------------------------------------------
|
|
29
35
|
// Match: Hash
|
|
36
|
+
//
|
|
37
|
+
// Resolves JSON Pointer fragments only. Plain anchor-style fragments
|
|
38
|
+
// (no leading '/') are handled exclusively by MatchAnchor and
|
|
39
|
+
// MatchDynamicAnchor to prevent accidentally resolving an anchor name
|
|
40
|
+
// as a pointer into the schema tree.
|
|
41
|
+
//
|
|
30
42
|
// ------------------------------------------------------------------
|
|
31
43
|
function MatchHash(schema, _base, ref) {
|
|
32
44
|
if (ref.href.endsWith('#'))
|
|
33
45
|
return schema;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
if (!ref.hash.startsWith('#'))
|
|
47
|
+
return undefined;
|
|
48
|
+
const fragment = decodeURIComponent(ref.hash.slice(1));
|
|
49
|
+
if (!fragment.startsWith('/'))
|
|
50
|
+
return undefined;
|
|
51
|
+
return Pointer.Get(schema, fragment);
|
|
37
52
|
}
|
|
38
53
|
// ------------------------------------------------------------------
|
|
39
54
|
// Match
|
|
@@ -49,6 +64,11 @@ function Match(schema, base, ref) {
|
|
|
49
64
|
if (!Guard.IsUndefined(result))
|
|
50
65
|
return result;
|
|
51
66
|
}
|
|
67
|
+
if (Schema.IsDynamicAnchor(schema)) {
|
|
68
|
+
const result = MatchDynamicAnchor(schema, base, ref);
|
|
69
|
+
if (!Guard.IsUndefined(result))
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
52
72
|
return MatchHash(schema, base, ref);
|
|
53
73
|
}
|
|
54
74
|
// ------------------------------------------------------------------
|
|
@@ -73,24 +93,54 @@ function FromObject(schema, base, ref) {
|
|
|
73
93
|
// FromValue
|
|
74
94
|
// ------------------------------------------------------------------
|
|
75
95
|
function FromValue(schema, base, ref) {
|
|
76
|
-
|
|
96
|
+
const nextBase = Schema.IsSchemaObject(schema) && Schema.IsId(schema)
|
|
97
|
+
? new URL(schema.$id, base.href)
|
|
98
|
+
: base;
|
|
77
99
|
if (Schema.IsSchemaObject(schema)) {
|
|
78
|
-
const result = Match(schema,
|
|
100
|
+
const result = Match(schema, nextBase, ref);
|
|
79
101
|
if (!Guard.IsUndefined(result))
|
|
80
102
|
return result;
|
|
81
103
|
}
|
|
82
104
|
if (Guard.IsArray(schema))
|
|
83
|
-
return FromArray(schema,
|
|
105
|
+
return FromArray(schema, nextBase, ref);
|
|
84
106
|
if (Guard.IsObject(schema))
|
|
85
|
-
return FromObject(schema,
|
|
107
|
+
return FromObject(schema, nextBase, ref);
|
|
86
108
|
return undefined;
|
|
87
109
|
}
|
|
88
110
|
// ------------------------------------------------------------------
|
|
89
111
|
// Ref
|
|
90
112
|
// ------------------------------------------------------------------
|
|
91
113
|
export function Ref(schema, ref) {
|
|
92
|
-
const defaultBase = new URL('http://unknown');
|
|
114
|
+
const defaultBase = new URL('http://unknown/');
|
|
93
115
|
const initialBase = Schema.IsId(schema) ? new URL(schema.$id, defaultBase.href) : defaultBase;
|
|
94
116
|
const initialRef = new URL(ref, initialBase.href);
|
|
95
117
|
return FromValue(schema, initialBase, initialRef);
|
|
96
118
|
}
|
|
119
|
+
// ------------------------------------------------------------------
|
|
120
|
+
// DynamicRef
|
|
121
|
+
// ------------------------------------------------------------------
|
|
122
|
+
export function DynamicRef(root, base, dynamicRef, dynamicAnchors) {
|
|
123
|
+
// Resolve the static target using either the local base (for fragment‑only references)
|
|
124
|
+
// or the document root (for absolute URI references).
|
|
125
|
+
const fragmentTarget = dynamicRef.$dynamicRef.startsWith('#')
|
|
126
|
+
? Ref(base, dynamicRef.$dynamicRef)
|
|
127
|
+
: Ref(root, dynamicRef.$dynamicRef);
|
|
128
|
+
if (Guard.IsUndefined(fragmentTarget))
|
|
129
|
+
return undefined;
|
|
130
|
+
// Dynamic override only applies if the resolved target itself declares a $dynamicAnchor.
|
|
131
|
+
// If it does not, return the static target unchanged.
|
|
132
|
+
if (!Schema.IsSchemaObject(fragmentTarget) || !Schema.IsDynamicAnchor(fragmentTarget))
|
|
133
|
+
return fragmentTarget;
|
|
134
|
+
// Extract the fragment portion of the reference. According to the test suite,
|
|
135
|
+
// only plain fragment names (e.g., "#foo") trigger the dynamic scope; JSON
|
|
136
|
+
// Pointer fragments (e.g., "#/definitions/foo") bypass dynamic resolution.
|
|
137
|
+
const fragment = new URL(dynamicRef.$dynamicRef, 'http://unknown/').hash;
|
|
138
|
+
if (fragment.startsWith('#/'))
|
|
139
|
+
return fragmentTarget;
|
|
140
|
+
// Search the live dynamic anchor stack for a schema whose $dynamicAnchor matches the
|
|
141
|
+
// target's $dynamicAnchor. The stack reflects the current evaluation path, and
|
|
142
|
+
// find() returns the outermost (first encountered) match, which is the correct
|
|
143
|
+
// lexical scope per the specification.
|
|
144
|
+
const anchorTarget = dynamicAnchors.find(anchor => anchor.$dynamicAnchor === fragmentTarget.$dynamicAnchor);
|
|
145
|
+
return anchorTarget ?? fragmentTarget;
|
|
146
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typebox",
|
|
3
3
|
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.25",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
7
7
|
"jsonschema"
|
|
@@ -16,29 +16,21 @@
|
|
|
16
16
|
"types": "./build/index.d.mts",
|
|
17
17
|
"module": "./build/index.mjs",
|
|
18
18
|
"exports": {
|
|
19
|
-
"./
|
|
20
|
-
"import": "./build/
|
|
21
|
-
"default": "./build/
|
|
22
|
-
},
|
|
23
|
-
"./compile": {
|
|
24
|
-
"import": "./build/compile/index.mjs",
|
|
25
|
-
"default": "./build/compile/index.mjs"
|
|
26
|
-
},
|
|
27
|
-
"./value": {
|
|
28
|
-
"import": "./build/value/index.mjs",
|
|
29
|
-
"default": "./build/value/index.mjs"
|
|
19
|
+
"./guard": {
|
|
20
|
+
"import": "./build/guard/index.mjs",
|
|
21
|
+
"default": "./build/guard/index.mjs"
|
|
30
22
|
},
|
|
31
23
|
"./error": {
|
|
32
24
|
"import": "./build/error/index.mjs",
|
|
33
25
|
"default": "./build/error/index.mjs"
|
|
34
26
|
},
|
|
35
|
-
"./
|
|
36
|
-
"import": "./build/
|
|
37
|
-
"default": "./build/
|
|
27
|
+
"./compile": {
|
|
28
|
+
"import": "./build/compile/index.mjs",
|
|
29
|
+
"default": "./build/compile/index.mjs"
|
|
38
30
|
},
|
|
39
|
-
"./
|
|
40
|
-
"import": "./build/
|
|
41
|
-
"default": "./build/
|
|
31
|
+
"./system": {
|
|
32
|
+
"import": "./build/system/index.mjs",
|
|
33
|
+
"default": "./build/system/index.mjs"
|
|
42
34
|
},
|
|
43
35
|
"./format": {
|
|
44
36
|
"import": "./build/format/index.mjs",
|
|
@@ -48,6 +40,14 @@
|
|
|
48
40
|
"import": "./build/type/index.mjs",
|
|
49
41
|
"default": "./build/type/index.mjs"
|
|
50
42
|
},
|
|
43
|
+
"./schema": {
|
|
44
|
+
"import": "./build/schema/index.mjs",
|
|
45
|
+
"default": "./build/schema/index.mjs"
|
|
46
|
+
},
|
|
47
|
+
"./value": {
|
|
48
|
+
"import": "./build/value/index.mjs",
|
|
49
|
+
"default": "./build/value/index.mjs"
|
|
50
|
+
},
|
|
51
51
|
".": {
|
|
52
52
|
"import": "./build/index.mjs",
|
|
53
53
|
"default": "./build/index.mjs"
|
|
@@ -55,23 +55,17 @@
|
|
|
55
55
|
},
|
|
56
56
|
"typesVersions": {
|
|
57
57
|
"*": {
|
|
58
|
-
"
|
|
59
|
-
"./build/
|
|
60
|
-
],
|
|
61
|
-
"compile": [
|
|
62
|
-
"./build/compile/index.d.mts"
|
|
63
|
-
],
|
|
64
|
-
"value": [
|
|
65
|
-
"./build/value/index.d.mts"
|
|
58
|
+
"guard": [
|
|
59
|
+
"./build/guard/index.d.mts"
|
|
66
60
|
],
|
|
67
61
|
"error": [
|
|
68
62
|
"./build/error/index.d.mts"
|
|
69
63
|
],
|
|
70
|
-
"
|
|
71
|
-
"./build/
|
|
64
|
+
"compile": [
|
|
65
|
+
"./build/compile/index.d.mts"
|
|
72
66
|
],
|
|
73
|
-
"
|
|
74
|
-
"./build/
|
|
67
|
+
"system": [
|
|
68
|
+
"./build/system/index.d.mts"
|
|
75
69
|
],
|
|
76
70
|
"format": [
|
|
77
71
|
"./build/format/index.d.mts"
|
|
@@ -79,6 +73,12 @@
|
|
|
79
73
|
"type": [
|
|
80
74
|
"./build/type/index.d.mts"
|
|
81
75
|
],
|
|
76
|
+
"schema": [
|
|
77
|
+
"./build/schema/index.d.mts"
|
|
78
|
+
],
|
|
79
|
+
"value": [
|
|
80
|
+
"./build/value/index.d.mts"
|
|
81
|
+
],
|
|
82
82
|
".": [
|
|
83
83
|
"./build/index.d.mts"
|
|
84
84
|
]
|
package/readme.md
CHANGED
|
@@ -43,6 +43,7 @@ type T = Type.Static<typeof T> // type T = {
|
|
|
43
43
|
// y: number,
|
|
44
44
|
// z: number
|
|
45
45
|
// }
|
|
46
|
+
|
|
46
47
|
```
|
|
47
48
|
|
|
48
49
|
## Overview
|
|
@@ -51,7 +52,7 @@ type T = Type.Static<typeof T> // type T = {
|
|
|
51
52
|
|
|
52
53
|
TypeBox is a runtime type system that creates in-memory JSON Schema objects that infer as TypeScript types. The schematics produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox offers a unified type system that can be statically checked by TypeScript and validated at runtime using standard JSON Schema.
|
|
53
54
|
|
|
54
|
-
This library is designed to allow JSON Schema to compose similar to how types compose within TypeScript's type system. It can be used as a simple tool to build up complex schematics or integrated into REST and
|
|
55
|
+
This library is designed to allow JSON Schema to compose similar to how types compose within TypeScript's type system. It can be used as a simple tool to build up complex schematics or integrated into REST, RPC and MCP services to help validate data received over the wire.
|
|
55
56
|
|
|
56
57
|
License: MIT
|
|
57
58
|
|
|
@@ -79,9 +80,8 @@ The following creates a User type and infers with Static.
|
|
|
79
80
|
```typescript
|
|
80
81
|
import Type from 'typebox'
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
|
|
83
84
|
// Type
|
|
84
|
-
// -------------------------------------------------------------------------------
|
|
85
85
|
|
|
86
86
|
const User = Type.Object({ // const User = {
|
|
87
87
|
id: Type.String(), // type: 'object',
|
|
@@ -100,22 +100,22 @@ const User = Type.Object({ // const User = {
|
|
|
100
100
|
// ]
|
|
101
101
|
// }
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
// Static
|
|
105
|
-
// -------------------------------------------------------------------------------
|
|
106
105
|
|
|
107
106
|
type User = Type.Static<typeof User> // type User = {
|
|
108
107
|
// id: string,
|
|
109
108
|
// name: string,
|
|
110
109
|
// email: string
|
|
111
110
|
// }
|
|
111
|
+
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
## Script
|
|
115
115
|
|
|
116
116
|
[Documentation](https://sinclairzx81.github.io/typebox/#/docs/script/overview) | [Example 1](https://www.typescriptlang.org/play/#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFonmXW32POvueHb6AygGMowMDH6Ne0mbLnNqQiADsAzvADecAKqrUUADQ69UbWAAmAQxjoAvnAC8iIgDpho8QAoABtThxgZRsoDEshdABRIOBCOA1Kf39gcwAuOHVRZQBzBLhbPwCg-VDw4304VDIbZXNVOCiYGKQ4uFz-ZUsQVDSMwKyjNoqQS2AAGx6YTKzW-3zcwjQy0wtrdCcIgDdLUYBXVYAeQYAFYCEAa33dfSMz1CQIDHrowgA+OAAyGcSjy1hgbf2AHkQDFLiYbncHk9Gq8Xrk4ZRvABKah0KTyDGYzGSABKqAwo1QQgkaKxZPJvEUKlUEEJLlGECyniuUCRiXZHM5XK5aPi3P5AsFgrR-gW3XwEGIACsiTA8AZBkKlcrOSK4GBsGg-qhVGk+SqDYa1UlUi0xWk8L1sng8grDfblca4B0unq4Ob8FasjbbHaHf7+U7UMMxm6PZbJn0fYqA7G4GrfTG4-61VBUABHHbANOmgDaSeT9qdeGS8q+hdjxZdqDLBYrKuLwZGoyo9cr9H8AF0622hWi5ko1LTUPTGcyTGYrDY2YXeT3ewK1eHJTLifL5wvuWqNRAtY0dXqN5vVR3Eskw0QLV6fX7jw3T+1OuKtOHr7aj3fEkGQ+MzZfPZG1p5B+n7xqeiagY6p5ppm2aoHmJbmHg3aQUq-aovQFJYdhLCSAIMDWKckg4SRFLUGKSyOM4aBuARjRCPsYpQiybxofQFEslR+qocKp7nukgH9CBoFqtWExTLePGBqeTahgJUzCZ+6GUBxE4rDYVHIDR+GEQxTGPCyk6rKxaKqfoRkaU43FSVufGml6kk2SeiTVgA-OJfSOU57JqrJozufJfSKXe6FAA) | [Example 2](https://www.typescriptlang.org/play/#code/JYWwDg9gTgLgBAFQJ5gKZwGZQiOByGFVAIwgA88AoSgehrgFonmXW32POvnb7k1ejbsJGj21AMYQAdgGd4AUWkxghOAF5ERAHQBJZaigYAhhNQAKANoBdADRwA3pThxgAEwBcWtNoDKMKGBpAHNzAEpKAF8Iyik5eABVWUMNb1Q9AyNTC0slFUI7R2c4aWMQVC9+dP9AkPDbYtQQY2AAG0qdGqDQiOjJGXk4JMMEsDdjGHRNKu0FADdjVoBXCYsZ-UmoZIkYK2KZgAVgCQBrc2GoexmAaVQkAHkMczzVJDCwhpdD41hgRfMZvcQKpzslLmltLcHk8XoR3hFrO9qHQhGI0eiMdxBAAlVAYVqoHaCTEk0mY-pyCAE7StCChC5hFxM5ks1lslkopzs7k83m8lEuQhoLx4CDEABWhJgeE+fLl8u5ArgYGwaF+qFkXi5Cp1uqVLncWrgQoq+HktWCeDgkVlurtfP1JTKpocxqIIvN3StNuK9r97MdTRa7UcbuFZoCXutvv9saZSp9caTLiVUFQAEclsA0544JYY8m-Y68O4ZXAC4W7cXSuUyxXKzri0G2lQG-6ldZ6225SjIhTZFT0rT6WDRuNJozk5yu93+fRBe78GLJTsZTPZ4r58rVYYVBqteuN2zHYbQyaPZGQt7bUee1uXDWXWHTXhPVfrTfb3OWc2Q67zxGFreoeX7xluiagQ6W5ppm2aoLmlglm4eCdpBUHRsSZJYdhnCCP4EzHJhOHEcR1AmkMYKpDM+EqBIAA8JoQBgFGGAAfPKKLkRcqTamhPJKqeb7BJ+fGskqj5eEJImicySq-pJl7BCBaG9mRRAsVAY6rFRnQwAR9GMcxFxaZM7FwJx6nGWM2maLxMliVugmKdJ9nmVuj4APwKRaLn2XJzRtF5cBCcpkG9kAA)
|
|
117
117
|
|
|
118
|
-
TypeBox
|
|
118
|
+
The TypeBox Script function is a micro DSL for constructing JSON Schema from TypeScript syntax. It offers a full syntactic frontend to Type.* with broad support for type-level expressions including Conditional, Mapped, Infer, Generic, Distributive types and more. This feature is implemented symmetrically at both runtime and in the type system.
|
|
119
119
|
|
|
120
120
|
### Example
|
|
121
121
|
|
|
@@ -124,9 +124,8 @@ The following uses the Script function to parse TypeScript interfaces into JSON
|
|
|
124
124
|
```typescript
|
|
125
125
|
import Type from 'typebox'
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
// Script
|
|
129
|
-
// -------------------------------------------------------------------------------
|
|
130
129
|
|
|
131
130
|
const { User, UserUpdate } = Type.Script(`
|
|
132
131
|
|
|
@@ -146,9 +145,8 @@ const { User, UserUpdate } = Type.Script(`
|
|
|
146
145
|
|
|
147
146
|
`)
|
|
148
147
|
|
|
149
|
-
|
|
148
|
+
|
|
150
149
|
// Reflect
|
|
151
|
-
// -------------------------------------------------------------------------------
|
|
152
150
|
|
|
153
151
|
console.log(User) // {
|
|
154
152
|
// type: 'object',
|
|
@@ -174,9 +172,8 @@ console.log(UserUpdate) // {
|
|
|
174
172
|
// required: ['id']
|
|
175
173
|
// }
|
|
176
174
|
|
|
177
|
-
|
|
175
|
+
|
|
178
176
|
// Static
|
|
179
|
-
// -------------------------------------------------------------------------------
|
|
180
177
|
|
|
181
178
|
type User = Type.Static<typeof User> // type User = {
|
|
182
179
|
// id: string,
|
|
@@ -190,15 +187,16 @@ type UserUpdate = Type.Static<typeof UserUpdate> // type UserUpdate = {
|
|
|
190
187
|
// email?: string
|
|
191
188
|
// }
|
|
192
189
|
|
|
190
|
+
|
|
193
191
|
```
|
|
194
192
|
|
|
195
193
|
<a name="Schema"></a>
|
|
196
194
|
|
|
197
195
|
## Schema
|
|
198
196
|
|
|
199
|
-
[Documentation](https://sinclairzx81.github.io/typebox/#/docs/schema/overview) | [Example 1](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAZQMYAsCmICGcBmUIhwDkMAnmGgEYQAeA9AM6oaZEBQokscAKuWrnyES-ajXZs6dOAFo58hYqXKVqteo0zJ0gMIEwwADZptszeYuWr8tmyQQAdg3gBVBmihwAvImZYAdHrgRmgAFHwU-gDylABWaEgwoQDebHBwwAAmAFy8-P4IMFDADgDmoQCUADRpcA6YIGi5EWgFRSXl1bUsRs35hcVlKbjQWDC5RD2GRHAAvhVs8wum1qtr61pScAAKmFDuKxtHx6q29k7wAK7unj5uHv67+2HJ6W-vH5-vW+fOcNceXKpdJZCYANgArDgAIyYABMlAAzEgACyZCFoME4ADsmAAHJQAJxIAAMmWhRCqX2pcC2IJycGcg1KNXS9UaEwBUEpNN5fO+0jZDSajPaZVZcCmnJuAAFMgRMCV-PYQDN+by6ZKsL1RczFhV1YajR8trNvHB-JagA) | [Example 2](https://www.typescriptlang.org/play/#code/JYWwDg9gTgLgBAZQMYAsCmICGcBmUIhwDkMAnmGgEYQAeA9AM6oaZEBQbddcAtH-wMFDhI0WPESenbgGECYYABs003pPUbNW-hyQQAdg3gBVBmihwAvImZYAdHPBK0ACgDebOHDIUAXMQhKACs0JBgiABpPODB8ClhgNAZ-Dy8vYAATFO9yNH8iIyhgfQBzIjgAXyi0uH1MEDy4Nxy-YkLissrqtJYlbJ9Ggpgi0sjcaCwYfN7FcoroquioNABHAFdgZay4AG1oryJMsf3iOobjmqIZ9i8AXTYKgEoOLjVtd4+P1QAFTCgzVSfIHAyS6AxGOBrMwWaymcx2X7-VzNGqotHouCvPSGeBQ8wpaKZfIANgArDgAIyYABMlAAzEgACwZUloYk4ADsmAAHJQAJxIAAMGQpYwx6Ne6W27VK3TOgzxUDF4pVqq8ktq9UaMpK3Rm+UVAAEMgRMMU7HoQOU1SqNfq4DqHo8bS7XajXhUrHA7D6gA) | [Specification](https://sinclairzx81.github.io/typebox/#/docs/schema/
|
|
197
|
+
[Documentation](https://sinclairzx81.github.io/typebox/#/docs/schema/overview) | [Example 1](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBAZQMYAsCmICGcBmUIhwDkMAnmGgEYQAeA9AM6oaZEBQokscAKuWrnyES-ajXZs6dOAFo58hYqXKVqteo0zJ0gMIEwwADZptszeYuWr8tmyQQAdg3gBVBmihwAvImZYAdHrgRmgAFHwU-gDylABWaEgwoQDebHBwwAAmAFy8-P4IMFDADgDmoQCUADRpcA6YIGi5EWgFRSXl1bUsRs35hcVlKbjQWDC5RD2GRHAAvhVs8wum1qtr61pScAAKmFDuKxtHx6q29k7wAK7unj5uHv67+2HJ6W-vH5-vW+fOcNceXKpdJZCYANgArDgAIyYABMlAAzEgACyZCFoME4ADsmAAHJQAJxIAAMmWhRCqX2pcC2IJycGcg1KNXS9UaEwBUEpNN5fO+0jZDSajPaZVZcCmnJuAAFMgRMCV-PYQDN+by6ZKsL1RczFhV1YajR8trNvHB-JagA) | [Example 2](https://www.typescriptlang.org/play/#code/JYWwDg9gTgLgBAZQMYAsCmICGcBmUIhwDkMAnmGgEYQAeA9AM6oaZEBQbddcAtH-wMFDhI0WPESenbgGECYYABs003pPUbNW-hyQQAdg3gBVBmihwAvImZYAdHPBK0ACgDebOHDIUAXMQhKACs0JBgiABpPODB8ClhgNAZ-Dy8vYAATFO9yNH8iIyhgfQBzIjgAXyi0uH1MEDy4Nxy-YkLissrqtJYlbJ9Ggpgi0sjcaCwYfN7FcoroquioNABHAFdgZay4AG1oryJMsf3iOobjmqIZ9i8AXTYKgEoOLjVtd4+P1QAFTCgzVSfIHAyS6AxGOBrMwWaymcx2X7-VzNGqotHouCvPSGeBQ8wpaKZfIANgArDgAIyYABMlAAzEgACwZUloYk4ADsmAAHJQAJxIAAMGQpYwx6Ne6W27VK3TOgzxUDF4pVqq8ktq9UaMpK3Rm+UVAAEMgRMMU7HoQOU1SqNfq4DqHo8bS7XajXhUrHA7D6gA) | [Specification](https://sinclairzx81.github.io/typebox/#/docs/schema/1_spec)
|
|
200
198
|
|
|
201
|
-
TypeBox
|
|
199
|
+
TypeBox has a high-performance JSON Schema compiler with support for drafts 3 through to 2020-12. The compiler is designed to be a lightweight industry-grade alternative to Ajv and offers improved compilation and validation performance. The compiler also offers automatic fallback to dynamic checking in JIT-restricted environments such as Cloudflare Workers.
|
|
202
200
|
|
|
203
201
|
### Example
|
|
204
202
|
|
|
@@ -207,32 +205,153 @@ The following uses the Schema submodule to compile a TypeBox type.
|
|
|
207
205
|
```typescript
|
|
208
206
|
import Schema from 'typebox/schema'
|
|
209
207
|
|
|
210
|
-
|
|
208
|
+
|
|
211
209
|
// Compile
|
|
212
|
-
// -------------------------------------------------------------------------------
|
|
213
210
|
|
|
214
|
-
const User = Schema.Compile(Type.Object({
|
|
215
|
-
id: Type.String(),
|
|
216
|
-
name: Type.String(),
|
|
217
|
-
email: Type.String({ format: 'email' })
|
|
218
|
-
}))
|
|
211
|
+
const User = Schema.Compile(Type.Object({ // const User = Validator<Type.TObject<{
|
|
212
|
+
id: Type.String(), // id: Type.TString;
|
|
213
|
+
name: Type.String(), // name: Type.TString;
|
|
214
|
+
email: Type.String({ format: 'email' }) // email: Type.TString;
|
|
215
|
+
})) // }>, { ... }>
|
|
216
|
+
|
|
219
217
|
|
|
220
|
-
// -------------------------------------------------------------------------------
|
|
221
218
|
// Parse
|
|
222
|
-
// -------------------------------------------------------------------------------
|
|
223
219
|
|
|
224
220
|
const user = User.Parse({ // const user: {
|
|
225
221
|
id: '65f1a2b3c4d5e6f7a8b9c0d1', // id: string,
|
|
226
222
|
name: 'user', // name: string,
|
|
227
223
|
email: 'user@domain.com' // email: string
|
|
228
224
|
}) // } = ...
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Coverage
|
|
229
|
+
|
|
230
|
+
The following table shows specification coverage implemented by TypeBox.
|
|
231
|
+
|
|
232
|
+
Ref: [JSON Schema Test Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite)
|
|
233
|
+
|
|
234
|
+
| Spec | 3 | 4 | 6 | 7 | 2019-09 | 2020-12 | v1 |
|
|
235
|
+
|:-----|:--|:--|:--|:--|:--|:--|:--|
|
|
236
|
+
| additionalItems | ✅ | ✅ | ✅ | ✅ | ✅ | - | - |
|
|
237
|
+
| additionalProperties | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
238
|
+
| allOf | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
239
|
+
| anchor | - | - | - | - | ✅ | ✅ | ✅ |
|
|
240
|
+
| anyOf | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
241
|
+
| boolean_schema | - | - | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
242
|
+
| const | - | - | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
243
|
+
| contains | - | - | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
244
|
+
| content | - | - | - | - | ✅ | ✅ | ✅ |
|
|
245
|
+
| default | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
246
|
+
| dependencies | 17/18 | ✅ | ✅ | ✅ | - | - | - |
|
|
247
|
+
| dependentRequired | - | - | - | - | ✅ | ✅ | ✅ |
|
|
248
|
+
| dependentSchemas | - | - | - | - | ✅ | ✅ | ✅ |
|
|
249
|
+
| dynamicRef | - | - | - | - | - | 38/44 | 19/27 |
|
|
250
|
+
| enum | 14/16 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
251
|
+
| exclusiveMaximum | - | - | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
252
|
+
| exclusiveMinimum | - | - | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
253
|
+
| if-then-else | - | - | - | ✅ | ✅ | ✅ | ✅ |
|
|
254
|
+
| infinite-loop-detection | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
255
|
+
| items | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
256
|
+
| maxContains | - | - | - | - | ✅ | ✅ | ✅ |
|
|
257
|
+
| maximum | 13/14 | 13/14 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
258
|
+
| maxItems | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
259
|
+
| maxLength | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
260
|
+
| maxProperties | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
261
|
+
| minContains | - | - | - | - | ✅ | ✅ | ✅ |
|
|
262
|
+
| minimum | 12/13 | 16/17 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
263
|
+
| minItems | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
264
|
+
| minLength | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
265
|
+
| minProperties | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
266
|
+
| multipleOf | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
267
|
+
| not | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
268
|
+
| oneOf | - | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
269
|
+
| pattern | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
270
|
+
| patternProperties | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
271
|
+
| prefixItems | - | - | - | - | - | ✅ | ✅ |
|
|
272
|
+
| properties | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
273
|
+
| propertyNames | - | - | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
274
|
+
| recursiveRef | - | - | - | - | ✅ | - | - |
|
|
275
|
+
| ref | 23/27 | 37/45 | 67/70 | 75/78 | 79/81 | 77/79 | 77/79 |
|
|
276
|
+
| required | 3/4 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
277
|
+
| type | 73/80 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
278
|
+
| unevaluatedItems | - | - | - | - | ✅ | 65/71 | 64/71 |
|
|
279
|
+
| unevaluatedProperties | - | - | - | - | ✅ | ✅ | 124/125 |
|
|
280
|
+
| uniqueItems | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
### Performance
|
|
284
|
+
|
|
285
|
+
The following table shows compile performance for various JSON Schema structures using AJV8 as a basis for comparison.
|
|
286
|
+
|
|
287
|
+
```python
|
|
288
|
+
┌──────────────────────┬─────────────┬─────────────┐
|
|
289
|
+
│ Compile │ TB1X │ AJV8 │
|
|
290
|
+
├──────────────────────┼─────────────┼─────────────┤
|
|
291
|
+
│ Boolean │ 28.4K ops/s │ 7K ops/s │
|
|
292
|
+
│ Number │ 21.8K ops/s │ 7.7K ops/s │
|
|
293
|
+
│ String │ 47.8K ops/s │ 7.3K ops/s │
|
|
294
|
+
│ Null │ 35.6K ops/s │ 7.8K ops/s │
|
|
295
|
+
│ Literal_String │ 28.6K ops/s │ 6.3K ops/s │
|
|
296
|
+
│ Literal_Number │ 46.6K ops/s │ 6.2K ops/s │
|
|
297
|
+
│ Literal_Boolean │ 40.8K ops/s │ 6.6K ops/s │
|
|
298
|
+
│ Pattern │ 29.7K ops/s │ 4.9K ops/s │
|
|
299
|
+
│ Object_Open │ 6.8K ops/s │ 1.1K ops/s │
|
|
300
|
+
│ Object_Close │ 7.4K ops/s │ 833 ops/s │
|
|
301
|
+
│ Object_Vector3 │ 19.4K ops/s │ 2.1K ops/s │
|
|
302
|
+
│ Object_Basis3 │ 6K ops/s │ 895 ops/s │
|
|
303
|
+
│ Intersect_And │ 12K ops/s │ 3.5K ops/s │
|
|
304
|
+
│ Intersect_Structural │ 8.4K ops/s │ 1.1K ops/s │
|
|
305
|
+
│ Union_Or │ 18.2K ops/s │ 2.5K ops/s │
|
|
306
|
+
│ Union_Structural │ 10.9K ops/s │ 1.3K ops/s │
|
|
307
|
+
│ Tuple_Values │ 7.3K ops/s │ 1.6K ops/s │
|
|
308
|
+
│ Tuple_Objects │ 1.9K ops/s │ 339 ops/s │
|
|
309
|
+
│ Array_Numbers_4 │ 29.9K ops/s │ 3.4K ops/s │
|
|
310
|
+
│ Array_Numbers_8 │ 20.3K ops/s │ 3.4K ops/s │
|
|
311
|
+
│ Array_Numbers_16 │ 29.4K ops/s │ 3.3K ops/s │
|
|
312
|
+
│ Array_Objects_Open │ 6.3K ops/s │ 684 ops/s │
|
|
313
|
+
│ Array_Objects_Close │ 7.3K ops/s │ 762 ops/s │
|
|
314
|
+
└──────────────────────┴─────────────┴─────────────┘
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
The following tables shows validation performance for various JSON Schema structures using AJV8 as a basis for comparison.
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
┌──────────────────────┬──────────────┬──────────────┐
|
|
322
|
+
│ Validate │ TB1X │ AJV8 │
|
|
323
|
+
├──────────────────────┼──────────────┼──────────────┤
|
|
324
|
+
│ Boolean │ 164.1M ops/s │ 181.5M ops/s │
|
|
325
|
+
│ Number │ 107M ops/s │ 50.2M ops/s │
|
|
326
|
+
│ String │ 102.2M ops/s │ 61.9M ops/s │
|
|
327
|
+
│ Null │ 112.1M ops/s │ 48.2M ops/s │
|
|
328
|
+
│ Literal_String │ 102.8M ops/s │ 61.5M ops/s │
|
|
329
|
+
│ Literal_Number │ 109.1M ops/s │ 46.4M ops/s │
|
|
330
|
+
│ Literal_Boolean │ 109.6M ops/s │ 63.3M ops/s │
|
|
331
|
+
│ Pattern │ 24.7M ops/s │ 20.3M ops/s │
|
|
332
|
+
│ Object_Open │ 75.4M ops/s │ 37.3M ops/s │
|
|
333
|
+
│ Object_Close │ 35.9M ops/s │ 21.9M ops/s │
|
|
334
|
+
│ Object_Vector3 │ 77.6M ops/s │ 47.4M ops/s │
|
|
335
|
+
│ Object_Basis3 │ 37M ops/s │ 24.3M ops/s │
|
|
336
|
+
│ Intersect_And │ 93.3M ops/s │ 61.1M ops/s │
|
|
337
|
+
│ Intersect_Structural │ 83M ops/s │ 36.4M ops/s │
|
|
338
|
+
│ Union_Or │ 99.7M ops/s │ 8.6M ops/s │
|
|
339
|
+
│ Union_Structural │ 81.3M ops/s │ 43.5M ops/s │
|
|
340
|
+
│ Tuple_Values │ 72.4M ops/s │ 41.7M ops/s │
|
|
341
|
+
│ Tuple_Objects │ 32.6M ops/s │ 22.4M ops/s │
|
|
342
|
+
│ Array_Numbers_4 │ 94.1M ops/s │ 42.8M ops/s │
|
|
343
|
+
│ Array_Numbers_8 │ 90.6M ops/s │ 42.3M ops/s │
|
|
344
|
+
│ Array_Numbers_16 │ 77.5M ops/s │ 40.2M ops/s │
|
|
345
|
+
│ Array_Objects_Open │ 26.3M ops/s │ 19.6M ops/s │
|
|
346
|
+
│ Array_Objects_Close │ 9.1M ops/s │ 10M ops/s │
|
|
347
|
+
└──────────────────────┴──────────────┴──────────────┘
|
|
229
348
|
```
|
|
230
349
|
|
|
231
350
|
<a name="Versions"></a>
|
|
232
351
|
|
|
233
352
|
## Versions
|
|
234
353
|
|
|
235
|
-
TypeBox
|
|
354
|
+
TypeBox ships two distinct versions that span two generations of the TypeScript compiler.
|
|
236
355
|
|
|
237
356
|
| TypeBox | TypeScript | Description |
|
|
238
357
|
| :--- | :--- | :--- |
|