@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.
Files changed (28) hide show
  1. package/dist/validation/ajv/jsonSchemaBuilder.d.ts +1 -1
  2. package/dist/validation/ajv/jsonSchemaBuilder.js +2 -4
  3. package/package.json +1 -3
  4. package/src/validation/ajv/jsonSchemaBuilder.ts +4 -5
  5. package/dist/validation/joi/index.d.ts +0 -9
  6. package/dist/validation/joi/index.js +0 -5
  7. package/dist/validation/joi/joi.extensions.d.ts +0 -11
  8. package/dist/validation/joi/joi.extensions.js +0 -25
  9. package/dist/validation/joi/joi.model.d.ts +0 -7
  10. package/dist/validation/joi/joi.model.js +0 -5
  11. package/dist/validation/joi/joi.shared.schemas.d.ts +0 -91
  12. package/dist/validation/joi/joi.shared.schemas.js +0 -135
  13. package/dist/validation/joi/joi.validation.error.d.ts +0 -29
  14. package/dist/validation/joi/joi.validation.error.js +0 -8
  15. package/dist/validation/joi/joi.validation.util.d.ts +0 -33
  16. package/dist/validation/joi/joi.validation.util.js +0 -139
  17. package/dist/validation/joi/number.extensions.d.ts +0 -6
  18. package/dist/validation/joi/number.extensions.js +0 -38
  19. package/dist/validation/joi/string.extensions.d.ts +0 -11
  20. package/dist/validation/joi/string.extensions.js +0 -104
  21. package/src/validation/joi/index.ts +0 -32
  22. package/src/validation/joi/joi.extensions.ts +0 -38
  23. package/src/validation/joi/joi.model.ts +0 -12
  24. package/src/validation/joi/joi.shared.schemas.ts +0 -207
  25. package/src/validation/joi/joi.validation.error.ts +0 -35
  26. package/src/validation/joi/joi.validation.util.ts +0 -183
  27. package/src/validation/joi/number.extensions.ts +0 -46
  28. 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> : JsonSchemaIsoDateBuilder<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.89.0",
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
- : JsonSchemaIsoDateBuilder<true> {
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,5 +0,0 @@
1
- export * from './joi.extensions.js';
2
- export * from './joi.model.js';
3
- export * from './joi.shared.schemas.js';
4
- export * from './joi.validation.error.js';
5
- export * from './joi.validation.util.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,5 +0,0 @@
1
- // export interface ObjectSchema<T = any> extends JoiObjectSchema<T> {
2
- // // Open-ended index signature to allow for easier .concat(baseDBEntitySchema)
3
- // [k: string]: any
4
- // }
5
- export {};
@@ -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,8 +0,0 @@
1
- import { AppError } from '@naturalcycles/js-lib/error/error.util.js';
2
- export class JoiValidationError extends AppError {
3
- constructor(message, data) {
4
- super(message, data, {
5
- name: 'JoiValidationError',
6
- });
7
- }
8
- }
@@ -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;