@naturalcycles/js-lib 15.35.0 → 15.37.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.
@@ -1,5 +1,5 @@
1
1
  import type { AnyObject, StringMap } from '../types.js';
2
- export type JsonSchema<T = unknown> = JsonSchemaAny<T> | JsonSchemaOneOf<T> | JsonSchemaAllOf<T> | JsonSchemaAnyOf<T> | JsonSchemaNot<T> | JsonSchemaRef<T> | JsonSchemaConst<T> | JsonSchemaEnum<T> | JsonSchemaString | JsonSchemaNumber | JsonSchemaBoolean | JsonSchemaNull | JsonSchemaObject | JsonSchemaArray<T> | JsonSchemaTuple<T>;
2
+ export type JsonSchema<T = unknown> = JsonSchemaAny<T> | JsonSchemaOneOf<T> | JsonSchemaAllOf<T> | JsonSchemaAnyOf<T> | JsonSchemaNot<T> | JsonSchemaRef<T> | JsonSchemaConst<T> | JsonSchemaEnum<T> | JsonSchemaString | JsonSchemaNumber | JsonSchemaBoolean | JsonSchemaNull | JsonSchemaObject<T extends AnyObject ? T : AnyObject> | JsonSchemaArray<T> | JsonSchemaTuple<T>;
3
3
  export interface JsonSchemaAny<T = unknown> {
4
4
  $schema?: string;
5
5
  $id?: string;
@@ -8,7 +8,7 @@ export interface JsonSchemaAny<T = unknown> {
8
8
  deprecated?: boolean;
9
9
  readOnly?: boolean;
10
10
  writeOnly?: boolean;
11
- type?: string;
11
+ type?: string | string[];
12
12
  default?: T;
13
13
  if?: JsonSchema;
14
14
  then?: JsonSchema;
@@ -1,4 +1,4 @@
1
- import type { AnyObject, BaseDBEntity, IsoDate, IsoDateTime, UnixTimestamp } from '../types.js';
1
+ import { type AnyObject, type BaseDBEntity, type IsoDate, type IsoDateTime, type UnixTimestamp } from '../types.js';
2
2
  import type { JsonSchema, JsonSchemaAllOf, JsonSchemaAny, JsonSchemaArray, JsonSchemaBoolean, JsonSchemaConst, JsonSchemaEnum, JsonSchemaNull, JsonSchemaNumber, JsonSchemaObject, JsonSchemaOneOf, JsonSchemaRef, JsonSchemaString, JsonSchemaTuple } from './jsonSchema.model.js';
3
3
  export interface JsonSchemaBuilder<T = unknown> {
4
4
  build: () => JsonSchema<T>;
@@ -8,36 +8,37 @@ export interface JsonSchemaBuilder<T = unknown> {
8
8
  * Inspired by Joi and Zod.
9
9
  */
10
10
  export declare const j: {
11
- any<T = unknown>(): JsonSchemaAnyBuilder<T, JsonSchemaAny<T>>;
12
- const<T = unknown>(value: T): JsonSchemaAnyBuilder<T, JsonSchemaConst<T>>;
13
- null(): JsonSchemaAnyBuilder<null, JsonSchemaNull>;
14
- ref<T = unknown>($ref: string): JsonSchemaAnyBuilder<T, JsonSchemaRef<T>>;
15
- enum<T = unknown>(enumValues: T[]): JsonSchemaAnyBuilder<T, JsonSchemaEnum<T>>;
16
- boolean(): JsonSchemaAnyBuilder<boolean, JsonSchemaBoolean>;
17
- buffer(): JsonSchemaAnyBuilder<Buffer<ArrayBufferLike>, JsonSchemaAny<Buffer<ArrayBufferLike>>>;
18
- number<T extends number = number>(): JsonSchemaNumberBuilder<T>;
19
- integer<T extends number = number>(): JsonSchemaNumberBuilder<T>;
20
- unixTimestamp(): JsonSchemaNumberBuilder<UnixTimestamp>;
21
- unixTimestamp2000(): JsonSchemaNumberBuilder<UnixTimestamp>;
22
- string<T extends string = string>(): JsonSchemaStringBuilder<T>;
11
+ any<T = unknown>(): JsonSchemaAnyBuilder<T, JsonSchemaAny<T>, false>;
12
+ const<T extends string | number | boolean | null>(value: T): JsonSchemaAnyBuilder<T, JsonSchemaConst<T>, false>;
13
+ null(): JsonSchemaAnyBuilder<null, JsonSchemaNull, false>;
14
+ ref<T = unknown>($ref: string): JsonSchemaAnyBuilder<T, JsonSchemaRef<T>, false>;
15
+ enum<T = unknown>(enumValues: T[]): JsonSchemaAnyBuilder<T, JsonSchemaEnum<T>, false>;
16
+ boolean(): JsonSchemaAnyBuilder<boolean, JsonSchemaBoolean, false>;
17
+ buffer(): JsonSchemaAnyBuilder<Buffer<ArrayBufferLike>, JsonSchemaAny<Buffer<ArrayBufferLike>>, false>;
18
+ number<T extends number = number>(): JsonSchemaNumberBuilder<T, false>;
19
+ integer<T extends number = number>(): JsonSchemaNumberBuilder<T, false>;
20
+ unixTimestamp(): JsonSchemaNumberBuilder<UnixTimestamp, false>;
21
+ unixTimestamp2000(): JsonSchemaNumberBuilder<UnixTimestamp, false>;
22
+ string<T extends string = string>(): JsonSchemaStringBuilder<T, false>;
23
+ jwt(): JsonSchemaStringBuilder<string, false>;
23
24
  /**
24
25
  * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
25
26
  */
26
- isoDate(): JsonSchemaStringBuilder<IsoDate>;
27
+ isoDate(): JsonSchemaStringBuilder<IsoDate, false>;
27
28
  /**
28
29
  * Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
29
30
  * and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
30
31
  */
31
- isoDateTime(): JsonSchemaStringBuilder<IsoDateTime>;
32
+ isoDateTime(): JsonSchemaStringBuilder<IsoDateTime, false>;
32
33
  object: typeof object;
33
- dbEntity<T extends AnyObject>(props: T): JsonSchemaObjectBuilder<BaseDBEntity & { [K in keyof T]: T[K] extends JsonSchemaAnyBuilder<infer U, any> ? U : never; }>;
34
- rootObject<T extends AnyObject>(props: { [K in keyof T]: JsonSchemaAnyBuilder<T[K]>; }): JsonSchemaObjectBuilder<T>;
35
- array<T extends JsonSchemaAnyBuilder<any>>(itemSchema: T): JsonSchemaArrayBuilder<T["infer"]>;
34
+ dbEntity<T extends AnyObject>(props: T): JsonSchemaObjectBuilder<BaseDBEntity & ({ [K in keyof T as T[K] extends JsonSchemaAnyBuilder<any, any, infer Opt extends boolean> ? Opt extends true ? never : K : never]: T[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never; } & { [K_1 in keyof T as T[K_1] extends JsonSchemaAnyBuilder<any, any, infer Opt extends boolean> ? Opt extends true ? K_1 : never : never]?: (T[K_1] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never) | undefined; } extends infer O ? { [K_2 in keyof O]: O[K_2]; } : never) extends infer O_1 ? { [K_3 in keyof O_1]: O_1[K_3]; } : never, false>;
35
+ rootObject<T extends AnyObject>(props: { [K in keyof T]: JsonSchemaAnyBuilder<T[K]>; }): JsonSchemaObjectBuilder<T, false>;
36
+ array<T extends JsonSchemaAnyBuilder<any>>(itemSchema: T): JsonSchemaArrayBuilder<T["infer"], false>;
36
37
  tuple<T extends any[] = unknown[]>(items: JsonSchemaAnyBuilder[]): JsonSchemaTupleBuilder<T>;
37
- oneOf<T = unknown>(items: JsonSchemaAnyBuilder[]): JsonSchemaAnyBuilder<T, JsonSchemaOneOf<T>>;
38
- allOf<T = unknown>(items: JsonSchemaAnyBuilder[]): JsonSchemaAnyBuilder<T, JsonSchemaAllOf<T>>;
38
+ oneOf<Builders extends JsonSchemaAnyBuilder<any, any, any>[]>(items: [...Builders]): JsonSchemaAnyBuilder<Builders[number] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never, JsonSchemaOneOf<Builders[number] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never>>;
39
+ allOf<T = unknown>(items: JsonSchemaAnyBuilder[]): JsonSchemaAnyBuilder<T, JsonSchemaAllOf<T>, false>;
39
40
  };
40
- export declare class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonSchema<T> = JsonSchema<T>> implements JsonSchemaBuilder<T> {
41
+ export declare class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonSchema<T> = JsonSchema<T>, Opt extends boolean = false> implements JsonSchemaBuilder<T> {
41
42
  protected schema: SCHEMA_TYPE;
42
43
  constructor(schema: SCHEMA_TYPE);
43
44
  /**
@@ -52,24 +53,23 @@ export declare class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonS
52
53
  deprecated(deprecated?: boolean): this;
53
54
  type(type: string): this;
54
55
  default(v: any): this;
55
- oneOf(schemas: JsonSchema[]): this;
56
- allOf(schemas: JsonSchema[]): this;
57
56
  instanceof(of: string): this;
58
- optional(): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>>;
59
- optional(optional: true): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>>;
60
- optional(optional: false): JsonSchemaAnyBuilder<Exclude<T, undefined>, JsonSchema<Exclude<T, undefined>>>;
57
+ optional(): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>, true>;
58
+ optional(optional: true): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>, true>;
59
+ optional(optional: false): JsonSchemaAnyBuilder<Exclude<T, undefined>, JsonSchema<Exclude<T, undefined>>, false>;
60
+ nullable(): JsonSchemaAnyBuilder<T | null, JsonSchema<T | null>, Opt>;
61
61
  /**
62
62
  * Produces a "clean schema object" without methods.
63
63
  * Same as if it would be JSON.stringified.
64
64
  */
65
65
  build(): SCHEMA_TYPE;
66
- clone(): JsonSchemaAnyBuilder<T, SCHEMA_TYPE>;
66
+ clone(): JsonSchemaAnyBuilder<T, SCHEMA_TYPE, Opt>;
67
67
  /**
68
68
  * @experimental
69
69
  */
70
70
  infer: T;
71
71
  }
72
- export declare class JsonSchemaNumberBuilder<T extends number = number> extends JsonSchemaAnyBuilder<T, JsonSchemaNumber<T>> {
72
+ export declare class JsonSchemaNumberBuilder<T extends number = number, Opt extends boolean = false> extends JsonSchemaAnyBuilder<T, JsonSchemaNumber<T>, Opt> {
73
73
  constructor();
74
74
  integer(): this;
75
75
  multipleOf(multipleOf: number): this;
@@ -94,7 +94,7 @@ export declare class JsonSchemaNumberBuilder<T extends number = number> extends
94
94
  utcOffsetHours: () => this;
95
95
  branded<B extends number>(): JsonSchemaNumberBuilder<B>;
96
96
  }
97
- export declare class JsonSchemaStringBuilder<T extends string = string> extends JsonSchemaAnyBuilder<T, JsonSchemaString<T>> {
97
+ export declare class JsonSchemaStringBuilder<T extends string = string, Opt extends boolean = false> extends JsonSchemaAnyBuilder<T, JsonSchemaString<T>, Opt> {
98
98
  constructor();
99
99
  regex(pattern: RegExp): this;
100
100
  pattern(pattern: string): this;
@@ -126,9 +126,10 @@ export declare class JsonSchemaStringBuilder<T extends string = string> extends
126
126
  * and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
127
127
  */
128
128
  isoDateTime(): JsonSchemaStringBuilder<IsoDateTime>;
129
+ jwt(): this;
129
130
  private transformModify;
130
131
  }
131
- export declare class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSchemaAnyBuilder<T, JsonSchemaObject<T>> {
132
+ export declare class JsonSchemaObjectBuilder<T extends AnyObject, Opt extends boolean = false> extends JsonSchemaAnyBuilder<T, JsonSchemaObject<T>, Opt> {
132
133
  constructor();
133
134
  addProperties(props: {
134
135
  [k in keyof T]: JsonSchemaBuilder<T[k]>;
@@ -142,9 +143,11 @@ export declare class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSc
142
143
  maxProps(maxProperties: number): this;
143
144
  additionalProps(additionalProperties: boolean): this;
144
145
  baseDBEntity(): JsonSchemaObjectBuilder<T & BaseDBEntity>;
145
- extend<T2 extends AnyObject>(s2: JsonSchemaObjectBuilder<T2>): JsonSchemaObjectBuilder<T & T2>;
146
+ extend<T2 extends AnyObject>(s2: JsonSchemaObjectBuilder<T2>): JsonSchemaObjectBuilder<T & T2 extends infer O ? {
147
+ [K in keyof O]: O[K];
148
+ } : never>;
146
149
  }
147
- export declare class JsonSchemaArrayBuilder<ITEM> extends JsonSchemaAnyBuilder<ITEM[], JsonSchemaArray<ITEM>> {
150
+ export declare class JsonSchemaArrayBuilder<ITEM, Opt extends boolean = false> extends JsonSchemaAnyBuilder<ITEM[], JsonSchemaArray<ITEM>, Opt> {
148
151
  constructor(itemsSchema: JsonSchemaBuilder<ITEM>);
149
152
  min(minItems: number): this;
150
153
  max(maxItems: number): this;
@@ -153,9 +156,13 @@ export declare class JsonSchemaArrayBuilder<ITEM> extends JsonSchemaAnyBuilder<I
153
156
  export declare class JsonSchemaTupleBuilder<T extends any[]> extends JsonSchemaAnyBuilder<T, JsonSchemaTuple<T>> {
154
157
  constructor(items: JsonSchemaBuilder[]);
155
158
  }
156
- declare function object<P extends Record<string, JsonSchemaAnyBuilder<any, any>>>(props: P): JsonSchemaObjectBuilder<{
157
- [K in keyof P]: P[K] extends JsonSchemaAnyBuilder<infer U, any> ? U : never;
158
- }>;
159
+ declare function object<P extends Record<string, JsonSchemaAnyBuilder<any, any, any>>>(props: P): JsonSchemaObjectBuilder<{
160
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer Opt> ? Opt extends true ? never : K : never]: P[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never;
161
+ } & {
162
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer Opt> ? Opt extends true ? K : never : never]?: P[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never;
163
+ } extends infer O ? {
164
+ [K in keyof O]: O[K];
165
+ } : never>;
159
166
  declare function object<T extends AnyObject>(props: {
160
167
  [K in keyof T]: JsonSchemaAnyBuilder<T[K]>;
161
168
  }): JsonSchemaObjectBuilder<T>;
@@ -1,6 +1,7 @@
1
1
  import { _uniq } from '../array/array.util.js';
2
2
  import { _deepCopy } from '../object/object.util.js';
3
3
  import { _sortObject } from '../object/sortObject.js';
4
+ import { JWT_REGEX, } from '../types.js';
4
5
  import { JSON_SCHEMA_ORDER } from './jsonSchema.cnst.js';
5
6
  import { mergeJsonSchemaObjects } from './jsonSchema.util.js';
6
7
  /**
@@ -56,6 +57,9 @@ export const j = {
56
57
  string() {
57
58
  return new JsonSchemaStringBuilder();
58
59
  },
60
+ jwt() {
61
+ return new JsonSchemaStringBuilder().jwt();
62
+ },
59
63
  /**
60
64
  * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
61
65
  */
@@ -144,14 +148,6 @@ export class JsonSchemaAnyBuilder {
144
148
  Object.assign(this.schema, { default: v });
145
149
  return this;
146
150
  }
147
- oneOf(schemas) {
148
- Object.assign(this.schema, { oneOf: schemas });
149
- return this;
150
- }
151
- allOf(schemas) {
152
- Object.assign(this.schema, { allOf: schemas });
153
- return this;
154
- }
155
151
  instanceof(of) {
156
152
  this.schema.instanceof = of;
157
153
  return this;
@@ -165,6 +161,11 @@ export class JsonSchemaAnyBuilder {
165
161
  }
166
162
  return this;
167
163
  }
164
+ nullable() {
165
+ return new JsonSchemaAnyBuilder({
166
+ anyOf: [this.build(), { type: 'null' }],
167
+ });
168
+ }
168
169
  /**
169
170
  * Produces a "clean schema object" without methods.
170
171
  * Same as if it would be JSON.stringified.
@@ -294,6 +295,9 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
294
295
  isoDateTime() {
295
296
  return this.format('IsoDateTime').branded().description('IsoDateTime');
296
297
  }
298
+ jwt() {
299
+ return this.regex(JWT_REGEX);
300
+ }
297
301
  transformModify(t, add) {
298
302
  if (add) {
299
303
  this.schema.transform = _uniq([...(this.schema.transform || []), t]);
@@ -1,2 +1,2 @@
1
1
  import type { BaseDBEntity } from '../types.js';
2
- export declare const baseDBEntityJsonSchema: import("./jsonSchemaBuilder.js").JsonSchemaObjectBuilder<BaseDBEntity>;
2
+ export declare const baseDBEntityJsonSchema: import("./jsonSchemaBuilder.js").JsonSchemaObjectBuilder<BaseDBEntity, false>;
package/dist/types.d.ts CHANGED
@@ -266,6 +266,7 @@ export type ShortBoolean = '1';
266
266
  export type Base64String = string;
267
267
  export type Base64UrlString = string;
268
268
  export type JWTString = string;
269
+ export declare const JWT_REGEX: RegExp;
269
270
  export type SemVerString = string;
270
271
  /**
271
272
  * Named type for JSON.parse / JSON.stringify second argument
package/dist/types.js CHANGED
@@ -20,6 +20,7 @@ export const _passUndefinedMapper = () => undefined;
20
20
  export const _noop = (..._args) => undefined;
21
21
  export const _passthroughPredicate = () => true;
22
22
  export const _passNothingPredicate = () => false;
23
+ export const JWT_REGEX = /^[\w-]+\.[\w-]+\.[\w-]+$/;
23
24
  /**
24
25
  * Like _stringMapValues, but values are sorted.
25
26
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
3
  "type": "module",
4
- "version": "15.35.0",
4
+ "version": "15.37.0",
5
5
  "dependencies": {
6
6
  "tslib": "^2",
7
7
  "undici": "^7",
@@ -13,7 +13,7 @@ export type JsonSchema<T = unknown> =
13
13
  | JsonSchemaNumber
14
14
  | JsonSchemaBoolean
15
15
  | JsonSchemaNull
16
- | JsonSchemaObject // cannot use <T>, because T needs to extend AnyObject
16
+ | JsonSchemaObject<T extends AnyObject ? T : AnyObject>
17
17
  | JsonSchemaArray<T>
18
18
  | JsonSchemaTuple<T>
19
19
 
@@ -28,7 +28,7 @@ export interface JsonSchemaAny<T = unknown> {
28
28
  readOnly?: boolean
29
29
  writeOnly?: boolean
30
30
 
31
- type?: string
31
+ type?: string | string[]
32
32
 
33
33
  default?: T
34
34
 
@@ -1,7 +1,15 @@
1
1
  import { _uniq } from '../array/array.util.js'
2
2
  import { _deepCopy } from '../object/object.util.js'
3
3
  import { _sortObject } from '../object/sortObject.js'
4
- import type { AnyObject, BaseDBEntity, IsoDate, IsoDateTime, UnixTimestamp } from '../types.js'
4
+ import {
5
+ type AnyObject,
6
+ type BaseDBEntity,
7
+ type IsoDate,
8
+ type IsoDateTime,
9
+ JWT_REGEX,
10
+ type JWTString,
11
+ type UnixTimestamp,
12
+ } from '../types.js'
5
13
  import { JSON_SCHEMA_ORDER } from './jsonSchema.cnst.js'
6
14
  import type {
7
15
  JsonSchema,
@@ -35,7 +43,7 @@ export const j = {
35
43
  any<T = unknown>() {
36
44
  return new JsonSchemaAnyBuilder<T, JsonSchemaAny<T>>({})
37
45
  },
38
- const<T = unknown>(value: T) {
46
+ const<T extends string | number | boolean | null>(value: T) {
39
47
  return new JsonSchemaAnyBuilder<T, JsonSchemaConst<T>>({
40
48
  const: value,
41
49
  })
@@ -82,6 +90,9 @@ export const j = {
82
90
  string<T extends string = string>() {
83
91
  return new JsonSchemaStringBuilder<T>()
84
92
  },
93
+ jwt() {
94
+ return new JsonSchemaStringBuilder<JWTString>().jwt()
95
+ },
85
96
 
86
97
  /**
87
98
  * Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
@@ -122,10 +133,15 @@ export const j = {
122
133
  tuple<T extends any[] = unknown[]>(items: JsonSchemaAnyBuilder[]) {
123
134
  return new JsonSchemaTupleBuilder<T>(items)
124
135
  },
125
- oneOf<T = unknown>(items: JsonSchemaAnyBuilder[]) {
126
- return new JsonSchemaAnyBuilder<T, JsonSchemaOneOf<T>>({
136
+ oneOf<Builders extends JsonSchemaAnyBuilder<any, any, any>[]>(
137
+ items: [...Builders],
138
+ ): JsonSchemaAnyBuilder<
139
+ Builders[number] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never,
140
+ JsonSchemaOneOf<Builders[number] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never>
141
+ > {
142
+ return new JsonSchemaAnyBuilder({
127
143
  oneOf: items.map(b => b.build()),
128
- })
144
+ }) as any
129
145
  },
130
146
  allOf<T = unknown>(items: JsonSchemaAnyBuilder[]) {
131
147
  return new JsonSchemaAnyBuilder<T, JsonSchemaAllOf<T>>({
@@ -134,8 +150,11 @@ export const j = {
134
150
  },
135
151
  }
136
152
 
137
- export class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonSchema<T> = JsonSchema<T>>
138
- implements JsonSchemaBuilder<T>
153
+ export class JsonSchemaAnyBuilder<
154
+ T = unknown,
155
+ SCHEMA_TYPE extends JsonSchema<T> = JsonSchema<T>,
156
+ Opt extends boolean = false,
157
+ > implements JsonSchemaBuilder<T>
139
158
  {
140
159
  constructor(protected schema: SCHEMA_TYPE) {}
141
160
 
@@ -186,27 +205,17 @@ export class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonSchema<T>
186
205
  return this
187
206
  }
188
207
 
189
- oneOf(schemas: JsonSchema[]): this {
190
- Object.assign(this.schema, { oneOf: schemas })
191
- return this
192
- }
193
-
194
- allOf(schemas: JsonSchema[]): this {
195
- Object.assign(this.schema, { allOf: schemas })
196
- return this
197
- }
198
-
199
208
  instanceof(of: string): this {
200
209
  this.schema.instanceof = of
201
210
  return this
202
211
  }
203
212
 
204
- optional(): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>>
205
- optional(optional: true): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>>
213
+ optional(): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>, true>
214
+ optional(optional: true): JsonSchemaAnyBuilder<T | undefined, JsonSchema<T | undefined>, true>
206
215
  optional(
207
216
  optional: false,
208
- ): JsonSchemaAnyBuilder<Exclude<T, undefined>, JsonSchema<Exclude<T, undefined>>>
209
- optional(optional = true): JsonSchemaAnyBuilder<any, JsonSchema<any>> {
217
+ ): JsonSchemaAnyBuilder<Exclude<T, undefined>, JsonSchema<Exclude<T, undefined>>, false>
218
+ optional(optional = true): JsonSchemaAnyBuilder<any, JsonSchema<any>, false> {
210
219
  if (optional) {
211
220
  this.schema.optionalField = true
212
221
  } else {
@@ -215,6 +224,12 @@ export class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonSchema<T>
215
224
  return this
216
225
  }
217
226
 
227
+ nullable(): JsonSchemaAnyBuilder<T | null, JsonSchema<T | null>, Opt> {
228
+ return new JsonSchemaAnyBuilder<T | null, JsonSchema<T | null>, Opt>({
229
+ anyOf: [this.build(), { type: 'null' }],
230
+ })
231
+ }
232
+
218
233
  /**
219
234
  * Produces a "clean schema object" without methods.
220
235
  * Same as if it would be JSON.stringified.
@@ -223,8 +238,8 @@ export class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonSchema<T>
223
238
  return _sortObject(JSON.parse(JSON.stringify(this.schema)), JSON_SCHEMA_ORDER)
224
239
  }
225
240
 
226
- clone(): JsonSchemaAnyBuilder<T, SCHEMA_TYPE> {
227
- return new JsonSchemaAnyBuilder<T, SCHEMA_TYPE>(_deepCopy(this.schema))
241
+ clone(): JsonSchemaAnyBuilder<T, SCHEMA_TYPE, Opt> {
242
+ return new JsonSchemaAnyBuilder<T, SCHEMA_TYPE, Opt>(_deepCopy(this.schema))
228
243
  }
229
244
 
230
245
  /**
@@ -233,10 +248,10 @@ export class JsonSchemaAnyBuilder<T = unknown, SCHEMA_TYPE extends JsonSchema<T>
233
248
  infer!: T
234
249
  }
235
250
 
236
- export class JsonSchemaNumberBuilder<T extends number = number> extends JsonSchemaAnyBuilder<
237
- T,
238
- JsonSchemaNumber<T>
239
- > {
251
+ export class JsonSchemaNumberBuilder<
252
+ T extends number = number,
253
+ Opt extends boolean = false,
254
+ > extends JsonSchemaAnyBuilder<T, JsonSchemaNumber<T>, Opt> {
240
255
  constructor() {
241
256
  super({
242
257
  type: 'number',
@@ -306,10 +321,10 @@ export class JsonSchemaNumberBuilder<T extends number = number> extends JsonSche
306
321
  }
307
322
  }
308
323
 
309
- export class JsonSchemaStringBuilder<T extends string = string> extends JsonSchemaAnyBuilder<
310
- T,
311
- JsonSchemaString<T>
312
- > {
324
+ export class JsonSchemaStringBuilder<
325
+ T extends string = string,
326
+ Opt extends boolean = false,
327
+ > extends JsonSchemaAnyBuilder<T, JsonSchemaString<T>, Opt> {
313
328
  constructor() {
314
329
  super({
315
330
  type: 'string',
@@ -380,6 +395,10 @@ export class JsonSchemaStringBuilder<T extends string = string> extends JsonSche
380
395
  return this.format('IsoDateTime').branded<IsoDateTime>().description('IsoDateTime')
381
396
  }
382
397
 
398
+ jwt(): this {
399
+ return this.regex(JWT_REGEX)
400
+ }
401
+
383
402
  private transformModify(t: 'trim' | 'toLowerCase' | 'toUpperCase', add: boolean): this {
384
403
  if (add) {
385
404
  this.schema.transform = _uniq([...(this.schema.transform || []), t])
@@ -393,10 +412,10 @@ export class JsonSchemaStringBuilder<T extends string = string> extends JsonSche
393
412
  // contentEncoding?: string
394
413
  }
395
414
 
396
- export class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSchemaAnyBuilder<
397
- T,
398
- JsonSchemaObject<T>
399
- > {
415
+ export class JsonSchemaObjectBuilder<
416
+ T extends AnyObject,
417
+ Opt extends boolean = false,
418
+ > extends JsonSchemaAnyBuilder<T, JsonSchemaObject<T>, Opt> {
400
419
  constructor() {
401
420
  super({
402
421
  type: 'object',
@@ -460,17 +479,20 @@ export class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSchemaAnyB
460
479
  return this.addRequired(['id', 'created', 'updated']) as any
461
480
  }
462
481
 
463
- extend<T2 extends AnyObject>(s2: JsonSchemaObjectBuilder<T2>): JsonSchemaObjectBuilder<T & T2> {
464
- const builder = new JsonSchemaObjectBuilder<T & T2>()
482
+ extend<T2 extends AnyObject>(
483
+ s2: JsonSchemaObjectBuilder<T2>,
484
+ ): JsonSchemaObjectBuilder<T & T2 extends infer O ? { [K in keyof O]: O[K] } : never> {
485
+ const builder = new JsonSchemaObjectBuilder<any>()
465
486
  Object.assign(builder.schema, _deepCopy(this.schema))
466
487
  mergeJsonSchemaObjects(builder.schema, s2.schema)
467
488
  return builder
468
489
  }
469
490
  }
470
491
 
471
- export class JsonSchemaArrayBuilder<ITEM> extends JsonSchemaAnyBuilder<
492
+ export class JsonSchemaArrayBuilder<ITEM, Opt extends boolean = false> extends JsonSchemaAnyBuilder<
472
493
  ITEM[],
473
- JsonSchemaArray<ITEM>
494
+ JsonSchemaArray<ITEM>,
495
+ Opt
474
496
  > {
475
497
  constructor(itemsSchema: JsonSchemaBuilder<ITEM>) {
476
498
  super({
@@ -509,16 +531,25 @@ export class JsonSchemaTupleBuilder<T extends any[]> extends JsonSchemaAnyBuilde
509
531
  }
510
532
  }
511
533
 
512
- // TODO and Notes
513
- // The issue is that in `j` we mix two approaches:
514
- // 1) the builder driven approach
515
- // 2) the type driven approach.
516
-
517
- function object<P extends Record<string, JsonSchemaAnyBuilder<any, any>>>(
534
+ function object<P extends Record<string, JsonSchemaAnyBuilder<any, any, any>>>(
518
535
  props: P,
519
- ): JsonSchemaObjectBuilder<{
520
- [K in keyof P]: P[K] extends JsonSchemaAnyBuilder<infer U, any> ? U : never
521
- }>
536
+ ): JsonSchemaObjectBuilder<
537
+ {
538
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer Opt>
539
+ ? Opt extends true
540
+ ? never
541
+ : K
542
+ : never]: P[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never
543
+ } & {
544
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer Opt>
545
+ ? Opt extends true
546
+ ? K
547
+ : never
548
+ : never]?: P[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never
549
+ } extends infer O
550
+ ? { [K in keyof O]: O[K] }
551
+ : never
552
+ >
522
553
  function object<T extends AnyObject>(props: {
523
554
  [K in keyof T]: JsonSchemaAnyBuilder<T[K]>
524
555
  }): JsonSchemaObjectBuilder<T>
package/src/types.ts CHANGED
@@ -335,6 +335,7 @@ export type ShortBoolean = '1'
335
335
  export type Base64String = string
336
336
  export type Base64UrlString = string
337
337
  export type JWTString = string
338
+ export const JWT_REGEX = /^[\w-]+\.[\w-]+\.[\w-]+$/
338
339
 
339
340
  export type SemVerString = string
340
341