@sinclair/typebox 0.21.1 → 0.23.0

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 +13 -9
  2. package/readme.md +10 -8
  3. package/typebox.d.ts +182 -140
  4. package/typebox.js +147 -113
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sinclair/typebox",
3
- "version": "0.21.1",
3
+ "version": "0.23.0",
4
4
  "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
5
5
  "keywords": [
6
6
  "json-schema",
@@ -20,17 +20,21 @@
20
20
  "clean": "hammer task clean",
21
21
  "build": "hammer task build",
22
22
  "example": "hammer task example",
23
- "test": "hammer task spec"
23
+ "spec": "hammer task spec",
24
+ "spec:types": "hammer task spec_types",
25
+ "spec:schemas": "hammer task spec_schemas",
26
+ "test": "npm run spec"
24
27
  },
25
28
  "devDependencies": {
26
- "@sinclair/hammer": "^0.15.7",
27
- "@types/chai": "^4.2.16",
28
- "@types/mocha": "^8.2.2",
29
- "@types/node": "^14.14.37",
30
- "ajv": "^8.6.2",
31
- "ajv-formats": "^2.0.2",
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",
34
+ "ajv-formats": "^2.1.1",
32
35
  "chai": "^4.3.4",
33
- "mocha": "^9.1.2",
36
+ "mocha": "^9.1.3",
37
+ "tsd": "^0.19.0",
34
38
  "typescript": "^4.5.2"
35
39
  }
36
40
  }
package/readme.md CHANGED
@@ -452,7 +452,7 @@ It can be helpful to organize shared referenced types under a common namespace.
452
452
  ```typescript
453
453
  const Math3D = Type.Namespace({ // const Math3D = {
454
454
  Vector4: Type.Object({ // $id: 'Math3D',
455
- x: Type.Number(), // definitions: {
455
+ x: Type.Number(), // $defs: {
456
456
  y: Type.Number(), // Vector4: {
457
457
  z: Type.Number(), // type: 'object',
458
458
  w: Type.Number() // properties: {
@@ -486,9 +486,9 @@ const Math3D = Type.Namespace({ // const Math3D = {
486
486
  const Vertex = Type.Object({ // const Vertex = {
487
487
  position: Type.Ref(Math3D, 'Vector4'), // type: 'object',
488
488
  normal: Type.Ref(Math3D, 'Vector3'), // properties: {
489
- uv: Type.Ref(Math3D, 'Vector2') // position: { $ref: 'Math3D#/definitions/Vector4' },
490
- }) // normal: { $ref: 'Math3D#/definitions/Vector3' },
491
- // uv: { $ref: 'Math3D#/definitions/Vector2' }
489
+ uv: Type.Ref(Math3D, 'Vector2') // position: { $ref: 'Math3D#/$defs/Vector4' },
490
+ }) // normal: { $ref: 'Math3D#/$defs/Vector3' },
491
+ // uv: { $ref: 'Math3D#/$defs/Vector2' }
492
492
  // },
493
493
  // required: ['position', 'normal', 'uv']
494
494
  // }
@@ -503,8 +503,8 @@ Recursive types can be created with the `Type.Rec(...)` function. The following
503
503
  ```typescript
504
504
  const Node = Type.Rec(Self => Type.Object({ // const Node = {
505
505
  id: Type.String(), // $id: 'Node',
506
- nodes: Type.Array(Self), // $ref: 'Node#/definitions/self',
507
- }), { $id: 'Node' }) // definitions: {
506
+ nodes: Type.Array(Self), // $ref: 'Node#/$defs/self',
507
+ }), { $id: 'Node' }) // $defs: {
508
508
  // self: {
509
509
  // type: 'object',
510
510
  // properties: {
