joi 17.4.0 → 17.5.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/joi-browser.min.js +1 -1
- package/lib/errors.js +12 -3
- package/lib/index.d.ts +64 -12
- package/lib/messages.js +2 -2
- package/lib/schemas.js +2 -1
- package/lib/template.js +6 -9
- package/lib/types/alternatives.js +26 -4
- package/lib/types/array.js +1 -1
- package/lib/types/number.js +1 -1
- package/lib/types/string.js +12 -5
- package/lib/validator.js +4 -1
- package/package.json +3 -3
package/lib/errors.js
CHANGED
|
@@ -131,10 +131,19 @@ exports.template = function (value, messages, code, state, prefs) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
if (lang &&
|
|
134
|
-
messages[lang]
|
|
135
|
-
messages[lang][code] !== undefined) {
|
|
134
|
+
messages[lang]) {
|
|
136
135
|
|
|
137
|
-
|
|
136
|
+
if (messages[lang][code] !== undefined) {
|
|
137
|
+
return messages[lang][code];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (messages[lang]['*'] !== undefined) {
|
|
141
|
+
return messages[lang]['*'];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!messages[code]) {
|
|
146
|
+
return messages['*'];
|
|
138
147
|
}
|
|
139
148
|
|
|
140
149
|
return messages[code];
|
package/lib/index.d.ts
CHANGED
|
@@ -77,11 +77,18 @@ declare namespace Joi {
|
|
|
77
77
|
label?: string | false,
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
* the characters used around array
|
|
80
|
+
* the characters used around array values. Defaults to `'[]'`
|
|
81
81
|
*
|
|
82
82
|
* @default '[]'
|
|
83
83
|
*/
|
|
84
84
|
array?: string | false
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* the characters used around array string values. Defaults to no wrapping.
|
|
88
|
+
*
|
|
89
|
+
* @default false
|
|
90
|
+
*/
|
|
91
|
+
string?: string | false
|
|
85
92
|
};
|
|
86
93
|
}
|
|
87
94
|
|
|
@@ -250,6 +257,12 @@ declare namespace Joi {
|
|
|
250
257
|
}
|
|
251
258
|
|
|
252
259
|
interface EmailOptions {
|
|
260
|
+
/**
|
|
261
|
+
* if `true`, domains ending with a `.` character are permitted
|
|
262
|
+
*
|
|
263
|
+
* @default false
|
|
264
|
+
*/
|
|
265
|
+
allowFullyQualified?: boolean;
|
|
253
266
|
/**
|
|
254
267
|
* If `true`, Unicode characters are permitted
|
|
255
268
|
*
|
|
@@ -289,6 +302,12 @@ declare namespace Joi {
|
|
|
289
302
|
}
|
|
290
303
|
|
|
291
304
|
interface DomainOptions {
|
|
305
|
+
/**
|
|
306
|
+
* if `true`, domains ending with a `.` character are permitted
|
|
307
|
+
*
|
|
308
|
+
* @default false
|
|
309
|
+
*/
|
|
310
|
+
allowFullyQualified?: boolean;
|
|
292
311
|
/**
|
|
293
312
|
* If `true`, Unicode characters are permitted
|
|
294
313
|
*
|
|
@@ -642,10 +661,14 @@ declare namespace Joi {
|
|
|
642
661
|
|
|
643
662
|
type ValidationErrorFunction = (errors: ErrorReport[]) => string | ValidationErrorItem | Error;
|
|
644
663
|
|
|
645
|
-
|
|
646
|
-
error
|
|
664
|
+
type ValidationResult<TSchema = any> = {
|
|
665
|
+
error: undefined;
|
|
647
666
|
warning?: ValidationError;
|
|
648
|
-
value:
|
|
667
|
+
value: TSchema;
|
|
668
|
+
} | {
|
|
669
|
+
error: ValidationError;
|
|
670
|
+
warning?: ValidationError;
|
|
671
|
+
value: undefined;
|
|
649
672
|
}
|
|
650
673
|
|
|
651
674
|
interface CreateErrorOptions {
|
|
@@ -681,15 +704,44 @@ declare namespace Joi {
|
|
|
681
704
|
|
|
682
705
|
type CustomValidator<V = any> = (value: V, helpers: CustomHelpers) => V | ErrorReport;
|
|
683
706
|
|
|
684
|
-
|
|
707
|
+
interface ExternalHelpers {
|
|
708
|
+
prefs: ValidationOptions;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
type ExternalValidationFunction<V = any> = (value: V, helpers: ExternalHelpers) => V | undefined;
|
|
685
712
|
|
|
686
713
|
type SchemaLikeWithoutArray = string | number | boolean | null | Schema | SchemaMap;
|
|
687
714
|
type SchemaLike = SchemaLikeWithoutArray | object;
|
|
688
715
|
|
|
689
|
-
type
|
|
716
|
+
type NullableType<T> = undefined | null | T
|
|
717
|
+
|
|
718
|
+
type ObjectPropertiesSchema<T = any> =
|
|
719
|
+
T extends NullableType<string>
|
|
720
|
+
? Joi.StringSchema
|
|
721
|
+
: T extends NullableType<number>
|
|
722
|
+
? Joi.NumberSchema
|
|
723
|
+
: T extends NullableType<bigint>
|
|
724
|
+
? Joi.NumberSchema
|
|
725
|
+
: T extends NullableType<boolean>
|
|
726
|
+
? Joi.BooleanSchema
|
|
727
|
+
: T extends NullableType<Date>
|
|
728
|
+
? Joi.DateSchema
|
|
729
|
+
: T extends NullableType<Array<any>>
|
|
730
|
+
? Joi.ArraySchema
|
|
731
|
+
: T extends NullableType<object>
|
|
732
|
+
? ObjectSchema<StrictSchemaMap<T>>
|
|
733
|
+
: never
|
|
734
|
+
|
|
735
|
+
type PartialSchemaMap<TSchema = any> = {
|
|
690
736
|
[key in keyof TSchema]?: SchemaLike | SchemaLike[];
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
type StrictSchemaMap<TSchema = any> = {
|
|
740
|
+
[key in keyof TSchema]-?: ObjectPropertiesSchema<TSchema[key]>
|
|
691
741
|
};
|
|
692
742
|
|
|
743
|
+
type SchemaMap<TSchema = any, isStrict = false> = isStrict extends true ? StrictSchemaMap<TSchema> : PartialSchemaMap<TSchema>
|
|
744
|
+
|
|
693
745
|
type Schema<P = any> =
|
|
694
746
|
| AnySchema
|
|
695
747
|
| ArraySchema
|
|
@@ -805,7 +857,7 @@ declare namespace Joi {
|
|
|
805
857
|
$_validate(value: any, state: State, prefs: ValidationOptions): ValidationResult;
|
|
806
858
|
}
|
|
807
859
|
|
|
808
|
-
interface AnySchema extends SchemaInternals {
|
|
860
|
+
interface AnySchema<TSchema = any> extends SchemaInternals {
|
|
809
861
|
/**
|
|
810
862
|
* Flags of current schema.
|
|
811
863
|
*/
|
|
@@ -1128,7 +1180,7 @@ declare namespace Joi {
|
|
|
1128
1180
|
/**
|
|
1129
1181
|
* Validates a value using the schema and options.
|
|
1130
1182
|
*/
|
|
1131
|
-
validate(value: any, options?: ValidationOptions): ValidationResult
|
|
1183
|
+
validate(value: any, options?: ValidationOptions): ValidationResult<TSchema>;
|
|
1132
1184
|
|
|
1133
1185
|
/**
|
|
1134
1186
|
* Validates a value using the schema and options.
|
|
@@ -1548,7 +1600,7 @@ declare namespace Joi {
|
|
|
1548
1600
|
matches: SchemaLike | Reference;
|
|
1549
1601
|
}
|
|
1550
1602
|
|
|
1551
|
-
interface ObjectSchema<TSchema = any> extends AnySchema {
|
|
1603
|
+
interface ObjectSchema<TSchema = any> extends AnySchema<TSchema> {
|
|
1552
1604
|
/**
|
|
1553
1605
|
* Defines an all-or-nothing relationship between keys where if one of the peers is present, all of them are required as well.
|
|
1554
1606
|
*
|
|
@@ -1764,7 +1816,7 @@ declare namespace Joi {
|
|
|
1764
1816
|
/**
|
|
1765
1817
|
* Adds a conditional alternative schema type, either based on another key value, or a schema peeking into the current value.
|
|
1766
1818
|
*/
|
|
1767
|
-
conditional(ref: string | Reference, options: WhenOptions): this;
|
|
1819
|
+
conditional(ref: string | Reference, options: WhenOptions | WhenOptions[]): this;
|
|
1768
1820
|
conditional(ref: Schema, options: WhenSchemaOptions): this;
|
|
1769
1821
|
|
|
1770
1822
|
/**
|
|
@@ -1972,7 +2024,7 @@ declare namespace Joi {
|
|
|
1972
2024
|
* Generates a schema object that matches an object data type (as well as JSON strings that have been parsed into objects).
|
|
1973
2025
|
*/
|
|
1974
2026
|
// tslint:disable-next-line:no-unnecessary-generics
|
|
1975
|
-
object<TSchema = any, T = TSchema>(schema?: SchemaMap<T>): ObjectSchema<TSchema>;
|
|
2027
|
+
object<TSchema = any, isStrict = false, T = TSchema>(schema?: SchemaMap<T, isStrict>): ObjectSchema<TSchema>;
|
|
1976
2028
|
|
|
1977
2029
|
/**
|
|
1978
2030
|
* Generates a schema object that matches a string data type. Note that empty strings are not allowed by default and must be enabled with allow('').
|
|
@@ -2090,7 +2142,7 @@ declare namespace Joi {
|
|
|
2090
2142
|
/**
|
|
2091
2143
|
* Checks whether or not the provided argument is a joi schema.
|
|
2092
2144
|
*/
|
|
2093
|
-
isSchema(schema: any, options?: CompileOptions):
|
|
2145
|
+
isSchema(schema: any, options?: CompileOptions): schema is AnySchema;
|
|
2094
2146
|
|
|
2095
2147
|
/**
|
|
2096
2148
|
* A special value used with `any.allow()`, `any.invalid()`, and `any.valid()` as the first value to reset any previously set values.
|
package/lib/messages.js
CHANGED
|
@@ -81,7 +81,7 @@ exports.decompile = function (messages) {
|
|
|
81
81
|
const message = messages[code];
|
|
82
82
|
|
|
83
83
|
if (code === 'root') {
|
|
84
|
-
target
|
|
84
|
+
target.root = message;
|
|
85
85
|
continue;
|
|
86
86
|
}
|
|
87
87
|
|
|
@@ -99,7 +99,7 @@ exports.decompile = function (messages) {
|
|
|
99
99
|
const localized = message[code];
|
|
100
100
|
|
|
101
101
|
if (code === 'root') {
|
|
102
|
-
target[language]
|
|
102
|
+
target[language].root = localized;
|
|
103
103
|
continue;
|
|
104
104
|
}
|
|
105
105
|
|
package/lib/schemas.js
CHANGED
package/lib/template.js
CHANGED
|
@@ -307,9 +307,10 @@ internals.wrap = function (value, ends) {
|
|
|
307
307
|
};
|
|
308
308
|
|
|
309
309
|
|
|
310
|
-
internals.stringify = function (value, original, state, prefs, local, options) {
|
|
310
|
+
internals.stringify = function (value, original, state, prefs, local, options = {}) {
|
|
311
311
|
|
|
312
312
|
const type = typeof value;
|
|
313
|
+
const wrap = prefs && prefs.errors && prefs.errors.wrap || {};
|
|
313
314
|
|
|
314
315
|
let skipWrap = false;
|
|
315
316
|
if (Ref.isRef(value) &&
|
|
@@ -324,7 +325,7 @@ internals.stringify = function (value, original, state, prefs, local, options) {
|
|
|
324
325
|
}
|
|
325
326
|
|
|
326
327
|
if (type === 'string') {
|
|
327
|
-
return value;
|
|
328
|
+
return internals.wrap(value, options.arrayItems && wrap.string);
|
|
328
329
|
}
|
|
329
330
|
|
|
330
331
|
if (type === 'number' ||
|
|
@@ -355,16 +356,12 @@ internals.stringify = function (value, original, state, prefs, local, options) {
|
|
|
355
356
|
return value.toString();
|
|
356
357
|
}
|
|
357
358
|
|
|
358
|
-
|
|
359
|
+
const values = [];
|
|
359
360
|
for (const item of value) {
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
if (skipWrap) {
|
|
364
|
-
return partial;
|
|
361
|
+
values.push(internals.stringify(item, original, state, prefs, local, { arrayItems: true, ...options }));
|
|
365
362
|
}
|
|
366
363
|
|
|
367
|
-
return internals.wrap(
|
|
364
|
+
return internals.wrap(values.join(', '), !skipWrap && wrap.array);
|
|
368
365
|
};
|
|
369
366
|
|
|
370
367
|
|
|
@@ -46,6 +46,7 @@ module.exports = Any.extend({
|
|
|
46
46
|
|
|
47
47
|
if (schema._flags.match) {
|
|
48
48
|
const matched = [];
|
|
49
|
+
const failed = [];
|
|
49
50
|
|
|
50
51
|
for (let i = 0; i < schema.$_terms.matches.length; ++i) {
|
|
51
52
|
const item = schema.$_terms.matches[i];
|
|
@@ -57,24 +58,45 @@ module.exports = Any.extend({
|
|
|
57
58
|
matched.push(result.value);
|
|
58
59
|
}
|
|
59
60
|
else {
|
|
61
|
+
failed.push(result.errors);
|
|
60
62
|
localState.restore();
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
if (matched.length === 0) {
|
|
65
|
-
|
|
67
|
+
const context = {
|
|
68
|
+
details: failed.map((f) => Errors.details(f, { override: false }))
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return { errors: error('alternatives.any', context) };
|
|
66
72
|
}
|
|
67
73
|
|
|
74
|
+
// Match one
|
|
75
|
+
|
|
68
76
|
if (schema._flags.match === 'one') {
|
|
69
77
|
return matched.length === 1 ? { value: matched[0] } : { errors: error('alternatives.one') };
|
|
70
78
|
}
|
|
71
79
|
|
|
80
|
+
// Match all
|
|
81
|
+
|
|
72
82
|
if (matched.length !== schema.$_terms.matches.length) {
|
|
73
|
-
|
|
83
|
+
const context = {
|
|
84
|
+
details: failed.map((f) => Errors.details(f, { override: false }))
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return { errors: error('alternatives.all', context) };
|
|
74
88
|
}
|
|
75
89
|
|
|
76
|
-
const
|
|
77
|
-
|
|
90
|
+
const isAnyObj = (alternative) => {
|
|
91
|
+
|
|
92
|
+
return alternative.$_terms.matches.some((v) => {
|
|
93
|
+
|
|
94
|
+
return v.schema.type === 'object' ||
|
|
95
|
+
(v.schema.type === 'alternatives' && isAnyObj(v.schema));
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return isAnyObj(schema) ? { value: matched.reduce((acc, v) => Merge(acc, v, { mergeArrays: false })) } : { value: matched[matched.length - 1] };
|
|
78
100
|
}
|
|
79
101
|
|
|
80
102
|
// Match any
|
package/lib/types/array.js
CHANGED
package/lib/types/number.js
CHANGED
package/lib/types/string.js
CHANGED
|
@@ -28,7 +28,7 @@ const internals = {
|
|
|
28
28
|
},
|
|
29
29
|
dataUriRegex: /^data:[\w+.-]+\/[\w+.-]+;((charset=[\w-]+|base64),)?(.*)$/,
|
|
30
30
|
hexRegex: /^[a-f0-9]+$/i,
|
|
31
|
-
ipRegex: Ip.regex().regex,
|
|
31
|
+
ipRegex: Ip.regex({ cidr: 'forbidden' }).regex,
|
|
32
32
|
isoDurationRegex: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/,
|
|
33
33
|
|
|
34
34
|
guidBrackets: {
|
|
@@ -123,13 +123,20 @@ module.exports = Any.extend({
|
|
|
123
123
|
}
|
|
124
124
|
},
|
|
125
125
|
|
|
126
|
-
validate(value, { error }) {
|
|
126
|
+
validate(value, { schema, error }) {
|
|
127
127
|
|
|
128
128
|
if (typeof value !== 'string') {
|
|
129
129
|
return { value, errors: error('string.base') };
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
if (value === '') {
|
|
133
|
+
const min = schema.$_getRule('min');
|
|
134
|
+
if (min &&
|
|
135
|
+
min.args.limit === 0) {
|
|
136
|
+
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
133
140
|
return { value, errors: error('string.empty') };
|
|
134
141
|
}
|
|
135
142
|
},
|
|
@@ -257,7 +264,7 @@ module.exports = Any.extend({
|
|
|
257
264
|
method(options) {
|
|
258
265
|
|
|
259
266
|
if (options) {
|
|
260
|
-
Common.assertOptions(options, ['allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
|
|
267
|
+
Common.assertOptions(options, ['allowFullyQualified', 'allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
|
|
261
268
|
}
|
|
262
269
|
|
|
263
270
|
const address = internals.addressOptions(options);
|
|
@@ -276,7 +283,7 @@ module.exports = Any.extend({
|
|
|
276
283
|
email: {
|
|
277
284
|
method(options = {}) {
|
|
278
285
|
|
|
279
|
-
Common.assertOptions(options, ['allowUnicode', 'ignoreLength', 'maxDomainSegments', 'minDomainSegments', 'multiple', 'separator', 'tlds']);
|
|
286
|
+
Common.assertOptions(options, ['allowFullyQualified', 'allowUnicode', 'ignoreLength', 'maxDomainSegments', 'minDomainSegments', 'multiple', 'separator', 'tlds']);
|
|
280
287
|
Assert(options.multiple === undefined || typeof options.multiple === 'boolean', 'multiple option must be an boolean');
|
|
281
288
|
|
|
282
289
|
const address = internals.addressOptions(options);
|
|
@@ -632,7 +639,7 @@ module.exports = Any.extend({
|
|
|
632
639
|
Common.assertOptions(options, ['allowRelative', 'allowQuerySquareBrackets', 'domain', 'relativeOnly', 'scheme']);
|
|
633
640
|
|
|
634
641
|
if (options.domain) {
|
|
635
|
-
Common.assertOptions(options.domain, ['allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
|
|
642
|
+
Common.assertOptions(options.domain, ['allowFullyQualified', 'allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
|
|
636
643
|
}
|
|
637
644
|
|
|
638
645
|
const { regex, scheme } = Uri.regex(options);
|
package/lib/validator.js
CHANGED
|
@@ -94,7 +94,10 @@ exports.entryAsync = async function (value, schema, prefs) {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
catch (err) {
|
|
97
|
-
|
|
97
|
+
if (settings.errors.label) {
|
|
98
|
+
err.message += ` (${label})`; // Change message to include path
|
|
99
|
+
}
|
|
100
|
+
|
|
98
101
|
throw err;
|
|
99
102
|
}
|
|
100
103
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "joi",
|
|
3
3
|
"description": "Object schema validation",
|
|
4
|
-
"version": "17.
|
|
4
|
+
"version": "17.5.0",
|
|
5
5
|
"repository": "git://github.com/sideway/joi",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@hapi/hoek": "^9.0.0",
|
|
19
19
|
"@hapi/topo": "^5.0.0",
|
|
20
|
-
"@sideway/address": "^4.1.
|
|
20
|
+
"@sideway/address": "^4.1.3",
|
|
21
21
|
"@sideway/formula": "^3.0.0",
|
|
22
22
|
"@sideway/pinpoint": "^2.0.0"
|
|
23
23
|
},
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@hapi/code": "8.x.x",
|
|
27
27
|
"@hapi/joi-legacy-test": "npm:@hapi/joi@15.x.x",
|
|
28
28
|
"@hapi/lab": "24.x.x",
|
|
29
|
-
"typescript": "4.
|
|
29
|
+
"typescript": "4.3.x"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"prepublishOnly": "cd browser && npm install && npm run build",
|