@naturalcycles/nodejs-lib 15.83.0 → 15.84.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.
@@ -24,9 +24,9 @@ export interface ReadableTyped<T = unknown> extends Readable {
24
24
  take: (limit: number, opt?: ReadableSignalOptions) => ReadableTyped<T>;
25
25
  drop: (limit: number, opt?: ReadableSignalOptions) => ReadableTyped<T>;
26
26
  }
27
- export interface WritableTyped<T> extends Writable {
27
+ export interface WritableTyped<_T> extends Writable {
28
28
  }
29
- export interface TransformTyped<IN = unknown, OUT = unknown> extends Transform {
29
+ export interface TransformTyped<_IN = unknown, _OUT = unknown> extends Transform {
30
30
  }
31
31
  export interface TransformOptions {
32
32
  /**
@@ -1,4 +1,5 @@
1
1
  import { _isBetween, _lazyValue } from '@naturalcycles/js-lib';
2
+ import { _assert } from '@naturalcycles/js-lib/error';
2
3
  import { _deepCopy, _mapObject, Set2 } from '@naturalcycles/js-lib/object';
3
4
  import { _substringAfterLast } from '@naturalcycles/js-lib/string';
4
5
  import { Ajv2020 } from 'ajv/dist/2020.js';
@@ -165,7 +166,7 @@ export function createAjv(opt) {
165
166
  }
166
167
  idx++;
167
168
  }
168
- if (ctx?.parentData && ctx.parentDataProperty) {
169
+ if (ctx?.parentData && ctx.parentDataProperty !== undefined) {
169
170
  ctx.parentData[ctx.parentDataProperty] = set;
170
171
  }
171
172
  return true;
@@ -215,7 +216,7 @@ export function createAjv(opt) {
215
216
  ];
216
217
  return false;
217
218
  }
218
- if (ctx?.parentData && ctx.parentDataProperty) {
219
+ if (ctx?.parentData && ctx.parentDataProperty !== undefined) {
219
220
  ctx.parentData[ctx.parentDataProperty] = buffer;
220
221
  }
221
222
  return true;
@@ -258,7 +259,7 @@ export function createAjv(opt) {
258
259
  return false;
259
260
  }
260
261
  }
261
- if (ctx?.parentData && ctx.parentDataProperty) {
262
+ if (ctx?.parentData && ctx.parentDataProperty !== undefined) {
262
263
  ctx.parentData[ctx.parentDataProperty] = cleanData;
263
264
  }
264
265
  return true;
@@ -381,18 +382,17 @@ export function createAjv(opt) {
381
382
  });
382
383
  ajv.addKeyword({
383
384
  keyword: 'optionalValues',
384
- type: ['string', 'number', 'boolean'],
385
+ type: ['string', 'number', 'boolean', 'null'],
385
386
  modifying: true,
386
387
  errors: false,
387
388
  schemaType: 'array',
388
389
  validate: function validate(optionalValues, data, _schema, ctx) {
389
390
  if (!optionalValues)
390
391
  return true;
392
+ _assert(ctx?.parentData && ctx.parentDataProperty !== undefined, 'You should only use `optional([x, y, z]) on a property of an object, or on an element of an array due to Ajv mutation issues.');
391
393
  if (!optionalValues.includes(data))
392
394
  return true;
393
- if (ctx?.parentData && ctx.parentDataProperty) {
394
- delete ctx.parentData[ctx.parentDataProperty];
395
- }
395
+ ctx.parentData[ctx.parentDataProperty] = undefined;
396
396
  return true;
397
397
  },
398
398
  });
@@ -417,7 +417,7 @@ export function createAjv(opt) {
417
417
  return validate;
418
418
  },
419
419
  });
420
- // This and `maxProperties2` are added because Ajv validates the `min/maxProperties` before validating the properties.
420
+ // This is added because Ajv validates the `min/maxProperties` before validating the properties.
421
421
  // So, in case of `minProperties(1)` and `{ foo: 'bar' }` Ajv will let it pass, even
422
422
  // if the property validation would strip `foo` from the data.
423
423
  // And Ajv would return `{}` as a successful validation.
@@ -434,7 +434,7 @@ export function createAjv(opt) {
434
434
  validate: function validate(minProperties, data, _schema, ctx) {
435
435
  if (typeof data !== 'object')
436
436
  return true;
437
- const numberOfProperties = Object.getOwnPropertyNames(data).length;
437
+ const numberOfProperties = Object.entries(data).filter(([, v]) => v !== undefined).length;
438
438
  const isValid = numberOfProperties >= minProperties;
439
439
  if (!isValid) {
440
440
  ;
@@ -533,7 +533,7 @@ export function createAjv(opt) {
533
533
  break;
534
534
  }
535
535
  }
536
- if (result && ctx?.parentData && ctx.parentDataProperty) {
536
+ if (result && ctx?.parentData && ctx.parentDataProperty !== undefined) {
537
537
  // If we found a validator and the data is valid and we are validating a property inside an object,
538
538
  // then we can inject our result and be done with it.
539
539
  ctx.parentData[ctx.parentDataProperty] = clonedData;
@@ -169,8 +169,13 @@ export declare class JsonSchemaStringBuilder<IN extends string | undefined = str
169
169
  *
170
170
  * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
171
171
  * due to how mutability works in Ajv.
172
+ *
173
+ * Make sure this `optional()` call is at the end of your call chain.
174
+ *
175
+ * When `null` is included in optionalValues, the return type becomes `JsonSchemaTerminal`
176
+ * (no further chaining allowed) because the schema is wrapped in an anyOf structure.
172
177
  */
173
- optional(optionalValues?: string[]): JsonSchemaStringBuilder<IN | undefined, OUT | undefined, true>;
178
+ optional<T extends readonly (string | null)[] | undefined = undefined>(optionalValues?: T): T extends readonly (infer U)[] ? null extends U ? JsonSchemaTerminal<IN | undefined, OUT | undefined, true> : JsonSchemaStringBuilder<IN | undefined, OUT | undefined, true> : JsonSchemaStringBuilder<IN | undefined, OUT | undefined, true>;
174
179
  regex(pattern: RegExp, opt?: JsonBuilderRuleOpt): this;
175
180
  pattern(pattern: string, opt?: JsonBuilderRuleOpt): this;
176
181
  minLength(minLength: number): this;
@@ -244,8 +249,13 @@ export declare class JsonSchemaNumberBuilder<IN extends number | undefined = num
244
249
  *
245
250
  * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
246
251
  * due to how mutability works in Ajv.
252
+ *
253
+ * Make sure this `optional()` call is at the end of your call chain.
254
+ *
255
+ * When `null` is included in optionalValues, the return type becomes `JsonSchemaTerminal`
256
+ * (no further chaining allowed) because the schema is wrapped in an anyOf structure.
247
257
  */
248
- optional(optionalValues?: number[]): JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true>;
258
+ optional<T extends readonly (number | null)[] | undefined = undefined>(optionalValues?: T): T extends readonly (infer U)[] ? null extends U ? JsonSchemaTerminal<IN | undefined, OUT | undefined, true> : JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true> : JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true>;
249
259
  integer(): this;
250
260
  branded<B extends number>(): JsonSchemaNumberBuilder<B, B, Opt>;
251
261
  multipleOf(multipleOf: number): this;
@@ -457,7 +467,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
457
467
  truncate?: number;
458
468
  };
459
469
  errorMessages?: StringMap<string>;
460
- optionalValues?: (string | number | boolean)[];
470
+ optionalValues?: (string | number | boolean | null)[];
461
471
  keySchema?: JsonSchema;
462
472
  minProperties2?: number;
463
473
  exclusiveProperties?: (readonly string[])[];
@@ -469,7 +479,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
469
479
  }
470
480
  declare function object(props: AnyObject): never;
471
481
  declare function object<IN extends AnyObject>(props: {
472
- [K in keyof Required<IN>]-?: JsonSchemaAnyBuilder<any, IN[K], any>;
482
+ [K in keyof Required<IN>]-?: JsonSchemaTerminal<any, IN[K], any>;
473
483
  }): JsonSchemaObjectBuilder<IN, IN, false>;
474
484
  declare function objectInfer<P extends Record<string, JsonSchemaAnyBuilder<any, any, any>>>(props: P): JsonSchemaObjectInferringBuilder<P, false>;
475
485
  declare function objectDbEntity(props: AnyObject): never;
@@ -4,7 +4,7 @@ import { _isUndefined, _numberEnumValues, _stringEnumValues, getEnumType, } from
4
4
  import { _uniq } from '@naturalcycles/js-lib/array';
5
5
  import { _assert } from '@naturalcycles/js-lib/error';
6
6
  import { _deepCopy, _sortObject } from '@naturalcycles/js-lib/object';
7
- import { _objectAssign, JWT_REGEX, } from '@naturalcycles/js-lib/types';
7
+ import { _objectAssign, _typeCast, JWT_REGEX, } from '@naturalcycles/js-lib/types';
8
8
  import { BASE64URL_REGEX, COUNTRY_CODE_REGEX, CURRENCY_REGEX, IPV4_REGEX, IPV6_REGEX, LANGUAGE_TAG_REGEX, SEMVER_REGEX, SLUG_REGEX, URL_REGEX, UUID_REGEX, } from '../regexes.js';
9
9
  import { TIMEZONES } from '../timezones.js';
10
10
  import { isEveryItemNumber, isEveryItemPrimitive, isEveryItemString, JSON_SCHEMA_ORDER, mergeJsonSchemaObjects, } from './jsonSchemaBuilder.util.js';
@@ -326,17 +326,33 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
326
326
  *
327
327
  * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
328
328
  * due to how mutability works in Ajv.
329
+ *
330
+ * Make sure this `optional()` call is at the end of your call chain.
331
+ *
332
+ * When `null` is included in optionalValues, the return type becomes `JsonSchemaTerminal`
333
+ * (no further chaining allowed) because the schema is wrapped in an anyOf structure.
329
334
  */
330
335
  optional(optionalValues) {
331
336
  if (!optionalValues) {
332
337
  return super.optional();
333
338
  }
334
- const newBuilder = new JsonSchemaStringBuilder().optional();
339
+ _typeCast(optionalValues);
340
+ let newBuilder = new JsonSchemaStringBuilder().optional();
335
341
  const alternativesSchema = j.enum(optionalValues);
336
342
  Object.assign(newBuilder.getSchema(), {
337
343
  anyOf: [this.build(), alternativesSchema.build()],
338
344
  optionalValues,
339
345
  });
346
+ // When `null` is specified, we want `null` to be stripped and the value to become `undefined`,
347
+ // so we must allow `null` values to be parsed by Ajv,
348
+ // but the typing should not reflect that.
349
+ // We also cannot accept more rules attached, since we're not building a StringSchema anymore.
350
+ if (optionalValues.includes(null)) {
351
+ newBuilder = new JsonSchemaTerminal({
352
+ anyOf: [{ type: 'null', optionalValues }, newBuilder.build()],
353
+ optionalField: true,
354
+ });
355
+ }
340
356
  return newBuilder;
341
357
  }
342
358
  regex(pattern, opt) {
@@ -502,17 +518,33 @@ export class JsonSchemaNumberBuilder extends JsonSchemaAnyBuilder {
502
518
  *
503
519
  * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
504
520
  * due to how mutability works in Ajv.
521
+ *
522
+ * Make sure this `optional()` call is at the end of your call chain.
523
+ *
524
+ * When `null` is included in optionalValues, the return type becomes `JsonSchemaTerminal`
525
+ * (no further chaining allowed) because the schema is wrapped in an anyOf structure.
505
526
  */
506
527
  optional(optionalValues) {
507
528
  if (!optionalValues) {
508
529
  return super.optional();
509
530
  }
510
- const newBuilder = new JsonSchemaNumberBuilder().optional();
531
+ _typeCast(optionalValues);
532
+ let newBuilder = new JsonSchemaNumberBuilder().optional();
511
533
  const alternativesSchema = j.enum(optionalValues);
512
534
  Object.assign(newBuilder.getSchema(), {
513
535
  anyOf: [this.build(), alternativesSchema.build()],
514
536
  optionalValues,
515
537
  });
538
+ // When `null` is specified, we want `null` to be stripped and the value to become `undefined`,
539
+ // so we must allow `null` values to be parsed by Ajv,
540
+ // but the typing should not reflect that.
541
+ // We also cannot accept more rules attached, since we're not building a NumberSchema anymore.
542
+ if (optionalValues.includes(null)) {
543
+ newBuilder = new JsonSchemaTerminal({
544
+ anyOf: [{ type: 'null', optionalValues }, newBuilder.build()],
545
+ optionalField: true,
546
+ });
547
+ }
516
548
  return newBuilder;
517
549
  }
518
550
  integer() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
3
  "type": "module",
4
- "version": "15.83.0",
4
+ "version": "15.84.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/js-lib": "^15",
7
7
  "@types/js-yaml": "^4",
@@ -50,9 +50,11 @@ export interface ReadableTyped<T = unknown> extends Readable {
50
50
  }
51
51
 
52
52
  // oxlint-disable no-unused-vars
53
- export interface WritableTyped<T> extends Writable {}
53
+ // eslint-disable-next-line @typescript-eslint/naming-convention
54
+ export interface WritableTyped<_T> extends Writable {}
54
55
 
55
- export interface TransformTyped<IN = unknown, OUT = unknown> extends Transform {}
56
+ // eslint-disable-next-line @typescript-eslint/naming-convention
57
+ export interface TransformTyped<_IN = unknown, _OUT = unknown> extends Transform {}
56
58
  // oxlint-enable
57
59
 
58
60
  export interface TransformOptions {
@@ -1,4 +1,5 @@
1
1
  import { _isBetween, _lazyValue } from '@naturalcycles/js-lib'
2
+ import { _assert } from '@naturalcycles/js-lib/error'
2
3
  import { _deepCopy, _mapObject, Set2 } from '@naturalcycles/js-lib/object'
3
4
  import { _substringAfterLast } from '@naturalcycles/js-lib/string'
4
5
  import type { AnyObject } from '@naturalcycles/js-lib/types'
@@ -195,7 +196,7 @@ export function createAjv(opt?: Options): Ajv2020 {
195
196
  idx++
196
197
  }
197
198
 
198
- if (ctx?.parentData && ctx.parentDataProperty) {
199
+ if (ctx?.parentData && ctx.parentDataProperty !== undefined) {
199
200
  ctx.parentData[ctx.parentDataProperty] = set
200
201
  }
201
202
 
@@ -248,7 +249,7 @@ export function createAjv(opt?: Options): Ajv2020 {
248
249
  return false
249
250
  }
250
251
 
251
- if (ctx?.parentData && ctx.parentDataProperty) {
252
+ if (ctx?.parentData && ctx.parentDataProperty !== undefined) {
252
253
  ctx.parentData[ctx.parentDataProperty] = buffer
253
254
  }
254
255
 
@@ -297,7 +298,7 @@ export function createAjv(opt?: Options): Ajv2020 {
297
298
  }
298
299
  }
299
300
 
300
- if (ctx?.parentData && ctx.parentDataProperty) {
301
+ if (ctx?.parentData && ctx.parentDataProperty !== undefined) {
301
302
  ctx.parentData[ctx.parentDataProperty] = cleanData
302
303
  }
303
304
 
@@ -435,7 +436,7 @@ export function createAjv(opt?: Options): Ajv2020 {
435
436
 
436
437
  ajv.addKeyword({
437
438
  keyword: 'optionalValues',
438
- type: ['string', 'number', 'boolean'],
439
+ type: ['string', 'number', 'boolean', 'null'],
439
440
  modifying: true,
440
441
  errors: false,
441
442
  schemaType: 'array',
@@ -447,11 +448,14 @@ export function createAjv(opt?: Options): Ajv2020 {
447
448
  ) {
448
449
  if (!optionalValues) return true
449
450
 
451
+ _assert(
452
+ ctx?.parentData && ctx.parentDataProperty !== undefined,
453
+ 'You should only use `optional([x, y, z]) on a property of an object, or on an element of an array due to Ajv mutation issues.',
454
+ )
455
+
450
456
  if (!optionalValues.includes(data)) return true
451
457
 
452
- if (ctx?.parentData && ctx.parentDataProperty) {
453
- delete ctx.parentData[ctx.parentDataProperty]
454
- }
458
+ ctx.parentData[ctx.parentDataProperty] = undefined
455
459
 
456
460
  return true
457
461
  },
@@ -482,7 +486,7 @@ export function createAjv(opt?: Options): Ajv2020 {
482
486
  },
483
487
  })
484
488
 
485
- // This and `maxProperties2` are added because Ajv validates the `min/maxProperties` before validating the properties.
489
+ // This is added because Ajv validates the `min/maxProperties` before validating the properties.
486
490
  // So, in case of `minProperties(1)` and `{ foo: 'bar' }` Ajv will let it pass, even
487
491
  // if the property validation would strip `foo` from the data.
488
492
  // And Ajv would return `{}` as a successful validation.
@@ -499,7 +503,7 @@ export function createAjv(opt?: Options): Ajv2020 {
499
503
  validate: function validate(minProperties: number, data: AnyObject, _schema, ctx) {
500
504
  if (typeof data !== 'object') return true
501
505
 
502
- const numberOfProperties = Object.getOwnPropertyNames(data).length
506
+ const numberOfProperties = Object.entries(data).filter(([, v]) => v !== undefined).length
503
507
  const isValid = numberOfProperties >= minProperties
504
508
  if (!isValid) {
505
509
  ;(validate as any).errors = [
@@ -608,7 +612,7 @@ export function createAjv(opt?: Options): Ajv2020 {
608
612
  }
609
613
  }
610
614
 
611
- if (result && ctx?.parentData && ctx.parentDataProperty) {
615
+ if (result && ctx?.parentData && ctx.parentDataProperty !== undefined) {
612
616
  // If we found a validator and the data is valid and we are validating a property inside an object,
613
617
  // then we can inject our result and be done with it.
614
618
  ctx.parentData[ctx.parentDataProperty] = clonedData
@@ -13,6 +13,7 @@ import type { Set2 } from '@naturalcycles/js-lib/object'
13
13
  import { _deepCopy, _sortObject } from '@naturalcycles/js-lib/object'
14
14
  import {
15
15
  _objectAssign,
16
+ _typeCast,
16
17
  type AnyObject,
17
18
  type BaseDBEntity,
18
19
  type IANATimezone,
@@ -468,26 +469,45 @@ export class JsonSchemaStringBuilder<
468
469
  *
469
470
  * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
470
471
  * due to how mutability works in Ajv.
472
+ *
473
+ * Make sure this `optional()` call is at the end of your call chain.
474
+ *
475
+ * When `null` is included in optionalValues, the return type becomes `JsonSchemaTerminal`
476
+ * (no further chaining allowed) because the schema is wrapped in an anyOf structure.
471
477
  */
472
- override optional(
473
- optionalValues?: string[],
474
- ): JsonSchemaStringBuilder<IN | undefined, OUT | undefined, true> {
478
+ override optional<T extends readonly (string | null)[] | undefined = undefined>(
479
+ optionalValues?: T,
480
+ ): T extends readonly (infer U)[]
481
+ ? null extends U
482
+ ? JsonSchemaTerminal<IN | undefined, OUT | undefined, true>
483
+ : JsonSchemaStringBuilder<IN | undefined, OUT | undefined, true>
484
+ : JsonSchemaStringBuilder<IN | undefined, OUT | undefined, true> {
475
485
  if (!optionalValues) {
476
- return super.optional() as unknown as JsonSchemaStringBuilder<
477
- IN | undefined,
478
- OUT | undefined,
479
- true
480
- >
486
+ return super.optional() as any
481
487
  }
482
488
 
483
- const newBuilder = new JsonSchemaStringBuilder<IN, OUT, Opt>().optional()
489
+ _typeCast<(string | null)[]>(optionalValues)
490
+
491
+ let newBuilder: JsonSchemaTerminal<IN | undefined, OUT | undefined, true> =
492
+ new JsonSchemaStringBuilder<IN, OUT, Opt>().optional()
484
493
  const alternativesSchema = j.enum(optionalValues)
485
494
  Object.assign(newBuilder.getSchema(), {
486
495
  anyOf: [this.build(), alternativesSchema.build()],
487
496
  optionalValues,
488
497
  })
489
498
 
490
- return newBuilder
499
+ // When `null` is specified, we want `null` to be stripped and the value to become `undefined`,
500
+ // so we must allow `null` values to be parsed by Ajv,
501
+ // but the typing should not reflect that.
502
+ // We also cannot accept more rules attached, since we're not building a StringSchema anymore.
503
+ if (optionalValues.includes(null)) {
504
+ newBuilder = new JsonSchemaTerminal({
505
+ anyOf: [{ type: 'null', optionalValues }, newBuilder.build()],
506
+ optionalField: true,
507
+ })
508
+ }
509
+
510
+ return newBuilder as any
491
511
  }
492
512
 
493
513
  regex(pattern: RegExp, opt?: JsonBuilderRuleOpt): this {
@@ -716,27 +736,45 @@ export class JsonSchemaNumberBuilder<
716
736
  *
717
737
  * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
718
738
  * due to how mutability works in Ajv.
739
+ *
740
+ * Make sure this `optional()` call is at the end of your call chain.
741
+ *
742
+ * When `null` is included in optionalValues, the return type becomes `JsonSchemaTerminal`
743
+ * (no further chaining allowed) because the schema is wrapped in an anyOf structure.
719
744
  */
720
-
721
- override optional(
722
- optionalValues?: number[],
723
- ): JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true> {
745
+ override optional<T extends readonly (number | null)[] | undefined = undefined>(
746
+ optionalValues?: T,
747
+ ): T extends readonly (infer U)[]
748
+ ? null extends U
749
+ ? JsonSchemaTerminal<IN | undefined, OUT | undefined, true>
750
+ : JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true>
751
+ : JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true> {
724
752
  if (!optionalValues) {
725
- return super.optional() as unknown as JsonSchemaNumberBuilder<
726
- IN | undefined,
727
- OUT | undefined,
728
- true
729
- >
753
+ return super.optional() as any
730
754
  }
731
755
 
732
- const newBuilder = new JsonSchemaNumberBuilder<IN, OUT, Opt>().optional()
756
+ _typeCast<(number | null)[]>(optionalValues)
757
+
758
+ let newBuilder: JsonSchemaTerminal<IN | undefined, OUT | undefined, true> =
759
+ new JsonSchemaNumberBuilder<IN, OUT, Opt>().optional()
733
760
  const alternativesSchema = j.enum(optionalValues)
734
761
  Object.assign(newBuilder.getSchema(), {
735
762
  anyOf: [this.build(), alternativesSchema.build()],
736
763
  optionalValues,
737
764
  })
738
765
 
739
- return newBuilder
766
+ // When `null` is specified, we want `null` to be stripped and the value to become `undefined`,
767
+ // so we must allow `null` values to be parsed by Ajv,
768
+ // but the typing should not reflect that.
769
+ // We also cannot accept more rules attached, since we're not building a NumberSchema anymore.
770
+ if (optionalValues.includes(null)) {
771
+ newBuilder = new JsonSchemaTerminal({
772
+ anyOf: [{ type: 'null', optionalValues }, newBuilder.build()],
773
+ optionalField: true,
774
+ })
775
+ }
776
+
777
+ return newBuilder as any
740
778
  }
741
779
 
742
780
  integer(): this {
@@ -1400,7 +1438,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
1400
1438
  instanceof?: string | string[]
1401
1439
  transform?: { trim?: true; toLowerCase?: true; toUpperCase?: true; truncate?: number }
1402
1440
  errorMessages?: StringMap<string>
1403
- optionalValues?: (string | number | boolean)[]
1441
+ optionalValues?: (string | number | boolean | null)[]
1404
1442
  keySchema?: JsonSchema
1405
1443
  minProperties2?: number
1406
1444
  exclusiveProperties?: (readonly string[])[]
@@ -1413,11 +1451,11 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
1413
1451
 
1414
1452
  function object(props: AnyObject): never
1415
1453
  function object<IN extends AnyObject>(props: {
1416
- [K in keyof Required<IN>]-?: JsonSchemaAnyBuilder<any, IN[K], any>
1454
+ [K in keyof Required<IN>]-?: JsonSchemaTerminal<any, IN[K], any>
1417
1455
  }): JsonSchemaObjectBuilder<IN, IN, false>
1418
1456
 
1419
1457
  function object<IN extends AnyObject>(props: {
1420
- [key in keyof IN]: JsonSchemaAnyBuilder<any, IN[key], any>
1458
+ [key in keyof IN]: JsonSchemaTerminal<any, IN[key], any>
1421
1459
  }): JsonSchemaObjectBuilder<IN, IN, false> {
1422
1460
  return new JsonSchemaObjectBuilder<IN, IN, false>(props)
1423
1461
  }