@naturalcycles/nodejs-lib 15.72.2 → 15.74.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 +7 -0
- package/dist/validation/ajv/jsonSchemaBuilder.js +18 -4
- package/dist/validation/regexes.d.ts +1 -0
- package/dist/validation/regexes.js +4 -0
- package/package.json +1 -1
- package/src/validation/ajv/jsonSchemaBuilder.ts +29 -4
- package/src/validation/regexes.ts +5 -0
|
@@ -50,6 +50,13 @@ export declare const j: {
|
|
|
50
50
|
buffer(): JsonSchemaBufferBuilder;
|
|
51
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>;
|
|
52
52
|
oneOf<B extends readonly JsonSchemaAnyBuilder<any, any, boolean>[], IN = BuilderInUnion<B>, OUT = BuilderOutUnion<B>>(items: [...B]): JsonSchemaAnyBuilder<IN, OUT, false>;
|
|
53
|
+
/**
|
|
54
|
+
* Value must match at least one of the provided schemas.
|
|
55
|
+
*
|
|
56
|
+
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
57
|
+
* Use `oneOf` when schemas are mutually exclusive.
|
|
58
|
+
*/
|
|
59
|
+
anyOf<B extends readonly JsonSchemaAnyBuilder<any, any, boolean>[], IN = BuilderInUnion<B>, OUT = BuilderOutUnion<B>>(items: [...B]): JsonSchemaAnyBuilder<IN, OUT, false>;
|
|
53
60
|
and(): {
|
|
54
61
|
silentBob: () => never;
|
|
55
62
|
};
|
|
@@ -5,7 +5,7 @@ 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, UUID_REGEX, } from '../regexes.js';
|
|
8
|
+
import { BASE64URL_REGEX, COUNTRY_CODE_REGEX, CURRENCY_REGEX, IPV4_REGEX, IPV6_REGEX, LANGUAGE_TAG_REGEX, SEMVER_REGEX, SLUG_REGEX, URL_REGEX, UUID_REGEX, } from '../regexes.js';
|
|
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 = {
|
|
@@ -112,6 +112,18 @@ export const j = {
|
|
|
112
112
|
oneOf: schemas,
|
|
113
113
|
});
|
|
114
114
|
},
|
|
115
|
+
/**
|
|
116
|
+
* Value must match at least one of the provided schemas.
|
|
117
|
+
*
|
|
118
|
+
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
119
|
+
* Use `oneOf` when schemas are mutually exclusive.
|
|
120
|
+
*/
|
|
121
|
+
anyOf(items) {
|
|
122
|
+
const schemas = items.map(b => b.build());
|
|
123
|
+
return new JsonSchemaAnyBuilder({
|
|
124
|
+
anyOf: schemas,
|
|
125
|
+
});
|
|
126
|
+
},
|
|
115
127
|
and() {
|
|
116
128
|
return {
|
|
117
129
|
silentBob: () => {
|
|
@@ -266,6 +278,7 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
266
278
|
return newBuilder;
|
|
267
279
|
}
|
|
268
280
|
regex(pattern, opt) {
|
|
281
|
+
_assert(!pattern.flags, `Regex flags are not supported by JSON Schema. Received: /${pattern.source}/${pattern.flags}`);
|
|
269
282
|
return this.pattern(pattern.source, opt);
|
|
270
283
|
}
|
|
271
284
|
pattern(pattern, opt) {
|
|
@@ -336,9 +349,7 @@ export class JsonSchemaStringBuilder extends JsonSchemaAnyBuilder {
|
|
|
336
349
|
return this.regex(JWT_REGEX, { msg: 'is not a valid JWT format' });
|
|
337
350
|
}
|
|
338
351
|
url() {
|
|
339
|
-
|
|
340
|
-
const regex = /^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u{00A1}-\u{FFFF}]+-)*[a-z0-9\u{00A1}-\u{FFFF}]+)(?:\.(?:[a-z0-9\u{00A1}-\u{FFFF}]+-)*[a-z0-9\u{00A1}-\u{FFFF}]+)*(?:\.(?:[a-z\u{00A1}-\u{FFFF}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu;
|
|
341
|
-
return this.regex(regex, { msg: 'is not a valid URL format' });
|
|
352
|
+
return this.regex(URL_REGEX, { msg: 'is not a valid URL format' });
|
|
342
353
|
}
|
|
343
354
|
ipv4() {
|
|
344
355
|
return this.regex(IPV4_REGEX, { msg: 'is not a valid IPv4 format' });
|
|
@@ -795,6 +806,9 @@ function record(keySchema, valueSchema) {
|
|
|
795
806
|
});
|
|
796
807
|
}
|
|
797
808
|
function withRegexKeys(keyRegex, schema) {
|
|
809
|
+
if (keyRegex instanceof RegExp) {
|
|
810
|
+
_assert(!keyRegex.flags, `Regex flags are not supported by JSON Schema. Received: /${keyRegex.source}/${keyRegex.flags}`);
|
|
811
|
+
}
|
|
798
812
|
const pattern = keyRegex instanceof RegExp ? keyRegex.source : keyRegex;
|
|
799
813
|
const jsonSchema = schema.build();
|
|
800
814
|
return new JsonSchemaObjectBuilder([], {
|
|
@@ -23,3 +23,7 @@ export const LANGUAGE_TAG_REGEX = /^[a-z]{2}(-[A-Z]{2})?$/;
|
|
|
23
23
|
export const MAC_ADDRESS_REGEX = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
|
24
24
|
export const SEMVER_REGEX = /^[0-9]+\.[0-9]+\.[0-9]+$/;
|
|
25
25
|
export const SLUG_REGEX = /^[a-z0-9-]+$/;
|
|
26
|
+
// URL regex based on `ajv-formats`, but without flags for JSON Schema compatibility.
|
|
27
|
+
// Uses [a-zA-Z] instead of [a-z] with i flag. Simplified to not require unicode flag.
|
|
28
|
+
// Without the unicode flag - it DOES NOT support urls like https://münchen.de
|
|
29
|
+
export const URL_REGEX = /^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-zA-Z0-9]+-)*[a-zA-Z0-9]+)(?:\.(?:[a-zA-Z0-9]+-)*[a-zA-Z0-9]+)*(?:\.(?:[a-zA-Z]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/;
|
package/package.json
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
LANGUAGE_TAG_REGEX,
|
|
37
37
|
SEMVER_REGEX,
|
|
38
38
|
SLUG_REGEX,
|
|
39
|
+
URL_REGEX,
|
|
39
40
|
UUID_REGEX,
|
|
40
41
|
} from '../regexes.js'
|
|
41
42
|
import { TIMEZONES } from '../timezones.js'
|
|
@@ -190,6 +191,23 @@ export const j = {
|
|
|
190
191
|
})
|
|
191
192
|
},
|
|
192
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Value must match at least one of the provided schemas.
|
|
196
|
+
*
|
|
197
|
+
* Use `anyOf` when schemas may overlap (e.g., AccountId | PartnerId with same format).
|
|
198
|
+
* Use `oneOf` when schemas are mutually exclusive.
|
|
199
|
+
*/
|
|
200
|
+
anyOf<
|
|
201
|
+
B extends readonly JsonSchemaAnyBuilder<any, any, boolean>[],
|
|
202
|
+
IN = BuilderInUnion<B>,
|
|
203
|
+
OUT = BuilderOutUnion<B>,
|
|
204
|
+
>(items: [...B]): JsonSchemaAnyBuilder<IN, OUT, false> {
|
|
205
|
+
const schemas = items.map(b => b.build())
|
|
206
|
+
return new JsonSchemaAnyBuilder<IN, OUT, false>({
|
|
207
|
+
anyOf: schemas,
|
|
208
|
+
})
|
|
209
|
+
},
|
|
210
|
+
|
|
193
211
|
and() {
|
|
194
212
|
return {
|
|
195
213
|
silentBob: () => {
|
|
@@ -388,6 +406,10 @@ export class JsonSchemaStringBuilder<
|
|
|
388
406
|
}
|
|
389
407
|
|
|
390
408
|
regex(pattern: RegExp, opt?: JsonBuilderRuleOpt): this {
|
|
409
|
+
_assert(
|
|
410
|
+
!pattern.flags,
|
|
411
|
+
`Regex flags are not supported by JSON Schema. Received: /${pattern.source}/${pattern.flags}`,
|
|
412
|
+
)
|
|
391
413
|
return this.pattern(pattern.source, opt)
|
|
392
414
|
}
|
|
393
415
|
|
|
@@ -473,10 +495,7 @@ export class JsonSchemaStringBuilder<
|
|
|
473
495
|
}
|
|
474
496
|
|
|
475
497
|
url(): this {
|
|
476
|
-
|
|
477
|
-
const regex =
|
|
478
|
-
/^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u{00A1}-\u{FFFF}]+-)*[a-z0-9\u{00A1}-\u{FFFF}]+)(?:\.(?:[a-z0-9\u{00A1}-\u{FFFF}]+-)*[a-z0-9\u{00A1}-\u{FFFF}]+)*(?:\.(?:[a-z\u{00A1}-\u{FFFF}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu
|
|
479
|
-
return this.regex(regex, { msg: 'is not a valid URL format' })
|
|
498
|
+
return this.regex(URL_REGEX, { msg: 'is not a valid URL format' })
|
|
480
499
|
}
|
|
481
500
|
|
|
482
501
|
ipv4(): this {
|
|
@@ -1336,6 +1355,12 @@ function withRegexKeys<
|
|
|
1336
1355
|
Opt extends true ? StringMap<SchemaOut<S>> : StringMap<SchemaOut<S>>,
|
|
1337
1356
|
false
|
|
1338
1357
|
> {
|
|
1358
|
+
if (keyRegex instanceof RegExp) {
|
|
1359
|
+
_assert(
|
|
1360
|
+
!keyRegex.flags,
|
|
1361
|
+
`Regex flags are not supported by JSON Schema. Received: /${keyRegex.source}/${keyRegex.flags}`,
|
|
1362
|
+
)
|
|
1363
|
+
}
|
|
1339
1364
|
const pattern = keyRegex instanceof RegExp ? keyRegex.source : keyRegex
|
|
1340
1365
|
const jsonSchema = schema.build()
|
|
1341
1366
|
|
|
@@ -24,3 +24,8 @@ export const LANGUAGE_TAG_REGEX = /^[a-z]{2}(-[A-Z]{2})?$/
|
|
|
24
24
|
export const MAC_ADDRESS_REGEX = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/
|
|
25
25
|
export const SEMVER_REGEX = /^[0-9]+\.[0-9]+\.[0-9]+$/
|
|
26
26
|
export const SLUG_REGEX = /^[a-z0-9-]+$/
|
|
27
|
+
// URL regex based on `ajv-formats`, but without flags for JSON Schema compatibility.
|
|
28
|
+
// Uses [a-zA-Z] instead of [a-z] with i flag. Simplified to not require unicode flag.
|
|
29
|
+
// Without the unicode flag - it DOES NOT support urls like https://münchen.de
|
|
30
|
+
export const URL_REGEX =
|
|
31
|
+
/^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-zA-Z0-9]+-)*[a-zA-Z0-9]+)(?:\.(?:[a-zA-Z0-9]+-)*[a-zA-Z0-9]+)*(?:\.(?:[a-zA-Z]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/
|