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.
@@ -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.Call()}`
49
- : `return ${build.Call()}`;
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 code;
9
- private readonly check;
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(context: Context, type: Type, isEvaluated: boolean, hasCodec: boolean, code: string, check: (value: unknown) => boolean);
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
- 6: (context, type, isEvalulated, hasCodec, code, check) => [context, type, isEvalulated, hasCodec, code, check],
15
+ 3: (hasCodec, buildResult, evaluateResult) => [hasCodec, buildResult, evaluateResult],
17
16
  2: (context, type) => [context, type]
18
17
  });
19
- if (matched.length === 6) {
20
- const [context, type, isEvaluated, hasCodec, code, check] = matched;
21
- this.context = context;
22
- this.type = type;
23
- this.isAccelerated = isEvaluated;
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.code = code;
26
- this.check = check;
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.context = context;
33
- this.type = type;
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.isAccelerated;
40
+ return this.evaluateResult.IsAccelerated();
45
41
  }
46
42
  // ----------------------------------------------------------------
47
- // Context | Type
43
+ // Context & Type
48
44
  // ----------------------------------------------------------------
49
45
  /** Returns the Context for this validator. */
50
46
  Context() {
51
- return this.context;
47
+ return this.buildResult.Context();
52
48
  }
53
49
  /** Returns the underlying Type used to construct this Validator. */
54
50
  Type() {
55
- return this.type;
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.code;
58
+ return this.evaluateResult.Code();
63
59
  }
64
60
  // ----------------------------------------------------------------
65
- // Base<...>
61
+ // Standard Validator
66
62
  // ----------------------------------------------------------------
67
63
  /** Performs a type-guard check on the provided value. */
68
64
  Check(value) {
69
- return this.check(value);
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 (Environment.CanEvaluate() && this.check(value))
78
+ if (this.IsAccelerated() && this.Check(value))
74
79
  return [];
75
- return Errors(this.context, this.type, value);
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.context, this.type, value);
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.context, this.type, value);
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.context, this.type);
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.context, this.type, value);
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.context, this.type, value) : this.Parse(value);
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.context, this.type, value) : this.Parse(value);
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
  }
@@ -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 the property keys for this object via `Object.getOwnPropertyKeys({ ... })` */
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[];
@@ -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
- const isProtoField = IsEqual(key, '__proto__') || IsEqual(key, 'constructor');
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 the property keys for this object via `Object.getOwnPropertyKeys({ ... })` */
188
+ /** Returns property keys for this object via `Object.getOwnPropertyKeys({ ... })` */
186
189
  export function Keys(value) {
187
190
  return Object.getOwnPropertyNames(value);
188
191
  }
@@ -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 interface EvaluateResult {
5
- IsAccelerated: boolean;
6
- Code: string;
7
- Check: CheckFunction;
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 call;
18
+ private readonly entry;
15
19
  private readonly useUnevaluated;
16
- constructor(context: Record<PropertyKey, Schema.XSchema>, schema: Schema.XSchema, external: Engine.TExternal, functions: string[], call: string, useUnevaluated: boolean);
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
- Call(): string;
32
+ Entry(): string;
29
33
  /** Evaluates the build into a validation function */
30
34
  Evaluate(): EvaluateResult;
31
35
  }
@@ -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.Call()}`]
16
- : [`return ${build.Call()}`];
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, call, useUnevaluated) {
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.call = call;
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
- Call() {
76
- return this.call;
94
+ Entry() {
95
+ return this.entry;
77
96
  }
78
97
  /** Evaluates the build into a validation function */
79
98
  Evaluate() {
80
- const Code = CreateCode(this);
81
- const Check = CreateCheck(this, Code);
82
- return { IsAccelerated: Environment.CanEvaluate(), Code, Check };
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 build;
6
- private readonly result;
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;
@@ -9,31 +9,31 @@ import { ParseError } from './parse.mjs';
9
9
  // ------------------------------------------------------------------
10
10
  export class Validator {
11
11
  constructor(context, schema) {
12
- this.build = Build.Build(context, schema);
13
- this.result = this.build.Evaluate();
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.result.IsAccelerated;
17
+ return this.evaluateResult.IsAccelerated();
18
18
  }
19
19
  /** Returns the underlying Schema used to construct this Validator. */
20
20
  Schema() {
21
- return this.build.Schema();
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.result.Check(value);
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.result.Check(value))
29
+ if (this.evaluateResult.Check(value))
30
30
  return value;
31
- const [_result, errors] = Errors(this.build.Context(), this.build.Schema(), value);
32
- throw new ParseError(this.build.Schema(), value, errors);
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.build.Context(), this.build.Schema(), value);
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: 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 Object.getOwnPropertyNames(value)) {
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 Object.getOwnPropertySymbols(value)) {
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
@@ -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.36",
4
+ "version": "1.1.38",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
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, RPC and MCP services to help validate data received over the wire.
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 │ 28.4K ops/s │ 7K ops/s │
285
- │ Number │ 21.8K ops/s │ 7.7K ops/s │
286
- │ String │ 47.8K ops/s │ 7.3K ops/s │
287
- │ Null │ 35.6K ops/s │ 7.8K ops/s │
288
- │ Literal_String │ 28.6K ops/s │ 6.3K ops/s │
289
- │ Literal_Number │ 46.6K ops/s │ 6.2K ops/s │
290
- │ Literal_Boolean │ 40.8K ops/s │ 6.6K ops/s │
291
- │ Pattern │ 29.7K ops/s │ 4.9K ops/s │
292
- │ Object_Open │ 6.8K ops/s │ 1.1K ops/s │
293
- │ Object_Close │ 7.4K ops/s │ 833 ops/s │
294
- │ Object_Vector3 │ 19.4K ops/s │ 2.1K ops/s │
295
- │ Object_Basis3 │ 6K ops/s │ 895 ops/s │
296
- │ Intersect_And │ 12K ops/s │ 3.5K ops/s │
297
- │ Intersect_Structural │ 8.4K ops/s │ 1.1K ops/s │
298
- │ Union_Or │ 18.2K ops/s │ 2.5K ops/s │
299
- │ Union_Structural │ 10.9K ops/s │ 1.3K ops/s │
300
- │ Tuple_Values │ 7.3K ops/s │ 1.6K ops/s │
301
- │ Tuple_Objects │ 1.9K ops/s │ 339 ops/s │
302
- │ Array_Numbers_4 │ 29.9K ops/s │ 3.4K ops/s │
303
- │ Array_Numbers_8 │ 20.3K ops/s │ 3.4K ops/s │
304
- │ Array_Numbers_16 │ 29.4K ops/s │ 3.3K ops/s │
305
- │ Array_Objects_Open │ 6.3K ops/s │ 684 ops/s │
306
- │ Array_Objects_Close │ 7.3K ops/s │ 762 ops/s │
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 │ 164.1M ops/s │ 181.5M ops/s │
318
- │ Number │ 107M ops/s │ 50.2M ops/s │
319
- │ String │ 102.2M ops/s │ 61.9M ops/s │
320
- │ Null │ 112.1M ops/s │ 48.2M ops/s │
321
- │ Literal_String │ 102.8M ops/s │ 61.5M ops/s │
322
- │ Literal_Number │ 109.1M ops/s │ 46.4M ops/s │
323
- │ Literal_Boolean │ 109.6M ops/s │ 63.3M ops/s │
324
- │ Pattern │ 24.7M ops/s │ 20.3M ops/s │
325
- │ Object_Open │ 75.4M ops/s │ 37.3M ops/s │
326
- │ Object_Close │ 35.9M ops/s │ 21.9M ops/s │
327
- │ Object_Vector3 │ 77.6M ops/s │ 47.4M ops/s │
328
- │ Object_Basis3 │ 37M ops/s │ 24.3M ops/s │
329
- │ Intersect_And │ 93.3M ops/s │ 61.1M ops/s │
330
- │ Intersect_Structural │ 83M ops/s │ 36.4M ops/s │
331
- │ Union_Or │ 99.7M ops/s │ 8.6M ops/s │
332
- │ Union_Structural │ 81.3M ops/s │ 43.5M ops/s │
333
- │ Tuple_Values │ 72.4M ops/s │ 41.7M ops/s │
334
- │ Tuple_Objects │ 32.6M ops/s │ 22.4M ops/s │
335
- │ Array_Numbers_4 │ 94.1M ops/s │ 42.8M ops/s │
336
- │ Array_Numbers_8 │ 90.6M ops/s │ 42.3M ops/s │
337
- │ Array_Numbers_16 │ 77.5M ops/s │ 40.2M ops/s │
338
- │ Array_Objects_Open │ 26.3M ops/s │ 19.6M ops/s │
339
- │ Array_Objects_Close │ 9.1M ops/s │ 10M ops/s │
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