@naturalcycles/nodejs-lib 15.54.0 → 15.55.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.
@@ -59,6 +59,12 @@ export class AjvSchema {
59
59
  else {
60
60
  jsonSchema = schema;
61
61
  }
62
+ // This is our own helper which marks a schema as optional
63
+ // in case it is going to be used in an object schema,
64
+ // where we need to mark the given property as not-required.
65
+ // But once all compilation is done, the presence of this field
66
+ // really upsets Ajv.
67
+ delete jsonSchema.optionalField;
62
68
  const ajvSchema = new AjvSchema(jsonSchema, cfg);
63
69
  AjvSchema.cacheAjvSchema(schema, ajvSchema);
64
70
  return ajvSchema;
@@ -91,7 +91,7 @@ export function createAjv(opt) {
91
91
  });
92
92
  ajv.addKeyword({
93
93
  keyword: 'instanceof',
94
- modifying: true,
94
+ modifying: false,
95
95
  schemaType: 'string',
96
96
  validate(instanceOf, data, _schema, _ctx) {
97
97
  if (typeof data !== 'object')
@@ -354,6 +354,23 @@ export function createAjv(opt) {
354
354
  keyword: 'hasIsOfTypeCheck',
355
355
  schemaType: 'boolean',
356
356
  });
357
+ ajv.addKeyword({
358
+ keyword: 'optionalValues',
359
+ type: ['string', 'number', 'boolean'],
360
+ modifying: true,
361
+ errors: false,
362
+ schemaType: 'array',
363
+ validate: function validate(optionalValues, data, _schema, ctx) {
364
+ if (!optionalValues)
365
+ return true;
366
+ if (!optionalValues.includes(data))
367
+ return true;
368
+ if (ctx?.parentData && ctx.parentDataProperty) {
369
+ ctx.parentData[ctx.parentDataProperty] = undefined;
370
+ }
371
+ return true;
372
+ },
373
+ });
357
374
  return ajv;
358
375
  }
359
376
  const monthLengths = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
@@ -19,6 +19,9 @@ export declare const j: {
19
19
  buffer(): JsonSchemaBufferBuilder;
20
20
  enum<const T extends readonly (string | number | boolean | null)[] | StringEnum | NumberEnum>(input: T, opt?: JsonBuilderRuleOpt): JsonSchemaEnumBuilder<T extends readonly (infer U)[] ? U : T extends StringEnum ? T[keyof T] : T extends NumberEnum ? T[keyof T] : never>;
21
21
  oneOf<B extends readonly JsonSchemaAnyBuilder<any, any, boolean>[], IN = BuilderInUnion<B>, OUT = BuilderOutUnion<B>>(items: [...B]): JsonSchemaAnyBuilder<IN, OUT, false>;
22
+ and(): {
23
+ silentBob: () => never;
24
+ };
22
25
  };
23
26
  export declare class JsonSchemaTerminal<IN, OUT, Opt> {
24
27
  protected schema: JsonSchema;
@@ -73,8 +76,15 @@ export declare class JsonSchemaAnyBuilder<IN, OUT, Opt> extends JsonSchemaTermin
73
76
  */
74
77
  final(): JsonSchemaTerminal<IN, OUT, Opt>;
75
78
  }
76
- export declare class JsonSchemaStringBuilder<IN extends string = string, OUT = IN, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
79
+ export declare class JsonSchemaStringBuilder<IN extends string | undefined = string, OUT = IN, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
77
80
  constructor();
81
+ /**
82
+ * @param optionalValues List of values that should be considered/converted as `undefined`.
83
+ *
84
+ * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
85
+ * due to how mutability works in Ajv.
86
+ */
87
+ optional(optionalValues?: string[]): JsonSchemaStringBuilder<IN | undefined, OUT | undefined, true>;
78
88
  regex(pattern: RegExp, opt?: JsonBuilderRuleOpt): this;
79
89
  pattern(pattern: string, opt?: JsonBuilderRuleOpt): this;
80
90
  minLength(minLength: number): this;
@@ -134,8 +144,15 @@ export interface JsonSchemaIsoDateOptions {
134
144
  after?: string;
135
145
  sameOrAfter?: string;
136
146
  }
137
- export declare class JsonSchemaNumberBuilder<IN extends number = number, OUT = IN, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
147
+ export declare class JsonSchemaNumberBuilder<IN extends number | undefined = number, OUT = IN, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
138
148
  constructor();
149
+ /**
150
+ * @param optionalValues List of values that should be considered/converted as `undefined`.
151
+ *
152
+ * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
153
+ * due to how mutability works in Ajv.
154
+ */
155
+ optional(optionalValues?: number[]): JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true>;
139
156
  integer(): this;
140
157
  branded<B extends number>(): JsonSchemaNumberBuilder<B, B, Opt>;
141
158
  multipleOf(multipleOf: number): this;
@@ -160,8 +177,15 @@ export declare class JsonSchemaNumberBuilder<IN extends number = number, OUT = I
160
177
  utcOffset(): this;
161
178
  utcOffsetHour(): this;
162
179
  }
