@sinclair/typebox 0.25.17 → 0.25.19

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.
@@ -134,7 +134,7 @@ var TypeCompiler;
134
134
  yield* Visit(schema.returns, `${value}.prototype`);
135
135
  }
136
136
  function* Date(schema, value) {
137
- yield `(${value} instanceof Date)`;
137
+ yield `(${value} instanceof Date) && !isNaN(${value}.getTime())`;
138
138
  if (IsNumber(schema.exclusiveMinimumTimestamp))
139
139
  yield `(${value}.getTime() > ${schema.exclusiveMinimumTimestamp})`;
140
140
  if (IsNumber(schema.exclusiveMaximumTimestamp))
package/errors/errors.js CHANGED
@@ -143,6 +143,9 @@ var ValueErrors;
143
143
  if (!(value instanceof globalThis.Date)) {
144
144
  return yield { type: ValueErrorType.Date, schema, path, value, message: `Expected Date object` };
145
145
  }
146
+ if (isNaN(value.getTime())) {
147
+ return yield { type: ValueErrorType.Date, schema, path, value, message: `Invalid Date` };
148
+ }
146
149
  if (IsNumber(schema.exclusiveMinimumTimestamp) && !(value.getTime() > schema.exclusiveMinimumTimestamp)) {
147
150
  yield { type: ValueErrorType.DateExclusiveMinimumTimestamp, schema, path, value, message: `Expected Date timestamp to be greater than ${schema.exclusiveMinimum}` };
148
151
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinclair/typebox",
3
- "version": "0.25.17",
3
+ "version": "0.25.19",
4
4
  "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
package/readme.md CHANGED
@@ -96,10 +96,11 @@ License MIT
96
96
  - [Errors](#values-errors)
97
97
  - [Pointer](#values-pointer)
98
98
  - [TypeCheck](#typecheck)
99
- - [Ajv](#typecheck-ajv)
100
99
  - [TypeCompiler](#typecheck-typecompiler)
101
- - [Custom Types](#typecheck-custom-types)
102
- - [Custom Formats](#typecheck-custom-formats)
100
+ - [Ajv](#typecheck-ajv)
101
+ - [TypeSystem](#typecheck)
102
+ - [Types](#typesystem-types)
103
+ - [Formats](#typesystem-formats)
103
104
  - [Benchmark](#benchmark)
104
105
  - [Compile](#benchmark-compile)
105
106
  - [Validate](#benchmark-validate)
@@ -936,6 +937,71 @@ TypeBox targets JSON Schema Draft 6 and is built and tested against the Ajv JSON
936
937
 
937
938
  The following sections detail using these validators.
938
939
 
940
+ <a name='typecheck-typecompiler'></a>
941
+
942
+ ### TypeCompiler
943
+
944
+ TypeBox includes an high performance just-in-time (JIT) compiler and type checker that can be used in applications that require extremely fast validation. Note that this compiler is optimized for TypeBox types only where the schematics are known in advance.
945
+
946
+ The compiler module is provided as an optional import.
947
+
948
+ ```typescript
949
+ import { TypeCompiler } from '@sinclair/typebox/compiler'
950
+ ```
951
+
952
+ Use the `Compile(...)` function to compile a type.
953
+
954
+ ```typescript
955
+ const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
956
+ x: Type.Number(), // x: TNumber;
957
+ y: Type.Number(), // y: TNumber;
958
+ z: Type.Number() // z: TNumber;
959
+ })) // }>>
960
+
961
+ const R = C.Check({ x: 1, y: 2, z: 3 }) // const R = true
962
+ ```
963
+
964
+ Validation errors can be read with the `Errors(...)` function.
965
+
966
+ ```typescript
967
+ const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
968
+ x: Type.Number(), // x: TNumber;
969
+ y: Type.Number(), // y: TNumber;
970
+ z: Type.Number() // z: TNumber;
971
+ })) // }>>
972
+
973
+ const value = { }
974
+
975
+ const errors = [...C.Errors(value)] // const errors = [{
976
+ // schema: { type: 'number' },
977
+ // path: '/x',
978
+ // value: undefined,
979
+ // message: 'Expected number'
980
+ // }, {
981
+ // schema: { type: 'number' },
982
+ // path: '/y',
983
+ // value: undefined,
984
+ // message: 'Expected number'
985
+ // }, {
986
+ // schema: { type: 'number' },
987
+ // path: '/z',
988
+ // value: undefined,
989
+ // message: 'Expected number'
990
+ // }]
991
+ ```
992
+
993
+ Compiled routines can be inspected with the `.Code()` function.
994
+
995
+ ```typescript
996
+ const C = TypeCompiler.Compile(Type.String()) // const C: TypeCheck<TString>
997
+
998
+ console.log(C.Code()) // return function check(value) {
999
+ // return (
1000
+ // (typeof value === 'string')
1001
+ // )
1002
+ // }
1003
+ ```
1004
+
939
1005
  <a name='typecheck-ajv'></a>
940
1006
 
941
1007
  ### Ajv
@@ -1066,125 +1132,87 @@ const R = ajv.validate(Type.Object({ // const R = true
1066
1132
  </details>
1067
1133
 
1068
1134
 
1069
- <a name='typecheck-typecompiler'></a>
1135
+ <a name='typesystem'></a>
1070
1136
 
1071
- ### TypeCompiler
1137
+ ## TypeSystem
1072
1138
 
1073
- TypeBox provides an optional high performance just-in-time (JIT) compiler and type checker that can be used in applications that require extremely fast validation. Note that this compiler is optimized for TypeBox types only where the schematics are known in advance. If defining custom types with `Type.Unsafe<T>` please consider Ajv.
1139
+ TypeBox provides an extensible TypeSystem module that enables developers to register additional types above and beyond the standard or extended type set. This module also allows developers to define custom string formats as well as override certain type checking behaviours.
1074
1140
 
1075
- The compiler module is provided as an optional import.
1141
+ The TypeSystem module is provided as an optional import.
1076
1142
 
1077
1143
  ```typescript
1078
- import { TypeCompiler } from '@sinclair/typebox/compiler'
1144
+ import { TypeSystem } from '@sinclair/typebox/system'
1079
1145
  ```
1080
1146
 
1081
- Use the `Compile(...)` function to compile a type.
1082
-
1083
- ```typescript
1084
- const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
1085
- x: Type.Number(), // x: TNumber;
1086
- y: Type.Number(), // y: TNumber;
1087
- z: Type.Number() // z: TNumber;
1088
- })) // }>>
1147
+ <a name='typesystem-types'></a>
1089
1148
 
1090
- const R = C.Check({ x: 1, y: 2, z: 3 }) // const R = true
1091
- ```
1149
+ ### Types
1092
1150
 
1093
- Validation errors can be read with the `Errors(...)` function.
1151
+ Use the `CreateType(...)` function to specify and return a custom type. This function will return a type factory function that can be used to construct the type. The following creates and registers a BigNumber type which will statically infer as `bigint`.
1094
1152
 
1095
1153
  ```typescript
1096
- const C = TypeCompiler.Compile(Type.Object({ // const C: TypeCheck<TObject<{
1097
- x: Type.Number(), // x: TNumber;
1098
- y: Type.Number(), // y: TNumber;
1099
- z: Type.Number() // z: TNumber;
1100
- })) // }>>
1154
+ //--------------------------------------------------------------------------------------------
1155
+ //
1156
+ // Use TypeSystem.CreateType(...) to define and return a type factory function
1157
+ //
1158
+ //--------------------------------------------------------------------------------------------
1101
1159
 
1102
- const value = { }
1160
+ type BigNumberOptions = { minimum?: bigint; maximum?: bigint }
1103
1161
 
1104
- const errors = [...C.Errors(value)] // const errors = [{
1105
- // schema: { type: 'number' },
1106
- // path: '/x',
1107
- // value: undefined,
1108
- // message: 'Expected number'
1109
- // }, {
1110
- // schema: { type: 'number' },
1111
- // path: '/y',
1112
- // value: undefined,
1113
- // message: 'Expected number'
1114
- // }, {
1115
- // schema: { type: 'number' },
1116
- // path: '/z',
1117
- // value: undefined,
1118
- // message: 'Expected number'
1119
- // }]
1120
- ```
1162
+ const BigNumber = TypeSystem.CreateType<bigint, BigNumberOptions>(
1163
+ 'BigNumber',
1164
+ (options, value) => {
1165
+ if (typeof value !== 'bigint') return false
1166
+ if (options.maximum !== undefined && value > options.maximum) return false
1167
+ if (options.minimum !== undefined && value < options.minimum) return false
1168
+ return true
1169
+ }
1170
+ )
1121
1171
 
1122
- Compiled routines can be inspected with the `.Code()` function.
1172
+ //--------------------------------------------------------------------------------------------
1173
+ //
1174
+ // Use the custom type like any other type
1175
+ //
1176
+ //--------------------------------------------------------------------------------------------
1123
1177
 
1124
- ```typescript
1125
- const C = TypeCompiler.Compile(Type.String()) // const C: TypeCheck<TString>
1178
+ const T = BigNumber({ minimum: 10n, maximum: 20n }) // const T = {
1179
+ // minimum: 10n,
1180
+ // maximum: 20n,
1181
+ // [Symbol(TypeBox.Kind)]: 'BigNumber'
1182
+ // }
1126
1183
 
1127
- console.log(C.Code()) // return function check(value) {
1128
- // return (
1129
- // (typeof value === 'string')
1130
- // )
1131
- // }
1184
+ const C = TypeCompiler.Compile(T)
1185
+ const X = C.Check(15n) // const X = true
1186
+ const Y = C.Check(5n) // const Y = false
1187
+ const Z = C.Check(25n) // const Z = false
1132
1188
  ```
1133
1189
 
1134
- <a name='typecheck-custom-types'></a>
1190
+ <a name='typesystem-formats'></a>
1135
1191
 
1136
- ### Custom Types
1192
+ ### Formats
1137
1193
 
1138
- Use the custom module to create user defined types. User defined types require a `[Kind]` symbol property which is used to match the schema against a registered type. Custom types are specific to TypeBox and can only be used with the TypeCompiler and Value modules.
1139
-
1140
- The custom module is an optional import.
1194
+ Use the `CreateFormat(...)` function to specify user defined string formats. The following creates a custom string format that checks for lowercase.
1141
1195
 
1142
1196
  ```typescript
1143
- import { Custom } from '@sinclair/typebox/custom'
1144
- ```
1145
-
1146
- The following creates a `bigint` type.
1147
-
1148
- ```typescript
1149
- import { Type, Kind } from '@sinclair/typebox'
1150
-
1151
- Custom.Set('bigint', (schema, value) => typeof value === 'bigint')
1152
- // ▲
1153
- // │
1154
- // └────────────────────────────┐
1155
- // │
1156
- const T = Type.Unsafe<bigint>({ [Kind]: 'bigint' }) // const T = { [Kind]: 'BigInt' }
1157
-
1158
- const A = TypeCompiler.Compile(T).Check(1n) // const A = true
1159
-
1160
- const B = Value.Check(T, 1) // const B = false
1161
- ```
1162
-
1163
- <a name='typecheck-custom-formats'></a>
1164
-
1165
- ### Custom Formats
1166
-
1167
- Use the format module to create user defined string formats. The format module is specific to TypeBox can only be used with the TypeCompiler and Value modules. If using Ajv, please refer to the official Ajv format documentation located [here](https://ajv.js.org/guide/formats.html).
1168
-
1169
- The format module is an optional import.
1197
+ //--------------------------------------------------------------------------------------------
1198
+ //
1199
+ // Use TypeSystem.CreateFormat(...) to define a custom string format
1200
+ //
1201
+ //--------------------------------------------------------------------------------------------
1170
1202
 
1171
- ```typescript
1172
- import { Format } from '@sinclair/typebox/format'
1173
- ```
1203
+ TypeSystem.CreateFormat('lowercase', value => value === value.toLowerCase())
1174
1204
 
1175
- The following creates a custom string format that checks for lowercase.
1205
+ //--------------------------------------------------------------------------------------------
1206
+ //
1207
+ // Use the format by creating string types with the 'format' option
1208
+ //
1209
+ //--------------------------------------------------------------------------------------------
1176
1210
 
1177
- ```typescript
1178
- Format.Set('lowercase', value => value === value.toLowerCase())
1179
- // ▲
1180
- // │
1181
- // └────────────────────┐
1182
- // │
1183
1211
  const T = Type.String({ format: 'lowercase' })
1184
1212
 
1185
- const A = TypeCompiler.Compile(T).Check('action') // const A = true
1213
+ const A = Value.Check(T, 'action') // const A = true
1186
1214
 
1187
- const B = Value.Check(T, 'Action') // const B = false
1215
+ const B = Value.Check(T, 'ACTION') // const B = false
1188
1216
  ```
1189
1217
 
1190
1218
  <a name='benchmark'></a>
@@ -1,10 +1,17 @@
1
+ export declare class TypeSystemDuplicateTypeKind extends Error {
2
+ constructor(kind: string);
3
+ }
4
+ export declare class TypeSystemDuplicateFormat extends Error {
5
+ constructor(kind: string);
6
+ }
7
+ /** Creates user defined types and formats and provides overrides for value checking behaviours */
1
8
  export declare namespace TypeSystem {
2
- /**
3
- * Sets whether arrays should be treated as kinds of objects. The default is `false`
4
- */
9
+ /** Sets whether arrays should be treated as kinds of objects. The default is `false` */
5
10
  let AllowArrayObjects: boolean;
6
- /**
7
- * Sets whether numeric checks should consider NaN a valid number type. The default is `false`
8
- */
11
+ /** Sets whether numeric checks should consider NaN a valid number type. The default is `false` */
9
12
  let AllowNaN: boolean;
13
+ /** Creates a custom type */
14
+ function CreateType<Type, Options = object>(kind: string, callback: (options: Options, value: unknown) => boolean): (options?: Partial<Options>) => import("@sinclair/typebox").TUnsafe<Type>;
15
+ /** Creates a custom string format */
16
+ function CreateFormat(format: string, callback: (value: string) => boolean): (value: string) => boolean;
10
17
  }
package/system/system.js CHANGED
@@ -27,15 +27,43 @@ THE SOFTWARE.
27
27
 
28
28
  ---------------------------------------------------------------------------*/
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.TypeSystem = void 0;
30
+ exports.TypeSystem = exports.TypeSystemDuplicateFormat = exports.TypeSystemDuplicateTypeKind = void 0;
31
+ const typebox_1 = require("@sinclair/typebox");
32
+ const index_1 = require("../custom/index");
33
+ const index_2 = require("../format/index");
34
+ class TypeSystemDuplicateTypeKind extends Error {
35
+ constructor(kind) {
36
+ super(`Duplicate kind '${kind}' detected`);
37
+ }
38
+ }
39
+ exports.TypeSystemDuplicateTypeKind = TypeSystemDuplicateTypeKind;
40
+ class TypeSystemDuplicateFormat extends Error {
41
+ constructor(kind) {
42
+ super(`Duplicate format '${kind}' detected`);
43
+ }
44
+ }
45
+ exports.TypeSystemDuplicateFormat = TypeSystemDuplicateFormat;
46
+ /** Creates user defined types and formats and provides overrides for value checking behaviours */
31
47
  var TypeSystem;
32
48
  (function (TypeSystem) {
33
- /**
34
- * Sets whether arrays should be treated as kinds of objects. The default is `false`
35
- */
49
+ /** Sets whether arrays should be treated as kinds of objects. The default is `false` */
36
50
  TypeSystem.AllowArrayObjects = false;
37
- /**
38
- * Sets whether numeric checks should consider NaN a valid number type. The default is `false`
39
- */
51
+ /** Sets whether numeric checks should consider NaN a valid number type. The default is `false` */
40
52
  TypeSystem.AllowNaN = false;
53
+ /** Creates a custom type */
54
+ function CreateType(kind, callback) {
55
+ if (index_1.Custom.Has(kind))
56
+ throw new TypeSystemDuplicateTypeKind(kind);
57
+ index_1.Custom.Set(kind, callback);
58
+ return (options = {}) => typebox_1.Type.Unsafe({ ...options, [typebox_1.Kind]: kind });
59
+ }
60
+ TypeSystem.CreateType = CreateType;
61
+ /** Creates a custom string format */
62
+ function CreateFormat(format, callback) {
63
+ if (index_2.Format.Has(format))
64
+ throw new TypeSystemDuplicateFormat(format);
65
+ index_2.Format.Set(format, callback);
66
+ return callback;
67
+ }
68
+ TypeSystem.CreateFormat = CreateFormat;
41
69
  })(TypeSystem = exports.TypeSystem || (exports.TypeSystem = {}));
package/value/cast.js CHANGED
@@ -127,6 +127,9 @@ var ValueCast;
127
127
  function IsArray(value) {
128
128
  return typeof value === 'object' && globalThis.Array.isArray(value);
129
129
  }
130
+ function IsDate(value) {
131
+ return typeof value === 'object' && value instanceof globalThis.Date;
132
+ }
130
133
  function IsString(value) {
131
134
  return typeof value === 'string';
132
135
  }
@@ -151,6 +154,21 @@ var ValueCast;
151
154
  function IsValueFalse(value) {
152
155
  return value === false || (IsNumber(value) && value === 0) || (IsBigInt(value) && value === globalThis.BigInt('0')) || (IsString(value) && (value.toLowerCase() === 'false' || value === '0'));
153
156
  }
157
+ function IsTimeStringWithTimeZone(value) {
158
+ return IsString(value) && /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i.test(value);
159
+ }
160
+ function IsTimeStringWithoutTimeZone(value) {
161
+ return IsString(value) && /^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)?$/i.test(value);
162
+ }
163
+ function IsDateTimeStringWithTimeZone(value) {
164
+ return IsString(value) && /^\d\d\d\d-[0-1]\d-[0-3]\dt(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i.test(value);
165
+ }
166
+ function IsDateTimeStringWithoutTimeZone(value) {
167
+ return IsString(value) && /^\d\d\d\d-[0-1]\d-[0-3]\dt(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)?$/i.test(value);
168
+ }
169
+ function IsDateString(value) {
170
+ return IsString(value) && /^\d\d\d\d-[0-1]\d-[0-3]\d$/i.test(value);
171
+ }
154
172
  // ----------------------------------------------------------------------------------------------
155
173
  // Convert
156
174
  // ----------------------------------------------------------------------------------------------
@@ -166,6 +184,31 @@ var ValueCast;
166
184
  function TryConvertBoolean(value) {
167
185
  return IsValueTrue(value) ? true : IsValueFalse(value) ? false : value;
168
186
  }
187
+ function TryConvertDate(value) {
188
+ // note: this function may return an invalid dates for the regex tests
189
+ // above. Invalid dates will however be checked during the casting
190
+ // function and will return a epoch date if invalid. Consider better
191
+ // string parsing for the iso dates in future revisions.
192
+ return IsDate(value)
193
+ ? value
194
+ : IsNumber(value)
195
+ ? new globalThis.Date(value)
196
+ : IsValueTrue(value)
197
+ ? new globalThis.Date(1)
198
+ : IsStringNumeric(value)
199
+ ? new globalThis.Date(parseInt(value))
200
+ : IsTimeStringWithoutTimeZone(value)
201
+ ? new globalThis.Date(`1970-01-01T${value}.000Z`)
202
+ : IsTimeStringWithTimeZone(value)
203
+ ? new globalThis.Date(`1970-01-01T${value}`)
204
+ : IsDateTimeStringWithoutTimeZone(value)
205
+ ? new globalThis.Date(`${value}.000Z`)
206
+ : IsDateTimeStringWithTimeZone(value)
207
+ ? new globalThis.Date(value)
208
+ : IsDateString(value)
209
+ ? new globalThis.Date(`${value}T00:00:00.000Z`)
210
+ : value;
211
+ }
169
212
  // ----------------------------------------------------------------------------------------------
170
213
  // Cast
171
214
  // ----------------------------------------------------------------------------------------------
@@ -203,7 +246,8 @@ var ValueCast;
203
246
  return result;
204
247
  }
205
248
  function Date(schema, references, value) {
206
- return check_1.ValueCheck.Check(schema, references, value) ? clone_1.ValueClone.Clone(value) : create_1.ValueCreate.Create(schema, references);
249
+ const conversion = TryConvertDate(value);
250
+ return check_1.ValueCheck.Check(schema, references, conversion) ? clone_1.ValueClone.Clone(conversion) : create_1.ValueCreate.Create(schema, references);
207
251
  }
208
252
  function Function(schema, references, value) {
209
253
  return check_1.ValueCheck.Check(schema, references, value) ? value : create_1.ValueCreate.Create(schema, references);
package/value/check.js CHANGED
@@ -82,6 +82,9 @@ var ValueCheck;
82
82
  if (!(value instanceof globalThis.Date)) {
83
83
  return false;
84
84
  }
85
+ if (isNaN(value.getTime())) {
86
+ return false;
87
+ }
85
88
  if (IsNumber(schema.exclusiveMinimumTimestamp) && !(value.getTime() > schema.exclusiveMinimumTimestamp)) {
86
89
  return false;
87
90
  }
package/value/value.d.ts CHANGED
@@ -3,9 +3,9 @@ import { ValueError } from '../errors/index';
3
3
  import { Edit } from './delta';
4
4
  /** Provides functions to perform structural updates to JavaScript values */
5
5
  export declare namespace Value {
6
- /** Casts a value into a given type. The return value will retain as much information of the original value as possible. Cast will convert string, number and boolean values if a reasonable conversion is possible. */
6
+ /** Casts a value into a given type. The return value will retain as much information of the original value as possible. Cast will convert string, number, boolean and date values if a reasonable conversion is possible. */
7
7
  function Cast<T extends Types.TSchema, R extends Types.TSchema[]>(schema: T, references: [...R], value: unknown): Types.Static<T>;
8
- /** Casts a value into a given type. The return value will retain as much information of the original value as possible. Cast will convert string, number and boolean values if a reasonable conversion is possible. */
8
+ /** Casts a value into a given type. The return value will retain as much information of the original value as possible. Cast will convert string, number, boolean and date values if a reasonable conversion is possible. */
9
9
  function Cast<T extends Types.TSchema>(schema: T, value: unknown): Types.Static<T>;
10
10
  /** Creates a value from the given type */
11
11
  function Create<T extends Types.TSchema, R extends Types.TSchema[]>(schema: T, references: [...R]): Types.Static<T>;