@naturalcycles/nodejs-lib 15.51.2 → 15.52.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.
- package/dist/validation/ajv/jsonSchemaBuilder.d.ts +11 -1
- package/dist/validation/ajv/jsonSchemaBuilder.js +27 -3
- package/dist/validation/ajv/jsonSchemaBuilder.util.d.ts +1 -0
- package/dist/validation/ajv/jsonSchemaBuilder.util.js +8 -0
- package/package.json +1 -1
- package/src/validation/ajv/jsonSchemaBuilder.ts +61 -2
- package/src/validation/ajv/jsonSchemaBuilder.util.ts +9 -0
|
@@ -8,6 +8,10 @@ export declare const j: {
|
|
|
8
8
|
dbEntity: typeof objectDbEntity;
|
|
9
9
|
infer: typeof objectInfer;
|
|
10
10
|
any(): JsonSchemaObjectBuilder<AnyObject, AnyObject, false>;
|
|
11
|
+
/**
|
|
12
|
+
* Builds the object schema with the indicated `keys` and uses the `schema` for their validation.
|
|
13
|
+
*/
|
|
14
|
+
withEnumKeys<const T extends readonly (string | number)[] | StringEnum | NumberEnum, S extends JsonSchemaTerminal<any, any, any>, K extends string | number = EnumKeyUnion<T>>(keys: T, schema: S): JsonSchemaObjectBuilder<Record<K, SchemaIn<S>>, Record<K, SchemaOut<S>>>;
|
|
11
15
|
};
|
|
12
16
|
array<IN, OUT, Opt>(itemSchema: JsonSchemaAnyBuilder<IN, OUT, Opt>): JsonSchemaArrayBuilder<IN, OUT, Opt>;
|
|
13
17
|
set<IN, OUT, Opt>(itemSchema: JsonSchemaAnyBuilder<IN, OUT, Opt>): JsonSchemaSet2Builder<IN, OUT, Opt>;
|
|
@@ -158,7 +162,7 @@ export declare class JsonSchemaBooleanBuilder<IN extends boolean = boolean, OUT
|
|
|
158
162
|
constructor();
|
|
159
163
|
}
|
|
160
164
|
export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends AnyObject, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
|
|
161
|
-
constructor(props?: AnyObject);
|
|
165
|
+
constructor(props?: AnyObject, opt?: JsonSchemaObjectBuilderOpts);
|
|
162
166
|
addProperties(props: AnyObject): this;
|
|
163
167
|
/**
|
|
164
168
|
* When set, the validation will not strip away properties that are not specified explicitly in the schema.
|
|
@@ -172,6 +176,9 @@ export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends A
|
|
|
172
176
|
minProperties(minProperties: number): this;
|
|
173
177
|
maxProperties(maxProperties: number): this;
|
|
174
178
|
}
|
|
179
|
+
interface JsonSchemaObjectBuilderOpts {
|
|
180
|
+
hasIsOfTypeCheck?: false;
|
|
181
|
+
}
|
|
175
182
|
export declare class JsonSchemaObjectInferringBuilder<PROPS extends Record<string, JsonSchemaAnyBuilder<any, any, any>>, Opt extends boolean = false> extends JsonSchemaAnyBuilder<Expand<{
|
|
176
183
|
[K in keyof PROPS as PROPS[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt> ? IsOpt extends true ? never : K : never]: PROPS[K] extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never;
|
|
177
184
|
} & {
|
|
@@ -326,4 +333,7 @@ interface JsonBuilderRuleOpt {
|
|
|
326
333
|
*/
|
|
327
334
|
name?: string;
|
|
328
335
|
}
|
|
336
|
+
type EnumKeyUnion<T> = T extends readonly (infer U)[] ? U : T extends StringEnum | NumberEnum ? T[keyof T] : never;
|
|
337
|
+
type SchemaIn<S> = S extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never;
|
|
338
|
+
type SchemaOut<S> = S extends JsonSchemaAnyBuilder<any, infer OUT, any> ? OUT : never;
|
|
329
339
|
export {};
|
|
@@ -7,7 +7,7 @@ import { _deepCopy, _sortObject } from '@naturalcycles/js-lib/object';
|
|
|
7
7
|
import { _objectAssign, 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, } from '../regexes.js';
|
|
9
9
|
import { TIMEZONES } from '../timezones.js';
|
|
10
|
-
import { isEveryItemNumber, isEveryItemString, JSON_SCHEMA_ORDER, mergeJsonSchemaObjects, } from './jsonSchemaBuilder.util.js';
|
|
10
|
+
import { isEveryItemNumber, isEveryItemPrimitive, isEveryItemString, JSON_SCHEMA_ORDER, mergeJsonSchemaObjects, } from './jsonSchemaBuilder.util.js';
|
|
11
11
|
export const j = {
|
|
12
12
|
string() {
|
|
13
13
|
return new JsonSchemaStringBuilder();
|
|
@@ -24,6 +24,30 @@ export const j = {
|
|
|
24
24
|
any() {
|
|
25
25
|
return j.object({}).allowAdditionalProperties();
|
|
26
26
|
},
|
|
27
|
+
/**
|
|
28
|
+
* Builds the object schema with the indicated `keys` and uses the `schema` for their validation.
|
|
29
|
+
*/
|
|
30
|
+
withEnumKeys(keys, schema) {
|
|
31
|
+
let enumValues;
|
|
32
|
+
if (Array.isArray(keys)) {
|
|
33
|
+
_assert(isEveryItemPrimitive(keys), 'Every item in the key list should be string, number or symbol');
|
|
34
|
+
enumValues = keys;
|
|
35
|
+
}
|
|
36
|
+
else if (typeof keys === 'object') {
|
|
37
|
+
const enumType = getEnumType(keys);
|
|
38
|
+
_assert(enumType === 'NumberEnum' || enumType === 'StringEnum', 'The key list should be StringEnum or NumberEnum');
|
|
39
|
+
if (enumType === 'NumberEnum') {
|
|
40
|
+
enumValues = _numberEnumValues(keys);
|
|
41
|
+
}
|
|
42
|
+
else if (enumType === 'StringEnum') {
|
|
43
|
+
enumValues = _stringEnumValues(keys);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
_assert(enumValues, 'The key list should be an array of values, NumberEnum or a StrinEnum');
|
|
47
|
+
const typedValues = enumValues;
|
|
48
|
+
const props = Object.fromEntries(typedValues.map(key => [key, schema]));
|
|
49
|
+
return new JsonSchemaObjectBuilder(props, { hasIsOfTypeCheck: false });
|
|
50
|
+
},
|
|
27
51
|
}),
|
|
28
52
|
array(itemSchema) {
|
|
29
53
|
return new JsonSchemaArrayBuilder(itemSchema);
|
|
@@ -441,13 +465,13 @@ export class JsonSchemaBooleanBuilder extends JsonSchemaAnyBuilder {
|
|
|
441
465
|
}
|
|
442
466
|
}
|
|
443
467
|
export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
|
|
444
|
-
constructor(props) {
|
|
468
|
+
constructor(props, opt) {
|
|
445
469
|
super({
|
|
446
470
|
type: 'object',
|
|
447
471
|
properties: {},
|
|
448
472
|
required: [],
|
|
449
473
|
additionalProperties: false,
|
|
450
|
-
hasIsOfTypeCheck: true,
|
|
474
|
+
hasIsOfTypeCheck: opt?.hasIsOfTypeCheck ?? true,
|
|
451
475
|
});
|
|
452
476
|
if (props)
|
|
453
477
|
this.addProperties(props);
|
|
@@ -9,3 +9,4 @@ export declare const JSON_SCHEMA_ORDER: string[];
|
|
|
9
9
|
export declare function mergeJsonSchemaObjects<T1 extends AnyObject, T2 extends AnyObject>(schema1: JsonSchema<T1>, schema2: JsonSchema<T2>): JsonSchema<T1 & T2>;
|
|
10
10
|
export declare function isEveryItemString(arr: any[]): boolean;
|
|
11
11
|
export declare function isEveryItemNumber(arr: any[]): boolean;
|
|
12
|
+
export declare function isEveryItemPrimitive(arr: any[]): boolean;
|
|
@@ -77,3 +77,11 @@ export function isEveryItemNumber(arr) {
|
|
|
77
77
|
}
|
|
78
78
|
return true;
|
|
79
79
|
}
|
|
80
|
+
export function isEveryItemPrimitive(arr) {
|
|
81
|
+
for (const item of arr) {
|
|
82
|
+
if (typeof item !== 'number' && typeof item !== 'string' && typeof item !== 'symbol') {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
package/package.json
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
import { TIMEZONES } from '../timezones.js'
|
|
40
40
|
import {
|
|
41
41
|
isEveryItemNumber,
|
|
42
|
+
isEveryItemPrimitive,
|
|
42
43
|
isEveryItemString,
|
|
43
44
|
JSON_SCHEMA_ORDER,
|
|
44
45
|
mergeJsonSchemaObjects,
|
|
@@ -63,6 +64,48 @@ export const j = {
|
|
|
63
64
|
any() {
|
|
64
65
|
return j.object<AnyObject>({}).allowAdditionalProperties()
|
|
65
66
|
},
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Builds the object schema with the indicated `keys` and uses the `schema` for their validation.
|
|
70
|
+
*/
|
|
71
|
+
withEnumKeys<
|
|
72
|
+
const T extends readonly (string | number)[] | StringEnum | NumberEnum,
|
|
73
|
+
S extends JsonSchemaTerminal<any, any, any>,
|
|
74
|
+
K extends string | number = EnumKeyUnion<T>,
|
|
75
|
+
>(
|
|
76
|
+
keys: T,
|
|
77
|
+
schema: S,
|
|
78
|
+
): JsonSchemaObjectBuilder<Record<K, SchemaIn<S>>, Record<K, SchemaOut<S>>> {
|
|
79
|
+
let enumValues: readonly (string | number)[] | undefined
|
|
80
|
+
if (Array.isArray(keys)) {
|
|
81
|
+
_assert(
|
|
82
|
+
isEveryItemPrimitive(keys),
|
|
83
|
+
'Every item in the key list should be string, number or symbol',
|
|
84
|
+
)
|
|
85
|
+
enumValues = keys
|
|
86
|
+
} else if (typeof keys === 'object') {
|
|
87
|
+
const enumType = getEnumType(keys)
|
|
88
|
+
_assert(
|
|
89
|
+
enumType === 'NumberEnum' || enumType === 'StringEnum',
|
|
90
|
+
'The key list should be StringEnum or NumberEnum',
|
|
91
|
+
)
|
|
92
|
+
if (enumType === 'NumberEnum') {
|
|
93
|
+
enumValues = _numberEnumValues(keys as NumberEnum)
|
|
94
|
+
} else if (enumType === 'StringEnum') {
|
|
95
|
+
enumValues = _stringEnumValues(keys as StringEnum)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
_assert(enumValues, 'The key list should be an array of values, NumberEnum or a StrinEnum')
|
|
100
|
+
|
|
101
|
+
const typedValues = enumValues as readonly K[]
|
|
102
|
+
const props = Object.fromEntries(typedValues.map(key => [key, schema])) as any
|
|
103
|
+
|
|
104
|
+
return new JsonSchemaObjectBuilder<Record<K, SchemaIn<S>>, Record<K, SchemaOut<S>>, false>(
|
|
105
|
+
props,
|
|
106
|
+
{ hasIsOfTypeCheck: false },
|
|
107
|
+
)
|
|
108
|
+
},
|
|
66
109
|
}),
|
|
67
110
|
|
|
68
111
|
array<IN, OUT, Opt>(
|
|
@@ -617,13 +660,13 @@ export class JsonSchemaObjectBuilder<
|
|
|
617
660
|
OUT extends AnyObject,
|
|
618
661
|
Opt extends boolean = false,
|
|
619
662
|
> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
|
|
620
|
-
constructor(props?: AnyObject) {
|
|
663
|
+
constructor(props?: AnyObject, opt?: JsonSchemaObjectBuilderOpts) {
|
|
621
664
|
super({
|
|
622
665
|
type: 'object',
|
|
623
666
|
properties: {},
|
|
624
667
|
required: [],
|
|
625
668
|
additionalProperties: false,
|
|
626
|
-
hasIsOfTypeCheck: true,
|
|
669
|
+
hasIsOfTypeCheck: opt?.hasIsOfTypeCheck ?? true,
|
|
627
670
|
})
|
|
628
671
|
|
|
629
672
|
if (props) this.addProperties(props)
|
|
@@ -692,6 +735,10 @@ export class JsonSchemaObjectBuilder<
|
|
|
692
735
|
}
|
|
693
736
|
}
|
|
694
737
|
|
|
738
|
+
interface JsonSchemaObjectBuilderOpts {
|
|
739
|
+
hasIsOfTypeCheck?: false
|
|
740
|
+
}
|
|
741
|
+
|
|
695
742
|
export class JsonSchemaObjectInferringBuilder<
|
|
696
743
|
PROPS extends Record<string, JsonSchemaAnyBuilder<any, any, any>>,
|
|
697
744
|
Opt extends boolean = false,
|
|
@@ -1049,3 +1096,15 @@ interface JsonBuilderRuleOpt {
|
|
|
1049
1096
|
*/
|
|
1050
1097
|
name?: string
|
|
1051
1098
|
}
|
|
1099
|
+
|
|
1100
|
+
type EnumKeyUnion<T> =
|
|
1101
|
+
// array of literals -> union of its elements
|
|
1102
|
+
T extends readonly (infer U)[]
|
|
1103
|
+
? U
|
|
1104
|
+
: // enum object -> union of its values
|
|
1105
|
+
T extends StringEnum | NumberEnum
|
|
1106
|
+
? T[keyof T]
|
|
1107
|
+
: never
|
|
1108
|
+
|
|
1109
|
+
type SchemaIn<S> = S extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never
|
|
1110
|
+
type SchemaOut<S> = S extends JsonSchemaAnyBuilder<any, infer OUT, any> ? OUT : never
|
|
@@ -90,3 +90,12 @@ export function isEveryItemNumber(arr: any[]): boolean {
|
|
|
90
90
|
}
|
|
91
91
|
return true
|
|
92
92
|
}
|
|
93
|
+
|
|
94
|
+
export function isEveryItemPrimitive(arr: any[]): boolean {
|
|
95
|
+
for (const item of arr) {
|
|
96
|
+
if (typeof item !== 'number' && typeof item !== 'string' && typeof item !== 'symbol') {
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return true
|
|
101
|
+
}
|