@naturalcycles/nodejs-lib 15.63.1 → 15.65.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.
@@ -75,7 +75,7 @@ export class AjvSchema {
75
75
  */
76
76
  static createFromZod(schema) {
77
77
  const jsonSchema = z.toJSONSchema(schema, {
78
- target: 'draft-7',
78
+ target: 'draft-2020-12',
79
79
  });
80
80
  return AjvSchema.create(jsonSchema);
81
81
  }
@@ -1,4 +1,4 @@
1
- import { Ajv, type Options } from 'ajv';
1
+ import { Ajv2020, type Options } from 'ajv/dist/2020.js';
2
2
  /**
3
3
  * Return cached instance of Ajv with default (recommended) options.
4
4
  *
@@ -27,4 +27,4 @@ export declare const getCoercingAjv: any;
27
27
  *
28
28
  * https://ajv.js.org/options.html
29
29
  */
30
- export declare function createAjv(opt?: Options): Ajv;
30
+ export declare function createAjv(opt?: Options): Ajv2020;
@@ -1,7 +1,7 @@
1
1
  import { _isBetween, _lazyValue } from '@naturalcycles/js-lib';
2
2
  import { Set2 } from '@naturalcycles/js-lib/object';
3
3
  import { _substringAfterLast } from '@naturalcycles/js-lib/string';
4
- import { Ajv } from 'ajv';
4
+ import { Ajv2020 } from 'ajv/dist/2020.js';
5
5
  import { validTLDs } from '../tlds.js';
6
6
  /* eslint-disable @typescript-eslint/prefer-string-starts-ends-with */
7
7
  // oxlint-disable unicorn/prefer-code-point
@@ -52,7 +52,7 @@ export const getCoercingAjv = _lazyValue(() => createAjv(AJV_MUTATING_COERCING_O
52
52
  * https://ajv.js.org/options.html
53
53
  */
54
54
  export function createAjv(opt) {
55
- const ajv = new Ajv({
55
+ const ajv = new Ajv2020({
56
56
  ...AJV_OPTIONS,
57
57
  ...opt,
58
58
  });
@@ -45,6 +45,7 @@ export declare const j: {
45
45
  withRegexKeys: typeof withRegexKeys;
46
46
  };
47
47
  array<IN, OUT, Opt>(itemSchema: JsonSchemaAnyBuilder<IN, OUT, Opt>): JsonSchemaArrayBuilder<IN, OUT, Opt>;
48
+ tuple<const S extends JsonSchemaAnyBuilder<any, any, any>[]>(items: S): JsonSchemaTupleBuilder<S>;
48
49
  set<IN, OUT, Opt>(itemSchema: JsonSchemaAnyBuilder<IN, OUT, Opt>): JsonSchemaSet2Builder<IN, OUT, Opt>;
49
50
  buffer(): JsonSchemaBufferBuilder;
50
51
  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>;
@@ -235,10 +236,15 @@ export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends A
235
236
  * When set, the validation will not strip away properties that are not specified explicitly in the schema.
236
237
  */
237
238
  allowAdditionalProperties(): this;
238
- extend(props: AnyObject): never;
239
- extend<IN2 extends AnyObject>(props: {
240
- [K in keyof Required<IN2>]-?: JsonSchemaAnyBuilder<any, IN2[K], any>;
241
- }): JsonSchemaObjectBuilder<IN & IN2, OUT & IN2, false>;
239
+ extend<P extends Record<string, JsonSchemaAnyBuilder<any, any, any>>>(props: P): JsonSchemaObjectBuilder<IN & {
240
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt> ? IsOpt extends true ? never : K : never]: P[K] extends JsonSchemaAnyBuilder<infer IN2, any, any> ? IN2 : never;
241
+ } & {
242
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt> ? IsOpt extends true ? K : never : never]?: P[K] extends JsonSchemaAnyBuilder<infer IN2, any, any> ? IN2 : never;
243
+ }, OUT & {
244
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt> ? IsOpt extends true ? never : K : never]: P[K] extends JsonSchemaAnyBuilder<any, infer OUT2, any> ? OUT2 : never;
245
+ } & {
246
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt> ? IsOpt extends true ? K : never : never]?: P[K] extends JsonSchemaAnyBuilder<any, infer OUT2, any> ? OUT2 : never;
247
+ }, false>;
242
248
  /**
243
249
  * Concatenates another schema to the current schema.
244
250
  *
@@ -261,7 +267,15 @@ export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends A
261
267
  /**
262
268
  * Extends the current schema with `id`, `created` and `updated` according to NC DB conventions.
263
269
  */
264
- dbEntity(): never;
270
+ dbEntity(): JsonSchemaObjectBuilder<IN & {
271
+ id: string;
272
+ created: any;
273
+ updated: any;
274
+ } & {}, OUT & {
275
+ id: string;
276
+ created: any;
277
+ updated: any;
278
+ } & {}, false>;
265
279
  minProperties(minProperties: number): this;
266
280
  maxProperties(maxProperties: number): this;
267
281
  }
@@ -291,7 +305,7 @@ export declare class JsonSchemaObjectInferringBuilder<PROPS extends Record<strin
291
305
  /**
292
306
  * Extends the current schema with `id`, `created` and `updated` according to NC DB conventions.
293
307
  */
294
- dbEntity(): JsonSchemaObjectInferringBuilder<{ [K in "id" | keyof PROPS | "created" | "updated"]: K extends "id" | "created" | "updated" ? {
308
+ dbEntity(): JsonSchemaObjectInferringBuilder<{ [K in "id" | "created" | "updated" | keyof PROPS]: K extends "id" | "created" | "updated" ? {
295
309
  id: JsonSchemaStringBuilder<string, string, false>;
296
310
  created: JsonSchemaNumberBuilder<UnixTimestamp, UnixTimestamp, false>;
297
311
  updated: JsonSchemaNumberBuilder<UnixTimestamp, UnixTimestamp, false>;
@@ -318,6 +332,10 @@ export declare class JsonSchemaEnumBuilder<IN extends string | number | boolean
318
332
  constructor(enumValues: readonly IN[], baseType: EnumBaseType, opt?: JsonBuilderRuleOpt);
319
333
  branded<B extends IN>(): JsonSchemaEnumBuilder<B | IN, B, Opt>;
320
334
  }
335
+ export declare class JsonSchemaTupleBuilder<ITEMS extends JsonSchemaAnyBuilder<any, any, any>[]> extends JsonSchemaAnyBuilder<TupleIn<ITEMS>, TupleOut<ITEMS>, false> {
336
+ private readonly _items;
337
+ constructor(items: ITEMS);
338
+ }
321
339
  type EnumBaseType = 'string' | 'number' | 'other';
322
340
  export interface JsonSchema<IN = unknown, OUT = IN> {
323
341
  readonly in?: IN;
@@ -331,6 +349,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
331
349
  writeOnly?: boolean;
332
350
  type?: string | string[];
333
351
  items?: JsonSchema;
352
+ prefixItems?: JsonSchema[];
334
353
  properties?: {
335
354
  [K in keyof IN & keyof OUT]: JsonSchema<IN[K], OUT[K]>;
336
355
  };
@@ -447,4 +466,10 @@ type EnumKeyUnion<T> = T extends readonly (infer U)[] ? U : T extends StringEnum
447
466
  type SchemaIn<S> = S extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never;
448
467
  type SchemaOut<S> = S extends JsonSchemaAnyBuilder<any, infer OUT, any> ? OUT : never;
449
468
  type SchemaOpt<S> = S extends JsonSchemaAnyBuilder<any, any, infer Opt> ? (Opt extends true ? true : false) : false;
469
+ type TupleIn<T extends readonly JsonSchemaAnyBuilder<any, any, any>[]> = {
470
+ [K in keyof T]: T[K] extends JsonSchemaAnyBuilder<infer I, any, any> ? I : never;
471
+ };
472
+ type TupleOut<T extends readonly JsonSchemaAnyBuilder<any, any, any>[]> = {
473
+ [K in keyof T]: T[K] extends JsonSchemaAnyBuilder<any, infer O, any> ? O : never;
474
+ };
450
475
  export {};
@@ -71,6 +71,9 @@ export const j = {
71
71
  array(itemSchema) {
72
72
  return new JsonSchemaArrayBuilder(itemSchema);
73
73
  },
74
+ tuple(items) {
75
+ return new JsonSchemaTupleBuilder(items);
76
+ },
74
77
  set(itemSchema) {
75
78
  return new JsonSchemaSet2Builder(itemSchema);
76
79
  },
@@ -586,14 +589,12 @@ export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
586
589
  return this.cloneAndUpdateSchema({ additionalProperties: true });
587
590
  }
588
591
  extend(props) {
589
- const clone = this.clone();
592
+ const newBuilder = new JsonSchemaObjectBuilder();
593
+ _objectAssign(newBuilder.schema, _deepCopy(this.schema));
590
594
  const incomingSchemaBuilder = new JsonSchemaObjectBuilder(props);
591
- mergeJsonSchemaObjects(clone.schema, incomingSchemaBuilder.schema);
592
- // The incoming object is type-safe because `extend<Foo>()` expects a passed in type that matches the passed in props,
593
- // but maybe the current schema was created differently, so that's what decides the typecheckedness.
594
- const hasIsOfTypeCheck = this.schema.hasIsOfTypeCheck;
595
- _objectAssign(clone.schema, { hasIsOfTypeCheck });
596
- return clone;
595
+ mergeJsonSchemaObjects(newBuilder.schema, incomingSchemaBuilder.schema);
596
+ _objectAssign(newBuilder.schema, { hasIsOfTypeCheck: false });
597
+ return newBuilder;
597
598
  }
598
599
  /**
599
600
  * Concatenates another schema to the current schema.
@@ -756,6 +757,18 @@ export class JsonSchemaEnumBuilder extends JsonSchemaAnyBuilder {
756
757
  return this;
757
758
  }
758
759
  }
760
+ export class JsonSchemaTupleBuilder extends JsonSchemaAnyBuilder {
761
+ _items;
762
+ constructor(items) {
763
+ super({
764
+ type: 'array',
765
+ prefixItems: items.map(i => i.build()),
766
+ minItems: items.length,
767
+ maxItems: items.length,
768
+ });
769
+ this._items = items;
770
+ }
771
+ }
759
772
  function object(props) {
760
773
  return new JsonSchemaObjectBuilder(props);
761
774
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
3
  "type": "module",
4
- "version": "15.63.1",
4
+ "version": "15.65.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/js-lib": "^15",
7
7
  "@types/js-yaml": "^4",
@@ -100,7 +100,7 @@ export class AjvSchema<IN = unknown, OUT = IN> {
100
100
  schema: T,
101
101
  ): AjvSchema<T['_input'], T['_output']> {
102
102
  const jsonSchema = z.toJSONSchema(schema, {
103
- target: 'draft-7',
103
+ target: 'draft-2020-12',
104
104
  }) as unknown as JsonSchema<T['_input'], T['_output']>
105
105
 
106
106
  return AjvSchema.create(jsonSchema)
@@ -2,7 +2,7 @@ import { _isBetween, _lazyValue } from '@naturalcycles/js-lib'
2
2
  import { Set2 } from '@naturalcycles/js-lib/object'
3
3
  import { _substringAfterLast } from '@naturalcycles/js-lib/string'
4
4
  import type { AnyObject } from '@naturalcycles/js-lib/types'
5
- import { Ajv, type Options, type ValidateFunction } from 'ajv'
5
+ import { Ajv2020, type Options, type ValidateFunction } from 'ajv/dist/2020.js'
6
6
  import { validTLDs } from '../tlds.js'
7
7
  import type {
8
8
  JsonSchemaIsoDateOptions,
@@ -65,8 +65,8 @@ export const getCoercingAjv = _lazyValue(() => createAjv(AJV_MUTATING_COERCING_O
65
65
  *
66
66
  * https://ajv.js.org/options.html
67
67
  */
68
- export function createAjv(opt?: Options): Ajv {
69
- const ajv = new Ajv({
68
+ export function createAjv(opt?: Options): Ajv2020 {
69
+ const ajv = new Ajv2020({
70
70
  ...AJV_OPTIONS,
71
71
  ...opt,
72
72
  })
@@ -126,6 +126,12 @@ export const j = {
126
126
  return new JsonSchemaArrayBuilder(itemSchema)
127
127
  },
128
128
 
129
+ tuple<const S extends JsonSchemaAnyBuilder<any, any, any>[]>(
130
+ items: S,
131
+ ): JsonSchemaTupleBuilder<S> {
132
+ return new JsonSchemaTupleBuilder<S>(items)
133
+ },
134
+
129
135
  set<IN, OUT, Opt>(
130
136
  itemSchema: JsonSchemaAnyBuilder<IN, OUT, Opt>,
131
137
  ): JsonSchemaSet2Builder<IN, OUT, Opt> {
@@ -828,24 +834,50 @@ export class JsonSchemaObjectBuilder<
828
834
  return this.cloneAndUpdateSchema({ additionalProperties: true })
829
835
  }
830
836
 
831
- extend(props: AnyObject): never
832
- extend<IN2 extends AnyObject>(props: {
833
- [K in keyof Required<IN2>]-?: JsonSchemaAnyBuilder<any, IN2[K], any>
834
- }): JsonSchemaObjectBuilder<IN & IN2, OUT & IN2, false>
835
- extend<IN2 extends AnyObject>(props: {
836
- [key in keyof IN2]: JsonSchemaAnyBuilder<any, IN2[key], any>
837
- }): JsonSchemaObjectBuilder<IN & IN2, OUT & IN2, false> {
838
- const clone = this.clone()
837
+ extend<P extends Record<string, JsonSchemaAnyBuilder<any, any, any>>>(
838
+ props: P,
839
+ ): JsonSchemaObjectBuilder<
840
+ IN & {
841
+ // required keys
842
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt>
843
+ ? IsOpt extends true
844
+ ? never
845
+ : K
846
+ : never]: P[K] extends JsonSchemaAnyBuilder<infer IN2, any, any> ? IN2 : never
847
+ } & {
848
+ // optional keys
849
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt>
850
+ ? IsOpt extends true
851
+ ? K
852
+ : never
853
+ : never]?: P[K] extends JsonSchemaAnyBuilder<infer IN2, any, any> ? IN2 : never
854
+ },
855
+ OUT & {
856
+ // required keys
857
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt>
858
+ ? IsOpt extends true
859
+ ? never
860
+ : K
861
+ : never]: P[K] extends JsonSchemaAnyBuilder<any, infer OUT2, any> ? OUT2 : never
862
+ } & {
863
+ // optional keys
864
+ [K in keyof P as P[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt>
865
+ ? IsOpt extends true
866
+ ? K
867
+ : never
868
+ : never]?: P[K] extends JsonSchemaAnyBuilder<any, infer OUT2, any> ? OUT2 : never
869
+ },
870
+ false
871
+ > {
872
+ const newBuilder = new JsonSchemaObjectBuilder()
873
+ _objectAssign(newBuilder.schema, _deepCopy(this.schema))
839
874
 
840
- const incomingSchemaBuilder = new JsonSchemaObjectBuilder<IN2, IN2, false>(props)
841
- mergeJsonSchemaObjects(clone.schema as any, incomingSchemaBuilder.schema as any)
875
+ const incomingSchemaBuilder = new JsonSchemaObjectBuilder(props)
876
+ mergeJsonSchemaObjects(newBuilder.schema as any, incomingSchemaBuilder.schema as any)
842
877
 
843
- // The incoming object is type-safe because `extend<Foo>()` expects a passed in type that matches the passed in props,
844
- // but maybe the current schema was created differently, so that's what decides the typecheckedness.
845
- const hasIsOfTypeCheck = this.schema.hasIsOfTypeCheck
846
- _objectAssign(clone.schema, { hasIsOfTypeCheck })
878
+ _objectAssign(newBuilder.schema, { hasIsOfTypeCheck: false })
847
879
 
848
- return clone as unknown as JsonSchemaObjectBuilder<IN & IN2, OUT & IN2, false>
880
+ return newBuilder as any
849
881
  }
850
882
 
851
883
  /**
@@ -1113,6 +1145,23 @@ export class JsonSchemaEnumBuilder<
1113
1145
  }
1114
1146
  }
1115
1147
 
1148
+ export class JsonSchemaTupleBuilder<
1149
+ ITEMS extends JsonSchemaAnyBuilder<any, any, any>[],
1150
+ > extends JsonSchemaAnyBuilder<TupleIn<ITEMS>, TupleOut<ITEMS>, false> {
1151
+ private readonly _items: ITEMS
1152
+
1153
+ constructor(items: ITEMS) {
1154
+ super({
1155
+ type: 'array',
1156
+ prefixItems: items.map(i => i.build()),
1157
+ minItems: items.length,
1158
+ maxItems: items.length,
1159
+ })
1160
+
1161
+ this._items = items
1162
+ }
1163
+ }
1164
+
1116
1165
  type EnumBaseType = 'string' | 'number' | 'other'
1117
1166
 
1118
1167
  export interface JsonSchema<IN = unknown, OUT = IN> {
@@ -1130,6 +1179,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
1130
1179
 
1131
1180
  type?: string | string[]
1132
1181
  items?: JsonSchema
1182
+ prefixItems?: JsonSchema[]
1133
1183
  properties?: {
1134
1184
  [K in keyof IN & keyof OUT]: JsonSchema<IN[K], OUT[K]>
1135
1185
  }
@@ -1395,3 +1445,11 @@ type SchemaIn<S> = S extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : nev
1395
1445
  type SchemaOut<S> = S extends JsonSchemaAnyBuilder<any, infer OUT, any> ? OUT : never
1396
1446
  type SchemaOpt<S> =
1397
1447
  S extends JsonSchemaAnyBuilder<any, any, infer Opt> ? (Opt extends true ? true : false) : false
1448
+
1449
+ type TupleIn<T extends readonly JsonSchemaAnyBuilder<any, any, any>[]> = {
1450
+ [K in keyof T]: T[K] extends JsonSchemaAnyBuilder<infer I, any, any> ? I : never
1451
+ }
1452
+
1453
+ type TupleOut<T extends readonly JsonSchemaAnyBuilder<any, any, any>[]> = {
1454
+ [K in keyof T]: T[K] extends JsonSchemaAnyBuilder<any, infer O, any> ? O : never
1455
+ }