@sinclair/typebox 0.23.0 → 0.23.4

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.
Files changed (4) hide show
  1. package/package.json +10 -10
  2. package/readme.md +209 -258
  3. package/typebox.d.ts +22 -20
  4. package/typebox.js +27 -24
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinclair/typebox",
3
- "version": "0.23.0",
3
+ "version": "0.23.4",
4
4
  "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
5
5
  "keywords": [
6
6
  "json-schema",
@@ -26,15 +26,15 @@
26
26
  "test": "npm run spec"
27
27
  },
28
28
  "devDependencies": {
29
- "@sinclair/hammer": "^0.15.8",
30
- "@types/chai": "^4.2.22",
31
- "@types/mocha": "^9.0.0",
32
- "@types/node": "^16.11.9",
33
- "ajv": "^8.8.2",
29
+ "@sinclair/hammer": "^0.16.3",
30
+ "@types/chai": "^4.3.0",
31
+ "@types/mocha": "^9.1.0",
32
+ "@types/node": "^17.0.12",
33
+ "ajv": "^8.9.0",
34
34
  "ajv-formats": "^2.1.1",
35
- "chai": "^4.3.4",
36
- "mocha": "^9.1.3",
37
- "tsd": "^0.19.0",
38
- "typescript": "^4.5.2"
35
+ "chai": "^4.3.5",
36
+ "mocha": "^9.2.0",
37
+ "tsd": "^0.19.1",
38
+ "typescript": "^4.5.5"
39
39
  }
40
40
  }
package/readme.md CHANGED
@@ -2,8 +2,12 @@
2
2
 
3
3
  <h1>TypeBox</h1>
4
4
 
5
+ <img src="https://github.com/sinclairzx81/typebox/blob/master/typebox.png?raw=true" />
6
+
5
7
  <p>JSON Schema Type Builder with Static Type Resolution for TypeScript</p>
6
8
 