163
- export declare class JsonSchemaBooleanBuilder<IN extends boolean = boolean, OUT = IN, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
180
+ export declare class JsonSchemaBooleanBuilder<IN extends boolean | undefined = boolean, OUT = IN, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
164
181
  constructor();
182
+ /**
183
+ * @param optionalValue One of the two possible boolean values that should be considered/converted as `undefined`.
184
+ *
185
+ * This `optionalValue` feature only works when the current schema is nested in an object or array schema,
186
+ * due to how mutability works in Ajv.
187
+ */
188
+ optional(optionalValue?: boolean): JsonSchemaBooleanBuilder<IN | undefined, OUT | undefined, true>;
165
189
  }
166
190
  export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends AnyObject, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
167
191
  constructor(props?: AnyObject, opt?: JsonSchemaObjectBuilderOpts);
@@ -276,6 +300,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
276
300
  maxItems?: number;
277
301
  uniqueItems?: boolean;
278
302
  enum?: any;
303
+ hasIsOfTypeCheck?: boolean;
279
304
  email?: JsonSchemaStringEmailOptions;
280
305
  Set2?: JsonSchema;
281
306
  Buffer?: true;
@@ -289,7 +314,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
289
314
  truncate?: number;
290
315
  };
291
316
  errorMessages?: StringMap<string>;
292
- hasIsOfTypeCheck?: boolean;
317
+ optionalValues?: (string | number | boolean)[];
293
318
  }
294
319
  declare function object(props: AnyObject): never;
295
320
  declare function object<IN extends AnyObject>(props: {
@@ -101,6 +101,13 @@ export const j = {
101
101
  oneOf: schemas,
102
102
  });
103
103
  },
104
+ and() {
105
+ return {
106
+ silentBob: () => {
107
+ throw new Error('...strike back!');
108
+ },
109
+ };
110
+ },
104
111
  };
105
112
  const TS_2500 = 16725225600; // 2500-01-01
106
113
  const TS_2500_MILLIS = TS_2500 * 1000;
@@ -227,6 +234,16 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
227
234
  type: 'string',
228
235
  });
229
236
  }
237
+ /**
238
+ * @param optionalValues List of values that should be considered/converted as `undefined`.
239
+ *
240
+ * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
241
+ * due to how mutability works in Ajv.
242
+ */
243
+ optional(optionalValues) {
244
+ _objectAssign(this.schema, { optionalValues });
245
+ return super.optional();
246
+ }
230
247
  regex(pattern, opt) {
231
248
  return this.pattern(pattern.source, opt);
232
249
  }
@@ -379,6 +396,16 @@ export class JsonSchemaNumberBuilder extends JsonSchemaAnyBuilder {
379
396
  type: 'number',
380
397
  });
381
398
  }
399
+ /**
400
+ * @param optionalValues List of values that should be considered/converted as `undefined`.
401
+ *
402
+ * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
403
+ * due to how mutability works in Ajv.
404
+ */
405
+ optional(optionalValues) {
406
+ _objectAssign(this.schema, { optionalValues });
407
+ return super.optional();
408
+ }
382
409
  integer() {
383
410
  _objectAssign(this.schema, { type: 'integer' });
384
411
  return this;
@@ -477,6 +504,18 @@ export class JsonSchemaBooleanBuilder extends JsonSchemaAnyBuilder {
477
504
  type: 'boolean',
478
505
  });