@@ -514,7 +514,7 @@ const Node = Type.Rec(Self => Type.Object({ // const Node = {
514
514
  // nodes: {
515
515
  // type: 'array',
516
516
  // items: {
517
- // $ref: 'Node#/definitions/self'
517
+ // $ref: 'Node#/$defs/self'
518
518
  // }
519
519
  // }
520
520
  // }
@@ -774,7 +774,9 @@ type T = Static<typeof T> // type T = string | null
774
774
  //
775
775
  //--------------------------------------------------------------------------------------------
776
776
 
777
- function StringUnion<T extends string[]>(values: [...T]): TUnion<{[K in keyof T]: T[K] }[number]> {
777
+ type IntoStringUnion<T> = {[K in keyof T]: T[K] extends string ? TLiteral<T[K]>: never }
778
+
779
+ function StringUnion<T extends string[]>(values: [...T]): TUnion<IntoStringUnion<T>> {
778
780
  return { enum: values } as any
779
781
  }
780
782
 
package/typebox.d.ts CHANGED
@@ -28,6 +28,7 @@ export declare const BooleanKind: unique symbol;
28
28
  export declare const NullKind: unique symbol;
29
29
  export declare const UnknownKind: unique symbol;
30
30
  export declare const AnyKind: unique symbol;
31
+ export declare const RefKind: unique symbol;
31
32
  export interface CustomOptions {
32
33
  $id?: string;
33
34
  title?: string;
@@ -68,239 +69,280 @@ export declare type TDefinitions = {
68
69
  };
69
70
  export declare type TNamespace<T extends TDefinitions> = {
70
71
  kind: typeof BoxKind;
71
- definitions: T;
72
+ $defs: T;
72
73
  } & CustomOptions;
73
- export declare type Infer<T> = {
74
- '_infer': T;
75
- };
74
+ export interface TSchema {
75
+ $static: unknown;
76
+ }
76
77
  export declare type TEnumType = Record<string, string | number>;
77
- export declare type TKey = string | number;
78
+ export declare type TKey = string | number | symbol;
78
79
  export declare type TValue = string | number | boolean;
79
- export declare type TRecordKey = TString | TNumber | TKeyOf<any> | TUnion<string | number>;
80
+ export declare type TRecordKey = TString | TNumber | TKeyOf<any> | TUnion<any>;
80
81
  export declare type TEnumKey<T = TKey> = {
81
82
  type: 'number' | 'string';
82
83
  const: T;
83
84
  };
84
- export declare type TProperties = {
85
+ export interface TProperties {
85
86
  [key: string]: TSchema;
86
- };
87
- export declare type TTuple<I> = Infer<I> & {
87
+ }
88
+ export interface TRecord<K extends TRecordKey, T extends TSchema> extends TSchema, ObjectOptions {
89
+ $static: StaticRecord<K, T>;
90
+ kind: typeof RecordKind;
91
+ type: 'object';
92
+ patternProperties: {
93
+ [pattern: string]: T;
94
+ };
95
+ }
96
+ export interface TTuple<T extends TSchema[]> extends TSchema, CustomOptions {
97
+ $static: StaticTuple<T>;
88
98
  kind: typeof TupleKind;
89
99
  type: 'array';
90
- items?: TSchema[];
100
+ items?: T;
91
101
  additionalItems?: false;
92
102
  minItems: number;
93
103
  maxItems: number;
94
- } & CustomOptions;
95
- export declare type TObject<I> = Infer<I> & {
104
+ }
105
+ export interface TObject<T extends TProperties> extends TSchema, ObjectOptions {
106
+ $static: StaticObject<T>;
96
107
  kind: typeof ObjectKind;
97
108
  type: 'object';
98
- properties: TProperties;
109
+ properties: T;
99
110
  required?: string[];
100
- } & ObjectOptions;
101
- export declare type TUnion<I> = Infer<I> & {
111
+ }
112
+ export interface TUnion<T extends TSchema[]> extends TSchema, CustomOptions {
113
+ $static: StaticUnion<T>;
102
114
  kind: typeof UnionKind;
103
- anyOf: TSchema[];
104
- } & CustomOptions;
105
- export declare type TIntersect<I> = Infer<I> & {
115
+ anyOf: T;
116
+ }
117
+ export interface TIntersect<T extends TSchema[]> extends TSchema, IntersectOptions {
118
+ $static: StaticIntersect<T>;
106
119
  kind: typeof IntersectKind;
107
120
  type: 'object';
108
- allOf: TSchema[];
109
- } & IntersectOptions;
110
- export declare type TKeyOf<I> = Infer<I> & {
121
+ allOf: T;
122
+ }
123
+ export interface TKeyOf<T extends TKey[]> extends TSchema, CustomOptions {
124
+ $static: StaticKeyOf<T>;
111
125
  kind: typeof KeyOfKind;
112
126
  type: 'string';
113
- enum: string[];
114
- } & CustomOptions;
115
- export declare type TRecord<I> = Infer<I> & {
116
- kind: typeof RecordKind;
117
- type: 'object';
118
- patternProperties: {
119
- [pattern: string]: TSchema;
120
- };
121
- } & ObjectOptions;
122
- export declare type TArray<I> = Infer<I> & {
127
+ enum: T;
128
+ }
129
+ export interface TArray<T extends TSchema> extends TSchema, ArrayOptions {
130
+ $static: StaticArray<T>;
123
131
  kind: typeof ArrayKind;
124
132
  type: 'array';
125
- items: any;
126
- } & ArrayOptions;
127
- export declare type TLiteral<I> = Infer<I> & {
133
+ items: T;
134
+ }
135
+ export interface TLiteral<T extends TValue> extends TSchema, CustomOptions {
136
+ $static: StaticLiteral<T>;
128
137
  kind: typeof LiteralKind;
129
- const: TValue;
130
- } & CustomOptions;
131
- export declare type TEnum<I> = Infer<I> & {
138
+ const: T;
139
+ }
140
+ export interface TEnum<T extends TEnumKey[]> extends TSchema, CustomOptions {
141
+ $static: StaticEnum<T>;
132
142
  kind: typeof EnumKind;
133
- anyOf: TSchema;
134
- } & CustomOptions;
135
- export declare type TString = Infer<string> & {
143
+ anyOf: T;
144
+ }
145
+ export interface TString extends TSchema, StringOptions<string> {
146
+ $static: string;
136
147
  kind: typeof StringKind;
137
148
  type: 'string';
138
- } & StringOptions<string>;
139
- export declare type TNumber = Infer<number> & {
149
+ }
150
+ export interface TNumber extends TSchema, NumberOptions {
151
+ $static: number;
140
152
  kind: typeof NumberKind;
141
153
  type: 'number';
142
- } & NumberOptions;
143
- export declare type TInteger = Infer<number> & {
154
+ }
155
+ export interface TInteger extends TSchema, NumberOptions {
156
+ $static: number;
144
157
  kind: typeof IntegerKind;
145
158
  type: 'integer';
146
- } & NumberOptions;
147
- export declare type TBoolean = Infer<boolean> & {
159
+ }
160
+ export interface TBoolean extends TSchema, CustomOptions {
161
+ $static: boolean;
148
162
  kind: typeof BooleanKind;
149
163
  type: 'boolean';
150
- } & CustomOptions;
151
- export declare type TNull = Infer<null> & {
164
+ }
165
+ export interface TNull extends TSchema, CustomOptions {
166
+ $static: null;
152
167
  kind: typeof NullKind;
153
168
  type: 'null';
154
- } & CustomOptions;
155
- export declare type TUnknown = Infer<unknown> & {
169
+ }
170
+ export interface TUnknown extends TSchema, CustomOptions {
171
+ $static: unknown;
156
172
  kind: typeof UnknownKind;
157
- } & CustomOptions;
158
- export declare type TAny = Infer<any> & {
173
+ }
174
+ export interface TAny extends TSchema, CustomOptions {
175
+ $static: any;
159
176
  kind: typeof AnyKind;
160
- } & CustomOptions;
177
+ }
178
+ export interface TRef<T extends TSchema> extends TSchema, CustomOptions {
179
+ $static: Static<T>;
180
+ kind: typeof RefKind;
181
+ $ref: string;
182
+ }
161
183
  export declare const ConstructorKind: unique symbol;
162
184
  export declare const FunctionKind: unique symbol;
163
185
  export declare const PromiseKind: unique symbol;
164
186
  export declare const UndefinedKind: unique symbol;
165
187
  export declare const VoidKind: unique symbol;
166
- export declare type TConstructor<T> = Infer<T> & {
188
+ export interface TConstructor<T extends TSchema[], U extends TSchema> extends TSchema, CustomOptions {
189
+ $static: StaticConstructor<T, U>;
167
190
  kind: typeof ConstructorKind;
168
191
  type: 'constructor';
169
192
  arguments: TSchema[];
170
193
  returns: TSchema;
171
- } & CustomOptions;
172
- export declare type TFunction<T> = Infer<T> & {
194
+ }
195
+ export interface TFunction<T extends TSchema[], U extends TSchema> extends TSchema, CustomOptions {
196
+ $static: StaticFunction<T, U>;
173
197
  kind: typeof FunctionKind;
174
198
  type: 'function';
175
199
  arguments: TSchema[];
176
200
  returns: TSchema;
177
- } & CustomOptions;
178
- export declare type TPromise<T> = Infer<T> & {
201
+ }
202
+ export interface TPromise<T extends TSchema> extends TSchema, CustomOptions {
203
+ $static: StaticPromise<T>;
179
204
  kind: typeof PromiseKind;
180
205
  type: 'promise';
181
206
  item: TSchema;
182
- } & CustomOptions;
183
- export declare type TUndefined = Infer<undefined> & {
207
+ }
208
+ export interface TUndefined extends TSchema, CustomOptions {
209
+ $static: undefined;
184
210
  kind: typeof UndefinedKind;
185
211
  type: 'undefined';
186
- } & CustomOptions;
187
- export declare type TVoid = Infer<void> & {
212
+ }
213
+ export interface TVoid extends TSchema, CustomOptions {
214
+ $static: void;
188
215
  kind: typeof VoidKind;
189
216
  type: 'void';
190
- } & CustomOptions;
191
- export declare type TSchema = TIntersect<any> | TUnion<any> | TTuple<any> | TObject<any> | TKeyOf<any> | TRecord<any> | TArray<any> | TEnum<any> | TLiteral<any> | TString | TNumber | TInteger | TBoolean | TNull | TUnknown | TAny | TConstructor<any> | TFunction<any> | TPromise<any> | TUndefined | TVoid;
217
+ }
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;
192
221
  export declare type UnionToIntersect<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
193
- export declare type ReadonlyOptionalPropertyKeys<T extends TProperties> = {
222
+ export declare type StaticReadonlyOptionalPropertyKeys<T extends TProperties> = {
194
223
  [K in keyof T]: T[K] extends TReadonlyOptional<TSchema> ? K : never;
195
224
  }[keyof T];
196
- export declare type ReadonlyPropertyKeys<T extends TProperties> = {
225
+ export declare type StaticReadonlyPropertyKeys<T extends TProperties> = {
197
226
  [K in keyof T]: T[K] extends TReadonly<TSchema> ? K : never;
198
227
  }[keyof T];
199
- export declare type OptionalPropertyKeys<T extends TProperties> = {
228
+ export declare type StaticOptionalPropertyKeys<T extends TProperties> = {
200
229
  [K in keyof T]: T[K] extends TOptional<TSchema> ? K : never;
201
230
  }[keyof T];
202
- export declare type RequiredPropertyKeys<T extends TProperties> = keyof Omit<T, ReadonlyOptionalPropertyKeys<T> | ReadonlyPropertyKeys<T> | OptionalPropertyKeys<T>>;
231
+ export declare type StaticRequiredPropertyKeys<T extends TProperties> = keyof Omit<T, StaticReadonlyOptionalPropertyKeys<T> | StaticReadonlyPropertyKeys<T> | StaticOptionalPropertyKeys<T>>;
232
+ export declare type StaticIntersectEvaluate<T extends readonly TSchema[]> = {
233
+ [K in keyof T]: T[K] extends TSchema ? Static<T[K]> : never;
234
+ };
235
+ export declare type StaticIntersectReduce<I extends unknown, T extends readonly any[]> = T extends [infer A, ...infer B] ? StaticIntersectReduce<I & A, B> : I;
236
+ export declare type StaticRequired<T extends TProperties> = {
237
+ [K in keyof T]: T[K] extends TReadonlyOptional<infer U> ? TReadonly<U> : T[K] extends TReadonly<infer U> ? TReadonly<U> : T[K] extends TOptional<infer U> ? U : T[K];
238
+ };
239
+ export declare type StaticPartial<T extends TProperties> = {
240
+ [K in keyof T]: T[K] extends TReadonlyOptional<infer U> ? TReadonlyOptional<U> : T[K] extends TReadonly<infer U> ? TReadonlyOptional<U> : T[K] extends TOptional<infer U> ? TOptional<U> : TOptional<T[K]>;
241
+ };
203
242
  export declare type StaticProperties<T extends TProperties> = {
204
- readonly [K in ReadonlyOptionalPropertyKeys<T>]?: Static<T[K]>;
243
+ readonly [K in StaticReadonlyOptionalPropertyKeys<T>]?: Static<T[K]>;
205
244
  } & {
206
- readonly [K in ReadonlyPropertyKeys<T>]: Static<T[K]>;
245
+ readonly [K in StaticReadonlyPropertyKeys<T>]: Static<T[K]>;
207
246
  } & {
208
- [K in OptionalPropertyKeys<T>]?: Static<T[K]>;
247
+ [K in StaticOptionalPropertyKeys<T>]?: Static<T[K]>;
209
248
  } & {
210
- [K in RequiredPropertyKeys<T>]: Static<T[K]>;
249
+ [K in StaticRequiredPropertyKeys<T>]: Static<T[K]>;
211
250
  };
251
+ export declare type StaticRecord<K extends TRecordKey, T extends TSchema> = K extends TString ? Record<string, Static<T>> : K extends TNumber ? Record<number, Static<T>> : K extends TKeyOf<TKey[]> ? Record<K['$static'], Static<T>> : K extends TUnion<TSchema[]> ? Record<K['$static'], Static<T>> : never;
212
252
  export declare type StaticEnum<T> = T extends TEnumKey<infer U>[] ? U : never;
213
253
  export declare type StaticKeyOf<T extends TKey[]> = T extends Array<infer K> ? K : never;
214
- export declare type StaticIntersect<T extends readonly TSchema[]> = UnionToIntersect<StaticUnion<T>>;
254
+ export declare type StaticIntersect<T extends readonly TSchema[]> = StaticIntersectReduce<unknown, StaticIntersectEvaluate<T>>;
215
255
  export declare type StaticUnion<T extends readonly TSchema[]> = {
216
- [K in keyof T]: Static<T[K]>;
256
+ [K in keyof T]: T[K] extends TSchema ? Static<T[K]> : never;
217
257
  }[number];
218
258
  export declare type StaticTuple<T extends readonly TSchema[]> = {
219
- [K in keyof T]: Static<T[K]>;
259
+ [K in keyof T]: T[K] extends TSchema ? Static<T[K]> : never;
220
260
  };
221
- export declare type StaticObject<T extends TProperties> = StaticProperties<StaticProperties<T>>;
222
- export declare type StaticRecord<K extends TRecordKey, T extends TSchema> = K extends TString ? Record<string, Static<T>> : K extends TNumber ? Record<number, Static<T>> : K extends TKeyOf<any> ? Record<K['_infer'], Static<T>> : K extends TUnion<any> ? Record<K['_infer'], Static<T>> : never;
261
+ export declare type StaticObject<T extends TProperties> = StaticProperties<T> extends infer I ? {
262
+ [K in keyof I]: I[K];
263
+ } : never;
223
264
  export declare type StaticArray<T extends TSchema> = Array<Static<T>>;
224
265
  export declare type StaticLiteral<T extends TValue> = T;
225
- export declare type StaticConstructor<T extends readonly TSchema[], U extends TSchema> = new (...args: [...{
226
- [K in keyof T]: Static<T[K]>;
227
- }]) => Static<U>;
228
- export declare type StaticFunction<T extends readonly TSchema[], U extends TSchema> = (...args: [...{
229
- [K in keyof T]: Static<T[K]>;
230
- }]) => Static<U>;
266
+ export declare type StaticParameters<T extends readonly TSchema[]> = {
267
+ [K in keyof T]: T[K] extends TSchema ? Static<T[K]> : never;
268
+ };
269
+ export declare type StaticConstructor<T extends readonly TSchema[], U extends TSchema> = new (...args: [...StaticParameters<T>]) => Static<U>;
270
+ export declare type StaticFunction<T extends readonly TSchema[], U extends TSchema> = (...args: [...StaticParameters<T>]) => Static<U>;
231
271
  export declare type StaticPromise<T extends TSchema> = Promise<Static<T>>;
232
- export declare type Static<T> = T extends TKeyOf<infer I> ? I : T extends TIntersect<infer I> ? I : T extends TUnion<infer I> ? I : T extends TTuple<infer I> ? I : T extends TObject<infer I> ? {
233
- [K in keyof I]: I[K];
234
- } : T extends TRecord<infer I> ? I : T extends TArray<infer I> ? I : T extends TEnum<infer I> ? I : T extends TLiteral<infer I> ? I : T extends TString ? T['_infer'] : T extends TNumber ? T['_infer'] : T extends TInteger ? T['_infer'] : T extends TBoolean ? T['_infer'] : T extends TNull ? T['_infer'] : T extends TUnknown ? T['_infer'] : T extends TAny ? T['_infer'] : T extends TConstructor<infer I> ? I : T extends TFunction<infer I> ? I : T extends TPromise<infer I> ? I : T extends TUndefined ? T['_infer'] : T extends TVoid ? T['_infer'] : never;
272
+ export declare type Static<T extends TSchema> = T['$static'];
235
273
  export declare class TypeBuilder {
236
- /** `standard` Modifies an object property to be both readonly and optional */
274
+ private readonly schemas;
275
+ /** `Standard` Modifies an object property to be both readonly and optional */
237
276
  ReadonlyOptional<T extends TSchema>(item: T): TReadonlyOptional<T>;
238
- /** `standard` Modifies an object property to be readonly */
277
+ /** `Standard` Modifies an object property to be readonly */
239
278
  Readonly<T extends TSchema>(item: T): TReadonly<T>;
240
- /** `standard` Modifies an object property to be optional */
279
+ /** `Standard` Modifies an object property to be optional */
241
280
  Optional<T extends TSchema>(item: T): TOptional<T>;
242
- /** `standard` Creates a type type */
243
- Tuple<T extends TSchema[]>(items: [...T], options?: CustomOptions): TTuple<StaticTuple<T>>;
244
- /** `standard` Creates an object type with the given properties */
245
- Object<T extends TProperties>(properties: T, options?: ObjectOptions): TObject<StaticProperties<T>>;
246
- /** `standard` Creates an intersection type. Note this function requires draft `2019-09` to constrain with `unevaluatedProperties` */
247
- Intersect<T extends TSchema[]>(items: [...T], options?: IntersectOptions): TIntersect<StaticIntersect<T>>;
248
- /** `standard` Creates a union type */
249
- Union<T extends TSchema[]>(items: [...T], options?: CustomOptions): TUnion<StaticUnion<T>>;
250
- /** `standard` Creates an array type */
251
- Array<T extends TSchema>(items: T, options?: ArrayOptions): TArray<StaticArray<T>>;
252
- /** `standard` Creates an enum type from a TypeScript enum */
253
- Enum<T extends TEnumType>(item: T, options?: CustomOptions): TEnum<StaticEnum<TEnumKey<T[keyof T]>[]>>;
254
- /** `standard` Creates a literal type. Supports string, number and boolean values only */
255
- Literal<T extends TValue>(value: T, options?: CustomOptions): TLiteral<StaticLiteral<T>>;
256
- /** `standard` Creates a string type */
281
+ /** `Standard` Creates a type type */
282
+ Tuple<T extends TSchema[]>(items: [...T], options?: CustomOptions): TTuple<T>;
283
+ /** `Standard` Creates an object type with the given properties */
284
+ Object<T extends TProperties>(properties: T, options?: ObjectOptions): TObject<T>;
285
+ /** `Standard` Creates an intersect type. */
286
+ Intersect<T extends TSchema[]>(items: [...T], options?: IntersectOptions): TIntersect<T>;
287
+ /** `Standard` Creates a union type */
288
+ Union<T extends TSchema[]>(items: [...T], options?: CustomOptions): TUnion<T>;
289
+ /** `Standard` Creates an array type */
290
+ Array<T extends TSchema>(items: T, options?: ArrayOptions): TArray<T>;
291
+ /** `Standard` Creates an enum type from a TypeScript enum */
292
+ Enum<T extends TEnumType>(item: T, options?: CustomOptions): TEnum<TEnumKey<T[keyof T]>[]>;
293
+ /** `Standard` Creates a literal type. Supports string, number and boolean values only */
294
+ Literal<T extends TValue>(value: T, options?: CustomOptions): TLiteral<T>;
295
+ /** `Standard` Creates a string type */
257
296
  String<TCustomFormatOption extends string>(options?: StringOptions<StringFormatOption | TCustomFormatOption>): TString;
258
- /** `standard` Creates a string type from a regular expression */
297
+ /** `Standard` Creates a string type from a regular expression */
259
298
  RegEx(regex: RegExp, options?: CustomOptions): TString;
260
- /** `standard` Creates a number type */
299
+ /** `Standard` Creates a number type */
261
300
  Number(options?: NumberOptions): TNumber;
262
- /** `standard` Creates an integer type */
301
+ /** `Standard` Creates an integer type */
263
302
  Integer(options?: NumberOptions): TInteger;
264
- /** `standard` Creates a boolean type */
303
+ /** `Standard` Creates a boolean type */
265
304
  Boolean(options?: CustomOptions): TBoolean;
266
- /** `standard` Creates a null type */
305
+ /** `Standard` Creates a null type */
267
306
  Null(options?: CustomOptions): TNull;
268
- /** `standard` Creates an unknown type */
307
+ /** `Standard` Creates an unknown type */
269
308
  Unknown(options?: CustomOptions): TUnknown;
270
- /** `standard` Creates an any type */
309
+ /** `Standard` Creates an any type */
271
310
  Any(options?: CustomOptions): TAny;
272
- /** `standard` Creates a keyof type from the given object */
273
- KeyOf<T extends TObject<any>>(schema: T, options?: CustomOptions): TKeyOf<keyof T['_infer']>;
274
- /** `standard` Creates a record type */
275
- Record<K extends TRecordKey, T extends TSchema>(key: K, value: T, options?: ObjectOptions): TRecord<StaticRecord<K, T>>;
276
- /** `standard` Makes all properties in the given object type required */
277
- Required<T extends TObject<any>>(schema: T, options?: ObjectOptions): TObject<Required<T['_infer']>>;
278
- /** `standard` Makes all properties in the given object type optional */
279
- Partial<T extends TObject<any>>(schema: T, options?: ObjectOptions): TObject<Partial<T['_infer']>>;
280
- /** `standard` Picks property keys from the given object type */
281
- Pick<T extends TObject<any>, K extends (keyof T['_infer'])[]>(schema: T, keys: [...K], options?: ObjectOptions): TObject<Pick<T['_infer'], K[number]>>;
282
- /** `standard` Omits property keys from the given object type */
283
- Omit<T extends TObject<any>, K extends (keyof T['_infer'])[]>(schema: T, keys: [...K], options?: ObjectOptions): TObject<Omit<T['_infer'], K[number]>>;
284
- /** `standard` Omits the `kind` and `modifier` properties from the underlying schema */
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
+ /** `Standard` Creates a record type */
314
+ Record<K extends TRecordKey, T extends TSchema>(key: K, value: T, options?: ObjectOptions): TRecord<K, T>;
315
+ /** `Standard` Makes all properties in the given object type required */
316
+ Required<T extends TObject<TProperties> | TRef<TObject<TProperties>>>(object: T, options?: ObjectOptions): TObject<StaticRequired<T['properties']>>;
317
+ /** `Standard` Makes all properties in the given object type optional */
318
+ Partial<T extends TObject<TProperties> | TRef<TObject<TProperties>>>(object: T, options?: ObjectOptions): TObject<StaticPartial<T['properties']>>;
319
+ /** `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]>>;
321
+ /** `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]>>;
323
+ /** `Standard` Omits the `kind` and `modifier` properties from the underlying schema */
285
324
  Strict<T extends TSchema>(schema: T, options?: CustomOptions): T;
286
- /** `extended` Creates a constructor type */
287
- Constructor<T extends TSchema[], U extends TSchema>(args: [...T], returns: U, options?: CustomOptions): TConstructor<StaticConstructor<T, U>>;
288
- /** `extended` Creates a function type */
289
- Function<T extends TSchema[], U extends TSchema>(args: [...T], returns: U, options?: CustomOptions): TFunction<StaticFunction<T, U>>;
290
- /** `extended` Creates a promise type */
291
- Promise<T extends TSchema>(item: T, options?: CustomOptions): TPromise<StaticPromise<T>>;
292
- /** `extended` Creates a undefined type */
325
+ /** `Extended` Creates a constructor type */
326
+ Constructor<T extends TSchema[], U extends TSchema>(args: [...T], returns: U, options?: CustomOptions): TConstructor<T, U>;
327
+ /** `Extended` Creates a function type */
328
+ Function<T extends TSchema[], U extends TSchema>(args: [...T], returns: U, options?: CustomOptions): TFunction<T, U>;
329
+ /** `Extended` Creates a promise type */
330
+ Promise<T extends TSchema>(item: T, options?: CustomOptions): TPromise<T>;
331
+ /** `Extended` Creates a undefined type */
293
332
  Undefined(options?: CustomOptions): TUndefined;
294
- /** `extended` Creates a void type */
333
+ /** `Extended` Creates a void type */
295
334
  Void(options?: CustomOptions): TVoid;
296
- /** `experimental` Creates a recursive type */
335
+ /** `Standard` Creates a namespace for a set of related types */
336
+ Namespace<T extends TDefinitions>($defs: T, options?: CustomOptions): TNamespace<T>;
337
+ /** `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]>;
339
+ /** `Standard` References type. The referenced type must specify an `$id` */
340
+ Ref<T extends TSchema>(schema: T): TRef<T>;
341
+ /** `Experimental` Creates a recursive type */
297
342
  Rec<T extends TSchema>(callback: (self: TAny) => T, options?: CustomOptions): T;
298
- /** `experimental` Creates a recursive type. Pending https://github.com/ajv-validator/ajv/issues/1709 */
299
- /** `experimental` Creates a namespace for a set of related types */
300
- Namespace<T extends TDefinitions>(definitions: T, options?: CustomOptions): TNamespace<T>;
301
- /** `experimental` References a type within a namespace. The referenced namespace must specify an `$id` */
302
- Ref<T extends TNamespace<TDefinitions>, K extends keyof T['definitions']>(box: T, key: K): T['definitions'][K];
303
- /** `experimental` References type. The referenced type must specify an `$id` */
304
- Ref<T extends TSchema>(schema: T): 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;
305
347
  }
306
348
  export declare const Type: TypeBuilder;
package/typebox.js CHANGED
@@ -27,16 +27,16 @@ 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.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;
31
- // ------------------------------------------------------------------------
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;
31
+ // --------------------------------------------------------------------------
32
32
  // Modifiers
33
- // ------------------------------------------------------------------------
33
+ // --------------------------------------------------------------------------
34
34
  exports.ReadonlyOptionalModifier = Symbol('ReadonlyOptionalModifier');
35
35
  exports.OptionalModifier = Symbol('OptionalModifier');
36
36
  exports.ReadonlyModifier = Symbol('ReadonlyModifier');
37
- // ------------------------------------------------------------------------
37
+ // --------------------------------------------------------------------------
38
38
  // Schema Standard
39
- // ------------------------------------------------------------------------
39
+ // --------------------------------------------------------------------------
40
40
  exports.BoxKind = Symbol('BoxKind');
41
41
  exports.KeyOfKind = Symbol('KeyOfKind');
42
42
  exports.IntersectKind = Symbol('IntersectKind');
@@ -54,17 +54,18 @@ exports.BooleanKind = Symbol('BooleanKind');
54
54
  exports.NullKind = Symbol('NullKind');
55
55
  exports.UnknownKind = Symbol('UnknownKind');
56
56
  exports.AnyKind = Symbol('AnyKind');
57
- // ------------------------------------------------------------------------
57
+ exports.RefKind = Symbol('RefKind');
58
+ // --------------------------------------------------------------------------
58
59
  // Extended Schema Types
59
- // ------------------------------------------------------------------------
60
+ // --------------------------------------------------------------------------
60
61
  exports.ConstructorKind = Symbol('ConstructorKind');
61
62
  exports.FunctionKind = Symbol('FunctionKind');
62
63
  exports.PromiseKind = Symbol('PromiseKind');
63
64
  exports.UndefinedKind = Symbol('UndefinedKind');
64
65
  exports.VoidKind = Symbol('VoidKind');
65
- // ------------------------------------------------------------------------
66
+ // --------------------------------------------------------------------------
66
67
  // Utility
67
- // ------------------------------------------------------------------------
68
+ // --------------------------------------------------------------------------
68
69
  function isObject(object) {
69
70
  return typeof object === 'object' && object !== null && !Array.isArray(object);
70
71
  }
@@ -78,32 +79,34 @@ function clone(object) {
78
79
  return object.map((item) => clone(item));
79
80
  return object;
80
81
  }
81
- // ------------------------------------------------------------------------
82
+ // --------------------------------------------------------------------------
82
83
  // TypeBuilder
83
- // ------------------------------------------------------------------------
84
+ // --------------------------------------------------------------------------
84
85
  class TypeBuilder {
85
- /** `standard` Modifies an object property to be both readonly and optional */
86
+ schemas = new Map();
87
+ /** `Standard` Modifies an object property to be both readonly and optional */
86
88
  ReadonlyOptional(item) {
87
89
  return { ...item, modifier: exports.ReadonlyOptionalModifier };
88
90
  }
89
- /** `standard` Modifies an object property to be readonly */
91
+ /** `Standard` Modifies an object property to be readonly */
90
92
  Readonly(item) {
91
93
  return { ...item, modifier: exports.ReadonlyModifier };
92
94
  }
93
- /** `standard` Modifies an object property to be optional */
95
+ /** `Standard` Modifies an object property to be optional */
94
96
  Optional(item) {
95
97
  return { ...item, modifier: exports.OptionalModifier };
96
98
  }
97
- /** `standard` Creates a type type */
99
+ /** `Standard` Creates a type type */
98
100
  Tuple(items, options = {}) {
99
101
  const additionalItems = false;
100
102
  const minItems = items.length;
101
103
  const maxItems = items.length;
102
- return (items.length > 0)
104
+ const schema = ((items.length > 0)
103
105
  ? { ...options, kind: exports.TupleKind, type: 'array', items, additionalItems, minItems, maxItems }
104
- : { ...options, kind: exports.TupleKind, type: 'array', minItems, maxItems };
106
+ : { ...options, kind: exports.TupleKind, type: 'array', minItems, maxItems });
107
+ return this.Store(schema);
105
108
  }
106
- /** `standard` Creates an object type with the given properties */
109
+ /** `Standard` Creates an object type with the given properties */
107
110
  Object(properties, options = {}) {
108
111
  const property_names = Object.keys(properties);
109
112
  const optional = property_names.filter(name => {
@@ -114,88 +117,89 @@ class TypeBuilder {
114
117
  });
115
118
  const required_names = property_names.filter(name => !optional.includes(name));
116
119
  const required = (required_names.length > 0) ? required_names : undefined;
117
- return (required) ?
118
- { ...options, kind: exports.ObjectKind, type: 'object', properties, required } :
119
- { ...options, kind: exports.ObjectKind, type: 'object', properties };
120
+ return this.Store(((required)
121
+ ? { ...options, kind: exports.ObjectKind, type: 'object', properties, required }
122
+ : { ...options, kind: exports.ObjectKind, type: 'object', properties }));
120
123
  }
121
- /** `standard` Creates an intersection type. Note this function requires draft `2019-09` to constrain with `unevaluatedProperties` */
124
+ /** `Standard` Creates an intersect type. */
122
125
  Intersect(items, options = {}) {
123
- return { ...options, kind: exports.IntersectKind, type: 'object', allOf: items };
126
+ return this.Store({ ...options, kind: exports.IntersectKind, type: 'object', allOf: items });
124
127
  }
125
- /** `standard` Creates a union type */
128
+ /** `Standard` Creates a union type */
126
129
  Union(items, options = {}) {
127
- return { ...options, kind: exports.UnionKind, anyOf: items };
130
+ return this.Store({ ...options, kind: exports.UnionKind, anyOf: items });
128
131
  }
129
- /** `standard` Creates an array type */
132
+ /** `Standard` Creates an array type */
130
133
  Array(items, options = {}) {
131
- return { ...options, kind: exports.ArrayKind, type: 'array', items };
134
+ return this.Store({ ...options, kind: exports.ArrayKind, type: 'array', items });
132
135
  }
133
- /** `standard` Creates an enum type from a TypeScript enum */
136
+ /** `Standard` Creates an enum type from a TypeScript enum */
134
137
  Enum(item, options = {}) {
135
138
  const values = Object.keys(item).filter(key => isNaN(key)).map(key => item[key]);
136
139
  const anyOf = values.map(value => typeof value === 'string' ? { type: 'string', const: value } : { type: 'number', const: value });
137
- return { ...options, kind: exports.EnumKind, anyOf };
140
+ return this.Store({ ...options, kind: exports.EnumKind, anyOf });
138
141
  }
139
- /** `standard` Creates a literal type. Supports string, number and boolean values only */
142
+ /** `Standard` Creates a literal type. Supports string, number and boolean values only */
140
143
  Literal(value, options = {}) {
141
- return { ...options, kind: exports.LiteralKind, const: value, type: typeof value };
144
+ return this.Store({ ...options, kind: exports.LiteralKind, const: value, type: typeof value });
142
145
  }
143
- /** `standard` Creates a string type */
146
+ /** `Standard` Creates a string type */
144
147
  String(options = {}) {
145
- return { ...options, kind: exports.StringKind, type: 'string' };
148
+ return this.Store({ ...options, kind: exports.StringKind, type: 'string' });
146
149
  }
147
- /** `standard` Creates a string type from a regular expression */
150
+ /** `Standard` Creates a string type from a regular expression */
148
151
  RegEx(regex, options = {}) {
149
152
  return this.String({ ...options, pattern: regex.source });
150
153
  }
151
- /** `standard` Creates a number type */
154
+ /** `Standard` Creates a number type */
152
155
  Number(options = {}) {
153
- return { ...options, kind: exports.NumberKind, type: 'number' };
156
+ return this.Store({ ...options, kind: exports.NumberKind, type: 'number' });
154
157
  }
155
- /** `standard` Creates an integer type */
158
+ /** `Standard` Creates an integer type */
156
159
  Integer(options = {}) {
157
- return { ...options, kind: exports.IntegerKind, type: 'integer' };
160
+ return this.Store({ ...options, kind: exports.IntegerKind, type: 'integer' });
158
161
  }
159
- /** `standard` Creates a boolean type */
162
+ /** `Standard` Creates a boolean type */
160
163
  Boolean(options = {}) {
161
- return { ...options, kind: exports.BooleanKind, type: 'boolean' };
164
+ return this.Store({ ...options, kind: exports.BooleanKind, type: 'boolean' });
162
165
  }
163
- /** `standard` Creates a null type */
166
+ /** `Standard` Creates a null type */
164
167
  Null(options = {}) {
165
- return { ...options, kind: exports.NullKind, type: 'null' };
168
+ return this.Store({ ...options, kind: exports.NullKind, type: 'null' });
166
169
  }
167
- /** `standard` Creates an unknown type */
170
+ /** `Standard` Creates an unknown type */
168
171
  Unknown(options = {}) {
169
- return { ...options, kind: exports.UnknownKind };
172
+ return this.Store({ ...options, kind: exports.UnknownKind });
170
173
  }
171
- /** `standard` Creates an any type */
174
+ /** `Standard` Creates an any type */
172
175
  Any(options = {}) {
173
- return { ...options, kind: exports.AnyKind };
176
+ return this.Store({ ...options, kind: exports.AnyKind });
174
177
  }
175
- /** `standard` Creates a keyof type from the given object */
176
- KeyOf(schema, options = {}) {
177
- const keys = Object.keys(schema.properties);
178
- return { ...options, kind: exports.KeyOfKind, type: 'string', enum: keys };
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 });
179
182
  }
180
- /** `standard` Creates a record type */
183
+ /** `Standard` Creates a record type */
181
184
  Record(key, value, options = {}) {
182
185
  const pattern = (() => {
183
186
  switch (key.kind) {
184
- case exports.UnionKind: return `^${key.anyOf.map(literal => literal.const).join('|')}$`;
187
+ case exports.UnionKind: return `^${key.anyOf.map((literal) => literal.const).join('|')}$`;
185
188
  case exports.KeyOfKind: return `^${key.enum.join('|')}$`;
186
189
  case exports.NumberKind: return '^(0|[1-9][0-9]*)$';
187
190
  case exports.StringKind: return key.pattern ? key.pattern : '^.*$';
188
191
  default: throw Error('Invalid Record Key');
189
192
  }
190
193
  })();
191
- return { ...options, kind: exports.RecordKind, type: 'object', patternProperties: { [pattern]: value } };
192
- }
193
- /** `standard` Makes all properties in the given object type required */
194
- Required(schema, options = {}) {
195
- const next = { ...clone(schema), ...options };
196
- next.required = Object.keys(next.properties);
197
- for (const key of Object.keys(next.properties)) {
198
- const property = next.properties[key];
194
+ return this.Store({ ...options, kind: exports.RecordKind, type: 'object', patternProperties: { [pattern]: value } });
195
+ }
196
+ /** `Standard` Makes all properties in the given object type required */
197
+ Required(object, options = {}) {
198
+ const source = this.Resolve(object);
199
+ const schema = { ...clone(source), ...options };
200
+ schema.required = Object.keys(schema.properties);
201
+ for (const key of Object.keys(schema.properties)) {
202
+ const property = schema.properties[key];
199
203
  switch (property.modifier) {
200
204
  case exports.ReadonlyOptionalModifier:
201
205
  property.modifier = exports.ReadonlyModifier;
@@ -211,14 +215,15 @@ class TypeBuilder {
211
215
  break;
212
216
  }
213
217
  }
214
- return next;
215
- }
216
- /** `standard` Makes all properties in the given object type optional */
217
- Partial(schema, options = {}) {
218
- const next = { ...clone(schema), ...options };
219
- delete next.required;
220
- for (const key of Object.keys(next.properties)) {
221
- const property = next.properties[key];
218
+ return this.Store(schema);
219
+ }
220
+ /** `Standard` Makes all properties in the given object type optional */
221
+ Partial(object, options = {}) {
222
+ const source = this.Resolve(object);
223
+ const schema = { ...clone(source), ...options };
224
+ delete schema.required;
225
+ for (const key of Object.keys(schema.properties)) {
226
+ const property = schema.properties[key];
222
227
  switch (property.modifier) {
223
228
  case exports.ReadonlyOptionalModifier:
224
229
  property.modifier = exports.ReadonlyOptionalModifier;
@@ -234,71 +239,100 @@ class TypeBuilder {
234
239
  break;
235
240
  }
236
241
  }
237
- return next;
238
- }
239
- /** `standard` Picks property keys from the given object type */
240
- Pick(schema, keys, options = {}) {
241
- const next = { ...clone(schema), ...options };
242
- next.required = next.required ? next.required.filter((key) => keys.includes(key)) : undefined;
243
- for (const key of Object.keys(next.properties)) {
242
+ return this.Store(schema);
243
+ }
244
+ /** `Standard` Picks property keys from the given object type */
245
+ Pick(object, keys, options = {}) {
246
+ const source = this.Resolve(object);
247
+ const schema = { ...clone(source), ...options };
248
+ schema.required = schema.required ? schema.required.filter((key) => keys.includes(key)) : undefined;
249
+ for (const key of Object.keys(schema.properties)) {
244
250
  if (!keys.includes(key))
245
- delete next.properties[key];
251
+ delete schema.properties[key];
246
252
  }
247
- return next;
248
- }
249
- /** `standard` Omits property keys from the given object type */
250
- Omit(schema, keys, options = {}) {
251
- const next = { ...clone(schema), ...options };
252
- next.required = next.required ? next.required.filter((key) => !keys.includes(key)) : undefined;
253
- for (const key of Object.keys(next.properties)) {
253
+ return this.Store(schema);
254
+ }
255
+ /** `Standard` Omits property keys from the given object type */
256
+ Omit(object, keys, options = {}) {
257
+ const source = this.Resolve(object);
258
+ const schema = { ...clone(source), ...options };
259
+ schema.required = schema.required ? schema.required.filter((key) => !keys.includes(key)) : undefined;
260
+ for (const key of Object.keys(schema.properties)) {
254
261
  if (keys.includes(key))
255
- delete next.properties[key];
262
+ delete schema.properties[key];
256
263
  }
257
- return next;
264
+ return this.Store(schema);
258
265
  }
259
- /** `standard` Omits the `kind` and `modifier` properties from the underlying schema */
266
+ /** `Standard` Omits the `kind` and `modifier` properties from the underlying schema */
260
267
  Strict(schema, options = {}) {
261
268
  return JSON.parse(JSON.stringify({ ...options, ...schema }));
262
269
  }
263
- /** `extended` Creates a constructor type */
270
+ /** `Extended` Creates a constructor type */
264
271
  Constructor(args, returns, options = {}) {
265
- return { ...options, kind: exports.ConstructorKind, type: 'constructor', arguments: args, returns };
272
+ return this.Store({ ...options, kind: exports.ConstructorKind, type: 'constructor', arguments: args, returns });
266
273
  }
267
- /** `extended` Creates a function type */
274
+ /** `Extended` Creates a function type */
268
275
  Function(args, returns, options = {}) {
269
- return { ...options, kind: exports.FunctionKind, type: 'function', arguments: args, returns };
276
+ return this.Store({ ...options, kind: exports.FunctionKind, type: 'function', arguments: args, returns });
270
277
  }
271
- /** `extended` Creates a promise type */
278
+ /** `Extended` Creates a promise type */
272
279
  Promise(item, options = {}) {
273
- return { ...options, type: 'promise', kind: exports.PromiseKind, item };
280
+ return this.Store({ ...options, type: 'promise', kind: exports.PromiseKind, item });
274
281
  }
275
- /** `extended` Creates a undefined type */
282
+ /** `Extended` Creates a undefined type */
276
283
  Undefined(options = {}) {
277
- return { ...options, type: 'undefined', kind: exports.UndefinedKind };
284
+ return this.Store({ ...options, type: 'undefined', kind: exports.UndefinedKind });
278
285
  }
279
- /** `extended` Creates a void type */
286
+ /** `Extended` Creates a void type */
280
287
  Void(options = {}) {
281
- return { ...options, type: 'void', kind: exports.VoidKind };
288
+ return this.Store({ ...options, type: 'void', kind: exports.VoidKind });
282
289
  }
283
- /** `experimental` Creates a recursive type */
284
- Rec(callback, options = {}) {
285
- const $id = options.$id || '';
286
- const self = callback({ $ref: `${$id}#/definitions/self` });
287
- return { ...options, $ref: `${$id}#/definitions/self`, definitions: { self } };
288
- }
289
- /** `experimental` Creates a recursive type. Pending https://github.com/ajv-validator/ajv/issues/1709 */
290
- // public Rec<T extends TProperties>($id: string, callback: (self: TAny) => T, options: ObjectOptions = {}): TObject<T> {
291
- // const properties = callback({ $recursiveRef: `${$id}` } as any)
292
- // return { ...options, kind: ObjectKind, $id, $recursiveAnchor: true, type: 'object', properties }
293
- // }
294
- /** `experimental` Creates a namespace for a set of related types */
295
- Namespace(definitions, options = {}) {
296
- return { ...options, kind: exports.BoxKind, definitions };
290
+ /** `Standard` Creates a namespace for a set of related types */
291
+ Namespace($defs, options = {}) {
292
+ return this.Store({ ...options, kind: exports.BoxKind, $defs });
297
293
  }
298
294
  Ref(...args) {
299
- const $id = args[0]['$id'] || '';
300
- const key = args[1];
301
- return (args.length === 2) ? { $ref: `${$id}#/definitions/${key}` } : { $ref: $id };
295
+ if (args.length === 2) {
296
+ const namespace = args[0];
297
+ const targetKey = args[1];
298
+ if (namespace.$id === undefined)
299
+ throw new Error(`Referenced namespace has no $id`);
300
+ if (!this.schemas.has(namespace.$id))
301
+ throw new Error(`Unable to locate namespace with $id '${namespace.$id}'`);
302
+ return this.Store({ kind: exports.RefKind, $ref: `${namespace.$id}#/$defs/${targetKey}` });
303
+ }
304
+ else if (args.length === 1) {
305
+ const target = args[0];
306
+ if (target.$id === undefined)
307
+ throw new Error(`Referenced schema has no $id`);
308
+ if (!this.schemas.has(target.$id))
309
+ throw new Error(`Unable to locate schema with $id '${target.$id}'`);
310
+ return this.Store({ kind: exports.RefKind, $ref: target.$id });
311
+ }
312
+ else {
313
+ throw new Error('Type.Ref: Invalid arguments');
314
+ }
315
+ }
316
+ /** `Experimental` Creates a recursive type */
317
+ Rec(callback, options = {}) {
318
+ const $id = options.$id || '';
319
+ const self = callback({ $ref: `${$id}#/$defs/self` });
320
+ return this.Store({ ...options, $ref: `${$id}#/$defs/self`, $defs: { self } });
321
+ }
322
+ /** Stores this schema if it contains an $id. This function is used for later referencing. */
323
+ 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)
332
+ 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));
302
336
  }
303
337
  }
304
338
  exports.TypeBuilder = TypeBuilder;