9
+
10
+
7
11
  [![npm version](https://badge.fury.io/js/%40sinclair%2Ftypebox.svg)](https://badge.fury.io/js/%40sinclair%2Ftypebox) [![GitHub CI](https://github.com/sinclairzx81/typebox/workflows/GitHub%20CI/badge.svg)](https://github.com/sinclairzx81/typebox/actions)
8
12
 
9
13
  </div>
@@ -24,7 +28,7 @@ $ npm install @sinclair/typebox --save
24
28
  import { Static, Type } from 'https://deno.land/x/typebox/src/typebox.ts'
25
29
  ```
26
30
 
27
- ## Usage
31
+ ## Example
28
32
 
29
33
  ```typescript
30
34
  import { Static, Type } from '@sinclair/typebox'
@@ -38,7 +42,7 @@ type T = Static<typeof T> // type T = string
38
42
 
39
43
  ## Overview
40
44
 
41
- TypeBox is a library that builds in-memory JSON Schema objects that can be statically resolved to TypeScript types. The schemas produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox allows one to create a unified type that can be statically checked by the TypeScript compiler and runtime asserted using standard JSON Schema validation.
45
+ TypeBox is a library that creates in-memory JSON Schema objects that can be statically inferred as TypeScript types. The schemas produced by this library are designed to match the static type checking rules of the TypeScript compiler. TypeBox allows one to create a unified type that can be both statically asserted by the TypeScript compiler and runtime asserted using standard JSON Schema validation.
42
46
 
43
47
  TypeBox can be used as a simple tool to build up complex schemas or integrated into RPC or REST services to help validate JSON data received over the wire. TypeBox does not provide any JSON schema validation. Please use libraries such as AJV to validate schemas built with this library.
44
48
 
@@ -49,7 +53,7 @@ License MIT
49
53
  ## Contents
50
54
  - [Install](#Install)
51
55
  - [Overview](#Overview)
52
- - [Example](#Example)
56
+ - [Usage](#Usage)
53
57
  - [Types](#Types)
54
58
  - [Modifiers](#Modifiers)
55
59
  - [Options](#Options)
@@ -63,7 +67,7 @@ License MIT
63
67
 
64
68
  <a name="Example"></a>
65
69
 
66
- ## Example
70
+ ## Usage
67
71
 
68
72
  The following demonstrates TypeBox's general usage.
69
73
 
@@ -89,25 +93,25 @@ type T = {
89
93
  //
90
94
  //--------------------------------------------------------------------------------------------
91
95
 
92
- const T = Type.Object({ // const T = {
93
- id: Type.String(), // type: 'object',
94
- name: Type.String(), // properties: {
95
- timestamp: Type.Integer() // id: {
96
- }) // type: 'string'
97
- // },
98
- // name: {
99
- // type: 'string'
100
- // },
101
- // timestamp: {
102
- // type: 'integer'
103
- // }
104
- // },
105
- // required: [
106
- // "id",
107
- // "name",
108
- // "timestamp"
109
- // ]
110
- // }
96
+ const T = Type.Object({ // const T = {
97
+ id: Type.String(), // type: 'object',
98
+ name: Type.String(), // properties: {
99
+ timestamp: Type.Integer() // id: {
100
+ }) // type: 'string'
101
+ // },
102
+ // name: {
103
+ // type: 'string'
104
+ // },
105
+ // timestamp: {
106
+ // type: 'integer'
107
+ // }
108
+ // },
109
+ // required: [
110
+ // "id",
111
+ // "name",
112
+ // "timestamp"
113
+ // ]
114
+ // }
111
115
 
112
116
  //--------------------------------------------------------------------------------------------
113
117
  //
@@ -115,11 +119,11 @@ const T = Type.Object({ // const T = {
115
119
  //
116
120
  //--------------------------------------------------------------------------------------------
117
121
 
118
- type T = Static<typeof T> // type T = {
119
- // id: string,
120
- // name: string,
121
- // timestamp: number
122
- // }
122
+ type T = Static<typeof T> // type T = {
123
+ // id: string,
124
+ // name: string,
125
+ // timestamp: number
126
+ // }
123
127
 
124
128
  //--------------------------------------------------------------------------------------------
125
129
  //
@@ -127,9 +131,9 @@ type T = Static<typeof T> // type T = {
127
131
  //
128
132
  //--------------------------------------------------------------------------------------------
129
133
 
130
- function receive(value: T) { // ... as a Type
134
+ function receive(value: T) { // ... as a Type
131
135
 
132
- if(JSON.validate(T, value)) { // ... as a Schema
136
+ if(JSON.validate(T, value)) { // ... as a Schema
133
137
 
134
138
  // ok...
135
139
  }
@@ -145,50 +149,50 @@ The following table outlines the TypeBox mappings between TypeScript and JSON sc
145
149
  ```typescript
146
150
  ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
147
151
  │ TypeBox │ TypeScript │ JSON Schema │
148
- │ │ │
152
+ │ │ │
149
153
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
150
154
  │ const T = Type.Any() │ type T = any │ const T = { } │
151
- │ │ │
155
+ │ │ │
152
156
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
153
157
  │ const T = Type.Unknown() │ type T = unknown │ const T = { } │
154
- │ │ │
158
+ │ │ │
155
159
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
156
160
  │ const T = Type.String() │ type T = string │ const T = { │
157
161
  │ │ │ type: 'string' │
158
162
  │ │ │ } │
159
- │ │ │
163
+ │ │ │
160
164
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
161
165
  │ const T = Type.Number() │ type T = number │ const T = { │
162
166
  │ │ │ type: 'number' │
163
167
  │ │ │ } │
164
- │ │ │
168
+ │ │ │
165
169
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
166
170
  │ const T = Type.Integer() │ type T = number │ const T = { │
167
171
  │ │ │ type: 'integer' │
168
172
  │ │ │ } │
169
- │ │ │
173
+ │ │ │
170
174
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
171
175
  │ const T = Type.Boolean() │ type T = boolean │ const T = { │
172
176
  │ │ │ type: 'boolean' │
173
177
  │ │ │ } │
174
- │ │ │
178
+ │ │ │
175
179
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
176
180
  │ const T = Type.Null() │ type T = null │ const T = { │
177
181
  │ │ │ type: 'null' │
178
182
  │ │ │ } │
179
- │ │ │
183
+ │ │ │
180
184
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
181
- │ const T = Type.RegEx(/foo/) │ type T = string │ const T = { │
185
+ │ const T = Type.RegEx(/foo/) │ type T = string │ const T = { │
182
186
  │ │ │ type: 'string', │
183
187
  │ │ │ pattern: 'foo' │
184
188
  │ │ │ } │
185
- │ │ │
189
+ │ │ │
186
190
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
187
191
  │ const T = Type.Literal(42) │ type T = 42 │ const T = { │
188
192
  │ │ │ const: 42 │
189
193
  │ │ │ type: 'number' │
190
194
  │ │ │ } │
191
- │ │ │
195
+ │ │ │
192
196
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
193
197
  │ const T = Type.Array( │ type T = number[] │ const T = { │
194
198
  │ Type.Number() │ │ type: 'array', │
@@ -196,36 +200,36 @@ The following table outlines the TypeBox mappings between TypeScript and JSON sc
196
200
  │ │ │ type: 'number' │
197
201
  │ │ │ } │
198
202
  │ │ │ } │
199
- │ │ │
203
+ │ │ │
200
204
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
201
205
  │ const T = Type.Object({ │ type T = { │ const T = { │
202
206
  │ x: Type.Number(), │ x: number, │ type: 'object', │
203
207
  │ y: Type.Number() │ y: number │ properties: { │
204
208
  │ }) │ } │ x: { │
205
209
  │ │ │ type: 'number' │
206
- │ │ }, │
207
- │ │ y: { │
208
- │ │ type: 'number' │
210
+ │ │ }, │
211
+ │ │ y: { │
212
+ │ │ type: 'number' │
209
213
  │ │ │ } │
210
- │ │ }, │
211
- │ │ required: ['x', 'y'] │
214
+ │ │ }, │
215
+ │ │ required: ['x', 'y'] │
212
216
  │ │ │ } │
213
- │ │ │
217
+ │ │ │
214
218
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
215
219
  │ const T = Type.Tuple([ │ type T = [number, number] │ const T = { │
216
220
  │ Type.Number(), │ │ type: 'array', │
217
221
  │ Type.Number() │ │ items: [ │
218
222
  │ ]) │ │ { │
219
- │ │ type: 'number' │
220
- │ │ }, { │
221
- │ │ type: 'number' │
222
- │ │ } │
223
- │ │ ], │
224
- │ │ additionalItems: false, │
225
- │ │ minItems: 2, │
226
- │ │ maxItems: 2, │
227
- │ │ } │
228
- │ │ │
223
+ │ │ type: 'number' │
224
+ │ │ }, { │
225
+ │ │ type: 'number' │
226
+ │ │ } │
227
+ │ │ ], │
228
+ │ │ additionalItems: false, │
229
+ │ │ minItems: 2, │
230
+ │ │ maxItems: 2, │
231
+ │ │ } │
232
+ │ │ │
229
233
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
230
234
  │ enum Foo { │ enum Foo { │ const T = { │
231
235
  │ A, │ A, │ anyOf: [{ │
@@ -244,7 +248,7 @@ The following table outlines the TypeBox mappings between TypeScript and JSON sc
244
248
  │ y: Type.Number() │ } │ } │
245
249
  │ }) │ │ │
246
250
  │ ) │ │ │
247
- │ │ │
251
+ │ │ │
248
252
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
249
253
  │ const T = Type.Union([ │ type T = string | number │ const T = { │
250
254
  │ Type.String(), │ │ anyOf: [{ │
@@ -253,38 +257,38 @@ The following table outlines the TypeBox mappings between TypeScript and JSON sc
253
257
  │ │ │ type: 'number' │
254
258
  │ │ │ }] │
255
259
  │ │ │ } │
256
- │ │ │
260
+ │ │ │
257
261
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
258
262
  │ const T = Type.Intersect([ │ type T = { │ const T = { │
259
263
  │ Type.Object({ │ x: number │ allOf: [{ │
260
264
  │ x: Type.Number() │ } & { │ type: 'object', │
261
265
  │ }), │ y: number │ properties: { │
262
- │ Type.Object({ │ } │ a: { │
263
- │ y: Type.Number() │ │ type: 'number' │
266
+ │ Type.Object({ │ } │ x: { │
267
+ │ y: Type.Number() │ │ type: 'number' │
264
268
  │ }) │ │ } │
265
269
  │ }) │ │ }, │
266
- │ │ │ required: ['a'] │
270
+ │ │ │ required: ['x'] │
267
271
  │ │ │ }, { │
268
272
  │ │ │ type: 'object', │
269
273
  │ │ │ properties: { │
270
- │ │ │ b: { │
271
- │ │ type: 'number' │
272
- │ │ } │
273
- │ │ }, │
274
- │ │ required: ['b'] │
275
- │ │ }] │
276
- │ │ } │
277
- │ │ │
274
+ │ │ │ y: { │
275
+ │ │ type: 'number' │
276
+ │ │ } │
277
+ │ │ }, │
278
+ │ │ required: ['y'] │
279
+ │ │ }] │
280
+ │ │ } │
281
+ │ │ │
278
282
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
279
283
  │ const T = Type.Record( │ type T = { │ const T = { │
280
284
  │ Type.String(), │ [key: string]: number │ type: 'object', │
281
285
  │ Type.Number() │ } │ patternProperties: { │
282
- │ ) │ │ '^.*$': { │
283
- │ │ type: 'number' │
284
- │ │ } │
285
- │ │ } │
286
- │ │ } │
287
- │ │ │
286
+ │ ) │ │ '^.*$': { │
287
+ │ │ type: 'number' │
288
+ │ │ } │
289
+ │ │ } │
290
+ │ │ } │
291
+ │ │ │
288
292
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
289
293
  │ const T = Type.Partial( │ type T = Partial<{ │ const T = { │
290
294
  │ Type.Object({ │ x: number, │ type: 'object', │
@@ -297,7 +301,7 @@ The following table outlines the TypeBox mappings between TypeScript and JSON sc
297
301
  │ │ │ } │
298
302
  │ │ │ } │
299
303
  │ │ │ } │
300
- │ │ │
304
+ │ │ │
301
305
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
302
306
  │ const T = Type.Required( │ type T = Required<{ │ const T = { │
303
307
  │ Type.Object({ │ x?: number, │ type: 'object', │
@@ -311,7 +315,7 @@ The following table outlines the TypeBox mappings between TypeScript and JSON sc
311
315
  │ ) │ │ }, │
312
316
  │ │ │ required: ['x', 'y'] │
313
317
  │ │ │ } │
314
- │ │ │
318
+ │ │ │
315
319
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
316
320
  │ const T = Type.Pick( │ type T = Pick<{ │ const T = { │
317
321
  │ Type.Object({ │ x: number, │ type: 'object', │
@@ -345,38 +349,38 @@ TypeBox provides modifiers that can be applied to an objects properties. This al
345
349
  ```typescript
346
350
  ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
347
351
  │ TypeBox │ TypeScript │ JSON Schema │
348
- │ │ │
352
+ │ │ │
349
353
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
350
354
  │ const T = Type.Object({ │ type T = { │ const T = { │
351
355
  │ name: Type.Optional( │ name?: string, │ type: 'object', │
352
356
  │ Type.String(), │ } │ properties: { │
353
- │ ) │ │ name: { │
357
+ │ ) │ │ name: { │
354
358
  │ }) │ │ type: 'string' │
355
- │ │ } │
356
- │ │ } │
357
- │ │ } │
358
- │ │ │
359
+ │ │ } │
360
+ │ │ } │
361
+ │ │ } │
362
+ │ │ │
359
363
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
360
364
  │ const T = Type.Object({ │ type T = { │ const T = { │
361
365
  │ name: Type.Readonly( │ readonly name: string, │ type: 'object', │
362
366
  │ Type.String(), │ } │ properties: { │
363
- │ ) │ │ name: { │
367
+ │ ) │ │ name: { │
364
368
  │ }) │ │ type: 'string' │
365
- │ │ } │
366
- │ │ }, │
369
+ │ │ } │
370
+ │ │ }, │
367
371
  │ │ │ required: ['name'] │
368
- │ │ } │
369
- │ │ │
372
+ │ │ } │
373
+ │ │ │
370
374
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
371
375
  │ const T = Type.Object({ │ type T = { │ const T = { │
372
376
  │ name: Type.ReadonlyOptional( │ readonly name?: string, │ type: 'object', │
373
377
  │ Type.String(), │ } │ properties: { │
374
- │ ) │ │ name: { │
378
+ │ ) │ │ name: { │
375
379
  │ }) │ │ type: 'string' │
376
- │ │ } │
377
- │ │ } │
380
+ │ │ } │
381
+ │ │ } │
378
382
  │ │ │ } │
379
- │ │ │
383
+ │ │ │
380
384
  └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
381
385
  ```
382
386
 
@@ -409,25 +413,25 @@ import { Type, Static, TSchema } from '@sinclair/typebox'
409
413
 
410
414
  const Nullable = <T extends TSchema>(type: T) => Type.Union([type, Type.Null()])
411
415
 
412
- const T = Nullable(Type.String()) // const T = {
413
- // "anyOf": [{
414
- // type: 'string'
415
- // }, {
416
- // type: 'null'
417
- // }]
418
- // }
419
-
420
- type T = Static<typeof T> // type T = string | null
421
-
422
- const U = Nullable(Type.Number()) // const U = {
423
- // "anyOf": [{
424
- // type: 'number'
425
- // }, {
426
- // type: 'null'
427
- // }]
428
- // }
429
-
430
- type U = Static<typeof U> // type U = number | null
416
+ const T = Nullable(Type.String()) // const T = {
417
+ // "anyOf": [{
418
+ // type: 'string'
419
+ // }, {
420
+ // type: 'null'
421
+ // }]
422
+ // }
423
+
424
+ type T = Static<typeof T> // type T = string | null
425
+
426
+ const U = Nullable(Type.Number()) // const U = {
427
+ // "anyOf": [{
428
+ // type: 'number'
429
+ // }, {
430
+ // type: 'null'
431
+ // }]
432
+ // }
433
+
434
+ type U = Static<typeof U> // type U = number | null
431
435
  ```
432
436
 
433
437
  <a name="Reference-Types"></a>
@@ -437,61 +441,61 @@ type U = Static<typeof U> // type U = number | null
437
441
  Types can be referenced with `Type.Ref(...)`. To reference a type, the target type must specify an `$id`.
438
442
 
439
443
  ```typescript
440
- const T = Type.String({ $id: 'T' }) // const T = {
441
- // $id: 'T',
442
- // type: 'string'
443
- // }
444
+ const T = Type.String({ $id: 'T' }) // const T = {
445
+ // $id: 'T',
446
+ // type: 'string'
447
+ // }
444
448
 
445
- const R = Type.Ref(T) // const R = {
446
- // $ref: 'T'
447
- // }
449
+ const R = Type.Ref(T) // const R = {
450
+ // $ref: 'T'
451
+ // }
448
452
  ```
449
453
 
450
- It can be helpful to organize shared referenced types under a common namespace. The `Type.Namespace(...)` function can be used to create a shared definition container for related types. The following creates a `Math3D` container and a `Vertex` structure that references types in the container.
454
+ It can sometimes be helpful to organize shared referenced types under a common namespace. The `Type.Namespace(...)` function can be used to create a shared definition container for related types. The following creates a `Math3D` container and a `Vertex` structure that references types in the container.
451
455
 
452
456
  ```typescript
453
- const Math3D = Type.Namespace({ // const Math3D = {
454
- Vector4: Type.Object({ // $id: 'Math3D',
455
- x: Type.Number(), // $defs: {
456
- y: Type.Number(), // Vector4: {
457
- z: Type.Number(), // type: 'object',
458
- w: Type.Number() // properties: {
459
- }), // x: { type: 'number' },
460
- Vector3: Type.Object({ // y: { type: 'number' },
461
- x: Type.Number(), // z: { type: 'number' },
462
- y: Type.Number(), // w: { type: 'number' }
463
- z: Type.Number() // },
464
- }), // required: ['x', 'y', 'z', 'w']
465
- Vector2: Type.Object({ // },
466
- x: Type.Number(), // Vector3: {
467
- y: Type.Number() // type: 'object',
468
- }) // properties: {
469
- }, { $id: 'Math3D' }) // x: { 'type': 'number' },
470
- // y: { 'type': 'number' },
471
- // z: { 'type': 'number' }
472
- // },
473
- // required: ['x', 'y', 'z']
474
- // },
475
- // Vector2: {
476
- // type: 'object',
477
- // properties: {
478
- // x: { 'type': 'number' },
479
- // y: { 'type': 'number' },
480
- // },
481
- // required: ['x', 'y']
482
- // }
483
- // }
484
- // }
457
+ const Math3D = Type.Namespace({ // const Math3D = {
458
+ Vector4: Type.Object({ // $id: 'Math3D',
459
+ x: Type.Number(), // $defs: {
460
+ y: Type.Number(), // Vector4: {
461
+ z: Type.Number(), // type: 'object',
462
+ w: Type.Number() // properties: {
463
+ }), // x: { type: 'number' },
464
+ Vector3: Type.Object({ // y: { type: 'number' },
465
+ x: Type.Number(), // z: { type: 'number' },
466
+ y: Type.Number(), // w: { type: 'number' }
467
+ z: Type.Number() // },
468
+ }), // required: ['x', 'y', 'z', 'w']
469
+ Vector2: Type.Object({ // },
470
+ x: Type.Number(), // Vector3: {
471
+ y: Type.Number() // type: 'object',
472
+ }) // properties: {
473
+ }, { $id: 'Math3D' }) // x: { 'type': 'number' },
474
+ // y: { 'type': 'number' },
475
+ // z: { 'type': 'number' }
476
+ // },
477
+ // required: ['x', 'y', 'z']
478
+ // },
479
+ // Vector2: {
480
+ // type: 'object',
481
+ // properties: {
482
+ // x: { 'type': 'number' },
483
+ // y: { 'type': 'number' },
484
+ // },
485
+ // required: ['x', 'y']
486
+ // }
487
+ // }
488
+ // }
485
489
 
486
- const Vertex = Type.Object({ // const Vertex = {
487
- position: Type.Ref(Math3D, 'Vector4'), // type: 'object',
488
- normal: Type.Ref(Math3D, 'Vector3'), // properties: {
489
- uv: Type.Ref(Math3D, 'Vector2') // position: { $ref: 'Math3D#/$defs/Vector4' },
490
- }) // normal: { $ref: 'Math3D#/$defs/Vector3' },
491
- // uv: { $ref: 'Math3D#/$defs/Vector2' }
492
- // },
493
- // required: ['position', 'normal', 'uv']
494
- // }
490
+ const Vertex = Type.Object({ // const Vertex = {
491
+ position: Type.Ref(Math3D, 'Vector4'), // type: 'object',
492
+ normal: Type.Ref(Math3D, 'Vector3'), // properties: {
493
+ uv: Type.Ref(Math3D, 'Vector2') // position: { $ref: 'Math3D#/$defs/Vector4' },
494
+ }) // normal: { $ref: 'Math3D#/$defs/Vector3' },
495
+ // uv: { $ref: 'Math3D#/$defs/Vector2' }
496
+ // },
497
+ // required: ['position', 'normal', 'uv']
498
+ // }
495
499
  ```
496
500
 
497
501
  <a name="Recursive-Types"></a>
@@ -501,30 +505,30 @@ const Vertex = Type.Object({ // const Vertex = {
501
505
  Recursive types can be created with the `Type.Rec(...)` function. The following creates a `Node` type that contains an array of inner Nodes. Note that due to current restrictions on TypeScript inference, it is not possible for TypeBox to statically infer for recursive types. TypeBox will infer the inner recursive type as `any`.
502
506
 
503
507
  ```typescript
504
- const Node = Type.Rec(Self => Type.Object({ // const Node = {
505
- id: Type.String(), // $id: 'Node',
506
- nodes: Type.Array(Self), // $ref: 'Node#/$defs/self',
507
- }), { $id: 'Node' }) // $defs: {
508
- // self: {
509
- // type: 'object',
510
- // properties: {
511
- // id: {
512
- // type: 'string'
513
- // },
514
- // nodes: {
515
- // type: 'array',
516
- // items: {
517
- // $ref: 'Node#/$defs/self'
518
- // }
519
- // }
520
- // }
521
- // }
522
- // }
523
-
524
- type Node = Static<typeof Node> // type Node = {
525
- // id: string
526
- // nodes: any[]
527
- //
508
+ const Node = Type.Rec(Self => Type.Object({ // const Node = {
509
+ id: Type.String(), // $id: 'Node',
510
+ nodes: Type.Array(Self), // $ref: 'Node#/$defs/self',
511
+ }), { $id: 'Node' }) // $defs: {
512
+ // self: {
513
+ // type: 'object',
514
+ // properties: {
515
+ // id: {
516
+ // type: 'string'
517
+ // },
518
+ // nodes: {
519
+ // type: 'array',
520
+ // items: {
521
+ // $ref: 'Node#/$defs/self'
522
+ // }
523
+ // }
524
+ // }
525
+ // }
526
+ // }
527
+
528
+ type Node = Static<typeof Node> // type Node = {
529
+ // id: string
530
+ // nodes: any[]
531
+ // }
528
532
 
529
533
  function visit(node: Node) {
530
534
  for(const inner of node.nodes) {
@@ -542,7 +546,7 @@ In addition to JSON schema types, TypeBox provides several extended types that a
542
546
  ```typescript
543
547
  ┌────────────────────────────────┬─────────────────────────────┬────────────────────────────────┐
544
548
  │ TypeBox │ TypeScript │ Extended Schema │
545
- │ │ │
549
+ │ │ │
546
550
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
547
551
  │ const T = Type.Constructor([ │ type T = new ( │ const T = { │
548
552
  │ Type.String(), │ arg0: string, │ type: 'constructor' │
@@ -555,7 +559,7 @@ In addition to JSON schema types, TypeBox provides several extended types that a
555
559
  │ │ │ type: 'boolean' │
556
560
  │ │ │ } │
557
561
  │ │ │ } │
558
- │ │ │
562
+ │ │ │
559
563
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
560
564
  │ const T = Type.Function([ │ type T = ( │ const T = { │
561
565
  | Type.String(), │ arg0: string, │ type : 'function', │
@@ -568,7 +572,7 @@ In addition to JSON schema types, TypeBox provides several extended types that a
568
572
  │ │ │ type: 'boolean' │
569
573
  │ │ │ } │
570
574
  │ │ │ } │
571
- │ │ │
575
+ │ │ │
572
576
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
573
577
  │ const T = Type.Promise( │ type T = Promise<string> │ const T = { │
574
578
  │ Type.String() │ │ type: 'promise', │
@@ -576,17 +580,17 @@ In addition to JSON schema types, TypeBox provides several extended types that a
576
580
  │ │ │ type: 'string' │
577
581
  │ │ │ } │
578
582
  │ │ │ } │
579
- │ │ │
583
+ │ │ │
580
584
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
581
585
  │ const T = Type.Undefined() │ type T = undefined │ const T = { │
582
586
  │ │ │ type: 'undefined' │
583
587
  │ │ │ } │
584
- │ │ │
588
+ │ │ │
585
589
  ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
586
590
  │ const T = Type.Void() │ type T = void │ const T = { │
587
591
  │ │ │ type: 'void' │
588
592
  │ │ │ } │
589
- │ │ │
593
+ │ │ │
590
594
  └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
591
595
  ```
592
596
 
@@ -594,7 +598,7 @@ In addition to JSON schema types, TypeBox provides several extended types that a
594
598
 
595
599
  ### Strict
596
600
 
597
- TypeBox includes the properties `kind` and `modifier` on each underlying schema. These properties are used to help TypeBox statically resolve the schemas to the appropriate TypeScript type as well as apply the appropriate modifiers to an objects properties (such as optional). These properties are not strictly valid JSON schema so in some cases it may be desirable to omit them. TypeBox provides a `Type.Strict()` function that will omit these properties if nessasary.
601
+ TypeBox schemas contain the properties `kind` and `modifier`. These properties are provided to enable runtime type reflection on schemas, as well as helping TypeBox apply the appropriate static type inference rules. These properties are not strictly valid JSON schema so in some cases it may be desirable to omit them. TypeBox provides a `Type.Strict()` function that will omit these properties if necessary.
598
602
 
599
603
  ```typescript
600
604
  const T = Type.Object({ // const T = {
@@ -623,7 +627,7 @@ const U = Type.Strict(T) // const U = {
623
627
 
624
628
  ### Validation
625
629
 
626
- TypeBox does not provide JSON schema validation functionality, so users will need to select an appropriate JSON Schema validator for their language or framework. TypeBox targets JSON Schema draft `2019-09` so any validator capable of draft `2019-09` should be fine. A good library to use for validation in JavaScript environments is [AJV](https://www.npmjs.com/package/ajv). The following example shows setting up AJV 7 to work with TypeBox.
630
+ TypeBox does not provide JSON schema validation so users will need to select an appropriate JSON Schema validator for their needs. TypeBox schemas target JSON Schema draft `2019-09` so any validator capable of draft `2019-09` should be fine. A good library to use for validation in JavaScript environments is [AJV](https://www.npmjs.com/package/ajv). The following example shows setting up AJV 7 to work with TypeBox.
627
631
 
628
632
  ```bash
629
633
  $ npm install ajv ajv-formats --save
@@ -689,64 +693,11 @@ const ok = ajv.validate(User, {
689
693
  }) // -> ok
690
694
  ```
691
695
 
692
- #### Reference Types
693
-
694
- Referenced types can be added to AJV with the `ajv.addSchema(...)` function. The following moves the `userId` and `email` property types into a `Type.Namespace(...)` and registers the box with AJV.
695
-
696
- ```typescript
697
- //--------------------------------------------------------------------------------------------
698
- //
699
- // Shared Types
700
- //
701
- //--------------------------------------------------------------------------------------------
702
-
703
- const Shared = Type.Namespace({
704
- UserId: Type.String({ format: 'uuid' }),
705
- Email: Type.String({ format: 'email' })
706
- }, { $id: 'Shared' })
707
-
708
- //--------------------------------------------------------------------------------------------
709
- //
710
- // Setup Validator and Register Shared Types
711
- //
712
- //--------------------------------------------------------------------------------------------
713
-
714
- const ajv = addFormats(new Ajv({}), [...])
715
- .addKeyword('kind')
716
- .addKeyword('modifier')
717
- .addSchema(Shared) // <-- Register Shared Types
718
-
719
- //--------------------------------------------------------------------------------------------
720
- //
721
- // Create a TypeBox type
722
- //
723
- //--------------------------------------------------------------------------------------------
724
-
725
- const User = Type.Object({
726
- userId: Type.Ref(Shared, 'UserId'),
727
- email: Type.Ref(Shared, 'Email'),
728
- online: Type.Boolean()
729
- }, { additionalProperties: false })
730
-
731
- //--------------------------------------------------------------------------------------------
732
- //
733
- // Validate Data
734
- //
735
- //--------------------------------------------------------------------------------------------
736
-
737
- const ok = ajv.validate(User, {
738
- userId: '68b4b1d8-0db6-468d-b551-02069a692044',
739
- email: 'dave@domain.com',
740
- online: true
741
- }) // -> ok
742
-
743
- ```
744
-
745
- Please refer to the official AJV [documentation](https://ajv.js.org/guide/getting-started.html) for additional information.
696
+ Please refer to the official AJV [documentation](https://ajv.js.org/guide/getting-started.html) for additional information on using AJV.
746
697
 
747
698
  ### OpenAPI
748
699
 
749
- TypeBox can be used to create schemas for OpenAPI, however users should be aware of the various differences between the JSON Schema and OpenAPI specifications. Two common instances where OpenAPI diverges from the JSON Schema specification is OpenAPI's handling of `string enum` and `nullable`. The following shows how you can use TypeBox to construct these types.
700
+ TypeBox can be used to create schemas for OpenAPI, however users should be mindful of some disparities between the JSON Schema and OpenAPI for versions prior to OpenAPI 3.1. Two common instances where OpenAPI diverges is the handling nullable and string enum schemas types. The following shows how you can use TypeBox to construct these types.
750
701
 
751
702
  ```typescript
752
703
  import { Type, Static, TNull, TLiteral, TUnion, TSchema } from '@sinclair/typebox'
@@ -761,12 +712,12 @@ function Nullable<T extends TSchema>(schema: T): TUnion<[T, TNull]> {
761
712
  return { ...schema, nullable: true } as any
762
713
  }
763
714
 
764
- const T = Nullable(Type.String()) // const T = {
765
- // type: 'string',
766
- // nullable: true
767
- // }
715
+ const T = Nullable(Type.String()) // const T = {
716
+ // type: 'string',
717
+ // nullable: true
718
+ // }
768
719
 
769
- type T = Static<typeof T> // type T = string | null
720
+ type T = Static<typeof T> // type T = string | null
770
721
 
771
722
  //--------------------------------------------------------------------------------------------
772
723
  //
@@ -780,9 +731,9 @@ function StringUnion<T extends string[]>(values: [...T]): TUnion<IntoStringUnion
780
731
  return { enum: values } as any
781
732
  }
782
733
 
783
- const T = StringUnion(['A', 'B', 'C']) // const T = {
784
- // enum: ['A', 'B', 'C']
785
- // }
734
+ const T = StringUnion(['A', 'B', 'C']) // const T = {
735
+ // enum: ['A', 'B', 'C']
736
+ // }
786
737
 
787
- type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
738
+ type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
788
739
  ```
package/typebox.d.ts CHANGED
@@ -11,7 +11,7 @@ export declare type TOptional<T extends TSchema> = T & {
11
11
  export declare type TReadonly<T extends TSchema> = T & {
12
12
  modifier: typeof ReadonlyModifier;
13
13
  };
14
- export declare const BoxKind: unique symbol;
14
+ export declare const NamespaceKind: unique symbol;
15
15
  export declare const KeyOfKind: unique symbol;
16
16
  export declare const IntersectKind: unique symbol;
17
17
  export declare const UnionKind: unique symbol;
@@ -63,12 +63,14 @@ export declare type IntersectOptions = {
63
63
  } & CustomOptions;
64
64
  export declare type ObjectOptions = {
65
65
  additionalProperties?: boolean;
66
+ minProperties?: number;
67
+ maxProperties?: number;
66
68
  } & CustomOptions;
67
69
  export declare type TDefinitions = {
68
70
  [key: string]: TSchema;
69
71
  };
70
72
  export declare type TNamespace<T extends TDefinitions> = {
71
- kind: typeof BoxKind;
73
+ kind: typeof NamespaceKind;
72
74
  $defs: T;
73
75
  } & CustomOptions;
74
76
  export interface TSchema {
@@ -142,6 +144,11 @@ export interface TEnum<T extends TEnumKey[]> extends TSchema, CustomOptions {
142
144
  kind: typeof EnumKind;
143
145
  anyOf: T;
144
146
  }
147
+ export interface TRef<T extends TSchema> extends TSchema, CustomOptions {
148
+ $static: Static<T>;
149
+ kind: typeof RefKind;
150
+ $ref: string;
151
+ }
145
152
  export interface TString extends TSchema, StringOptions<string> {
146
153
  $static: string;
147
154
  kind: typeof StringKind;
@@ -175,11 +182,6 @@ export interface TAny extends TSchema, CustomOptions {
175
182
  $static: any;
176
183
  kind: typeof AnyKind;
177
184
  }
178
- export interface TRef<T extends TSchema> extends TSchema, CustomOptions {
179
- $static: Static<T>;
180
- kind: typeof RefKind;
181
- $ref: string;
182
- }
183
185
  export declare const ConstructorKind: unique symbol;
184
186
  export declare const FunctionKind: unique symbol;
185
187
  export declare const PromiseKind: unique symbol;
@@ -215,9 +217,9 @@ export interface TVoid extends TSchema, CustomOptions {
215
217
  kind: typeof VoidKind;
216
218
  type: 'void';
217
219
  }
218
- export declare type Pickable = TObject<TProperties> | TRef<TObject<TProperties>>;
219
- export declare type PickablePropertyKeys<T extends Pickable> = T extends TObject<infer U> ? keyof U : T extends TRef<TObject<infer U>> ? keyof U : never;
220
- export declare type PickableProperties<T extends Pickable> = T extends TObject<infer U> ? U : T extends TRef<TObject<infer U>> ? U : never;
220
+ export declare type Selectable = TObject<TProperties> | TRef<TObject<TProperties>>;
221
+ export declare type SelectablePropertyKeys<T extends Selectable> = T extends TObject<infer U> ? keyof U : T extends TRef<TObject<infer U>> ? keyof U : never;
222
+ export declare type SelectableProperties<T extends Selectable> = T extends TObject<infer U> ? U : T extends TRef<TObject<infer U>> ? U : never;
221
223
  export declare type UnionToIntersect<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
222
224
  export declare type StaticReadonlyOptionalPropertyKeys<T extends TProperties> = {
223
225
  [K in keyof T]: T[K] extends TReadonlyOptional<TSchema> ? K : never;
@@ -271,7 +273,7 @@ export declare type StaticFunction<T extends readonly TSchema[], U extends TSche
271
273
  export declare type StaticPromise<T extends TSchema> = Promise<Static<T>>;
272
274
  export declare type Static<T extends TSchema> = T['$static'];
273
275
  export declare class TypeBuilder {
274
- private readonly schemas;
276
+ protected readonly schemas: Map<string, TSchema>;
275
277
  /** `Standard` Modifies an object property to be both readonly and optional */
276
278
  ReadonlyOptional<T extends TSchema>(item: T): TReadonlyOptional<T>;
277
279
  /** `Standard` Modifies an object property to be readonly */
@@ -308,18 +310,18 @@ export declare class TypeBuilder {
308
310
  Unknown(options?: CustomOptions): TUnknown;
309
311
  /** `Standard` Creates an any type */
310
312
  Any(options?: CustomOptions): TAny;
311
- /** `Standard` Creates a keyof type from the given object */
312
- KeyOf<T extends TObject<TProperties>>(object: T, options?: CustomOptions): TKeyOf<(keyof T['properties'])[]>;
313
313
  /** `Standard` Creates a record type */
314
314
  Record<K extends TRecordKey, T extends TSchema>(key: K, value: T, options?: ObjectOptions): TRecord<K, T>;
315
+ /** `Standard` Creates a keyof type from the given object */
316
+ KeyOf<T extends TObject<TProperties> | TRef<TObject<TProperties>>>(object: T, options?: CustomOptions): TKeyOf<SelectablePropertyKeys<T>[]>;
315
317
  /** `Standard` Makes all properties in the given object type required */
316
318
  Required<T extends TObject<TProperties> | TRef<TObject<TProperties>>>(object: T, options?: ObjectOptions): TObject<StaticRequired<T['properties']>>;
317
319
  /** `Standard` Makes all properties in the given object type optional */
318
320
  Partial<T extends TObject<TProperties> | TRef<TObject<TProperties>>>(object: T, options?: ObjectOptions): TObject<StaticPartial<T['properties']>>;
319
321
  /** `Standard` Picks property keys from the given object type */
320
- Pick<T extends TObject<TProperties> | TRef<TObject<TProperties>>, K extends PickablePropertyKeys<T>[]>(object: T, keys: [...K], options?: ObjectOptions): TObject<Pick<PickableProperties<T>, K[number]>>;
322
+ Pick<T extends TObject<TProperties> | TRef<TObject<TProperties>>, K extends SelectablePropertyKeys<T>[]>(object: T, keys: [...K], options?: ObjectOptions): TObject<Pick<SelectableProperties<T>, K[number]>>;
321
323
  /** `Standard` Omits property keys from the given object type */
322
- Omit<T extends TObject<TProperties> | TRef<TObject<TProperties>>, K extends PickablePropertyKeys<T>[]>(object: T, keys: [...K], options?: ObjectOptions): TObject<Omit<PickableProperties<T>, K[number]>>;
324
+ Omit<T extends TObject<TProperties> | TRef<TObject<TProperties>>, K extends SelectablePropertyKeys<T>[]>(object: T, keys: [...K], options?: ObjectOptions): TObject<Omit<SelectableProperties<T>, K[number]>>;
323
325
  /** `Standard` Omits the `kind` and `modifier` properties from the underlying schema */
324
326
  Strict<T extends TSchema>(schema: T, options?: CustomOptions): T;
325
327
  /** `Extended` Creates a constructor type */
@@ -335,14 +337,14 @@ export declare class TypeBuilder {
335
337
  /** `Standard` Creates a namespace for a set of related types */
336
338
  Namespace<T extends TDefinitions>($defs: T, options?: CustomOptions): TNamespace<T>;
337
339
  /** `Standard` References a type within a namespace. The referenced namespace must specify an `$id` */
338
- Ref<T extends TNamespace<TDefinitions>, K extends keyof T['$defs']>(box: T, key: K): TRef<T['$defs'][K]>;
340
+ Ref<T extends TNamespace<TDefinitions>, K extends keyof T['$defs']>(namespace: T, key: K): TRef<T['$defs'][K]>;
339
341
  /** `Standard` References type. The referenced type must specify an `$id` */
340
342
  Ref<T extends TSchema>(schema: T): TRef<T>;
341
343
  /** `Experimental` Creates a recursive type */
342
344
  Rec<T extends TSchema>(callback: (self: TAny) => T, options?: CustomOptions): T;
343
- /** Stores this schema if it contains an $id. This function is used for later referencing. */
344
- private Store;
345
- /** Resolves a schema by $id. May resolve recursively if the target is a TRef. */
346
- private Resolve;
345
+ /** Conditionally stores and schema if it contains an $id and returns */
346
+ protected Store<T extends TSchema | TNamespace<TDefinitions>, S = Omit<T, '$static'>>(schema: S): T;
347
+ /** Conditionally dereferences a schema if RefKind. Otherwise return argument */
348
+ protected Deref<T extends TSchema>(schema: T): any;
347
349
  }
348
350
  export declare const Type: TypeBuilder;
package/typebox.js CHANGED
@@ -27,7 +27,7 @@ THE SOFTWARE.
27
27
 
28
28
  ---------------------------------------------------------------------------*/
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.Type = exports.TypeBuilder = exports.VoidKind = exports.UndefinedKind = exports.PromiseKind = exports.FunctionKind = exports.ConstructorKind = exports.RefKind = exports.AnyKind = exports.UnknownKind = exports.NullKind = exports.BooleanKind = exports.IntegerKind = exports.NumberKind = exports.StringKind = exports.LiteralKind = exports.EnumKind = exports.ArrayKind = exports.RecordKind = exports.ObjectKind = exports.TupleKind = exports.UnionKind = exports.IntersectKind = exports.KeyOfKind = exports.BoxKind = exports.ReadonlyModifier = exports.OptionalModifier = exports.ReadonlyOptionalModifier = void 0;
30
+ exports.Type = exports.TypeBuilder = exports.VoidKind = exports.UndefinedKind = exports.PromiseKind = exports.FunctionKind = exports.ConstructorKind = exports.RefKind = exports.AnyKind = exports.UnknownKind = exports.NullKind = exports.BooleanKind = exports.IntegerKind = exports.NumberKind = exports.StringKind = exports.LiteralKind = exports.EnumKind = exports.ArrayKind = exports.RecordKind = exports.ObjectKind = exports.TupleKind = exports.UnionKind = exports.IntersectKind = exports.KeyOfKind = exports.NamespaceKind = exports.ReadonlyModifier = exports.OptionalModifier = exports.ReadonlyOptionalModifier = void 0;
31
31
  // --------------------------------------------------------------------------
32
32
  // Modifiers
33
33
  // --------------------------------------------------------------------------
@@ -37,7 +37,7 @@ exports.ReadonlyModifier = Symbol('ReadonlyModifier');
37
37
  // --------------------------------------------------------------------------
38
38
  // Schema Standard
39
39
  // --------------------------------------------------------------------------
40
- exports.BoxKind = Symbol('BoxKind');
40
+ exports.NamespaceKind = Symbol('NamespaceKind');
41
41
  exports.KeyOfKind = Symbol('KeyOfKind');
42
42
  exports.IntersectKind = Symbol('IntersectKind');
43
43
  exports.UnionKind = Symbol('UnionKind');
@@ -175,11 +175,6 @@ class TypeBuilder {
175
175
  Any(options = {}) {
176
176
  return this.Store({ ...options, kind: exports.AnyKind });
177
177
  }
178
- /** `Standard` Creates a keyof type from the given object */
179
- KeyOf(object, options = {}) {
180
- const keys = Object.keys(object.properties);
181
- return this.Store({ ...options, kind: exports.KeyOfKind, type: 'string', enum: keys });
182
- }
183
178
  /** `Standard` Creates a record type */
184
179
  Record(key, value, options = {}) {
185
180
  const pattern = (() => {
@@ -193,9 +188,15 @@ class TypeBuilder {
193
188
  })();
194
189
  return this.Store({ ...options, kind: exports.RecordKind, type: 'object', patternProperties: { [pattern]: value } });
195
190
  }
191
+ /** `Standard` Creates a keyof type from the given object */
192
+ KeyOf(object, options = {}) {
193
+ const source = this.Deref(object);
194
+ const keys = Object.keys(source.properties);
195
+ return this.Store({ ...options, kind: exports.KeyOfKind, type: 'string', enum: keys });
196
+ }
196
197
  /** `Standard` Makes all properties in the given object type required */
197
198
  Required(object, options = {}) {
198
- const source = this.Resolve(object);
199
+ const source = this.Deref(object);
199
200
  const schema = { ...clone(source), ...options };
200
201
  schema.required = Object.keys(schema.properties);
201
202
  for (const key of Object.keys(schema.properties)) {
@@ -219,7 +220,7 @@ class TypeBuilder {
219
220
  }
220
221
  /** `Standard` Makes all properties in the given object type optional */
221
222
  Partial(object, options = {}) {
222
- const source = this.Resolve(object);
223
+ const source = this.Deref(object);
223
224
  const schema = { ...clone(source), ...options };
224
225
  delete schema.required;
225
226
  for (const key of Object.keys(schema.properties)) {
@@ -243,7 +244,7 @@ class TypeBuilder {
243
244
  }
244
245
  /** `Standard` Picks property keys from the given object type */
245
246
  Pick(object, keys, options = {}) {
246
- const source = this.Resolve(object);
247
+ const source = this.Deref(object);
247
248
  const schema = { ...clone(source), ...options };
248
249
  schema.required = schema.required ? schema.required.filter((key) => keys.includes(key)) : undefined;
249
250
  for (const key of Object.keys(schema.properties)) {
@@ -254,7 +255,7 @@ class TypeBuilder {
254
255
  }
255
256
  /** `Standard` Omits property keys from the given object type */
256
257
  Omit(object, keys, options = {}) {
257
- const source = this.Resolve(object);
258
+ const source = this.Deref(object);
258
259
  const schema = { ...clone(source), ...options };
259
260
  schema.required = schema.required ? schema.required.filter((key) => !keys.includes(key)) : undefined;
260
261
  for (const key of Object.keys(schema.properties)) {
@@ -289,7 +290,7 @@ class TypeBuilder {
289
290
  }
290
291
  /** `Standard` Creates a namespace for a set of related types */
291
292
  Namespace($defs, options = {}) {
292
- return this.Store({ ...options, kind: exports.BoxKind, $defs });
293
+ return this.Store({ ...options, kind: exports.NamespaceKind, $defs });
293
294
  }
294
295
  Ref(...args) {
295
296
  if (args.length === 2) {
@@ -319,20 +320,22 @@ class TypeBuilder {
319
320
  const self = callback({ $ref: `${$id}#/$defs/self` });
320
321
  return this.Store({ ...options, $ref: `${$id}#/$defs/self`, $defs: { self } });
321
322
  }
322
- /** Stores this schema if it contains an $id. This function is used for later referencing. */
323
+ /** Conditionally stores and schema if it contains an $id and returns */
323
324
  Store(schema) {
324
- if (!schema.$id)
325
- return schema;
326
- this.schemas.set(schema.$id, schema);
327
- return schema;
328
- }
329
- /** Resolves a schema by $id. May resolve recursively if the target is a TRef. */
330
- Resolve(schema) {
331
- if (schema.kind !== exports.RefKind)
325
+ const $schema = schema;
326
+ if (!$schema['$id'])
327
+ return $schema;
328
+ this.schemas.set($schema['$id'], $schema);
329
+ return $schema;
330
+ }
331
+ /** Conditionally dereferences a schema if RefKind. Otherwise return argument */
332
+ Deref(schema) {
333
+ const $schema = schema;
334
+ if ($schema['kind'] !== exports.RefKind)
332
335
  return schema;
333
- if (!this.schemas.has(schema.$ref))
334
- throw Error(`Unable to locate schema with $id '${schema.$ref}'`);
335
- return this.Resolve(this.schemas.get(schema.$ref));
336
+ if (!this.schemas.has($schema['$ref']))
337
+ throw Error(`Unable to locate schema with $id '${$schema['$ref']}'`);
338
+ return this.Deref(this.schemas.get($schema['$ref']));
336
339
  }
337
340
  }
338
341
  exports.TypeBuilder = TypeBuilder;