479
506
  }
507
+ /**
508
+ * @param optionalValue One of the two possible boolean values that should be considered/converted as `undefined`.
509
+ *
510
+ * This `optionalValue` feature only works when the current schema is nested in an object or array schema,
511
+ * due to how mutability works in Ajv.
512
+ */
513
+ optional(optionalValue) {
514
+ if (typeof optionalValue !== 'undefined') {
515
+ _objectAssign(this.schema, { optionalValues: [optionalValue] });
516
+ }
517
+ return super.optional();
518
+ }
480
519
  }
481
520
  export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
482
521
  constructor(props, opt) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
3
  "type": "module",
4
- "version": "15.54.0",
4
+ "version": "15.55.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/js-lib": "^15",
7
7
  "@types/js-yaml": "^4",
@@ -79,6 +79,13 @@ export class AjvSchema<IN = unknown, OUT = IN> {
79
79
  jsonSchema = schema
80
80
  }
81
81
 
82
+ // This is our own helper which marks a schema as optional
83
+ // in case it is going to be used in an object schema,
84
+ // where we need to mark the given property as not-required.
85
+ // But once all compilation is done, the presence of this field
86
+ // really upsets Ajv.
87
+ delete jsonSchema.optionalField
88
+
82
89
  const ajvSchema = new AjvSchema<IN, OUT>(jsonSchema, cfg)
83
90
  AjvSchema.cacheAjvSchema(schema, ajvSchema)
84
91
 
@@ -109,7 +109,7 @@ export function createAjv(opt?: Options): Ajv {
109
109
 
110
110
  ajv.addKeyword({
111
111
  keyword: 'instanceof',
112
- modifying: true,
112
+ modifying: false,
113
113
  schemaType: 'string',
114
114
  validate(instanceOf: string, data: unknown, _schema, _ctx) {
115
115
  if (typeof data !== 'object') return false
@@ -396,6 +396,30 @@ export function createAjv(opt?: Options): Ajv {
396
396
  schemaType: 'boolean',
397
397
  })
398
398
 
399
+ ajv.addKeyword({
400
+ keyword: 'optionalValues',
401
+ type: ['string', 'number', 'boolean'],
402
+ modifying: true,
403
+ errors: false,
404
+ schemaType: 'array',
405
+ validate: function validate(
406
+ optionalValues: (string | number | boolean)[],
407
+ data: string | number | boolean,
408
+ _schema,
409
+ ctx,
410
+ ) {
411
+ if (!optionalValues) return true
412
+
413
+ if (!optionalValues.includes(data)) return true
414
+
415
+ if (ctx?.parentData && ctx.parentDataProperty) {
416
+ ctx.parentData[ctx.parentDataProperty] = undefined
417
+ }
418
+
419
+ return true
420
+ },
421
+ })
422
+
399
423
  return ajv
400
424
  }
401
425
 
@@ -193,6 +193,14 @@ export const j = {
193
193
  oneOf: schemas,
194
194
  })
195
195
  },
196
+
197
+ and() {
198
+ return {
199
+ silentBob: () => {
200
+ throw new Error('...strike back!')
201
+ },
202
+ }
203
+ },
196
204
  }
197
205
 
198
206
  const TS_2500 = 16725225600 // 2500-01-01
@@ -338,7 +346,7 @@ export class JsonSchemaAnyBuilder<IN, OUT, Opt> extends JsonSchemaTerminal<IN, O
338
346
  }
339
347
 
340
348
  export class JsonSchemaStringBuilder<
341
- IN extends string = string,
349
+ IN extends string | undefined = string,
342
350
  OUT = IN,
343
351
  Opt extends boolean = false,
344
352
  > extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
@@ -348,6 +356,23 @@ export class JsonSchemaStringBuilder<
348
356
  })
349
357
  }
350
358
 
