@naturalcycles/nodejs-lib 15.78.2 → 15.80.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 { _isBetween, _lazyValue } from '@naturalcycles/js-lib';
|
|
2
|
-
import { Set2 } from '@naturalcycles/js-lib/object';
|
|
2
|
+
import { _mapObject, Set2 } from '@naturalcycles/js-lib/object';
|
|
3
3
|
import { _substringAfterLast } from '@naturalcycles/js-lib/string';
|
|
4
4
|
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
5
5
|
import { validTLDs } from '../tlds.js';
|
|
@@ -477,6 +477,37 @@ export function createAjv(opt) {
|
|
|
477
477
|
return true;
|
|
478
478
|
},
|
|
479
479
|
});
|
|
480
|
+
ajv.addKeyword({
|
|
481
|
+
keyword: 'anyOfBy',
|
|
482
|
+
type: 'object',
|
|
483
|
+
modifying: true,
|
|
484
|
+
errors: false,
|
|
485
|
+
schemaType: 'object',
|
|
486
|
+
compile(config, _parentSchema, _it) {
|
|
487
|
+
const { propertyName, schemaDictionary } = config;
|
|
488
|
+
const isValidFnByKey = _mapObject(schemaDictionary, (key, value) => {
|
|
489
|
+
return [key, ajv.compile(value)];
|
|
490
|
+
});
|
|
491
|
+
function validate(data, ctx) {
|
|
492
|
+
if (typeof data !== 'object' || data === null)
|
|
493
|
+
return true;
|
|
494
|
+
const determinant = data[propertyName];
|
|
495
|
+
const isValidFn = isValidFnByKey[determinant];
|
|
496
|
+
if (!isValidFn) {
|
|
497
|
+
;
|
|
498
|
+
validate.errors = [
|
|
499
|
+
{
|
|
500
|
+
instancePath: ctx?.instancePath ?? '',
|
|
501
|
+
message: `could not find a suitable schema to validate against based on "${propertyName}"`,
|
|
502
|
+
},
|
|
503
|
+
];
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
return isValidFn(data);
|
|
507
|
+
}
|
|
508
|
+
return validate;
|
|
509
|
+
},
|
|
510
|
+
});
|
|
480
511
|
return ajv;
|
|
481
512
|
}
|
|
482
513
|
const monthLengths = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
@@ -54,17 +54,35 @@ export declare const j: {
|
|
|
54
54
|
set<IN, OUT, Opt>(itemSchema: JsonSchemaAnyBuilder<IN, OUT, Opt>): JsonSchemaSet2Builder<IN, OUT, Opt>;
|
|
55
55
|
buffer(): JsonSchemaBufferBuilder;
|
|
56
56
|
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>;
|
|
57
|
+
/**
|
|
58
|
+
* Use only with primitive values, otherwise this function will throw to avoid bugs.
|
|
59
|
+
* To validate objects, use `anyOfBy`.
|
|
60
|
+
*
|
|
61
|
+
* Our Ajv is configured to strip unexpected properties from objects,
|
|
62
|
+
* and since Ajv is mutating the input, this means that it cannot
|
|
63
|
+
* properly validate the same data over multiple schemas.
|
|
64
|
+
*
|
|
65
|
+
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
66
|
+
* Use `oneOf` when schemas are mutually exclusive.
|
|
67
|
+
*/
|
|
57
68
|
oneOf<B extends readonly JsonSchemaAnyBuilder<any, any, boolean>[], IN = BuilderInUnion<B>, OUT = BuilderOutUnion<B>>(items: [...B]): JsonSchemaAnyBuilder<IN, OUT, false>;
|
|
58
69
|
/**
|
|
59
|
-
*
|
|
70
|
+
* Use only with primitive values, otherwise this function will throw to avoid bugs.
|
|
71
|
+
* To validate objects, use `anyOfBy`.
|
|
72
|
+
*
|
|
73
|
+
* Our Ajv is configured to strip unexpected properties from objects,
|
|
74
|
+
* and since Ajv is mutating the input, this means that it cannot
|
|
75
|
+
* properly validate the same data over multiple schemas.
|
|
60
76
|
*
|
|
61
77
|
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
62
78
|
* Use `oneOf` when schemas are mutually exclusive.
|
|
63
79
|
*/
|
|
64
80
|
anyOf<B extends readonly JsonSchemaAnyBuilder<any, any, boolean>[], IN = BuilderInUnion<B>, OUT = BuilderOutUnion<B>>(items: [...B]): JsonSchemaAnyBuilder<IN, OUT, false>;
|
|
81
|
+
anyOfBy<P extends string, D extends Record<PropertyKey, JsonSchemaTerminal<any, any, any>>, IN = AnyOfByIn<D>, OUT = AnyOfByOut<D>>(propertyName: P, schemaDictionary: D): JsonSchemaAnyOfByBuilder<IN, OUT, P>;
|
|
65
82
|
and(): {
|
|
66
83
|
silentBob: () => never;
|
|
67
84
|
};
|
|
85
|
+
literal<const V extends string | number | boolean | null>(v: V): JsonSchemaEnumBuilder<V, V, false>;
|
|
68
86
|
};
|
|
69
87
|
export declare class JsonSchemaTerminal<IN, OUT, Opt> {
|
|
70
88
|
protected schema: JsonSchema;
|
|
@@ -347,6 +365,10 @@ export declare class JsonSchemaTupleBuilder<ITEMS extends JsonSchemaAnyBuilder<a
|
|
|
347
365
|
private readonly _items;
|
|
348
366
|
constructor(items: ITEMS);
|
|
349
367
|
}
|
|
368
|
+
export declare class JsonSchemaAnyOfByBuilder<IN, OUT, _P extends string = string> extends JsonSchemaAnyBuilder<AnyOfByInput<IN, _P> | IN, OUT, false> {
|
|
369
|
+
in: IN;
|
|
370
|
+
constructor(propertyName: string, schemaDictionary: Record<PropertyKey, JsonSchemaTerminal<any, any, any>>);
|
|
371
|
+
}
|
|
350
372
|
type EnumBaseType = 'string' | 'number' | 'other';
|
|
351
373
|
export interface JsonSchema<IN = unknown, OUT = IN> {
|
|
352
374
|
readonly in?: IN;
|
|
@@ -414,6 +436,10 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
|
|
|
414
436
|
keySchema?: JsonSchema;
|
|
415
437
|
minProperties2?: number;
|
|
416
438
|
exclusiveProperties?: (readonly string[])[];
|
|
439
|
+
anyOfBy?: {
|
|
440
|
+
propertyName: string;
|
|
441
|
+
schemaDictionary: Record<string, JsonSchema>;
|
|
442
|
+
};
|
|
417
443
|
}
|
|
418
444
|
declare function object(props: AnyObject): never;
|
|
419
445
|
declare function object<IN extends AnyObject>(props: {
|
|
@@ -475,6 +501,18 @@ type BuilderOutUnion<B extends readonly JsonSchemaAnyBuilder<any, any, any>[]> =
|
|
|
475
501
|
type BuilderInUnion<B extends readonly JsonSchemaAnyBuilder<any, any, any>[]> = {
|
|
476
502
|
[K in keyof B]: B[K] extends JsonSchemaAnyBuilder<infer I, any, any> ? I : never;
|
|
477
503
|
}[number];
|
|
504
|
+
type AnyOfByIn<D extends Record<PropertyKey, JsonSchemaTerminal<any, any, any>>> = {
|
|
505
|
+
[K in keyof D]: D[K] extends JsonSchemaTerminal<infer I, any, any> ? I : never;
|
|
506
|
+
}[keyof D];
|
|
507
|
+
type AnyOfByOut<D extends Record<PropertyKey, JsonSchemaTerminal<any, any, any>>> = {
|
|
508
|
+
[K in keyof D]: D[K] extends JsonSchemaTerminal<any, infer O, any> ? O : never;
|
|
509
|
+
}[keyof D];
|
|
510
|
+
type AnyOfByDiscriminant<IN, P extends string> = IN extends {
|
|
511
|
+
[K in P]: infer V;
|
|
512
|
+
} ? V : never;
|
|
513
|
+
type AnyOfByInput<IN, P extends string, D = AnyOfByDiscriminant<IN, P>> = IN extends unknown ? Omit<Partial<IN>, P> & {
|
|
514
|
+
[K in P]?: D;
|
|
515
|
+
} : never;
|
|
478
516
|
type BuilderFor<T> = JsonSchemaAnyBuilder<any, T, any>;
|
|
479
517
|
interface JsonBuilderRuleOpt {
|
|
480
518
|
/**
|
|
@@ -113,24 +113,45 @@ export const j = {
|
|
|
113
113
|
_assert(enumValues, 'Unsupported enum input');
|
|
114
114
|
return new JsonSchemaEnumBuilder(enumValues, baseType, opt);
|
|
115
115
|
},
|
|
116
|
+
/**
|
|
117
|
+
* Use only with primitive values, otherwise this function will throw to avoid bugs.
|
|
118
|
+
* To validate objects, use `anyOfBy`.
|
|
119
|
+
*
|
|
120
|
+
* Our Ajv is configured to strip unexpected properties from objects,
|
|
121
|
+
* and since Ajv is mutating the input, this means that it cannot
|
|
122
|
+
* properly validate the same data over multiple schemas.
|
|
123
|
+
*
|
|
124
|
+
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
125
|
+
* Use `oneOf` when schemas are mutually exclusive.
|
|
126
|
+
*/
|
|
116
127
|
oneOf(items) {
|
|
117
128
|
const schemas = items.map(b => b.build());
|
|
129
|
+
_assert(schemas.every(hasOnlySchemasForPrimitives), 'Do not use `oneOf` validation with non-primitive types!');
|
|
118
130
|
return new JsonSchemaAnyBuilder({
|
|
119
131
|
oneOf: schemas,
|
|
120
132
|
});
|
|
121
133
|
},
|
|
122
134
|
/**
|
|
123
|
-
*
|
|
135
|
+
* Use only with primitive values, otherwise this function will throw to avoid bugs.
|
|
136
|
+
* To validate objects, use `anyOfBy`.
|
|
137
|
+
*
|
|
138
|
+
* Our Ajv is configured to strip unexpected properties from objects,
|
|
139
|
+
* and since Ajv is mutating the input, this means that it cannot
|
|
140
|
+
* properly validate the same data over multiple schemas.
|
|
124
141
|
*
|
|
125
142
|
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
126
143
|
* Use `oneOf` when schemas are mutually exclusive.
|
|
127
144
|
*/
|
|
128
145
|
anyOf(items) {
|
|
129
146
|
const schemas = items.map(b => b.build());
|
|
147
|
+
_assert(schemas.every(hasOnlySchemasForPrimitives), 'Do not use `anyOf` validation with non-primitive types!');
|
|
130
148
|
return new JsonSchemaAnyBuilder({
|
|
131
149
|
anyOf: schemas,
|
|
132
150
|
});
|
|
133
151
|
},
|
|
152
|
+
anyOfBy(propertyName, schemaDictionary) {
|
|
153
|
+
return new JsonSchemaAnyOfByBuilder(propertyName, schemaDictionary);
|
|
154
|
+
},
|
|
134
155
|
and() {
|
|
135
156
|
return {
|
|
136
157
|
silentBob: () => {
|
|
@@ -138,6 +159,14 @@ export const j = {
|
|
|
138
159
|
},
|
|
139
160
|
};
|
|
140
161
|
},
|
|
162
|
+
literal(v) {
|
|
163
|
+
let baseType = 'other';
|
|
164
|
+
if (typeof v === 'string')
|
|
165
|
+
baseType = 'string';
|
|
166
|
+
if (typeof v === 'number')
|
|
167
|
+
baseType = 'number';
|
|
168
|
+
return new JsonSchemaEnumBuilder([v], baseType);
|
|
169
|
+
},
|
|
141
170
|
};
|
|
142
171
|
const TS_2500 = 16725225600; // 2500-01-01
|
|
143
172
|
const TS_2500_MILLIS = TS_2500 * 1000;
|
|
@@ -792,6 +821,22 @@ export class JsonSchemaTupleBuilder extends JsonSchemaAnyBuilder {
|
|
|
792
821
|
this._items = items;
|
|
793
822
|
}
|
|
794
823
|
}
|
|
824
|
+
export class JsonSchemaAnyOfByBuilder extends JsonSchemaAnyBuilder {
|
|
825
|
+
constructor(propertyName, schemaDictionary) {
|
|
826
|
+
const builtSchemaDictionary = {};
|
|
827
|
+
for (const [key, schema] of Object.entries(schemaDictionary)) {
|
|
828
|
+
builtSchemaDictionary[key] = schema.build();
|
|
829
|
+
}
|
|
830
|
+
super({
|
|
831
|
+
type: 'object',
|
|
832
|
+
hasIsOfTypeCheck: true,
|
|
833
|
+
anyOfBy: {
|
|
834
|
+
propertyName,
|
|
835
|
+
schemaDictionary: builtSchemaDictionary,
|
|
836
|
+
},
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
}
|
|
795
840
|
function object(props) {
|
|
796
841
|
return new JsonSchemaObjectBuilder(props);
|
|
797
842
|
}
|
|
@@ -854,3 +899,18 @@ function withEnumKeys(keys, schema) {
|
|
|
854
899
|
const props = Object.fromEntries(typedValues.map(key => [key, schema]));
|
|
855
900
|
return new JsonSchemaObjectBuilder(props, { hasIsOfTypeCheck: false });
|
|
856
901
|
}
|
|
902
|
+
function hasOnlySchemasForPrimitives(schema) {
|
|
903
|
+
if (Array.isArray(schema.type)) {
|
|
904
|
+
schema.type.every(type => ['string', 'number', 'integer', 'boolean', 'null'].includes(type));
|
|
905
|
+
}
|
|
906
|
+
else if (schema.anyOf) {
|
|
907
|
+
return schema.anyOf.every(hasOnlySchemasForPrimitives);
|
|
908
|
+
}
|
|
909
|
+
else if (schema.oneOf) {
|
|
910
|
+
return schema.oneOf.every(hasOnlySchemasForPrimitives);
|
|
911
|
+
}
|
|
912
|
+
else {
|
|
913
|
+
return !!schema.type && ['string', 'number', 'integer', 'boolean', 'null'].includes(schema.type);
|
|
914
|
+
}
|
|
915
|
+
return false;
|
|
916
|
+
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { _isBetween, _lazyValue } from '@naturalcycles/js-lib'
|
|
2
|
-
import { Set2 } from '@naturalcycles/js-lib/object'
|
|
2
|
+
import { _mapObject, 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
5
|
import { Ajv2020, type Options, type ValidateFunction } from 'ajv/dist/2020.js'
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
JsonSchemaIsoDateOptions,
|
|
9
9
|
JsonSchemaIsoMonthOptions,
|
|
10
10
|
JsonSchemaStringEmailOptions,
|
|
11
|
+
JsonSchemaTerminal,
|
|
11
12
|
} from './jsonSchemaBuilder.js'
|
|
12
13
|
|
|
13
14
|
/* eslint-disable @typescript-eslint/prefer-string-starts-ends-with */
|
|
@@ -542,6 +543,44 @@ export function createAjv(opt?: Options): Ajv2020 {
|
|
|
542
543
|
},
|
|
543
544
|
})
|
|
544
545
|
|
|
546
|
+
ajv.addKeyword({
|
|
547
|
+
keyword: 'anyOfBy',
|
|
548
|
+
type: 'object',
|
|
549
|
+
modifying: true,
|
|
550
|
+
errors: false,
|
|
551
|
+
schemaType: 'object',
|
|
552
|
+
compile(config, _parentSchema, _it) {
|
|
553
|
+
const { propertyName, schemaDictionary } = config
|
|
554
|
+
|
|
555
|
+
const isValidFnByKey: Record<any, ValidateFunction> = _mapObject(
|
|
556
|
+
schemaDictionary as Record<any, JsonSchemaTerminal<any, any, any>>,
|
|
557
|
+
(key, value) => {
|
|
558
|
+
return [key, ajv.compile(value)]
|
|
559
|
+
},
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
function validate(data: AnyObject, ctx: any): boolean {
|
|
563
|
+
if (typeof data !== 'object' || data === null) return true
|
|
564
|
+
|
|
565
|
+
const determinant = data[propertyName]
|
|
566
|
+
const isValidFn = isValidFnByKey[determinant]
|
|
567
|
+
if (!isValidFn) {
|
|
568
|
+
;(validate as any).errors = [
|
|
569
|
+
{
|
|
570
|
+
instancePath: ctx?.instancePath ?? '',
|
|
571
|
+
message: `could not find a suitable schema to validate against based on "${propertyName}"`,
|
|
572
|
+
},
|
|
573
|
+
]
|
|
574
|
+
return false
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return isValidFn(data)
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return validate
|
|
581
|
+
},
|
|
582
|
+
})
|
|
583
|
+
|
|
545
584
|
return ajv
|
|
546
585
|
}
|
|
547
586
|
|
|
@@ -188,19 +188,40 @@ export const j = {
|
|
|
188
188
|
return new JsonSchemaEnumBuilder(enumValues as any, baseType, opt)
|
|
189
189
|
},
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Use only with primitive values, otherwise this function will throw to avoid bugs.
|
|
193
|
+
* To validate objects, use `anyOfBy`.
|
|
194
|
+
*
|
|
195
|
+
* Our Ajv is configured to strip unexpected properties from objects,
|
|
196
|
+
* and since Ajv is mutating the input, this means that it cannot
|
|
197
|
+
* properly validate the same data over multiple schemas.
|
|
198
|
+
*
|
|
199
|
+
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
200
|
+
* Use `oneOf` when schemas are mutually exclusive.
|
|
201
|
+
*/
|
|
191
202
|
oneOf<
|
|
192
203
|
B extends readonly JsonSchemaAnyBuilder<any, any, boolean>[],
|
|
193
204
|
IN = BuilderInUnion<B>,
|
|
194
205
|
OUT = BuilderOutUnion<B>,
|
|
195
206
|
>(items: [...B]): JsonSchemaAnyBuilder<IN, OUT, false> {
|
|
196
207
|
const schemas = items.map(b => b.build())
|
|
208
|
+
_assert(
|
|
209
|
+
schemas.every(hasOnlySchemasForPrimitives),
|
|
210
|
+
'Do not use `oneOf` validation with non-primitive types!',
|
|
211
|
+
)
|
|
212
|
+
|
|
197
213
|
return new JsonSchemaAnyBuilder<IN, OUT, false>({
|
|
198
214
|
oneOf: schemas,
|
|
199
215
|
})
|
|
200
216
|
},
|
|
201
217
|
|
|
202
218
|
/**
|
|
203
|
-
*
|
|
219
|
+
* Use only with primitive values, otherwise this function will throw to avoid bugs.
|
|
220
|
+
* To validate objects, use `anyOfBy`.
|
|
221
|
+
*
|
|
222
|
+
* Our Ajv is configured to strip unexpected properties from objects,
|
|
223
|
+
* and since Ajv is mutating the input, this means that it cannot
|
|
224
|
+
* properly validate the same data over multiple schemas.
|
|
204
225
|
*
|
|
205
226
|
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
206
227
|
* Use `oneOf` when schemas are mutually exclusive.
|
|
@@ -211,11 +232,25 @@ export const j = {
|
|
|
211
232
|
OUT = BuilderOutUnion<B>,
|
|
212
233
|
>(items: [...B]): JsonSchemaAnyBuilder<IN, OUT, false> {
|
|
213
234
|
const schemas = items.map(b => b.build())
|
|
235
|
+
_assert(
|
|
236
|
+
schemas.every(hasOnlySchemasForPrimitives),
|
|
237
|
+
'Do not use `anyOf` validation with non-primitive types!',
|
|
238
|
+
)
|
|
239
|
+
|
|
214
240
|
return new JsonSchemaAnyBuilder<IN, OUT, false>({
|
|
215
241
|
anyOf: schemas,
|
|
216
242
|
})
|
|
217
243
|
},
|
|
218
244
|
|
|
245
|
+
anyOfBy<
|
|
246
|
+
P extends string,
|
|
247
|
+
D extends Record<PropertyKey, JsonSchemaTerminal<any, any, any>>,
|
|
248
|
+
IN = AnyOfByIn<D>,
|
|
249
|
+
OUT = AnyOfByOut<D>,
|
|
250
|
+
>(propertyName: P, schemaDictionary: D): JsonSchemaAnyOfByBuilder<IN, OUT, P> {
|
|
251
|
+
return new JsonSchemaAnyOfByBuilder<IN, OUT, P>(propertyName, schemaDictionary)
|
|
252
|
+
},
|
|
253
|
+
|
|
219
254
|
and() {
|
|
220
255
|
return {
|
|
221
256
|
silentBob: () => {
|
|
@@ -223,6 +258,13 @@ export const j = {
|
|
|
223
258
|
},
|
|
224
259
|
}
|
|
225
260
|
},
|
|
261
|
+
|
|
262
|
+
literal<const V extends string | number | boolean | null>(v: V) {
|
|
263
|
+
let baseType: EnumBaseType = 'other'
|
|
264
|
+
if (typeof v === 'string') baseType = 'string'
|
|
265
|
+
if (typeof v === 'number') baseType = 'number'
|
|
266
|
+
return new JsonSchemaEnumBuilder<V>([v], baseType)
|
|
267
|
+
},
|
|
226
268
|
}
|
|
227
269
|
|
|
228
270
|
const TS_2500 = 16725225600 // 2500-01-01
|
|
@@ -1197,6 +1239,34 @@ export class JsonSchemaTupleBuilder<
|
|
|
1197
1239
|
}
|
|
1198
1240
|
}
|
|
1199
1241
|
|
|
1242
|
+
export class JsonSchemaAnyOfByBuilder<
|
|
1243
|
+
IN,
|
|
1244
|
+
OUT,
|
|
1245
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1246
|
+
_P extends string = string,
|
|
1247
|
+
> extends JsonSchemaAnyBuilder<AnyOfByInput<IN, _P> | IN, OUT, false> {
|
|
1248
|
+
declare in: IN
|
|
1249
|
+
|
|
1250
|
+
constructor(
|
|
1251
|
+
propertyName: string,
|
|
1252
|
+
schemaDictionary: Record<PropertyKey, JsonSchemaTerminal<any, any, any>>,
|
|
1253
|
+
) {
|
|
1254
|
+
const builtSchemaDictionary: Record<string, JsonSchema> = {}
|
|
1255
|
+
for (const [key, schema] of Object.entries(schemaDictionary)) {
|
|
1256
|
+
builtSchemaDictionary[key] = schema.build()
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
super({
|
|
1260
|
+
type: 'object',
|
|
1261
|
+
hasIsOfTypeCheck: true,
|
|
1262
|
+
anyOfBy: {
|
|
1263
|
+
propertyName,
|
|
1264
|
+
schemaDictionary: builtSchemaDictionary,
|
|
1265
|
+
},
|
|
1266
|
+
})
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1200
1270
|
type EnumBaseType = 'string' | 'number' | 'other'
|
|
1201
1271
|
|
|
1202
1272
|
export interface JsonSchema<IN = unknown, OUT = IN> {
|
|
@@ -1276,6 +1346,10 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
|
|
|
1276
1346
|
keySchema?: JsonSchema
|
|
1277
1347
|
minProperties2?: number
|
|
1278
1348
|
exclusiveProperties?: (readonly string[])[]
|
|
1349
|
+
anyOfBy?: {
|
|
1350
|
+
propertyName: string
|
|
1351
|
+
schemaDictionary: Record<string, JsonSchema>
|
|
1352
|
+
}
|
|
1279
1353
|
}
|
|
1280
1354
|
|
|
1281
1355
|
function object(props: AnyObject): never
|
|
@@ -1441,6 +1515,20 @@ function withEnumKeys<
|
|
|
1441
1515
|
>(props, { hasIsOfTypeCheck: false })
|
|
1442
1516
|
}
|
|
1443
1517
|
|
|
1518
|
+
function hasOnlySchemasForPrimitives(schema: JsonSchema): boolean {
|
|
1519
|
+
if (Array.isArray(schema.type)) {
|
|
1520
|
+
schema.type.every(type => ['string', 'number', 'integer', 'boolean', 'null'].includes(type))
|
|
1521
|
+
} else if (schema.anyOf) {
|
|
1522
|
+
return schema.anyOf.every(hasOnlySchemasForPrimitives)
|
|
1523
|
+
} else if (schema.oneOf) {
|
|
1524
|
+
return schema.oneOf.every(hasOnlySchemasForPrimitives)
|
|
1525
|
+
} else {
|
|
1526
|
+
return !!schema.type && ['string', 'number', 'integer', 'boolean', 'null'].includes(schema.type)
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
return false
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1444
1532
|
type Expand<T> = { [K in keyof T]: T[K] }
|
|
1445
1533
|
|
|
1446
1534
|
type StripIndexSignatureDeep<T> = T extends readonly unknown[]
|
|
@@ -1504,6 +1592,20 @@ type BuilderInUnion<B extends readonly JsonSchemaAnyBuilder<any, any, any>[]> =
|
|
|
1504
1592
|
[K in keyof B]: B[K] extends JsonSchemaAnyBuilder<infer I, any, any> ? I : never
|
|
1505
1593
|
}[number]
|
|
1506
1594
|
|
|
1595
|
+
type AnyOfByIn<D extends Record<PropertyKey, JsonSchemaTerminal<any, any, any>>> = {
|
|
1596
|
+
[K in keyof D]: D[K] extends JsonSchemaTerminal<infer I, any, any> ? I : never
|
|
1597
|
+
}[keyof D]
|
|
1598
|
+
|
|
1599
|
+
type AnyOfByOut<D extends Record<PropertyKey, JsonSchemaTerminal<any, any, any>>> = {
|
|
1600
|
+
[K in keyof D]: D[K] extends JsonSchemaTerminal<any, infer O, any> ? O : never
|
|
1601
|
+
}[keyof D]
|
|
1602
|
+
|
|
1603
|
+
type AnyOfByDiscriminant<IN, P extends string> = IN extends { [K in P]: infer V } ? V : never
|
|
1604
|
+
|
|
1605
|
+
type AnyOfByInput<IN, P extends string, D = AnyOfByDiscriminant<IN, P>> = IN extends unknown
|
|
1606
|
+
? Omit<Partial<IN>, P> & { [K in P]?: D }
|
|
1607
|
+
: never
|
|
1608
|
+
|
|
1507
1609
|
type BuilderFor<T> = JsonSchemaAnyBuilder<any, T, any>
|
|
1508
1610
|
|
|
1509
1611
|
interface JsonBuilderRuleOpt {
|