@naturalcycles/nodejs-lib 15.51.2 → 15.53.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 +12 -1
- package/dist/validation/ajv/jsonSchemaBuilder.js +31 -4
- package/dist/validation/ajv/jsonSchemaBuilder.util.d.ts +1 -0
- package/dist/validation/ajv/jsonSchemaBuilder.util.js +8 -0
- package/dist/validation/regexes.d.ts +1 -0
- package/dist/validation/regexes.js +2 -0
- package/package.json +1 -1
- package/src/validation/ajv/jsonSchemaBuilder.ts +66 -2
- package/src/validation/ajv/jsonSchemaBuilder.util.ts +9 -0
- package/src/validation/regexes.ts +2 -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>;
|
|
@@ -110,6 +114,7 @@ export declare class JsonSchemaStringBuilder<IN extends string = string, OUT = I
|
|
|
110
114
|
*/
|
|
111
115
|
ianaTimezone(): JsonSchemaEnumBuilder<string | IANATimezone, IANATimezone, false>;
|
|
112
116
|
base64Url(): this;
|
|
117
|
+
uuid(): this;
|
|
113
118
|
}
|
|
114
119
|
export interface JsonSchemaStringEmailOptions {
|
|
115
120
|
checkTLD: boolean;
|
|
@@ -158,7 +163,7 @@ export declare class JsonSchemaBooleanBuilder<IN extends boolean = boolean, OUT
|
|
|
158
163
|
constructor();
|
|
159
164
|
}
|
|
160
165
|
export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends AnyObject, Opt extends boolean = false> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
|
|
161
|
-
constructor(props?: AnyObject);
|
|
166
|
+
constructor(props?: AnyObject, opt?: JsonSchemaObjectBuilderOpts);
|
|
162
167
|
addProperties(props: AnyObject): this;
|
|
163
168
|
/**
|
|
164
169
|
* When set, the validation will not strip away properties that are not specified explicitly in the schema.
|
|
@@ -172,6 +177,9 @@ export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends A
|
|
|
172
177
|
minProperties(minProperties: number): this;
|
|
173
178
|
maxProperties(maxProperties: number): this;
|
|
174
179
|
}
|
|
180
|
+
interface JsonSchemaObjectBuilderOpts {
|
|
181
|
+
hasIsOfTypeCheck?: false;
|
|
182
|
+
}
|
|
175
183
|
export declare class JsonSchemaObjectInferringBuilder<PROPS extends Record<string, JsonSchemaAnyBuilder<any, any, any>>, Opt extends boolean = false> extends JsonSchemaAnyBuilder<Expand<{
|
|
176
184
|
[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
185
|
} & {
|
|
@@ -326,4 +334,7 @@ interface JsonBuilderRuleOpt {
|
|
|
326
334
|
*/
|
|
327
335
|
name?: string;
|
|
328
336
|
}
|
|
337
|
+
type EnumKeyUnion<T> = T extends readonly (infer U)[] ? U : T extends StringEnum | NumberEnum ? T[keyof T] : never;
|
|
338
|
+
type SchemaIn<S> = S extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never;
|
|
339
|
+
type SchemaOut<S> = S extends JsonSchemaAnyBuilder<any, infer OUT, any> ? OUT : never;
|
|
329
340
|
export {};
|
|
@@ -5,9 +5,9 @@ import { _uniq } from '@naturalcycles/js-lib/array';
|
|
|
5
5
|
import { _assert } from '@naturalcycles/js-lib/error';
|
|
6
6
|
import { _deepCopy, _sortObject } from '@naturalcycles/js-lib/object';
|
|
7
7
|
import { _objectAssign, JWT_REGEX, } from '@naturalcycles/js-lib/types';
|
|
8
|
-
import { BASE64URL_REGEX, COUNTRY_CODE_REGEX, CURRENCY_REGEX, IPV4_REGEX, IPV6_REGEX, LANGUAGE_TAG_REGEX, SEMVER_REGEX, SLUG_REGEX, } from '../regexes.js';
|
|
8
|
+
import { BASE64URL_REGEX, COUNTRY_CODE_REGEX, CURRENCY_REGEX, IPV4_REGEX, IPV6_REGEX, LANGUAGE_TAG_REGEX, SEMVER_REGEX, SLUG_REGEX, UUID_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);
|
|
@@ -301,6 +325,9 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
301
325
|
msg: 'contains characters not allowed in Base64 URL characterset',
|
|
302
326
|
});
|
|
303
327
|
}
|
|
328
|
+
uuid() {
|
|
329
|
+
return this.regex(UUID_REGEX, { msg: 'is an invalid UUID' });
|
|
330
|
+
}
|
|
304
331
|
}
|
|
305
332
|
export class JsonSchemaIsoDateBuilder extends JsonSchemaAnyBuilder {
|
|
306
333
|
constructor() {
|
|
@@ -441,13 +468,13 @@ export class JsonSchemaBooleanBuilder extends JsonSchemaAnyBuilder {
|
|
|
441
468
|
}
|
|
442
469
|
}
|
|
443
470
|
export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
|
|
444
|
-
constructor(props) {
|
|
471
|
+
constructor(props, opt) {
|
|
445
472
|
super({
|
|
446
473
|
type: 'object',
|
|
447
474
|
properties: {},
|
|
448
475
|
required: [],
|
|
449
476
|
additionalProperties: false,
|
|
450
|
-
hasIsOfTypeCheck: true,
|
|
477
|
+
hasIsOfTypeCheck: opt?.hasIsOfTypeCheck ?? true,
|
|
451
478
|
});
|
|
452
479
|
if (props)
|
|
453
480
|
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
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const BASE62_REGEX: RegExp;
|
|
2
2
|
export declare const BASE64_REGEX: RegExp;
|
|
3
3
|
export declare const BASE64URL_REGEX: RegExp;
|
|
4
|
+
export declare const UUID_REGEX: RegExp;
|
|
4
5
|
export declare const COUNTRY_CODE_REGEX: RegExp;
|
|
5
6
|
export declare const CURRENCY_REGEX: RegExp;
|
|
6
7
|
/**
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export const BASE62_REGEX = /^[a-zA-Z0-9]+$/;
|
|
2
2
|
export const BASE64_REGEX = /^[a-zA-Z0-9+/]+={0,2}$/;
|
|
3
3
|
export const BASE64URL_REGEX = /^[a-zA-Z0-9_-]+$/;
|
|
4
|
+
// from `ajv-formats`
|
|
5
|
+
export const UUID_REGEX = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i;
|
|
4
6
|
export const COUNTRY_CODE_REGEX = /^[A-Z]{2}$/;
|
|
5
7
|
export const CURRENCY_REGEX = /^[A-Z]{3}$/;
|
|
6
8
|
/**
|
package/package.json
CHANGED
|
@@ -35,10 +35,12 @@ import {
|
|
|
35
35
|
LANGUAGE_TAG_REGEX,
|
|
36
36
|
SEMVER_REGEX,
|
|
37
37
|
SLUG_REGEX,
|
|
38
|
+
UUID_REGEX,
|
|
38
39
|
} from '../regexes.js'
|
|
39
40
|
import { TIMEZONES } from '../timezones.js'
|
|
40
41
|
import {
|
|
41
42
|
isEveryItemNumber,
|
|
43
|
+
isEveryItemPrimitive,
|
|
42
44
|
isEveryItemString,
|
|
43
45
|
JSON_SCHEMA_ORDER,
|
|
44
46
|
mergeJsonSchemaObjects,
|
|
@@ -63,6 +65,48 @@ export const j = {
|
|
|
63
65
|
any() {
|
|
64
66
|
return j.object<AnyObject>({}).allowAdditionalProperties()
|
|
65
67
|
},
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Builds the object schema with the indicated `keys` and uses the `schema` for their validation.
|
|
71
|
+
*/
|
|
72
|
+
withEnumKeys<
|
|
73
|
+
const T extends readonly (string | number)[] | StringEnum | NumberEnum,
|
|
74
|
+
S extends JsonSchemaTerminal<any, any, any>,
|
|
75
|
+
K extends string | number = EnumKeyUnion<T>,
|
|
76
|
+
>(
|
|
77
|
+
keys: T,
|
|
78
|
+
schema: S,
|
|
79
|
+
): JsonSchemaObjectBuilder<Record<K, SchemaIn<S>>, Record<K, SchemaOut<S>>> {
|
|
80
|
+
let enumValues: readonly (string | number)[] | undefined
|
|
81
|
+
if (Array.isArray(keys)) {
|
|
82
|
+
_assert(
|
|
83
|
+
isEveryItemPrimitive(keys),
|
|
84
|
+
'Every item in the key list should be string, number or symbol',
|
|
85
|
+
)
|
|
86
|
+
enumValues = keys
|
|
87
|
+
} else if (typeof keys === 'object') {
|
|
88
|
+
const enumType = getEnumType(keys)
|
|
89
|
+
_assert(
|
|
90
|
+
enumType === 'NumberEnum' || enumType === 'StringEnum',
|
|
91
|
+
'The key list should be StringEnum or NumberEnum',
|
|
92
|
+
)
|
|
93
|
+
if (enumType === 'NumberEnum') {
|
|
94
|
+
enumValues = _numberEnumValues(keys as NumberEnum)
|
|
95
|
+
} else if (enumType === 'StringEnum') {
|
|
96
|
+
enumValues = _stringEnumValues(keys as StringEnum)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_assert(enumValues, 'The key list should be an array of values, NumberEnum or a StrinEnum')
|
|
101
|
+
|
|
102
|
+
const typedValues = enumValues as readonly K[]
|
|
103
|
+
const props = Object.fromEntries(typedValues.map(key => [key, schema])) as any
|
|
104
|
+
|
|
105
|
+
return new JsonSchemaObjectBuilder<Record<K, SchemaIn<S>>, Record<K, SchemaOut<S>>, false>(
|
|
106
|
+
props,
|
|
107
|
+
{ hasIsOfTypeCheck: false },
|
|
108
|
+
)
|
|
109
|
+
},
|
|
66
110
|
}),
|
|
67
111
|
|
|
68
112
|
array<IN, OUT, Opt>(
|
|
@@ -414,6 +458,10 @@ export class JsonSchemaStringBuilder<
|
|
|
414
458
|
msg: 'contains characters not allowed in Base64 URL characterset',
|
|
415
459
|
})
|
|
416
460
|
}
|
|
461
|
+
|
|
462
|
+
uuid(): this {
|
|
463
|
+
return this.regex(UUID_REGEX, { msg: 'is an invalid UUID' })
|
|
464
|
+
}
|
|
417
465
|
}
|
|
418
466
|
|
|
419
467
|
export interface JsonSchemaStringEmailOptions {
|
|
@@ -617,13 +665,13 @@ export class JsonSchemaObjectBuilder<
|
|
|
617
665
|
OUT extends AnyObject,
|
|
618
666
|
Opt extends boolean = false,
|
|
619
667
|
> extends JsonSchemaAnyBuilder<IN, OUT, Opt> {
|
|
620
|
-
constructor(props?: AnyObject) {
|
|
668
|
+
constructor(props?: AnyObject, opt?: JsonSchemaObjectBuilderOpts) {
|
|
621
669
|
super({
|
|
622
670
|
type: 'object',
|
|
623
671
|
properties: {},
|
|
624
672
|
required: [],
|
|
625
673
|
additionalProperties: false,
|
|
626
|
-
hasIsOfTypeCheck: true,
|
|
674
|
+
hasIsOfTypeCheck: opt?.hasIsOfTypeCheck ?? true,
|
|
627
675
|
})
|
|
628
676
|
|
|
629
677
|
if (props) this.addProperties(props)
|
|
@@ -692,6 +740,10 @@ export class JsonSchemaObjectBuilder<
|
|
|
692
740
|
}
|
|
693
741
|
}
|
|
694
742
|
|
|
743
|
+
interface JsonSchemaObjectBuilderOpts {
|
|
744
|
+
hasIsOfTypeCheck?: false
|
|
745
|
+
}
|
|
746
|
+
|
|
695
747
|
export class JsonSchemaObjectInferringBuilder<
|
|
696
748
|
PROPS extends Record<string, JsonSchemaAnyBuilder<any, any, any>>,
|
|
697
749
|
Opt extends boolean = false,
|
|
@@ -1049,3 +1101,15 @@ interface JsonBuilderRuleOpt {
|
|
|
1049
1101
|
*/
|
|
1050
1102
|
name?: string
|
|
1051
1103
|
}
|
|
1104
|
+
|
|
1105
|
+
type EnumKeyUnion<T> =
|
|
1106
|
+
// array of literals -> union of its elements
|
|
1107
|
+
T extends readonly (infer U)[]
|
|
1108
|
+
? U
|
|
1109
|
+
: // enum object -> union of its values
|
|
1110
|
+
T extends StringEnum | NumberEnum
|
|
1111
|
+
? T[keyof T]
|
|
1112
|
+
: never
|
|
1113
|
+
|
|
1114
|
+
type SchemaIn<S> = S extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never
|
|
1115
|
+
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
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export const BASE62_REGEX = /^[a-zA-Z0-9]+$/
|
|
2
2
|
export const BASE64_REGEX = /^[a-zA-Z0-9+/]+={0,2}$/
|
|
3
3
|
export const BASE64URL_REGEX = /^[a-zA-Z0-9_-]+$/
|
|
4
|
+
// from `ajv-formats`
|
|
5
|
+
export const UUID_REGEX = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i
|
|
4
6
|
export const COUNTRY_CODE_REGEX = /^[A-Z]{2}$/
|
|
5
7
|
export const CURRENCY_REGEX = /^[A-Z]{3}$/
|
|
6
8
|
/**
|