359
+ /**
360
+ * @param optionalValues List of values that should be considered/converted as `undefined`.
361
+ *
362
+ * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
363
+ * due to how mutability works in Ajv.
364
+ */
365
+ override optional(
366
+ optionalValues?: string[],
367
+ ): JsonSchemaStringBuilder<IN | undefined, OUT | undefined, true> {
368
+ _objectAssign(this.schema, { optionalValues })
369
+ return super.optional() as unknown as JsonSchemaStringBuilder<
370
+ IN | undefined,
371
+ OUT | undefined,
372
+ true
373
+ >
374
+ }
375
+
351
376
  regex(pattern: RegExp, opt?: JsonBuilderRuleOpt): this {
352
377
  return this.pattern(pattern.source, opt)
353
378
  }
@@ -540,7 +565,7 @@ export interface JsonSchemaIsoDateOptions {
540
565
  }
541
566
 
542
567
  export class JsonSchemaNumberBuilder<
543
- IN extends number = number,
568
+ IN extends number | undefined = number,
544
569
  OUT = IN,
545
570
  Opt extends boolean = false,
546
571
  > extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
@@ -550,6 +575,23 @@ export class JsonSchemaNumberBuilder<
550
575
  })
551
576
  }
552
577
 
578
+ /**
579
+ * @param optionalValues List of values that should be considered/converted as `undefined`.
580
+ *
581
+ * This `optionalValues` feature only works when the current schema is nested in an object or array schema,
582
+ * due to how mutability works in Ajv.
583
+ */
584
+ override optional(
585
+ optionalValues?: number[],
586
+ ): JsonSchemaNumberBuilder<IN | undefined, OUT | undefined, true> {
587
+ _objectAssign(this.schema, { optionalValues })
588
+ return super.optional() as unknown as JsonSchemaNumberBuilder<
589
+ IN | undefined,
590
+ OUT | undefined,
591
+ true
592
+ >
593
+ }
594
+
553
595
  integer(): this {
554
596
  _objectAssign(this.schema, { type: 'integer' })
555
597
  return this
@@ -670,7 +712,7 @@ export class JsonSchemaNumberBuilder<
670
712
  }
671
713
 
672
714
  export class JsonSchemaBooleanBuilder<
673
- IN extends boolean = boolean,
715
+ IN extends boolean | undefined = boolean,
674
716
  OUT = IN,
675
717
  Opt extends boolean = false,
676
718
  > extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
@@ -679,6 +721,26 @@ export class JsonSchemaBooleanBuilder<
679
721
  type: 'boolean',
680
722
  })
681
723
  }
724
+
725
+ /**
726
+ * @param optionalValue One of the two possible boolean values that should be considered/converted as `undefined`.
727
+ *
728
+ * This `optionalValue` feature only works when the current schema is nested in an object or array schema,
729
+ * due to how mutability works in Ajv.
730
+ */
731
+ override optional(
732
+ optionalValue?: boolean,
733
+ ): JsonSchemaBooleanBuilder<IN | undefined, OUT | undefined, true> {
734
+ if (typeof optionalValue !== 'undefined') {
735
+ _objectAssign(this.schema, { optionalValues: [optionalValue] })
736
+ }
737
+
738
+ return super.optional() as unknown as JsonSchemaBooleanBuilder<
739
+ IN | undefined,
740
+ OUT | undefined,
741
+ true
742
+ >
743
+ }
682
744
  }
683
745
 
684
746
  export class JsonSchemaObjectBuilder<
@@ -1036,6 +1098,8 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
1036
1098
 
1037
1099
  enum?: any
1038
1100
 
1101
+ hasIsOfTypeCheck?: boolean
1102
+
1039
1103
  // Below we add custom Ajv keywords
1040
1104
 
1041
1105
  email?: JsonSchemaStringEmailOptions
@@ -1046,7 +1110,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
1046
1110
  instanceof?: string | string[]
1047
1111
  transform?: { trim?: true; toLowerCase?: true; toUpperCase?: true; truncate?: number }
1048
1112
  errorMessages?: StringMap<string>
1049
- hasIsOfTypeCheck?: boolean
1113
+ optionalValues?: (string | number | boolean)[]
1050
1114
  }
1051
1115
 
1052
1116
  function object(props: AnyObject): never