@naturalcycles/nodejs-lib 15.75.0 → 15.77.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.
@@ -448,6 +448,35 @@ export function createAjv(opt) {
448
448
  return isValid;
449
449
  },
450
450
  });
451
+ ajv.addKeyword({
452
+ keyword: 'exclusiveProperties',
453
+ type: 'object',
454
+ modifying: false,
455
+ errors: true,
456
+ schemaType: 'array',
457
+ validate: function validate(exclusiveProperties, data, _schema, ctx) {
458
+ if (typeof data !== 'object')
459
+ return true;
460
+ for (const props of exclusiveProperties) {
461
+ let numberOfDefinedProperties = 0;
462
+ for (const prop of props) {
463
+ if (data[prop] !== undefined)
464
+ numberOfDefinedProperties++;
465
+ if (numberOfDefinedProperties > 1) {
466
+ ;
467
+ validate.errors = [
468
+ {
469
+ instancePath: ctx?.instancePath ?? '',
470
+ message: `must have only one of the "${props.join(', ')}" properties`,
471
+ },
472
+ ];
473
+ return false;
474
+ }
475
+ }
476
+ }
477
+ return true;
478
+ },
479
+ });
451
480
  return ajv;
452
481
  }
453
482
  const monthLengths = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
@@ -1,6 +1,11 @@
1
1
  import type { Set2 } from '@naturalcycles/js-lib/object';
2
2
  import { type AnyObject, type BaseDBEntity, type IANATimezone, type Inclusiveness, type IsoDate, type IsoDateTime, type IsoMonth, type NumberEnum, type StringEnum, type StringMap, type UnixTimestamp, type UnixTimestampMillis } from '@naturalcycles/js-lib/types';
3
3
  export declare const j: {
4
+ /**
5
+ * Matches literally any value - equivalent to TypeScript's `any` type.
6
+ * Use sparingly, as it bypasses type validation entirely.
7
+ */
8
+ any(): JsonSchemaAnyBuilder<any, any, false>;
4
9
  string(): JsonSchemaStringBuilder<string, string, false>;
5
10
  number(): JsonSchemaNumberBuilder<number, number, false>;
6
11
  boolean(): JsonSchemaBooleanBuilder<boolean, boolean, false>;
@@ -285,6 +290,7 @@ export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends A
285
290
  } & {}, false>;
286
291
  minProperties(minProperties: number): this;
287
292
  maxProperties(maxProperties: number): this;
293
+ exclusiveProperties(propNames: readonly (keyof IN & string)[]): this;
288
294
  }
289
295
  interface JsonSchemaObjectBuilderOpts {
290
296
  hasIsOfTypeCheck?: false;
@@ -409,6 +415,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
409
415
  optionalValues?: (string | number | boolean)[];
410
416
  keySchema?: JsonSchema;
411
417
  minProperties2?: number;
418
+ exclusiveProperties?: (readonly string[])[];
412
419
  }
413
420
  declare function object(props: AnyObject): never;
414
421
  declare function object<IN extends AnyObject>(props: {
@@ -9,6 +9,13 @@ import { BASE64URL_REGEX, COUNTRY_CODE_REGEX, CURRENCY_REGEX, IPV4_REGEX, IPV6_R
9
9
  import { TIMEZONES } from '../timezones.js';
10
10
  import { isEveryItemNumber, isEveryItemPrimitive, isEveryItemString, JSON_SCHEMA_ORDER, mergeJsonSchemaObjects, } from './jsonSchemaBuilder.util.js';
11
11
  export const j = {
12
+ /**
13
+ * Matches literally any value - equivalent to TypeScript's `any` type.
14
+ * Use sparingly, as it bypasses type validation entirely.
15
+ */
16
+ any() {
17
+ return new JsonSchemaAnyBuilder({});
18
+ },
12
19
  string() {
13
20
  return new JsonSchemaStringBuilder();
14
21
  },
@@ -649,6 +656,10 @@ export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
649
656
  maxProperties(maxProperties) {
650
657
  return this.cloneAndUpdateSchema({ maxProperties });
651
658
  }
659
+ exclusiveProperties(propNames) {
660
+ const exclusiveProperties = this.schema.exclusiveProperties ?? [];
661
+ return this.cloneAndUpdateSchema({ exclusiveProperties: [...exclusiveProperties, propNames] });
662
+ }
652
663
  }
653
664
  export class JsonSchemaObjectInferringBuilder extends JsonSchemaAnyBuilder {
654
665
  constructor(props) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
3
  "type": "module",
4
- "version": "15.75.0",
4
+ "version": "15.77.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/js-lib": "^15",
7
7
  "@types/js-yaml": "^4",
@@ -513,6 +513,35 @@ export function createAjv(opt?: Options): Ajv2020 {
513
513
  },
514
514
  })
515
515
 
516
+ ajv.addKeyword({
517
+ keyword: 'exclusiveProperties',
518
+ type: 'object',
519
+ modifying: false,
520
+ errors: true,
521
+ schemaType: 'array',
522
+ validate: function validate(exclusiveProperties: string[][], data: AnyObject, _schema, ctx) {
523
+ if (typeof data !== 'object') return true
524
+
525
+ for (const props of exclusiveProperties) {
526
+ let numberOfDefinedProperties = 0
527
+ for (const prop of props) {
528
+ if (data[prop] !== undefined) numberOfDefinedProperties++
529
+ if (numberOfDefinedProperties > 1) {
530
+ ;(validate as any).errors = [
531
+ {
532
+ instancePath: ctx?.instancePath ?? '',
533
+ message: `must have only one of the "${props.join(', ')}" properties`,
534
+ },
535
+ ]
536
+ return false
537
+ }
538
+ }
539
+ }
540
+
541
+ return true
542
+ },
543
+ })
544
+
516
545
  return ajv
517
546
  }
518
547
 
@@ -49,6 +49,14 @@ import {
49
49
  } from './jsonSchemaBuilder.util.js'
50
50
 
51
51
  export const j = {
52
+ /**
53
+ * Matches literally any value - equivalent to TypeScript's `any` type.
54
+ * Use sparingly, as it bypasses type validation entirely.
55
+ */
56
+ any(): JsonSchemaAnyBuilder<any, any, false> {
57
+ return new JsonSchemaAnyBuilder({})
58
+ },
59
+
52
60
  string(): JsonSchemaStringBuilder<string, string, false> {
53
61
  return new JsonSchemaStringBuilder()
54
62
  },
@@ -950,6 +958,11 @@ export class JsonSchemaObjectBuilder<
950
958
  maxProperties(maxProperties: number): this {
951
959
  return this.cloneAndUpdateSchema({ maxProperties })
952
960
  }
961
+
962
+ exclusiveProperties(propNames: readonly (keyof IN & string)[]): this {
963
+ const exclusiveProperties = this.schema.exclusiveProperties ?? []
964
+ return this.cloneAndUpdateSchema({ exclusiveProperties: [...exclusiveProperties, propNames] })
965
+ }
953
966
  }
954
967
 
955
968
  interface JsonSchemaObjectBuilderOpts {
@@ -1264,6 +1277,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
1264
1277
  optionalValues?: (string | number | boolean)[]
1265
1278
  keySchema?: JsonSchema
1266
1279
  minProperties2?: number
1280
+ exclusiveProperties?: (readonly string[])[]
1267
1281
  }
1268
1282
 
1269
1283
  function object(props: AnyObject): never