@naturalcycles/nodejs-lib 15.89.0 → 15.90.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 +1 -1
- package/dist/validation/ajv/jsonSchemaBuilder.js +2 -4
- package/package.json +1 -3
- package/src/validation/ajv/jsonSchemaBuilder.ts +4 -5
- package/dist/validation/joi/index.d.ts +0 -9
- package/dist/validation/joi/index.js +0 -5
- package/dist/validation/joi/joi.extensions.d.ts +0 -11
- package/dist/validation/joi/joi.extensions.js +0 -25
- package/dist/validation/joi/joi.model.d.ts +0 -7
- package/dist/validation/joi/joi.model.js +0 -5
- package/dist/validation/joi/joi.shared.schemas.d.ts +0 -91
- package/dist/validation/joi/joi.shared.schemas.js +0 -135
- package/dist/validation/joi/joi.validation.error.d.ts +0 -29
- package/dist/validation/joi/joi.validation.error.js +0 -8
- package/dist/validation/joi/joi.validation.util.d.ts +0 -33
- package/dist/validation/joi/joi.validation.util.js +0 -139
- package/dist/validation/joi/number.extensions.d.ts +0 -6
- package/dist/validation/joi/number.extensions.js +0 -38
- package/dist/validation/joi/string.extensions.d.ts +0 -11
- package/dist/validation/joi/string.extensions.js +0 -104
- package/src/validation/joi/index.ts +0 -32
- package/src/validation/joi/joi.extensions.ts +0 -38
- package/src/validation/joi/joi.model.ts +0 -12
- package/src/validation/joi/joi.shared.schemas.ts +0 -207
- package/src/validation/joi/joi.validation.error.ts +0 -35
- package/src/validation/joi/joi.validation.util.ts +0 -183
- package/src/validation/joi/number.extensions.ts +0 -46
- package/src/validation/joi/string.extensions.ts +0 -129
|
@@ -254,7 +254,7 @@ export declare class JsonSchemaIsoDateBuilder<Opt extends boolean = false> exten
|
|
|
254
254
|
* When `null` is included in optionalValues, the return type becomes `JsonSchemaTerminal`
|
|
255
255
|
* (no further chaining allowed) because the schema is wrapped in an anyOf structure.
|
|
256
256
|
*/
|
|
257
|
-
optional<T extends readonly null[] | undefined = undefined>(optionalValues?: T): T extends readonly null[] ? JsonSchemaTerminal<string | IsoDate | undefined, IsoDate | undefined, true> :
|
|
257
|
+
optional<T extends readonly null[] | undefined = undefined>(optionalValues?: T): T extends readonly null[] ? JsonSchemaTerminal<string | IsoDate | undefined, IsoDate | undefined, true> : JsonSchemaAnyBuilder<string | IsoDate | undefined, IsoDate | undefined, true>;
|
|
258
258
|
before(date: string): this;
|
|
259
259
|
sameOrBefore(date: string): this;
|
|
260
260
|
after(date: string): this;
|
|
@@ -524,11 +524,9 @@ export class JsonSchemaIsoDateBuilder extends JsonSchemaAnyBuilder {
|
|
|
524
524
|
return super.optional();
|
|
525
525
|
}
|
|
526
526
|
_typeCast(optionalValues);
|
|
527
|
+
const optionalBuilder = this.cloneAndUpdateSchema({ optionalField: true });
|
|
527
528
|
const newBuilder = new JsonSchemaTerminal({
|
|
528
|
-
anyOf: [
|
|
529
|
-
{ type: 'null', optionalValues },
|
|
530
|
-
this.cloneAndUpdateSchema({ optionalField: true }).build(),
|
|
531
|
-
],
|
|
529
|
+
anyOf: [{ type: 'null', optionalValues }, optionalBuilder.build()],
|
|
532
530
|
optionalField: true,
|
|
533
531
|
});
|
|
534
532
|
return newBuilder;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/nodejs-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.90.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@naturalcycles/js-lib": "^15",
|
|
7
7
|
"@types/js-yaml": "^4",
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
"ajv": "^8",
|
|
11
11
|
"chalk": "^5",
|
|
12
12
|
"dotenv": "^17",
|
|
13
|
-
"joi": "^18",
|
|
14
13
|
"js-yaml": "^4",
|
|
15
14
|
"jsonwebtoken": "^9",
|
|
16
15
|
"lru-cache": "^11",
|
|
@@ -39,7 +38,6 @@
|
|
|
39
38
|
"./stream/*.js": "./dist/stream/*.js",
|
|
40
39
|
"./yargs": "./dist/yargs/yargs.util.js",
|
|
41
40
|
"./ajv": "./dist/validation/ajv/index.js",
|
|
42
|
-
"./joi": "./dist/validation/joi/index.js",
|
|
43
41
|
"./zip": "./dist/zip/zip.util.js"
|
|
44
42
|
},
|
|
45
43
|
"bin": {
|
|
@@ -718,22 +718,21 @@ export class JsonSchemaIsoDateBuilder<Opt extends boolean = false> extends JsonS
|
|
|
718
718
|
optionalValues?: T,
|
|
719
719
|
): T extends readonly null[]
|
|
720
720
|
? JsonSchemaTerminal<string | IsoDate | undefined, IsoDate | undefined, true>
|
|
721
|
-
:
|
|
721
|
+
: JsonSchemaAnyBuilder<string | IsoDate | undefined, IsoDate | undefined, true> {
|
|
722
722
|
if (!optionalValues) {
|
|
723
723
|
return super.optional() as any
|
|
724
724
|
}
|
|
725
725
|
|
|
726
726
|
_typeCast<null[]>(optionalValues)
|
|
727
727
|
|
|
728
|
+
const optionalBuilder = this.cloneAndUpdateSchema({ optionalField: true })
|
|
729
|
+
|
|
728
730
|
const newBuilder = new JsonSchemaTerminal<
|
|
729
731
|
string | IsoDate | undefined,
|
|
730
732
|
IsoDate | undefined,
|
|
731
733
|
true
|
|
732
734
|
>({
|
|
733
|
-
anyOf: [
|
|
734
|
-
{ type: 'null', optionalValues },
|
|
735
|
-
this.cloneAndUpdateSchema({ optionalField: true }).build(),
|
|
736
|
-
],
|
|
735
|
+
anyOf: [{ type: 'null', optionalValues }, optionalBuilder.build()],
|
|
737
736
|
optionalField: true,
|
|
738
737
|
})
|
|
739
738
|
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { AlternativesSchema, AnySchema, ArraySchema, BinarySchema, BooleanSchema, DateSchema, FunctionSchema, ObjectSchema, ValidationErrorItem } from 'joi';
|
|
2
|
-
export * from './joi.extensions.js';
|
|
3
|
-
export * from './joi.model.js';
|
|
4
|
-
export * from './joi.shared.schemas.js';
|
|
5
|
-
export * from './joi.validation.error.js';
|
|
6
|
-
export * from './joi.validation.util.js';
|
|
7
|
-
export type { AlternativesSchema, AnySchema, ArraySchema, BinarySchema, BooleanSchema, DateSchema, FunctionSchema, ObjectSchema, ValidationErrorItem, };
|
|
8
|
-
export type { NumberSchema } from './number.extensions.js';
|
|
9
|
-
export type { StringSchema } from './string.extensions.js';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import JoiLib from 'joi';
|
|
2
|
-
import type { NumberSchema } from './number.extensions.js';
|
|
3
|
-
import type { StringSchema } from './string.extensions.js';
|
|
4
|
-
export interface ExtendedJoi extends JoiLib.Root {
|
|
5
|
-
string: <TSchema = string>() => StringSchema<TSchema>;
|
|
6
|
-
number: <TSchema = number>() => NumberSchema<TSchema>;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* This is the only right place to import Joi from
|
|
10
|
-
*/
|
|
11
|
-
export declare const Joi: ExtendedJoi;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import JoiLib from 'joi';
|
|
2
|
-
import { numberExtensions } from './number.extensions.js';
|
|
3
|
-
import { stringExtensions } from './string.extensions.js';
|
|
4
|
-
/**
|
|
5
|
-
* This is the only right place to import Joi from
|
|
6
|
-
*/
|
|
7
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
8
|
-
export const Joi = JoiLib.defaults(schema => {
|
|
9
|
-
// hack to prevent infinite recursion due to .empty('') where '' is a stringSchema itself
|
|
10
|
-
if (schema.type === 'string') {
|
|
11
|
-
return (schema
|
|
12
|
-
.trim() // trim all strings by default
|
|
13
|
-
// 2020-09-21: null values are NOT treated as EMPTY enymore
|
|
14
|
-
// .empty([schema.valid('', null)]) // treat '' or null as empty (undefined, will be stripped out)
|
|
15
|
-
// treat '' as empty (undefined, will be stripped out)
|
|
16
|
-
.empty([schema.valid('')]));
|
|
17
|
-
}
|
|
18
|
-
// Treat `null` as undefined for all schema types
|
|
19
|
-
// undefined values will be stripped by default from object values
|
|
20
|
-
// 2020-09-21: breaking change: null values are NOT treated as EMPTY anymore
|
|
21
|
-
// return schema.empty(null)
|
|
22
|
-
return schema;
|
|
23
|
-
})
|
|
24
|
-
.extend((joi) => stringExtensions(joi))
|
|
25
|
-
.extend((joi) => numberExtensions(joi));
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This type is useful to allow "joi schema merging".
|
|
3
|
-
* Because by default Joi doesn't allow normal merging.
|
|
4
|
-
* E.g `joiSchema.concat` doesn't play well when some property exists
|
|
5
|
-
* in both left and right side.
|
|
6
|
-
*/
|
|
7
|
-
export type JoiSchemaObject<T> = Partial<Record<keyof T, any>>;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { type AnyObject, type BaseDBEntity, type IANATimezone, type IsoDate, type IsoDateTime, type NumberEnum, type StringEnum, type StringMap, type UnixTimestamp, type UnixTimestampMillis } from '@naturalcycles/js-lib/types';
|
|
2
|
-
import type { AlternativesSchema, AnySchema, ArraySchema, ObjectSchema } from 'joi';
|
|
3
|
-
import type { NumberSchema } from './number.extensions.js';
|
|
4
|
-
import type { StringSchema } from './string.extensions.js';
|
|
5
|
-
export declare const booleanSchema: import("joi").BooleanSchema<boolean>;
|
|
6
|
-
export declare const booleanDefaultToFalseSchema: import("joi").BooleanSchema<boolean>;
|
|
7
|
-
export declare const stringSchema: StringSchema<string>;
|
|
8
|
-
export declare const stringSchemaTyped: <T>() => StringSchema<T>;
|
|
9
|
-
export declare const numberSchema: NumberSchema<number>;
|
|
10
|
-
export declare const numberSchemaTyped: <T>() => NumberSchema<T>;
|
|
11
|
-
export declare const integerSchema: NumberSchema<number>;
|
|
12
|
-
export declare const percentageSchema: NumberSchema<number>;
|
|
13
|
-
export declare const dateStringSchema: StringSchema<IsoDate>;
|
|
14
|
-
export declare const binarySchema: import("joi").BinarySchema<Buffer<ArrayBufferLike>>;
|
|
15
|
-
export declare const dateObjectSchema: ObjectSchema<any>;
|
|
16
|
-
export declare const dateIntervalStringSchema: StringSchema<string>;
|
|
17
|
-
export declare const DATE_TIME_STRING_REGEX: RegExp;
|
|
18
|
-
export declare const dateTimeStringSchema: StringSchema<IsoDateTime>;
|
|
19
|
-
/**
|
|
20
|
-
* Allows all values of a String Enum.
|
|
21
|
-
*/
|
|
22
|
-
export declare const stringEnumValueSchema: <ENUM extends StringEnum>(en: ENUM) => StringSchema<ENUM[keyof ENUM]>;
|
|
23
|
-
/**
|
|
24
|
-
* Allows all keys of a String Enum.
|
|
25
|
-
*/
|
|
26
|
-
export declare const stringEnumKeySchema: <ENUM extends StringEnum>(en: ENUM) => StringSchema;
|
|
27
|
-
/**
|
|
28
|
-
* Allows all values of a String Enum.
|
|
29
|
-
*/
|
|
30
|
-
export declare const numberEnumValueSchema: <ENUM extends NumberEnum>(en: ENUM) => NumberSchema<ENUM[keyof ENUM]>;
|
|
31
|
-
/**
|
|
32
|
-
* Allows all keys of a Number Enum.
|
|
33
|
-
*/
|
|
34
|
-
export declare const numberEnumKeySchema: <ENUM extends NumberEnum>(en: ENUM) => StringSchema;
|
|
35
|
-
export declare const urlSchema: (scheme?: string | string[]) => StringSchema;
|
|
36
|
-
export declare function arraySchema<T>(items: AnySchema<T>): ArraySchema<T[]>;
|
|
37
|
-
export declare function anyObjectSchema<T extends AnyObject>(): ObjectSchema<T>;
|
|
38
|
-
export declare function objectSchema<T extends AnyObject>(schema: {
|
|
39
|
-
[key in keyof Partial<T>]: AnySchema<T[key]>;
|
|
40
|
-
}): ObjectSchema<T>;
|
|
41
|
-
export declare function stringMapSchema<T>(key: AnySchema, value: AnySchema<T>): ObjectSchema<StringMap<T>>;
|
|
42
|
-
export declare function oneOfSchema<T = any>(...schemas: AnySchema[]): AlternativesSchema<T>;
|
|
43
|
-
export declare const anySchema: AnySchema<any>;
|
|
44
|
-
export declare const base62Schema: StringSchema<string>;
|
|
45
|
-
export declare const base64Schema: StringSchema<string>;
|
|
46
|
-
export declare const base64UrlSchema: StringSchema<string>;
|
|
47
|
-
export declare const jwtSchema: StringSchema<string>;
|
|
48
|
-
/**
|
|
49
|
-
* [a-zA-Z0-9_]*
|
|
50
|
-
* 6-64 length
|
|
51
|
-
*/
|
|
52
|
-
export declare const idSchema: StringSchema<string>;
|
|
53
|
-
export declare const idBase62Schema: StringSchema<string>;
|
|
54
|
-
export declare const idBase64Schema: StringSchema<string>;
|
|
55
|
-
export declare const idBase64UrlSchema: StringSchema<string>;
|
|
56
|
-
/**
|
|
57
|
-
* "Slug" - a valid URL, filename, etc.
|
|
58
|
-
*/
|
|
59
|
-
export declare const slugSchema: StringSchema<string>;
|
|
60
|
-
/**
|
|
61
|
-
* Between years 1970 and 2050
|
|
62
|
-
*/
|
|
63
|
-
export declare const unixTimestampSchema: NumberSchema<UnixTimestamp>;
|
|
64
|
-
/**
|
|
65
|
-
* Between years 2000 and 2050
|
|
66
|
-
*/
|
|
67
|
-
export declare const unixTimestamp2000Schema: NumberSchema<UnixTimestamp>;
|
|
68
|
-
/**
|
|
69
|
-
* Between years 1970 and 2050
|
|
70
|
-
*/
|
|
71
|
-
export declare const unixTimestampMillisSchema: NumberSchema<UnixTimestampMillis>;
|
|
72
|
-
/**
|
|
73
|
-
* Between years 2000 and 2050
|
|
74
|
-
*/
|
|
75
|
-
export declare const unixTimestampMillis2000Schema: NumberSchema<UnixTimestampMillis>;
|
|
76
|
-
export declare const verSchema: NumberSchema<number>;
|
|
77
|
-
/**
|
|
78
|
-
* Be careful, by default emailSchema does TLD validation. To disable it - use `stringSchema.email({tld: false}).lowercase()`
|
|
79
|
-
*/
|
|
80
|
-
export declare const emailSchema: StringSchema<string>;
|
|
81
|
-
/**
|
|
82
|
-
* Pattern is simplified for our use, it's not a canonical SemVer.
|
|
83
|
-
*/
|
|
84
|
-
export declare const semVerSchema: StringSchema<string>;
|
|
85
|
-
export declare const userAgentSchema: StringSchema<string>;
|
|
86
|
-
export declare const utcOffsetSchema: NumberSchema<number>;
|
|
87
|
-
export declare const ianaTimezoneSchema: StringSchema<IANATimezone>;
|
|
88
|
-
export declare const ipAddressSchema: StringSchema<string>;
|
|
89
|
-
export declare const baseDBEntitySchema: ObjectSchema<BaseDBEntity>;
|
|
90
|
-
export declare const macAddressSchema: StringSchema<string>;
|
|
91
|
-
export declare const uuidSchema: StringSchema<string>;
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { _numberEnumKeys, _numberEnumValues, _stringEnumKeys, _stringEnumValues, } from '@naturalcycles/js-lib';
|
|
2
|
-
import { JWT_REGEX, } from '@naturalcycles/js-lib/types';
|
|
3
|
-
import { BASE62_REGEX, BASE64_REGEX, BASE64URL_REGEX, ID_REGEX, MAC_ADDRESS_REGEX, SEMVER_REGEX, SLUG_REGEX, } from '../regexes.js';
|
|
4
|
-
import { Joi } from './joi.extensions.js';
|
|
5
|
-
export const booleanSchema = Joi.boolean();
|
|
6
|
-
export const booleanDefaultToFalseSchema = Joi.boolean().default(false);
|
|
7
|
-
export const stringSchema = Joi.string();
|
|
8
|
-
export const stringSchemaTyped = () => Joi.string();
|
|
9
|
-
export const numberSchema = Joi.number();
|
|
10
|
-
export const numberSchemaTyped = () => Joi.number();
|
|
11
|
-
export const integerSchema = Joi.number().integer();
|
|
12
|
-
export const percentageSchema = Joi.number().integer().min(0).max(100);
|
|
13
|
-
export const dateStringSchema = stringSchema.dateString();
|
|
14
|
-
export const binarySchema = Joi.binary();
|
|
15
|
-
export const dateObjectSchema = Joi.object().instance(Date);
|
|
16
|
-
const DATE_INTERVAL_REGEX = /^\d{4}-\d{2}-\d{2}\/\d{4}-\d{2}-\d{2}$/;
|
|
17
|
-
export const dateIntervalStringSchema = stringSchema.regex(DATE_INTERVAL_REGEX).messages({
|
|
18
|
-
'string.pattern.base': `must be a DateInterval string`,
|
|
19
|
-
});
|
|
20
|
-
export const DATE_TIME_STRING_REGEX = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})?)?$/;
|
|
21
|
-
export const dateTimeStringSchema = stringSchema.regex(DATE_TIME_STRING_REGEX).messages({
|
|
22
|
-
'string.pattern.base': `must be a DateTime string`,
|
|
23
|
-
});
|
|
24
|
-
/**
|
|
25
|
-
* Allows all values of a String Enum.
|
|
26
|
-
*/
|
|
27
|
-
export const stringEnumValueSchema = (en) => Joi.string().valid(..._stringEnumValues(en));
|
|
28
|
-
/**
|
|
29
|
-
* Allows all keys of a String Enum.
|
|
30
|
-
*/
|
|
31
|
-
export const stringEnumKeySchema = (en) => Joi.string().valid(..._stringEnumKeys(en));
|
|
32
|
-
/**
|
|
33
|
-
* Allows all values of a String Enum.
|
|
34
|
-
*/
|
|
35
|
-
export const numberEnumValueSchema = (en) => Joi.number().valid(..._numberEnumValues(en));
|
|
36
|
-
/**
|
|
37
|
-
* Allows all keys of a Number Enum.
|
|
38
|
-
*/
|
|
39
|
-
export const numberEnumKeySchema = (en) => Joi.string().valid(..._numberEnumKeys(en));
|
|
40
|
-
export const urlSchema = (scheme = 'https') => Joi.string().uri({ scheme });
|
|
41
|
-
export function arraySchema(items) {
|
|
42
|
-
return Joi.array().items(items);
|
|
43
|
-
}
|
|
44
|
-
export function anyObjectSchema() {
|
|
45
|
-
return Joi.object().options({ stripUnknown: false });
|
|
46
|
-
}
|
|
47
|
-
export function objectSchema(schema) {
|
|
48
|
-
return Joi.object(schema);
|
|
49
|
-
}
|
|
50
|
-
export function stringMapSchema(key, value) {
|
|
51
|
-
return Joi.object().pattern(key, value);
|
|
52
|
-
}
|
|
53
|
-
export function oneOfSchema(...schemas) {
|
|
54
|
-
return Joi.alternatives(schemas);
|
|
55
|
-
}
|
|
56
|
-
export const anySchema = Joi.any();
|
|
57
|
-
export const base62Schema = stringSchema.regex(BASE62_REGEX);
|
|
58
|
-
export const base64Schema = stringSchema.regex(BASE64_REGEX);
|
|
59
|
-
export const base64UrlSchema = stringSchema.regex(BASE64URL_REGEX);
|
|
60
|
-
export const jwtSchema = stringSchema.regex(JWT_REGEX);
|
|
61
|
-
// 1g498efj5sder3324zer
|
|
62
|
-
/**
|
|
63
|
-
* [a-zA-Z0-9_]*
|
|
64
|
-
* 6-64 length
|
|
65
|
-
*/
|
|
66
|
-
export const idSchema = stringSchema.regex(ID_REGEX);
|
|
67
|
-
export const idBase62Schema = base62Schema.min(8).max(64);
|
|
68
|
-
export const idBase64Schema = base64Schema.min(8).max(64);
|
|
69
|
-
export const idBase64UrlSchema = base64UrlSchema.min(8).max(64);
|
|
70
|
-
/**
|
|
71
|
-
* "Slug" - a valid URL, filename, etc.
|
|
72
|
-
*/
|
|
73
|
-
export const slugSchema = stringSchema.regex(SLUG_REGEX).min(1).max(255);
|
|
74
|
-
const TS_2500 = 16725225600; // 2500-01-01
|
|
75
|
-
const TS_2000 = 946684800; // 2000-01-01
|
|
76
|
-
/**
|
|
77
|
-
* Between years 1970 and 2050
|
|
78
|
-
*/
|
|
79
|
-
export const unixTimestampSchema = numberSchema
|
|
80
|
-
.integer()
|
|
81
|
-
.min(0)
|
|
82
|
-
.max(TS_2500);
|
|
83
|
-
/**
|
|
84
|
-
* Between years 2000 and 2050
|
|
85
|
-
*/
|
|
86
|
-
export const unixTimestamp2000Schema = numberSchema
|
|
87
|
-
.integer()
|
|
88
|
-
.min(TS_2000)
|
|
89
|
-
.max(TS_2500);
|
|
90
|
-
/**
|
|
91
|
-
* Between years 1970 and 2050
|
|
92
|
-
*/
|
|
93
|
-
export const unixTimestampMillisSchema = numberSchema
|
|
94
|
-
.integer()
|
|
95
|
-
.min(0)
|
|
96
|
-
.max(TS_2500 * 1000);
|
|
97
|
-
/**
|
|
98
|
-
* Between years 2000 and 2050
|
|
99
|
-
*/
|
|
100
|
-
export const unixTimestampMillis2000Schema = numberSchema
|
|
101
|
-
.integer()
|
|
102
|
-
.min(TS_2000 * 1000)
|
|
103
|
-
.max(TS_2500 * 1000);
|
|
104
|
-
// 2
|
|
105
|
-
export const verSchema = numberSchema.optional().integer().min(1).max(100);
|
|
106
|
-
/**
|
|
107
|
-
* Be careful, by default emailSchema does TLD validation. To disable it - use `stringSchema.email({tld: false}).lowercase()`
|
|
108
|
-
*/
|
|
109
|
-
export const emailSchema = stringSchema.email().lowercase();
|
|
110
|
-
/**
|
|
111
|
-
* Pattern is simplified for our use, it's not a canonical SemVer.
|
|
112
|
-
*/
|
|
113
|
-
export const semVerSchema = stringSchema.regex(SEMVER_REGEX);
|
|
114
|
-
// todo: .error(() => 'should be SemVer')
|
|
115
|
-
export const userAgentSchema = stringSchema
|
|
116
|
-
.min(5) // I've seen UA of `Android` (7 characters)
|
|
117
|
-
.max(400);
|
|
118
|
-
export const utcOffsetSchema = numberSchema
|
|
119
|
-
.min(-14 * 60)
|
|
120
|
-
.max(14 * 60)
|
|
121
|
-
.dividable(15);
|
|
122
|
-
export const ianaTimezoneSchema = stringSchema
|
|
123
|
-
// UTC is added to assist unit-testing, which uses UTC by default (not technically a valid Iana timezone identifier)
|
|
124
|
-
.valid(...Intl.supportedValuesOf('timeZone'), 'UTC')
|
|
125
|
-
.messages({
|
|
126
|
-
'any.only': `must be a valid IANA timezone string`,
|
|
127
|
-
});
|
|
128
|
-
export const ipAddressSchema = stringSchema.ip();
|
|
129
|
-
export const baseDBEntitySchema = objectSchema({
|
|
130
|
-
id: stringSchema.optional(),
|
|
131
|
-
created: unixTimestamp2000Schema.optional(),
|
|
132
|
-
updated: unixTimestamp2000Schema.optional(),
|
|
133
|
-
});
|
|
134
|
-
export const macAddressSchema = stringSchema.regex(MAC_ADDRESS_REGEX);
|
|
135
|
-
export const uuidSchema = stringSchema.uuid();
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { ErrorData } from '@naturalcycles/js-lib/error';
|
|
2
|
-
import { AppError } from '@naturalcycles/js-lib/error/error.util.js';
|
|
3
|
-
import type { ValidationErrorItem } from 'joi';
|
|
4
|
-
/**
|
|
5
|
-
* Example of ValidationErrorItem:
|
|
6
|
-
*
|
|
7
|
-
* {
|
|
8
|
-
* message: '"temperature" must be larger than or equal to 33',
|
|
9
|
-
* path: [ 'entries', 10, 'temperature' ],
|
|
10
|
-
* type: 'number.min',
|
|
11
|
-
* context: { limit: 33, value: 30, key: 'temperature', label: 'temperature' }
|
|
12
|
-
* }
|
|
13
|
-
*/
|
|
14
|
-
export interface JoiValidationErrorData extends ErrorData {
|
|
15
|
-
joiValidationErrorItems: ValidationErrorItem[];
|
|
16
|
-
joiValidationInputName?: string;
|
|
17
|
-
joiValidationInputId?: string;
|
|
18
|
-
/**
|
|
19
|
-
* Error "annotation" is stripped in Error.message.
|
|
20
|
-
* This field contains the "full" annotation.
|
|
21
|
-
*
|
|
22
|
-
* This field is non-enumerable, won't be printed or included in JSON by default,
|
|
23
|
-
* but still accessible programmatically (via `err.data.annotation`) when needed!
|
|
24
|
-
*/
|
|
25
|
-
annotation?: string;
|
|
26
|
-
}
|
|
27
|
-
export declare class JoiValidationError extends AppError<JoiValidationErrorData> {
|
|
28
|
-
constructor(message: string, data: JoiValidationErrorData);
|
|
29
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { type ValidationFunction, type ValidationFunctionResult } from '@naturalcycles/js-lib';
|
|
2
|
-
import type { AnySchema, ValidationOptions } from 'joi';
|
|
3
|
-
import { JoiValidationError } from './joi.validation.error.js';
|
|
4
|
-
export declare function getJoiValidationFunction<T>(schema: AnySchema<T>): ValidationFunction<T, T, JoiValidationError>;
|
|
5
|
-
/**
|
|
6
|
-
* Validates with Joi.
|
|
7
|
-
* Throws JoiValidationError if invalid.
|
|
8
|
-
* Returns *converted* value.
|
|
9
|
-
*
|
|
10
|
-
* If `schema` is undefined - returns value as is.
|
|
11
|
-
*/
|
|
12
|
-
export declare function validate<T>(input: any, schema?: AnySchema<T>, inputName?: string, opt?: ValidationOptions): T;
|
|
13
|
-
/**
|
|
14
|
-
* Validates with Joi.
|
|
15
|
-
* Returns JoiValidationResult with converted value and error (if any).
|
|
16
|
-
* Does not throw.
|
|
17
|
-
*
|
|
18
|
-
* Joi does NOT mutate the input.
|
|
19
|
-
*
|
|
20
|
-
* If `schema` is undefined - returns value as is.
|
|
21
|
-
*/
|
|
22
|
-
export declare function getValidationResult<T>(input: T, schema?: AnySchema<T>, inputName?: string, options?: ValidationOptions): ValidationFunctionResult<T, JoiValidationError>;
|
|
23
|
-
/**
|
|
24
|
-
* Convenience function that returns true if !error.
|
|
25
|
-
*/
|
|
26
|
-
export declare function isValid<T>(input: T, schema?: AnySchema<T>): boolean;
|
|
27
|
-
export declare function undefinedIfInvalid<T>(input: any, schema?: AnySchema<T>): T | undefined;
|
|
28
|
-
/**
|
|
29
|
-
* Will do joi-conversion, regardless of error/validity of value.
|
|
30
|
-
*
|
|
31
|
-
* @returns converted value
|
|
32
|
-
*/
|
|
33
|
-
export declare function convert<T>(input: any, schema?: AnySchema<T>): T;
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Does 2 things:
|
|
3
|
-
* 1. Validates the value according to Schema passed.
|
|
4
|
-
* 2. Converts the value (also according to Schema).
|
|
5
|
-
*
|
|
6
|
-
* "Converts" mean e.g trims all strings from leading/trailing spaces.
|
|
7
|
-
*/
|
|
8
|
-
import { _hb, _isObject, } from '@naturalcycles/js-lib';
|
|
9
|
-
import { _assert } from '@naturalcycles/js-lib/error/assert.js';
|
|
10
|
-
import { _truncateMiddle } from '@naturalcycles/js-lib/string/string.util.js';
|
|
11
|
-
import { JoiValidationError } from './joi.validation.error.js';
|
|
12
|
-
// Strip colors in production (for e.g Sentry reporting)
|
|
13
|
-
// const stripColors = process.env.NODE_ENV === 'production' || !!process.env.GAE_INSTANCE
|
|
14
|
-
// Currently colors do more bad than good, so let's strip them always for now
|
|
15
|
-
const stripColors = true;
|
|
16
|
-
const defaultOptions = {
|
|
17
|
-
abortEarly: false,
|
|
18
|
-
convert: true,
|
|
19
|
-
allowUnknown: true,
|
|
20
|
-
stripUnknown: {
|
|
21
|
-
objects: true,
|
|
22
|
-
// true: it will SILENTLY strip invalid values from arrays. Very dangerous! Can lead to data loss!
|
|
23
|
-
// false: it will THROW validation error if any of array items is invalid
|
|
24
|
-
// Q: is it invalid if it has unknown properties?
|
|
25
|
-
// A: no, unknown properties are just stripped (in both 'false' and 'true' states), array is still valid
|
|
26
|
-
// Q: will it strip or keep unknown properties in array items?..
|
|
27
|
-
// A: strip
|
|
28
|
-
arrays: false, // let's be very careful with that! https://github.com/hapijs/joi/issues/658
|
|
29
|
-
},
|
|
30
|
-
presence: 'required',
|
|
31
|
-
// errors: {
|
|
32
|
-
// stack: true,
|
|
33
|
-
// }
|
|
34
|
-
};
|
|
35
|
-
export function getJoiValidationFunction(schema) {
|
|
36
|
-
return (input, opt) => {
|
|
37
|
-
_assert(!opt?.mutateInput, 'mutateInput=true is not yet supported with Joi');
|
|
38
|
-
return getValidationResult(input, schema, opt?.inputName);
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Validates with Joi.
|
|
43
|
-
* Throws JoiValidationError if invalid.
|
|
44
|
-
* Returns *converted* value.
|
|
45
|
-
*
|
|
46
|
-
* If `schema` is undefined - returns value as is.
|
|
47
|
-
*/
|
|
48
|
-
export function validate(input, schema, inputName, opt = {}) {
|
|
49
|
-
const [error, returnValue] = getValidationResult(input, schema, inputName, opt);
|
|
50
|
-
if (error)
|
|
51
|
-
throw error;
|
|
52
|
-
return returnValue;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Validates with Joi.
|
|
56
|
-
* Returns JoiValidationResult with converted value and error (if any).
|
|
57
|
-
* Does not throw.
|
|
58
|
-
*
|
|
59
|
-
* Joi does NOT mutate the input.
|
|
60
|
-
*
|
|
61
|
-
* If `schema` is undefined - returns value as is.
|
|
62
|
-
*/
|
|
63
|
-
export function getValidationResult(input, schema, inputName, options = {}) {
|
|
64
|
-
if (!schema)
|
|
65
|
-
return [null, input];
|
|
66
|
-
const { value, error } = schema.validate(input, {
|
|
67
|
-
...defaultOptions,
|
|
68
|
-
...options,
|
|
69
|
-
});
|
|
70
|
-
const err = error ? createError(input, error, inputName) : null;
|
|
71
|
-
return [err, value];
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Convenience function that returns true if !error.
|
|
75
|
-
*/
|
|
76
|
-
export function isValid(input, schema) {
|
|
77
|
-
if (!schema)
|
|
78
|
-
return true;
|
|
79
|
-
const { error } = schema.validate(input, defaultOptions);
|
|
80
|
-
return !error;
|
|
81
|
-
}
|
|
82
|
-
export function undefinedIfInvalid(input, schema) {
|
|
83
|
-
if (!schema)
|
|
84
|
-
return input;
|
|
85
|
-
const { value, error } = schema.validate(input, defaultOptions);
|
|
86
|
-
return error ? undefined : value;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Will do joi-conversion, regardless of error/validity of value.
|
|
90
|
-
*
|
|
91
|
-
* @returns converted value
|
|
92
|
-
*/
|
|
93
|
-
export function convert(input, schema) {
|
|
94
|
-
if (!schema)
|
|
95
|
-
return input;
|
|
96
|
-
const { value } = schema.validate(input, defaultOptions);
|
|
97
|
-
return value;
|
|
98
|
-
}
|
|
99
|
-
function createError(value, err, inputName) {
|
|
100
|
-
const tokens = [];
|
|
101
|
-
const inputId = _isObject(value) ? value['id'] : undefined;
|
|
102
|
-
if (inputId || inputName) {
|
|
103
|
-
inputName ||= value?.constructor?.name;
|
|
104
|
-
tokens.push('Invalid ' + [inputName, inputId].filter(Boolean).join('.'));
|
|
105
|
-
}
|
|
106
|
-
const annotation = err.annotate(stripColors);
|
|
107
|
-
if (annotation.length > 100) {
|
|
108
|
-
// For rather large annotations - we include up to 5 errors up front, before printing the whole object.
|
|
109
|
-
// Up to 5 `details`
|
|
110
|
-
tokens.push(...err.details.slice(0, 5).map(i => {
|
|
111
|
-
return i.message;
|
|
112
|
-
// Currently not specifying the path, to not "overwhelm" the message
|
|
113
|
-
// Can be reverted if needed.
|
|
114
|
-
// let msg = i.message
|
|
115
|
-
// const paths = i.path.filter(Boolean).join('.')
|
|
116
|
-
// if (paths) msg += ` @ .${paths}`
|
|
117
|
-
// return msg
|
|
118
|
-
}));
|
|
119
|
-
if (err.details.length > 5)
|
|
120
|
-
tokens.push(`... ${err.details.length} errors in total`);
|
|
121
|
-
tokens.push('');
|
|
122
|
-
}
|
|
123
|
-
tokens.push(_truncateMiddle(annotation, 4000, `\n... ${_hb(annotation.length)} message truncated ...\n`));
|
|
124
|
-
const msg = tokens.join('\n');
|
|
125
|
-
const data = {
|
|
126
|
-
joiValidationErrorItems: err.details,
|
|
127
|
-
...(inputName && { joiValidationInputName: inputName }),
|
|
128
|
-
...(inputId && { joiValidationInputId: inputId }),
|
|
129
|
-
};
|
|
130
|
-
// Make annotation non-enumerable, to not get it automatically printed,
|
|
131
|
-
// but still accessible
|
|
132
|
-
Object.defineProperty(data, 'annotation', {
|
|
133
|
-
writable: true,
|
|
134
|
-
configurable: true,
|
|
135
|
-
enumerable: false,
|
|
136
|
-
value: annotation,
|
|
137
|
-
});
|
|
138
|
-
return new JoiValidationError(msg, data);
|
|
139
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type Joi from 'joi';
|
|
2
|
-
import type { Extension, NumberSchema as JoiNumberSchema } from 'joi';
|
|
3
|
-
export interface NumberSchema<TSchema = number> extends JoiNumberSchema<TSchema> {
|
|
4
|
-
dividable: (q: number) => this;
|
|
5
|
-
}
|
|
6
|
-
export declare function numberExtensions(joi: typeof Joi): Extension;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export function numberExtensions(joi) {
|
|
2
|
-
return {
|
|
3
|
-
base: joi.number(),
|
|
4
|
-
type: 'number',
|
|
5
|
-
messages: {
|
|
6
|
-
'number.dividable': `"{{#label}}" must be dividable by {{#q}}`,
|
|
7
|
-
},
|
|
8
|
-
// validate (v, helpers) {
|
|
9
|
-
// console.log('number validate called', {v})
|
|
10
|
-
// },
|
|
11
|
-
rules: {
|
|
12
|
-
// Based on: https://github.com/hapijs/joi/blob/master/API.md#extensions
|
|
13
|
-
dividable: {
|
|
14
|
-
multi: true,
|
|
15
|
-
method(q) {
|
|
16
|
-
return this.$_addRule({
|
|
17
|
-
name: 'dividable',
|
|
18
|
-
args: { q },
|
|
19
|
-
});
|
|
20
|
-
},
|
|
21
|
-
args: [
|
|
22
|
-
{
|
|
23
|
-
name: 'q',
|
|
24
|
-
ref: true,
|
|
25
|
-
assert: v => typeof v === 'number' && !Number.isNaN(v),
|
|
26
|
-
message: 'must be a number',
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
validate(v, helpers, args) {
|
|
30
|
-
if (v % args['q'] === 0) {
|
|
31
|
-
return v;
|
|
32
|
-
}
|
|
33
|
-
return helpers.error('number.dividable', args);
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { IsoDate } from '@naturalcycles/js-lib/types';
|
|
2
|
-
import type Joi from 'joi';
|
|
3
|
-
import type { Extension, StringSchema as JoiStringSchema } from 'joi';
|
|
4
|
-
export interface StringSchema<TSchema = string> extends JoiStringSchema<TSchema> {
|
|
5
|
-
dateString: (min?: IsoDate | 'today', max?: IsoDate | 'today') => StringSchema<IsoDate>;
|
|
6
|
-
}
|
|
7
|
-
export interface JoiDateStringOptions {
|
|
8
|
-
min?: IsoDate | 'today';
|
|
9
|
-
max?: IsoDate | 'today';
|
|
10
|
-
}
|
|
11
|
-
export declare function stringExtensions(joi: typeof Joi): Extension;
|