typebox 1.1.36 → 1.1.38
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/compile/code.mjs +2 -2
- package/build/compile/validator.d.mts +11 -10
- package/build/compile/validator.mjs +49 -44
- package/build/guard/guard.d.mts +3 -1
- package/build/guard/guard.mjs +6 -3
- package/build/schema/build.d.mts +11 -7
- package/build/schema/build.mjs +28 -9
- package/build/schema/compile.d.mts +2 -2
- package/build/schema/compile.mjs +9 -9
- package/build/schema/engine/additionalProperties.mjs +1 -1
- package/build/schema/pointer/pointer.mjs +11 -1
- package/build/value/clone/clone.mjs +4 -3
- package/build/value/delta/diff.mjs +6 -0
- package/build/value/mutate/from_object.mjs +13 -0
- package/package.json +1 -1
- package/readme.md +47 -47
package/build/compile/code.mjs
CHANGED
|
@@ -45,8 +45,8 @@ function FunctionSection(build) {
|
|
|
45
45
|
// ------------------------------------------------------------------
|
|
46
46
|
function ExportSection(build) {
|
|
47
47
|
const body = build.UseUnevaluated()
|
|
48
|
-
? `const context = new CheckContext({}, {}); return ${build.
|
|
49
|
-
: `return ${build.
|
|
48
|
+
? `const context = new CheckContext({}, {}); return ${build.Entry()}`
|
|
49
|
+
: `return ${build.Entry()}`;
|
|
50
50
|
return [
|
|
51
51
|
Separator(),
|
|
52
52
|
TsIgnore(),
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { type TLocalizedValidationError } from '../error/index.mjs';
|
|
2
2
|
import { type StaticDecode, type StaticEncode, type TProperties, type TSchema, Base } from '../type/index.mjs';
|
|
3
|
+
import { BuildResult, EvaluateResult } from '../schema/index.mjs';
|
|
3
4
|
export declare class Validator<Context extends TProperties = TProperties, Type extends TSchema = TSchema, Encode extends unknown = StaticEncode<Type, Context>, Decode extends unknown = StaticDecode<Type, Context>> extends Base<Encode> {
|
|
4
|
-
private readonly context;
|
|
5
|
-
private readonly type;
|
|
6
|
-
private readonly isAccelerated;
|
|
7
5
|
private readonly hasCodec;
|
|
8
|
-
private readonly
|
|
9
|
-
private readonly
|
|
6
|
+
private readonly buildResult;
|
|
7
|
+
private readonly evaluateResult;
|
|
10
8
|
/** Constructs a Validator with the given Context and Type. */
|
|
11
9
|
constructor(context: Context, type: Type);
|
|
12
10
|
/** Constructs a Validator with the given arguments. */
|
|
13
|
-
constructor(
|
|
11
|
+
constructor(hasCodec: boolean, buildResult: BuildResult, evaluateResult: EvaluateResult);
|
|
14
12
|
/** Returns true if this Validator is using JIT acceleration. */
|
|
15
13
|
IsAccelerated(): boolean;
|
|
16
14
|
/** Returns the Context for this validator. */
|
|
@@ -21,6 +19,8 @@ export declare class Validator<Context extends TProperties = TProperties, Type e
|
|
|
21
19
|
Code(): string;
|
|
22
20
|
/** Performs a type-guard check on the provided value. */
|
|
23
21
|
Check(value: unknown): value is Encode;
|
|
22
|
+
/** Validates a value and returns it. Will throw if invalid. */
|
|
23
|
+
Parse(value: unknown): Encode;
|
|
24
24
|
/** Inspects a value and returns a detailed list of validation errors. */
|
|
25
25
|
Errors(value: unknown): TLocalizedValidationError[];
|
|
26
26
|
/** Cleans a value using the Validator type. */
|
|
@@ -31,12 +31,13 @@ export declare class Validator<Context extends TProperties = TProperties, Type e
|
|
|
31
31
|
Create(): Encode;
|
|
32
32
|
/** Creates defaults using the Validator type. */
|
|
33
33
|
Default(value: unknown): unknown;
|
|
34
|
-
/** Clones this validator. */
|
|
35
|
-
Clone(): Validator<Context, Type>;
|
|
36
|
-
/** Validates a value and returns it. Will throw if invalid. */
|
|
37
|
-
Parse(value: unknown): Encode;
|
|
38
34
|
/** Decodes a value */
|
|
39
35
|
Decode(value: unknown): Decode;
|
|
40
36
|
/** Encodes a value */
|
|
41
37
|
Encode(value: unknown): Encode;
|
|
38
|
+
/**
|
|
39
|
+
* @deprecated Validator instances should not support Clone because they are owners of JIT evaluated functions. This function will be
|
|
40
|
+
* removed in the next version of TypeBox (relates to Type.Base deprecation)
|
|
41
|
+
*/
|
|
42
|
+
Clone(): Validator<Context, Type>;
|
|
42
43
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
// deno-fmt-ignore-file
|
|
2
2
|
import { Settings } from '../system/settings/index.mjs';
|
|
3
3
|
import { Arguments } from '../system/arguments/index.mjs';
|
|
4
|
-
import { Environment } from '../system/environment/index.mjs';
|
|
5
4
|
import { Base } from '../type/index.mjs';
|
|
6
5
|
import { Errors, Clean, Convert, Create, Default, Decode, Encode, HasCodec, Parser, ParseError } from '../value/index.mjs';
|
|
7
|
-
import { Build } from '../schema/index.mjs';
|
|
6
|
+
import { Build, BuildResult, EvaluateResult } from '../schema/index.mjs';
|
|
8
7
|
// ------------------------------------------------------------------
|
|
9
8
|
// Validator<...>
|
|
10
9
|
// ------------------------------------------------------------------
|
|
@@ -13,27 +12,24 @@ export class Validator extends Base {
|
|
|
13
12
|
constructor(...args) {
|
|
14
13
|
super();
|
|
15
14
|
const matched = Arguments.Match(args, {
|
|
16
|
-
|
|
15
|
+
3: (hasCodec, buildResult, evaluateResult) => [hasCodec, buildResult, evaluateResult],
|
|
17
16
|
2: (context, type) => [context, type]
|
|
18
17
|
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
// Note: The Base type requires this Validator to be Clone, but where we cannot safely clone
|
|
19
|
+
// the BuildResult or the EvaluateResult. For now we pass the Validator constructor a shared
|
|
20
|
+
// reference of BuildResult and EvaluateResult to mitigate re-compile on Clone. We must remove
|
|
21
|
+
// this overload when Base is removed (memory-gc-ref)
|
|
22
|
+
if (matched.length === 3 && matched[1] instanceof BuildResult && matched[2] instanceof EvaluateResult) {
|
|
23
|
+
const [hasCodec, buildResult, evaluateResult] = matched;
|
|
24
24
|
this.hasCodec = hasCodec;
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
25
|
+
this.buildResult = buildResult;
|
|
26
|
+
this.evaluateResult = evaluateResult;
|
|
27
27
|
}
|
|
28
28
|
else {
|
|
29
29
|
const [context, type] = matched;
|
|
30
|
-
const result = Build(context, type).Evaluate();
|
|
31
30
|
this.hasCodec = HasCodec(context, type);
|
|
32
|
-
this.
|
|
33
|
-
this.
|
|
34
|
-
this.isAccelerated = result.IsAccelerated;
|
|
35
|
-
this.code = result.Code;
|
|
36
|
-
this.check = result.Check;
|
|
31
|
+
this.buildResult = Build(context, type);
|
|
32
|
+
this.evaluateResult = this.buildResult.Evaluate();
|
|
37
33
|
}
|
|
38
34
|
}
|
|
39
35
|
// ----------------------------------------------------------------
|
|
@@ -41,76 +37,85 @@ export class Validator extends Base {
|
|
|
41
37
|
// ----------------------------------------------------------------
|
|
42
38
|
/** Returns true if this Validator is using JIT acceleration. */
|
|
43
39
|
IsAccelerated() {
|
|
44
|
-
return this.
|
|
40
|
+
return this.evaluateResult.IsAccelerated();
|
|
45
41
|
}
|
|
46
42
|
// ----------------------------------------------------------------
|
|
47
|
-
// Context
|
|
43
|
+
// Context & Type
|
|
48
44
|
// ----------------------------------------------------------------
|
|
49
45
|
/** Returns the Context for this validator. */
|
|
50
46
|
Context() {
|
|
51
|
-
return this.
|
|
47
|
+
return this.buildResult.Context();
|
|
52
48
|
}
|
|
53
49
|
/** Returns the underlying Type used to construct this Validator. */
|
|
54
50
|
Type() {
|
|
55
|
-
return this.
|
|
51
|
+
return this.buildResult.Schema();
|
|
56
52
|
}
|
|
57
53
|
// ----------------------------------------------------------------
|
|
58
54
|
// Code
|
|
59
55
|
// ----------------------------------------------------------------
|
|
60
56
|
/** Returns the generated code for this validator. */
|
|
61
57
|
Code() {
|
|
62
|
-
return this.
|
|
58
|
+
return this.evaluateResult.Code();
|
|
63
59
|
}
|
|
64
60
|
// ----------------------------------------------------------------
|
|
65
|
-
//
|
|
61
|
+
// Standard Validator
|
|
66
62
|
// ----------------------------------------------------------------
|
|
67
63
|
/** Performs a type-guard check on the provided value. */
|
|
68
64
|
Check(value) {
|
|
69
|
-
return this.
|
|
65
|
+
return this.evaluateResult.Check(value);
|
|
66
|
+
}
|
|
67
|
+
/** Validates a value and returns it. Will throw if invalid. */
|
|
68
|
+
Parse(value) {
|
|
69
|
+
const checked = this.Check(value);
|
|
70
|
+
if (checked)
|
|
71
|
+
return value;
|
|
72
|
+
if (Settings.Get().correctiveParse)
|
|
73
|
+
return Parser(this.Context(), this.Type(), value);
|
|
74
|
+
throw new ParseError(value, this.Errors(value));
|
|
70
75
|
}
|
|
71
76
|
/** Inspects a value and returns a detailed list of validation errors. */
|
|
72
77
|
Errors(value) {
|
|
73
|
-
if (
|
|
78
|
+
if (this.IsAccelerated() && this.Check(value))
|
|
74
79
|
return [];
|
|
75
|
-
return Errors(this.
|
|
80
|
+
return Errors(this.Context(), this.Type(), value);
|
|
76
81
|
}
|
|
82
|
+
// ----------------------------------------------------------------
|
|
83
|
+
// Value.* Operations
|
|
84
|
+
// ----------------------------------------------------------------
|
|
77
85
|
/** Cleans a value using the Validator type. */
|
|
78
86
|
Clean(value) {
|
|
79
|
-
return Clean(this.
|
|
87
|
+
return Clean(this.Context(), this.Type(), value);
|
|
80
88
|
}
|
|
81
89
|
/** Converts a value using the Validator type. */
|
|
82
90
|
Convert(value) {
|
|
83
|
-
return Convert(this.
|
|
91
|
+
return Convert(this.Context(), this.Type(), value);
|
|
84
92
|
}
|
|
85
93
|
/** Creates a value using the Validator type. */
|
|
86
94
|
Create() {
|
|
87
|
-
return Create(this.
|
|
95
|
+
return Create(this.Context(), this.Type());
|
|
88
96
|
}
|
|
89
97
|
/** Creates defaults using the Validator type. */
|
|
90
98
|
Default(value) {
|
|
91
|
-
return Default(this.
|
|
92
|
-
}
|
|
93
|
-
/** Clones this validator. */
|
|
94
|
-
Clone() {
|
|
95
|
-
return new Validator(this.context, this.type, this.isAccelerated, this.hasCodec, this.code, this.check);
|
|
96
|
-
}
|
|
97
|
-
/** Validates a value and returns it. Will throw if invalid. */
|
|
98
|
-
Parse(value) {
|
|
99
|
-
const checked = this.Check(value);
|
|
100
|
-
if (checked)
|
|
101
|
-
return value;
|
|
102
|
-
if (Settings.Get().correctiveParse)
|
|
103
|
-
return Parser(this.context, this.type, value);
|
|
104
|
-
throw new ParseError(value, this.Errors(value));
|
|
99
|
+
return Default(this.Context(), this.Type(), value);
|
|
105
100
|
}
|
|
106
101
|
/** Decodes a value */
|
|
107
102
|
Decode(value) {
|
|
108
|
-
const result = this.hasCodec ? Decode(this.
|
|
103
|
+
const result = this.hasCodec ? Decode(this.Context(), this.Type(), value) : this.Parse(value);
|
|
109
104
|
return result;
|
|
110
105
|
}
|
|
111
106
|
/** Encodes a value */
|
|
112
107
|
Encode(value) {
|
|
113
|
-
const result = this.hasCodec ? Encode(this.
|
|
108
|
+
const result = this.hasCodec ? Encode(this.Context(), this.Type(), value) : this.Parse(value);
|
|
114
109
|
return result;
|
|
115
110
|
}
|
|
111
|
+
// ----------------------------------------------------------------
|
|
112
|
+
// Deprecations
|
|
113
|
+
// ----------------------------------------------------------------
|
|
114
|
+
/**
|
|
115
|
+
* @deprecated Validator instances should not support Clone because they are owners of JIT evaluated functions. This function will be
|
|
116
|
+
* removed in the next version of TypeBox (relates to Type.Base deprecation)
|
|
117
|
+
*/
|
|
118
|
+
Clone() {
|
|
119
|
+
return new Validator(this.hasCodec, this.buildResult, this.evaluateResult);
|
|
120
|
+
}
|
|
116
121
|
}
|
package/build/guard/guard.d.mts
CHANGED
|
@@ -49,6 +49,8 @@ export declare function Every<T>(value: T[], offset: number, callback: (value: T
|
|
|
49
49
|
export declare function EveryAll<T>(value: T[], offset: number, callback: (value: T, index: number) => boolean): boolean;
|
|
50
50
|
/** Takes the left-most element from an array and dispatches to the true arm, or the false arm if empty */
|
|
51
51
|
export declare function TakeLeft<T, True extends (left: T, right: T[]) => unknown, False extends () => unknown>(array: T[], true_: True, false_: False): ReturnType<True> | ReturnType<False>;
|
|
52
|
+
/** Returns true if the PropertyKey is Unsafe (ref: prototype-pollution). */
|
|
53
|
+
export declare function IsUnsafePropertyKey(key: PropertyKey): boolean;
|
|
52
54
|
/** Returns true if this value has this property key */
|
|
53
55
|
export declare function HasPropertyKey<Key extends PropertyKey>(value: object, key: Key): value is {
|
|
54
56
|
[_ in Key]: unknown;
|
|
@@ -57,7 +59,7 @@ export declare function HasPropertyKey<Key extends PropertyKey>(value: object, k
|
|
|
57
59
|
export declare function EntriesRegExp<Value extends unknown = unknown>(value: Record<PropertyKey, Value>): [RegExp, Value][];
|
|
58
60
|
/** Returns object entries as `[string, Value][]` */
|
|
59
61
|
export declare function Entries<Value extends unknown = unknown>(value: Record<PropertyKey, Value>): [string, Value][];
|
|
60
|
-
/** Returns
|
|
62
|
+
/** Returns property keys for this object via `Object.getOwnPropertyKeys({ ... })` */
|
|
61
63
|
export declare function Keys(value: Record<PropertyKey, unknown>): string[];
|
|
62
64
|
/** Returns the property keys for this object via `Object.getOwnPropertyKeys({ ... })` */
|
|
63
65
|
export declare function Symbols(value: Record<PropertyKey, unknown>): symbol[];
|
package/build/guard/guard.mjs
CHANGED
|
@@ -169,10 +169,13 @@ export function TakeLeft(array, true_, false_) {
|
|
|
169
169
|
// --------------------------------------------------------------------------
|
|
170
170
|
// Object
|
|
171
171
|
// --------------------------------------------------------------------------
|
|
172
|
+
/** Returns true if the PropertyKey is Unsafe (ref: prototype-pollution). */
|
|
173
|
+
export function IsUnsafePropertyKey(key) {
|
|
174
|
+
return IsEqual(key, '__proto__') || IsEqual(key, 'constructor') || IsEqual(key, 'prototype');
|
|
175
|
+
}
|
|
172
176
|
/** Returns true if this value has this property key */
|
|
173
177
|
export function HasPropertyKey(value, key) {
|
|
174
|
-
|
|
175
|
-
return isProtoField ? Object.prototype.hasOwnProperty.call(value, key) : key in value;
|
|
178
|
+
return IsUnsafePropertyKey(key) ? Object.prototype.hasOwnProperty.call(value, key) : key in value;
|
|
176
179
|
}
|
|
177
180
|
/** Returns object entries as `[RegExp, Value][]` */
|
|
178
181
|
export function EntriesRegExp(value) {
|
|
@@ -182,7 +185,7 @@ export function EntriesRegExp(value) {
|
|
|
182
185
|
export function Entries(value) {
|
|
183
186
|
return Object.entries(value);
|
|
184
187
|
}
|
|
185
|
-
/** Returns
|
|
188
|
+
/** Returns property keys for this object via `Object.getOwnPropertyKeys({ ... })` */
|
|
186
189
|
export function Keys(value) {
|
|
187
190
|
return Object.getOwnPropertyNames(value);
|
|
188
191
|
}
|
package/build/schema/build.d.mts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import * as Engine from './engine/index.mjs';
|
|
2
2
|
import * as Schema from './types/index.mjs';
|
|
3
3
|
export type CheckFunction = (value: unknown) => boolean;
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export declare class EvaluateResult {
|
|
5
|
+
private readonly isAccelerated;
|
|
6
|
+
private readonly code;
|
|
7
|
+
private readonly check;
|
|
8
|
+
constructor(isAccelerated: boolean, code: string, check: CheckFunction);
|
|
9
|
+
IsAccelerated(): boolean;
|
|
10
|
+
Code(): string;
|
|
11
|
+
Check(value: unknown): boolean;
|
|
8
12
|
}
|
|
9
13
|
export declare class BuildResult {
|
|
10
14
|
private readonly context;
|
|
11
15
|
private readonly schema;
|
|
12
16
|
private readonly external;
|
|
13
17
|
private readonly functions;
|
|
14
|
-
private readonly
|
|
18
|
+
private readonly entry;
|
|
15
19
|
private readonly useUnevaluated;
|
|
16
|
-
constructor(context: Record<PropertyKey, Schema.XSchema>, schema: Schema.XSchema, external: Engine.TExternal, functions: string[],
|
|
20
|
+
constructor(context: Record<PropertyKey, Schema.XSchema>, schema: Schema.XSchema, external: Engine.TExternal, functions: string[], entry: string, useUnevaluated: boolean);
|
|
17
21
|
/** Returns the Context used for this build */
|
|
18
22
|
Context(): Record<PropertyKey, Schema.XSchema>;
|
|
19
23
|
/** Returns the Schema used for this build */
|
|
@@ -25,7 +29,7 @@ export declare class BuildResult {
|
|
|
25
29
|
/** Returns check functions */
|
|
26
30
|
Functions(): string[];
|
|
27
31
|
/** Return entry function call. */
|
|
28
|
-
|
|
32
|
+
Entry(): string;
|
|
29
33
|
/** Evaluates the build into a validation function */
|
|
30
34
|
Evaluate(): EvaluateResult;
|
|
31
35
|
}
|
package/build/schema/build.mjs
CHANGED
|
@@ -12,8 +12,8 @@ import * as Engine from './engine/index.mjs';
|
|
|
12
12
|
function CreateCode(build) {
|
|
13
13
|
const functions = build.Functions().join(';\n');
|
|
14
14
|
const statements = build.UseUnevaluated()
|
|
15
|
-
? ['const context = new CheckContext({}, {})', `return ${build.
|
|
16
|
-
: [`return ${build.
|
|
15
|
+
? ['const context = new CheckContext({}, {})', `return ${build.Entry()}`]
|
|
16
|
+
: [`return ${build.Entry()}`];
|
|
17
17
|
return `${functions}; return (value) => { ${statements.join('; ')} }`;
|
|
18
18
|
}
|
|
19
19
|
// ------------------------------------------------------------------
|
|
@@ -40,15 +40,34 @@ function CreateCheck(build, code) {
|
|
|
40
40
|
: CreateDynamicCheck(build);
|
|
41
41
|
}
|
|
42
42
|
// ------------------------------------------------------------------
|
|
43
|
+
// EvaluateResult
|
|
44
|
+
// ------------------------------------------------------------------
|
|
45
|
+
export class EvaluateResult {
|
|
46
|
+
constructor(isAccelerated, code, check) {
|
|
47
|
+
this.isAccelerated = isAccelerated;
|
|
48
|
+
this.code = code;
|
|
49
|
+
this.check = check;
|
|
50
|
+
}
|
|
51
|
+
IsAccelerated() {
|
|
52
|
+
return this.isAccelerated;
|
|
53
|
+
}
|
|
54
|
+
Code() {
|
|
55
|
+
return this.code;
|
|
56
|
+
}
|
|
57
|
+
Check(value) {
|
|
58
|
+
return this.check(value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ------------------------------------------------------------------
|
|
43
62
|
// BuildResult
|
|
44
63
|
// ------------------------------------------------------------------
|
|
45
64
|
export class BuildResult {
|
|
46
|
-
constructor(context, schema, external, functions,
|
|
65
|
+
constructor(context, schema, external, functions, entry, useUnevaluated) {
|
|
47
66
|
this.context = context;
|
|
48
67
|
this.schema = schema;
|
|
49
68
|
this.external = external;
|
|
50
69
|
this.functions = functions;
|
|
51
|
-
this.
|
|
70
|
+
this.entry = entry;
|
|
52
71
|
this.useUnevaluated = useUnevaluated;
|
|
53
72
|
}
|
|
54
73
|
/** Returns the Context used for this build */
|
|
@@ -72,14 +91,14 @@ export class BuildResult {
|
|
|
72
91
|
return this.functions;
|
|
73
92
|
}
|
|
74
93
|
/** Return entry function call. */
|
|
75
|
-
|
|
76
|
-
return this.
|
|
94
|
+
Entry() {
|
|
95
|
+
return this.entry;
|
|
77
96
|
}
|
|
78
97
|
/** Evaluates the build into a validation function */
|
|
79
98
|
Evaluate() {
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
return
|
|
99
|
+
const code = CreateCode(this);
|
|
100
|
+
const check = CreateCheck(this, code);
|
|
101
|
+
return new EvaluateResult(Environment.CanEvaluate(), code, check);
|
|
83
102
|
}
|
|
84
103
|
}
|
|
85
104
|
/** Builds a schema into a optimized runtime validator */
|
|
@@ -2,8 +2,8 @@ import { type TLocalizedValidationError } from '../error/index.mjs';
|
|
|
2
2
|
import { type Static } from '../type/types/static.mjs';
|
|
3
3
|
import * as Schema from './types/index.mjs';
|
|
4
4
|
export declare class Validator<const Schema extends Schema.XSchema = Schema.XSchema, Value extends unknown = Static<Schema>> {
|
|
5
|
-
private readonly
|
|
6
|
-
private readonly
|
|
5
|
+
private readonly buildResult;
|
|
6
|
+
private readonly evaluateResult;
|
|
7
7
|
constructor(context: Record<string, Schema.XSchema>, schema: Schema);
|
|
8
8
|
/** Returns true if this Validator is using JIT acceleration. */
|
|
9
9
|
IsAccelerated(): boolean;
|
package/build/schema/compile.mjs
CHANGED
|
@@ -9,31 +9,31 @@ import { ParseError } from './parse.mjs';
|
|
|
9
9
|
// ------------------------------------------------------------------
|
|
10
10
|
export class Validator {
|
|
11
11
|
constructor(context, schema) {
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
12
|
+
this.buildResult = Build.Build(context, schema);
|
|
13
|
+
this.evaluateResult = this.buildResult.Evaluate();
|
|
14
14
|
}
|
|
15
15
|
/** Returns true if this Validator is using JIT acceleration. */
|
|
16
16
|
IsAccelerated() {
|
|
17
|
-
return this.
|
|
17
|
+
return this.evaluateResult.IsAccelerated();
|
|
18
18
|
}
|
|
19
19
|
/** Returns the underlying Schema used to construct this Validator. */
|
|
20
20
|
Schema() {
|
|
21
|
-
return this.
|
|
21
|
+
return this.buildResult.Schema();
|
|
22
22
|
}
|
|
23
23
|
/** Performs a type-guard check on the provided value. */
|
|
24
24
|
Check(value) {
|
|
25
|
-
return this.
|
|
25
|
+
return this.evaluateResult.Check(value);
|
|
26
26
|
}
|
|
27
27
|
/** Validates a value and returns it. Will throw if invalid. */
|
|
28
28
|
Parse(value) {
|
|
29
|
-
if (this.
|
|
29
|
+
if (this.evaluateResult.Check(value))
|
|
30
30
|
return value;
|
|
31
|
-
const [_result, errors] = Errors(this.
|
|
32
|
-
throw new ParseError(this.
|
|
31
|
+
const [_result, errors] = Errors(this.buildResult.Context(), this.buildResult.Schema(), value);
|
|
32
|
+
throw new ParseError(this.buildResult.Schema(), value, errors);
|
|
33
33
|
}
|
|
34
34
|
/** Inspects a value and returns a detailed list of validation errors. */
|
|
35
35
|
Errors(value) {
|
|
36
|
-
return Errors(this.
|
|
36
|
+
return Errors(this.buildResult.Context(), this.buildResult.Schema(), value);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
/** Compiles this schema into a high performance Validator */
|
|
@@ -104,7 +104,7 @@ export function ErrorAdditionalProperties(stack, context, schemaPath, instancePa
|
|
|
104
104
|
return isAdditionalProperties || context.AddError({
|
|
105
105
|
keyword: 'additionalProperties',
|
|
106
106
|
schemaPath,
|
|
107
|
-
instancePath
|
|
107
|
+
instancePath,
|
|
108
108
|
params: { additionalProperties },
|
|
109
109
|
});
|
|
110
110
|
}
|
|
@@ -11,6 +11,14 @@ function AssertCanSet(value) {
|
|
|
11
11
|
if (!Guard.IsObject(value))
|
|
12
12
|
throw Error('Cannot set value');
|
|
13
13
|
}
|
|
14
|
+
function AssertIndex(index) {
|
|
15
|
+
if (Guard.IsUnsafePropertyKey(index))
|
|
16
|
+
throw Error('Pointer contains unsafe property key');
|
|
17
|
+
}
|
|
18
|
+
function AssertIndices(indices) {
|
|
19
|
+
for (const index of indices)
|
|
20
|
+
AssertIndex(index);
|
|
21
|
+
}
|
|
14
22
|
// ------------------------------------------------------------------
|
|
15
23
|
// Indices
|
|
16
24
|
// ------------------------------------------------------------------
|
|
@@ -27,7 +35,7 @@ function HasIndex(index, value) {
|
|
|
27
35
|
return Guard.IsObject(value) && Guard.HasPropertyKey(value, index);
|
|
28
36
|
}
|
|
29
37
|
function GetIndex(index, value) {
|
|
30
|
-
return Guard.IsObject(value) ? value[index] : undefined;
|
|
38
|
+
return Guard.IsObject(value) && !Guard.IsUnsafePropertyKey(index) ? value[index] : undefined;
|
|
31
39
|
}
|
|
32
40
|
function GetIndices(indices, value) {
|
|
33
41
|
return indices.reduce((value, index) => GetIndex(index, value), value);
|
|
@@ -70,6 +78,7 @@ export function Get(value, pointer) {
|
|
|
70
78
|
export function Set(value, pointer, next) {
|
|
71
79
|
const indices = Indices(pointer);
|
|
72
80
|
AssertNotRoot(indices);
|
|
81
|
+
AssertIndices(indices);
|
|
73
82
|
const [head, index] = TakeIndexRight(indices);
|
|
74
83
|
const parent = GetIndices(head, value);
|
|
75
84
|
AssertCanSet(parent);
|
|
@@ -83,6 +92,7 @@ export function Set(value, pointer, next) {
|
|
|
83
92
|
export function Delete(value, pointer) {
|
|
84
93
|
const indices = Indices(pointer);
|
|
85
94
|
AssertNotRoot(indices);
|
|
95
|
+
AssertIndices(indices);
|
|
86
96
|
const [head, index] = TakeIndexRight(indices);
|
|
87
97
|
const parent = GetIndices(head, value);
|
|
88
98
|
AssertCanSet(parent);
|
|
@@ -18,15 +18,16 @@ function FromClassInstance(value) {
|
|
|
18
18
|
// ------------------------------------------------------------------
|
|
19
19
|
function FromObjectInstance(value) {
|
|
20
20
|
const result = {};
|
|
21
|
-
for (const key of
|
|
21
|
+
for (const key of Guard.Keys(value)) {
|
|
22
|
+
if (Guard.IsUnsafePropertyKey(key))
|
|
23
|
+
continue; // (ignore: prototype-pollution)
|
|
22
24
|
result[key] = Clone(value[key]);
|
|
23
25
|
}
|
|
24
|
-
for (const key of
|
|
26
|
+
for (const key of Guard.Symbols(value)) {
|
|
25
27
|
result[key] = Clone(value[key]);
|
|
26
28
|
}
|
|
27
29
|
return result;
|
|
28
30
|
}
|
|
29
|
-
Object.create({});
|
|
30
31
|
// ------------------------------------------------------------------
|
|
31
32
|
// Object
|
|
32
33
|
// ------------------------------------------------------------------
|
|
@@ -37,6 +37,8 @@ function* FromObject(path, left, right) {
|
|
|
37
37
|
for (const key of rightKeys) {
|
|
38
38
|
if (Guard.HasPropertyKey(left, key))
|
|
39
39
|
continue;
|
|
40
|
+
if (Guard.IsUnsafePropertyKey(key))
|
|
41
|
+
continue;
|
|
40
42
|
yield CreateInsert(`${path}/${key}`, right[key]);
|
|
41
43
|
}
|
|
42
44
|
// ----------------------------------------------------------------
|
|
@@ -45,6 +47,8 @@ function* FromObject(path, left, right) {
|
|
|
45
47
|
for (const key of leftKeys) {
|
|
46
48
|
if (!Guard.HasPropertyKey(right, key))
|
|
47
49
|
continue;
|
|
50
|
+
if (Guard.IsUnsafePropertyKey(key))
|
|
51
|
+
continue;
|
|
48
52
|
if (Equal(left, right))
|
|
49
53
|
continue;
|
|
50
54
|
yield* FromValue(`${path}/${key}`, left[key], right[key]);
|
|
@@ -55,6 +59,8 @@ function* FromObject(path, left, right) {
|
|
|
55
59
|
for (const key of leftKeys) {
|
|
56
60
|
if (Guard.HasPropertyKey(right, key))
|
|
57
61
|
continue;
|
|
62
|
+
if (Guard.IsUnsafePropertyKey(key))
|
|
63
|
+
continue;
|
|
58
64
|
yield CreateDelete(`${path}/${key}`);
|
|
59
65
|
}
|
|
60
66
|
}
|
|
@@ -3,6 +3,16 @@ import { Guard } from '../../guard/index.mjs';
|
|
|
3
3
|
import { Pointer } from '../pointer/index.mjs';
|
|
4
4
|
import { Clone } from '../clone/index.mjs';
|
|
5
5
|
import { FromValue } from './from_value.mjs';
|
|
6
|
+
// ------------------------------------------------------------------
|
|
7
|
+
// AssertKey
|
|
8
|
+
// ------------------------------------------------------------------
|
|
9
|
+
function AssertKey(key) {
|
|
10
|
+
if (Guard.IsUnsafePropertyKey(key))
|
|
11
|
+
throw Error('Attempted to Mutate with unsafe property key');
|
|
12
|
+
}
|
|
13
|
+
// ------------------------------------------------------------------
|
|
14
|
+
// AssertKey
|
|
15
|
+
// ------------------------------------------------------------------
|
|
6
16
|
export function FromObject(root, path, current, next) {
|
|
7
17
|
if (!Guard.IsObjectNotArray(current)) {
|
|
8
18
|
Pointer.Set(root, path, Clone(next));
|
|
@@ -11,16 +21,19 @@ export function FromObject(root, path, current, next) {
|
|
|
11
21
|
const currentKeys = Guard.Keys(current);
|
|
12
22
|
const nextKeys = Guard.Keys(next);
|
|
13
23
|
for (const currentKey of currentKeys) {
|
|
24
|
+
AssertKey(currentKey);
|
|
14
25
|
if (!nextKeys.includes(currentKey)) {
|
|
15
26
|
delete current[currentKey];
|
|
16
27
|
}
|
|
17
28
|
}
|
|
18
29
|
for (const nextKey of nextKeys) {
|
|
30
|
+
AssertKey(nextKey);
|
|
19
31
|
if (!currentKeys.includes(nextKey)) {
|
|
20
32
|
current[nextKey] = next[nextKey];
|
|
21
33
|
}
|
|
22
34
|
}
|
|
23
35
|
for (const nextKey of nextKeys) {
|
|
36
|
+
AssertKey(nextKey);
|
|
24
37
|
FromValue(root, `${path}/${nextKey}`, current[nextKey], next[nextKey]);
|
|
25
38
|
}
|
|
26
39
|
}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -52,7 +52,7 @@ type T = Type.Static<typeof T> // type T = {
|
|
|
52
52
|
|
|
53
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.
|
|
54
54
|
|
|
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
|
|
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 and RPC services to help validate data received over the wire.
|
|
56
56
|
|
|
57
57
|
License: MIT
|
|
58
58
|
|
|
@@ -281,29 +281,29 @@ The following table shows compile performance for various JSON Schema structures
|
|
|
281
281
|
┌──────────────────────┬─────────────┬─────────────┐
|
|
282
282
|
│ Compile │ TB1X │ AJV8 │
|
|
283
283
|
├──────────────────────┼─────────────┼─────────────┤
|
|
284
|
-
│ Boolean │
|
|
285
|
-
│ Number │
|
|
286
|
-
│ String │
|
|
287
|
-
│ Null │
|
|
288
|
-
│ Literal_String │
|
|
289
|
-
│ Literal_Number │
|
|
290
|
-
│ Literal_Boolean │
|
|
291
|
-
│ Pattern │
|
|
292
|
-
│ Object_Open │ 6.
|
|
293
|
-
│ Object_Close │ 7.
|
|
294
|
-
│ Object_Vector3 │
|
|
295
|
-
│ Object_Basis3 │
|
|
296
|
-
│ Intersect_And │
|
|
297
|
-
│ Intersect_Structural │ 8.
|
|
298
|
-
│ Union_Or │
|
|
299
|
-
│ Union_Structural │
|
|
300
|
-
│ Tuple_Values │
|
|
301
|
-
│ Tuple_Objects │
|
|
302
|
-
│ Array_Numbers_4 │
|
|
303
|
-
│ Array_Numbers_8 │
|
|
304
|
-
│ Array_Numbers_16 │ 29.
|
|
305
|
-
│ Array_Objects_Open │
|
|
306
|
-
│ Array_Objects_Close │ 7.
|
|
284
|
+
│ Boolean │ 29.2K ops/s │ 7.1K ops/s │
|
|
285
|
+
│ Number │ 34.5K ops/s │ 7.6K ops/s │
|
|
286
|
+
│ String │ 48.9K ops/s │ 8.7K ops/s │
|
|
287
|
+
│ Null │ 39.6K ops/s │ 7.6K ops/s │
|
|
288
|
+
│ Literal_String │ 46.8K ops/s │ 6.8K ops/s │
|
|
289
|
+
│ Literal_Number │ 48.3K ops/s │ 7.4K ops/s │
|
|
290
|
+
│ Literal_Boolean │ 48.8K ops/s │ 7.3K ops/s │
|
|
291
|
+
│ Pattern │ 32.5K ops/s │ 6.1K ops/s │
|
|
292
|
+
│ Object_Open │ 6.6K ops/s │ 1.4K ops/s │
|
|
293
|
+
│ Object_Close │ 7.6K ops/s │ 1K ops/s │
|
|
294
|
+
│ Object_Vector3 │ 20.8K ops/s │ 2.8K ops/s │
|
|
295
|
+
│ Object_Basis3 │ 7.5K ops/s │ 1K ops/s │
|
|
296
|
+
│ Intersect_And │ 23K ops/s │ 3.9K ops/s │
|
|
297
|
+
│ Intersect_Structural │ 8.7K ops/s │ 1.2K ops/s │
|
|
298
|
+
│ Union_Or │ 17.9K ops/s │ 3.4K ops/s │
|
|
299
|
+
│ Union_Structural │ 11.3K ops/s │ 2.1K ops/s │
|
|
300
|
+
│ Tuple_Values │ 9.6K ops/s │ 2.1K ops/s │
|
|
301
|
+
│ Tuple_Objects │ 2.1K ops/s │ 350 ops/s │
|
|
302
|
+
│ Array_Numbers_4 │ 33.6K ops/s │ 4.2K ops/s │
|
|
303
|
+
│ Array_Numbers_8 │ 39K ops/s │ 3.7K ops/s │
|
|
304
|
+
│ Array_Numbers_16 │ 29.6K ops/s │ 3.8K ops/s │
|
|
305
|
+
│ Array_Objects_Open │ 7.7K ops/s │ 833 ops/s │
|
|
306
|
+
│ Array_Objects_Close │ 7.6K ops/s │ 860 ops/s │
|
|
307
307
|
└──────────────────────┴─────────────┴─────────────┘
|
|
308
308
|
```
|
|
309
309
|
|
|
@@ -314,29 +314,29 @@ The following tables shows validation performance for various JSON Schema struct
|
|
|
314
314
|
┌──────────────────────┬──────────────┬──────────────┐
|
|
315
315
|
│ Validate │ TB1X │ AJV8 │
|
|
316
316
|
├──────────────────────┼──────────────┼──────────────┤
|
|
317
|
-
│ Boolean │
|
|
318
|
-
│ Number │
|
|
319
|
-
│ String │
|
|
320
|
-
│ Null │ 112.
|
|
321
|
-
│ Literal_String │
|
|
322
|
-
│ Literal_Number │
|
|
323
|
-
│ Literal_Boolean │ 109.
|
|
324
|
-
│ Pattern │
|
|
325
|
-
│ Object_Open │
|
|
326
|
-
│ Object_Close │
|
|
327
|
-
│ Object_Vector3 │
|
|
328
|
-
│ Object_Basis3 │
|
|
329
|
-
│ Intersect_And │
|
|
330
|
-
│ Intersect_Structural │
|
|
331
|
-
│ Union_Or │
|
|
332
|
-
│ Union_Structural │
|
|
333
|
-
│ Tuple_Values │
|
|
334
|
-
│ Tuple_Objects │ 32.
|
|
335
|
-
│ Array_Numbers_4 │
|
|
336
|
-
│ Array_Numbers_8 │ 90.
|
|
337
|
-
│ Array_Numbers_16 │
|
|
338
|
-
│ Array_Objects_Open │
|
|
339
|
-
│ Array_Objects_Close │
|
|
317
|
+
│ Boolean │ 192.2M ops/s │ 189.5M ops/s │
|
|
318
|
+
│ Number │ 112.4M ops/s │ 61M ops/s │
|
|
319
|
+
│ String │ 113.7M ops/s │ 64.1M ops/s │
|
|
320
|
+
│ Null │ 112.8M ops/s │ 64.9M ops/s │
|
|
321
|
+
│ Literal_String │ 108M ops/s │ 62.9M ops/s │
|
|
322
|
+
│ Literal_Number │ 113.5M ops/s │ 63.2M ops/s │
|
|
323
|
+
│ Literal_Boolean │ 109.2M ops/s │ 64.1M ops/s │
|
|
324
|
+
│ Pattern │ 26.5M ops/s │ 22.4M ops/s │
|
|
325
|
+
│ Object_Open │ 78M ops/s │ 47.2M ops/s │
|
|
326
|
+
│ Object_Close │ 38.6M ops/s │ 27.6M ops/s │
|
|
327
|
+
│ Object_Vector3 │ 91M ops/s │ 51.3M ops/s │
|
|
328
|
+
│ Object_Basis3 │ 41.1M ops/s │ 27.4M ops/s │
|
|
329
|
+
│ Intersect_And │ 107.6M ops/s │ 59.9M ops/s │
|
|
330
|
+
│ Intersect_Structural │ 83.6M ops/s │ 46.3M ops/s │
|
|
331
|
+
│ Union_Or │ 95M ops/s │ 7.9M ops/s │
|
|
332
|
+
│ Union_Structural │ 84.5M ops/s │ 52.3M ops/s │
|
|
333
|
+
│ Tuple_Values │ 74.7M ops/s │ 53M ops/s │
|
|
334
|
+
│ Tuple_Objects │ 32.9M ops/s │ 22.3M ops/s │
|
|
335
|
+
│ Array_Numbers_4 │ 93.3M ops/s │ 55.1M ops/s │
|
|
336
|
+
│ Array_Numbers_8 │ 90.3M ops/s │ 50.8M ops/s │
|
|
337
|
+
│ Array_Numbers_16 │ 76.8M ops/s │ 39.6M ops/s │
|
|
338
|
+
│ Array_Objects_Open │ 28.7M ops/s │ 20.4M ops/s │
|
|
339
|
+
│ Array_Objects_Close │ 10.3M ops/s │ 10.8M ops/s │
|
|
340
340
|
└──────────────────────┴──────────────┴──────────────┘
|
|
341
341
|
```
|
|
342
342
|
|