joi 8.4.2 → 9.0.0-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/.eslintignore +2 -0
- package/.github/CONTRIBUTING.md +14 -0
- package/.github/ISSUE_TEMPLATE.md +19 -0
- package/.npmignore +21 -0
- package/.travis.yml +8 -0
- package/API.md +1690 -0
- package/README.md +1 -1
- package/examples/conditionalRequire.js +52 -0
- package/examples/customMessage.js +31 -0
- package/examples/multipleWhen.js +26 -0
- package/examples/timestamps.js +22 -0
- package/generate-readme-toc.js +49 -0
- package/images/joi.png +0 -0
- package/images/validation.png +0 -0
- package/lib/any.js +74 -35
- package/lib/array.js +11 -44
- package/lib/boolean.js +9 -2
- package/lib/date.js +0 -3
- package/lib/errors.js +21 -22
- package/lib/index.js +142 -3
- package/lib/language.js +2 -6
- package/lib/object.js +36 -33
- package/lib/string.js +0 -17
- package/package.json +5 -5
- package/test/alternatives.js +490 -0
- package/test/any.js +1751 -0
- package/test/array.js +1049 -0
- package/test/binary.js +190 -0
- package/test/boolean.js +163 -0
- package/test/date.js +441 -0
- package/test/errors.js +512 -0
- package/test/function.js +224 -0
- package/test/helper.js +65 -0
- package/test/index.js +2450 -0
- package/test/number.js +836 -0
- package/test/object.js +1318 -0
- package/test/ref.js +470 -0
- package/test/string.js +3206 -0
- package/lib/lazy.js +0 -51
- package/lib/schemas.js +0 -25
package/README.md
CHANGED
|
@@ -95,4 +95,4 @@ When validating a schema:
|
|
|
95
95
|
* Rules are defined in an additive fashion and evaluated in order after whitelist and blacklist checks.
|
|
96
96
|
|
|
97
97
|
# API
|
|
98
|
-
See the [API Reference](https://github.com/hapijs/joi/blob/
|
|
98
|
+
See the [API Reference](https://github.com/hapijs/joi/blob/v9.0.0-0/API.md).
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Load modules
|
|
4
|
+
|
|
5
|
+
const Joi = require('../');
|
|
6
|
+
|
|
7
|
+
// Delcare internals
|
|
8
|
+
|
|
9
|
+
const internals = {};
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
// This is an example of a survey to obtain the reputation of Parisians
|
|
13
|
+
// It contains examples of how to conditionally require keys based on values of other keys
|
|
14
|
+
|
|
15
|
+
// This is a valid value for integer rating 1 - 5
|
|
16
|
+
const intRating = Joi.number().integer().min(1).max(5);
|
|
17
|
+
|
|
18
|
+
const schema = Joi.object().keys({
|
|
19
|
+
// Do you know any French people? yes or no (required)
|
|
20
|
+
q1: Joi.boolean().required(),
|
|
21
|
+
// Do you know any Parisians? yes or no (required if answered yes in q1)
|
|
22
|
+
q2: Joi.boolean()
|
|
23
|
+
.when('q1', { is: true, then: Joi.required() }),
|
|
24
|
+
// How many french in paris do you know? 1-6, 6-10, 11-50 or 50+ (required if answered yes in q2)
|
|
25
|
+
q3: Joi.string()
|
|
26
|
+
.when('q2', { is: true, then: Joi.valid('1-5', '6-10', '11-50', '50+').required() }),
|
|
27
|
+
// Rate 20% of most friendly Parisians, from how many people you know answered in q3, individually on 1-5 rating
|
|
28
|
+
q4: Joi.array()
|
|
29
|
+
.when('q3', {is: '1-5', then: Joi.array().min(0).max(1).items(intRating).required() })
|
|
30
|
+
.when('q3', {is: '6-10', then: Joi.array().min(1).max(2).items(intRating).required() })
|
|
31
|
+
.when('q3', {is: '11-50', then: Joi.array().min(2).max(10).items(intRating).required() })
|
|
32
|
+
.when('q3', {is: '50+', then: Joi.array().min(10).items(intRating).required() }),
|
|
33
|
+
// Rate remaining 80% of Parisians, from how many people you know answered in q3, individually on 1-5 rating
|
|
34
|
+
q5: Joi.array()
|
|
35
|
+
.when('q3', {is: '1-5', then: Joi.array().min(1).max(4).items(intRating).required() })
|
|
36
|
+
.when('q3', {is: '6-10', then: Joi.array().min(4).max(8).items(intRating).required() })
|
|
37
|
+
.when('q3', {is: '11-50', then: Joi.array().min(8).max(40).items(intRating).required() })
|
|
38
|
+
.when('q3', {is: '50+', then: Joi.array().min(40).items(intRating).required().required() }),
|
|
39
|
+
// Rate the reputation of Parisians in general, 1-5 rating
|
|
40
|
+
q6: intRating.required()
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const response = {
|
|
44
|
+
q1: true,
|
|
45
|
+
q2: true,
|
|
46
|
+
q3: '1-5',
|
|
47
|
+
q4: [5],
|
|
48
|
+
q5: [1],
|
|
49
|
+
q6: 2
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
Joi.assert(response, schema);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Load modules
|
|
4
|
+
|
|
5
|
+
const Joi = require('../');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// Declare internals
|
|
9
|
+
|
|
10
|
+
const internals = {};
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const schema = Joi.object().options({ abortEarly: false }).keys({
|
|
14
|
+
email: Joi.string().email().required().label('User Email'),
|
|
15
|
+
password: Joi.string().min(8).required(),
|
|
16
|
+
password_confirmation: Joi.any().valid(Joi.ref('password')).required().options({ language: { any: { allowOnly: 'must match password' }, label: 'Password Confirmation' } }).label('This label is not used because language.label takes precedence'),
|
|
17
|
+
first_name: Joi.string().required(),
|
|
18
|
+
last_name: Joi.string().required(),
|
|
19
|
+
company: Joi.string().optional()
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
const data = {
|
|
24
|
+
email: 'not_a_valid_email_to_show_custom_label',
|
|
25
|
+
password: 'abcd1234',
|
|
26
|
+
password_confirmation: 'abc1',
|
|
27
|
+
first_name: 'Joe',
|
|
28
|
+
last_name: 'Doe'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
Joi.assert(data, schema);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Load modules
|
|
4
|
+
|
|
5
|
+
const Joi = require('../');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// Declare internals
|
|
9
|
+
|
|
10
|
+
const internals = {};
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const schema = {
|
|
14
|
+
type: Joi.string().required(),
|
|
15
|
+
subtype: Joi.alternatives()
|
|
16
|
+
.when('type', {is: 'video', then: Joi.valid('mp4', 'wav')})
|
|
17
|
+
.when('type', {is: 'audio', then: Joi.valid('mp3')})
|
|
18
|
+
.when('type', {is: 'image', then: Joi.valid('jpg', 'png')})
|
|
19
|
+
.when('type', {is: 'pdf' , then: Joi.valid('document')})
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
Joi.assert({ type: 'video', subtype: 'mp4' }, schema); // Pass
|
|
24
|
+
Joi.assert({ type: 'video', subtype: 'wav' }, schema); // Pass
|
|
25
|
+
Joi.assert({ type: 'other', subtype: 'something' }, schema); // Fail
|
|
26
|
+
Joi.assert({ type: 'audio', subtype: 'mp4' }, schema); // Fail
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Load modules
|
|
4
|
+
const Joi = require('../');
|
|
5
|
+
|
|
6
|
+
const now = new Date();
|
|
7
|
+
const javascriptTimestamp = now.getTime();
|
|
8
|
+
const unixTimestamp = now.getTime() / 1000;
|
|
9
|
+
|
|
10
|
+
const schema = Joi.object().options({ abortEarly: false }).keys({
|
|
11
|
+
javascript1: Joi.date().timestamp(),
|
|
12
|
+
javascript2: Joi.date().timestamp('javascript'),
|
|
13
|
+
unix: Joi.date().timestamp('unix')
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const data = {
|
|
17
|
+
javascript1: javascriptTimestamp,
|
|
18
|
+
javascript2: javascriptTimestamp,
|
|
19
|
+
unix: unixTimestamp
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
Joi.assert(data, schema);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Load modules
|
|
4
|
+
|
|
5
|
+
const Toc = require('markdown-toc');
|
|
6
|
+
const Fs = require('fs');
|
|
7
|
+
const Package = require('./package.json');
|
|
8
|
+
|
|
9
|
+
// Declare internals
|
|
10
|
+
|
|
11
|
+
const internals = {
|
|
12
|
+
api: {
|
|
13
|
+
filename: './API.md',
|
|
14
|
+
contents: Fs.readFileSync('./API.md', 'utf8')
|
|
15
|
+
},
|
|
16
|
+
readme: {
|
|
17
|
+
filename: './README.md',
|
|
18
|
+
contents: Fs.readFileSync('./README.md', 'utf8')
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
internals.generateToc = function () {
|
|
23
|
+
|
|
24
|
+
const tocOptions = {
|
|
25
|
+
bullets: '-',
|
|
26
|
+
slugify: function (text) {
|
|
27
|
+
|
|
28
|
+
return text.toLowerCase()
|
|
29
|
+
.replace(/\s/g, '-')
|
|
30
|
+
.replace(/[^\w-]/g, '');
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const api = Toc.insert(internals.api.contents, tocOptions)
|
|
35
|
+
.replace(/<!-- version -->(.|\n)*<!-- versionstop -->/, `<!-- version -->\n# ${Package.version} API Reference\n<!-- versionstop -->`);
|
|
36
|
+
|
|
37
|
+
Fs.writeFileSync(internals.api.filename, api);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
internals.generateLink = function () {
|
|
41
|
+
// create absolute URL for versioned docs
|
|
42
|
+
const readme = internals.readme.contents
|
|
43
|
+
.replace(/\[API Reference\]\(.*\)/gi, `[API Reference](${Package.homepage || ''}/blob/v${Package.version}/${internals.api.filename.substr(2)})`);
|
|
44
|
+
|
|
45
|
+
Fs.writeFileSync(internals.readme.filename, readme);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
internals.generateToc();
|
|
49
|
+
internals.generateLink();
|
package/images/joi.png
ADDED
|
Binary file
|
|
Binary file
|
package/lib/any.js
CHANGED
|
@@ -32,10 +32,37 @@ internals.defaults = {
|
|
|
32
32
|
|
|
33
33
|
internals.checkOptions = function (options) {
|
|
34
34
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
const optionType = {
|
|
36
|
+
abortEarly: 'boolean',
|
|
37
|
+
convert: 'boolean',
|
|
38
|
+
allowUnknown: 'boolean',
|
|
39
|
+
skipFunctions: 'boolean',
|
|
40
|
+
stripUnknown: 'boolean',
|
|
41
|
+
language: 'object',
|
|
42
|
+
presence: ['string', 'required', 'optional', 'forbidden', 'ignore'],
|
|
43
|
+
raw: 'boolean',
|
|
44
|
+
context: 'object',
|
|
45
|
+
strip: 'boolean',
|
|
46
|
+
noDefaults: 'boolean'
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const keys = Object.keys(options);
|
|
50
|
+
for (let i = 0; i < keys.length; ++i) {
|
|
51
|
+
const key = keys[i];
|
|
52
|
+
const opt = optionType[key];
|
|
53
|
+
let type = opt;
|
|
54
|
+
let values = null;
|
|
55
|
+
|
|
56
|
+
if (Array.isArray(opt)) {
|
|
57
|
+
type = opt[0];
|
|
58
|
+
values = opt.slice(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Hoek.assert(type, 'unknown key ' + key);
|
|
62
|
+
Hoek.assert(typeof options[key] === type, key + ' should be of type ' + type);
|
|
63
|
+
if (values) {
|
|
64
|
+
Hoek.assert(values.indexOf(options[key]) >= 0, key + ' should be one of ' + values.join(', '));
|
|
65
|
+
}
|
|
39
66
|
}
|
|
40
67
|
};
|
|
41
68
|
|
|
@@ -51,8 +78,7 @@ module.exports = internals.Any = function () {
|
|
|
51
78
|
this._invalids = new internals.Set();
|
|
52
79
|
this._tests = [];
|
|
53
80
|
this._refs = [];
|
|
54
|
-
this._flags = {
|
|
55
|
-
/*
|
|
81
|
+
this._flags = { /*
|
|
56
82
|
presence: 'optional', // optional, required, forbidden, ignore
|
|
57
83
|
allowOnly: false,
|
|
58
84
|
allowUnknown: undefined,
|
|
@@ -64,8 +90,7 @@ module.exports = internals.Any = function () {
|
|
|
64
90
|
case: undefined, // upper, lower
|
|
65
91
|
empty: undefined,
|
|
66
92
|
func: false
|
|
67
|
-
*/
|
|
68
|
-
};
|
|
93
|
+
*/ };
|
|
69
94
|
|
|
70
95
|
this._description = null;
|
|
71
96
|
this._unit = null;
|
|
@@ -192,10 +217,10 @@ internals.Any.prototype.concat = function (schema) {
|
|
|
192
217
|
};
|
|
193
218
|
|
|
194
219
|
|
|
195
|
-
internals.Any.prototype._test = function (name, arg, func) {
|
|
220
|
+
internals.Any.prototype._test = function (name, arg, func, options) {
|
|
196
221
|
|
|
197
222
|
const obj = this.clone();
|
|
198
|
-
obj._tests.push({ func, name, arg });
|
|
223
|
+
obj._tests.push({ func, name, arg, options });
|
|
199
224
|
return obj;
|
|
200
225
|
};
|
|
201
226
|
|
|
@@ -229,17 +254,6 @@ internals.Any.prototype.raw = function (isRaw) {
|
|
|
229
254
|
};
|
|
230
255
|
|
|
231
256
|
|
|
232
|
-
internals.Any.prototype.error = function (err) {
|
|
233
|
-
|
|
234
|
-
Hoek.assert(err && err instanceof Error, 'Must provide a valid Error object');
|
|
235
|
-
|
|
236
|
-
const obj = this.clone();
|
|
237
|
-
obj._settings = obj._settings || {};
|
|
238
|
-
obj._settings.error = err;
|
|
239
|
-
return obj;
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
|
|
243
257
|
internals.Any.prototype._allow = function () {
|
|
244
258
|
|
|
245
259
|
const values = Hoek.flatten(Array.prototype.slice.call(arguments));
|
|
@@ -378,7 +392,7 @@ internals.Any.prototype.when = function (ref, options) {
|
|
|
378
392
|
Alternatives = Alternatives || require('./alternatives');
|
|
379
393
|
const obj = Alternatives.when(ref, { is: options.is, then, otherwise });
|
|
380
394
|
obj._flags.presence = 'ignore';
|
|
381
|
-
obj._settings = internals.concatSettings(
|
|
395
|
+
obj._settings = internals.concatSettings({ baseType: this }, obj._settings);
|
|
382
396
|
|
|
383
397
|
return obj;
|
|
384
398
|
};
|
|
@@ -609,13 +623,16 @@ internals.Any.prototype._validate = function (value, state, options, reference)
|
|
|
609
623
|
|
|
610
624
|
for (let i = 0; i < this._tests.length; ++i) {
|
|
611
625
|
const test = this._tests[i];
|
|
612
|
-
const
|
|
613
|
-
if (
|
|
614
|
-
errors.push(
|
|
626
|
+
const ret = test.func.call(this, value, state, options);
|
|
627
|
+
if (ret && ret.isJoi) {
|
|
628
|
+
errors.push(ret);
|
|
615
629
|
if (options.abortEarly) {
|
|
616
630
|
return finish();
|
|
617
631
|
}
|
|
618
632
|
}
|
|
633
|
+
else if (ret !== null) {
|
|
634
|
+
value = ret;
|
|
635
|
+
}
|
|
619
636
|
}
|
|
620
637
|
|
|
621
638
|
return finish();
|
|
@@ -640,13 +657,16 @@ internals.Any.prototype._validateWithOptions = function (value, options, callbac
|
|
|
640
657
|
};
|
|
641
658
|
|
|
642
659
|
|
|
643
|
-
internals.Any.prototype.validate = function (value,
|
|
660
|
+
internals.Any.prototype.validate = function (value, callback) {
|
|
661
|
+
|
|
662
|
+
const result = this._validate(value, null, internals.defaults);
|
|
663
|
+
const errors = Errors.process(result.errors, value);
|
|
644
664
|
|
|
645
|
-
if (
|
|
646
|
-
return
|
|
665
|
+
if (callback) {
|
|
666
|
+
return callback(errors, result.value);
|
|
647
667
|
}
|
|
648
668
|
|
|
649
|
-
return
|
|
669
|
+
return { error: errors, value: result.value };
|
|
650
670
|
};
|
|
651
671
|
|
|
652
672
|
|
|
@@ -658,7 +678,7 @@ internals.Any.prototype.describe = function () {
|
|
|
658
678
|
|
|
659
679
|
const flags = Object.keys(this._flags);
|
|
660
680
|
if (flags.length) {
|
|
661
|
-
if (this._flags.hasOwnProperty('empty') || this._flags.hasOwnProperty('default')
|
|
681
|
+
if (this._flags.hasOwnProperty('empty') || this._flags.hasOwnProperty('default')) {
|
|
662
682
|
description.flags = {};
|
|
663
683
|
for (let i = 0; i < flags.length; ++i) {
|
|
664
684
|
const flag = flags[i];
|
|
@@ -676,9 +696,6 @@ internals.Any.prototype.describe = function () {
|
|
|
676
696
|
description.flags[flag] = this._flags[flag];
|
|
677
697
|
}
|
|
678
698
|
}
|
|
679
|
-
else if (flag === 'lazy') {
|
|
680
|
-
// We don't want it in the description
|
|
681
|
-
}
|
|
682
699
|
else {
|
|
683
700
|
description.flags[flag] = this._flags[flag];
|
|
684
701
|
}
|
|
@@ -734,9 +751,31 @@ internals.Any.prototype.describe = function () {
|
|
|
734
751
|
for (let i = 0; i < this._tests.length; ++i) {
|
|
735
752
|
const validator = this._tests[i];
|
|
736
753
|
const item = { name: validator.name };
|
|
754
|
+
|
|
737
755
|
if (validator.arg !== void 0) {
|
|
738
756
|
item.arg = Ref.isRef(validator.arg) ? validator.arg.toString() : validator.arg;
|
|
739
757
|
}
|
|
758
|
+
|
|
759
|
+
const options = validator.options;
|
|
760
|
+
if (options) {
|
|
761
|
+
if (options.hasRef) {
|
|
762
|
+
item.arg = {};
|
|
763
|
+
const keys = Object.keys(validator.arg);
|
|
764
|
+
for (let j = 0; j < keys.length; ++j) {
|
|
765
|
+
const key = keys[j];
|
|
766
|
+
const value = validator.arg[key];
|
|
767
|
+
item.arg[key] = Ref.isRef(value) ? value.toString() : value;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (typeof options.description === 'string') {
|
|
772
|
+
item.description = options.description;
|
|
773
|
+
}
|
|
774
|
+
else if (typeof options.description === 'function') {
|
|
775
|
+
item.description = options.description(item.arg);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
740
779
|
description.rules.push(item);
|
|
741
780
|
}
|
|
742
781
|
|
|
@@ -752,7 +791,6 @@ internals.Any.prototype.describe = function () {
|
|
|
752
791
|
return description;
|
|
753
792
|
};
|
|
754
793
|
|
|
755
|
-
|
|
756
794
|
internals.Any.prototype.label = function (name) {
|
|
757
795
|
|
|
758
796
|
Hoek.assert(name && typeof name === 'string', 'Label name must be a non-empty string');
|
|
@@ -760,7 +798,8 @@ internals.Any.prototype.label = function (name) {
|
|
|
760
798
|
const obj = this.clone();
|
|
761
799
|
const options = { language: { label: name } };
|
|
762
800
|
|
|
763
|
-
|
|
801
|
+
// If language.label is set, it should override this label
|
|
802
|
+
obj._settings = internals.concatSettings(options, obj._settings);
|
|
764
803
|
return obj;
|
|
765
804
|
};
|
|
766
805
|
|
package/lib/array.js
CHANGED
|
@@ -38,17 +38,6 @@ internals.Array = function () {
|
|
|
38
38
|
Hoek.inherits(internals.Array, Any);
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
internals.safeParse = function (value, result) {
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const converted = JSON.parse(value);
|
|
45
|
-
if (Array.isArray(converted)) {
|
|
46
|
-
result.value = converted;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
catch (e) { }
|
|
50
|
-
};
|
|
51
|
-
|
|
52
41
|
internals.Array.prototype._base = function (value, state, options) {
|
|
53
42
|
|
|
54
43
|
const result = {
|
|
@@ -58,7 +47,13 @@ internals.Array.prototype._base = function (value, state, options) {
|
|
|
58
47
|
if (typeof value === 'string' &&
|
|
59
48
|
options.convert) {
|
|
60
49
|
|
|
61
|
-
|
|
50
|
+
try {
|
|
51
|
+
const converted = JSON.parse(value);
|
|
52
|
+
if (Array.isArray(converted)) {
|
|
53
|
+
result.value = converted;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (e) { }
|
|
62
57
|
}
|
|
63
58
|
|
|
64
59
|
let isArray = Array.isArray(result.value);
|
|
@@ -75,8 +70,6 @@ internals.Array.prototype._base = function (value, state, options) {
|
|
|
75
70
|
|
|
76
71
|
if (this._inner.inclusions.length ||
|
|
77
72
|
this._inner.exclusions.length ||
|
|
78
|
-
this._inner.requireds.length ||
|
|
79
|
-
this._inner.ordereds.length ||
|
|
80
73
|
!this._flags.sparse) {
|
|
81
74
|
|
|
82
75
|
// Clone the array so that we don't modify the original
|
|
@@ -129,7 +122,7 @@ internals.checkItems = function (items, wasArray, state, options) {
|
|
|
129
122
|
// Sparse
|
|
130
123
|
|
|
131
124
|
if (!this._flags.sparse && item === undefined) {
|
|
132
|
-
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path
|
|
125
|
+
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path }, options));
|
|
133
126
|
|
|
134
127
|
if (options.abortEarly) {
|
|
135
128
|
return errors;
|
|
@@ -170,15 +163,6 @@ internals.checkItems = function (items, wasArray, state, options) {
|
|
|
170
163
|
--i;
|
|
171
164
|
--il;
|
|
172
165
|
}
|
|
173
|
-
else if (!this._flags.sparse && res.value === undefined) {
|
|
174
|
-
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
|
|
175
|
-
|
|
176
|
-
if (options.abortEarly) {
|
|
177
|
-
return errors;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
166
|
else {
|
|
183
167
|
items[i] = res.value;
|
|
184
168
|
}
|
|
@@ -212,15 +196,6 @@ internals.checkItems = function (items, wasArray, state, options) {
|
|
|
212
196
|
internals.fastSplice(requireds, j);
|
|
213
197
|
--j;
|
|
214
198
|
--jl;
|
|
215
|
-
|
|
216
|
-
if (!this._flags.sparse && res.value === undefined) {
|
|
217
|
-
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
|
|
218
|
-
|
|
219
|
-
if (options.abortEarly) {
|
|
220
|
-
return errors;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
199
|
break;
|
|
225
200
|
}
|
|
226
201
|
}
|
|
@@ -231,10 +206,6 @@ internals.checkItems = function (items, wasArray, state, options) {
|
|
|
231
206
|
|
|
232
207
|
// Inclusions
|
|
233
208
|
|
|
234
|
-
const stripUnknown = options.stripUnknown
|
|
235
|
-
? (options.stripUnknown === true ? true : !!options.stripUnknown.arrays)
|
|
236
|
-
: false;
|
|
237
|
-
|
|
238
209
|
jl = inclusions.length;
|
|
239
210
|
for (let j = 0; j < jl; ++j) {
|
|
240
211
|
const inclusion = inclusions[j];
|
|
@@ -253,10 +224,6 @@ internals.checkItems = function (items, wasArray, state, options) {
|
|
|
253
224
|
--i;
|
|
254
225
|
--il;
|
|
255
226
|
}
|
|
256
|
-
else if (!this._flags.sparse && res.value === undefined) {
|
|
257
|
-
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
|
|
258
|
-
errored = true;
|
|
259
|
-
}
|
|
260
227
|
else {
|
|
261
228
|
items[i] = res.value;
|
|
262
229
|
}
|
|
@@ -267,7 +234,7 @@ internals.checkItems = function (items, wasArray, state, options) {
|
|
|
267
234
|
|
|
268
235
|
// Return the actual error if only one inclusion defined
|
|
269
236
|
if (jl === 1) {
|
|
270
|
-
if (stripUnknown) {
|
|
237
|
+
if (options.stripUnknown) {
|
|
271
238
|
internals.fastSplice(items, i);
|
|
272
239
|
--i;
|
|
273
240
|
--il;
|
|
@@ -291,7 +258,7 @@ internals.checkItems = function (items, wasArray, state, options) {
|
|
|
291
258
|
}
|
|
292
259
|
|
|
293
260
|
if (this._inner.inclusions.length && !isValid) {
|
|
294
|
-
if (stripUnknown) {
|
|
261
|
+
if (options.stripUnknown) {
|
|
295
262
|
internals.fastSplice(items, i);
|
|
296
263
|
--i;
|
|
297
264
|
--il;
|
|
@@ -334,7 +301,7 @@ internals.fillMissedErrors = function (errors, requireds, state, options) {
|
|
|
334
301
|
|
|
335
302
|
if (knownMisses.length) {
|
|
336
303
|
if (unknownMisses) {
|
|
337
|
-
errors.push(this.createError('array.includesRequiredBoth', { knownMisses: knownMisses, unknownMisses: unknownMisses }, { key: state.key, path: state.
|
|
304
|
+
errors.push(this.createError('array.includesRequiredBoth', { knownMisses: knownMisses, unknownMisses: unknownMisses }, { key: state.key, path: state.patk }, options));
|
|
338
305
|
}
|
|
339
306
|
else {
|
|
340
307
|
errors.push(this.createError('array.includesRequiredKnowns', { knownMisses: knownMisses }, { key: state.key, path: state.path }, options));
|
package/lib/boolean.js
CHANGED
|
@@ -30,8 +30,15 @@ internals.Boolean.prototype._base = function (value, state, options) {
|
|
|
30
30
|
options.convert) {
|
|
31
31
|
|
|
32
32
|
const lower = value.toLowerCase();
|
|
33
|
-
result.value = (lower === 'true' || lower === 'yes' || lower === 'on' ? true
|
|
34
|
-
|
|
33
|
+
result.value = (lower === 'true' || lower === 'yes' || lower === 'on' || lower === '1' ? true
|
|
34
|
+
: (lower === 'false' || lower === 'no' || lower === 'off' || lower === '0' ? false : value));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (typeof value === 'number' &&
|
|
38
|
+
options.convert) {
|
|
39
|
+
|
|
40
|
+
result.value = (value === 1 ? true
|
|
41
|
+
: (value === 0 ? false : value));
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
result.errors = (typeof result.value === 'boolean') ? null : this.createError('boolean.base', null, state, options);
|
package/lib/date.js
CHANGED
|
@@ -41,9 +41,6 @@ internals.Date.prototype._base = function (value, state, options) {
|
|
|
41
41
|
if (result.value instanceof Date && !isNaN(result.value.getTime())) {
|
|
42
42
|
result.errors = null;
|
|
43
43
|
}
|
|
44
|
-
else if (!options.convert) {
|
|
45
|
-
result.errors = this.createError('date.strict', null, state, options);
|
|
46
|
-
}
|
|
47
44
|
else {
|
|
48
45
|
let type;
|
|
49
46
|
if (internals.isIsoDate(this._flags.format)) {
|
package/lib/errors.js
CHANGED
|
@@ -115,39 +115,28 @@ exports.process = function (errors, object) {
|
|
|
115
115
|
for (let i = 0; i < localErrors.length; ++i) {
|
|
116
116
|
const item = localErrors[i];
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
const detail = {
|
|
119
|
+
message: item.toString(),
|
|
120
|
+
path: internals.getPath(item),
|
|
121
|
+
type: item.type,
|
|
122
|
+
context: item.context
|
|
123
|
+
};
|
|
121
124
|
|
|
122
|
-
let itemMessage;
|
|
123
125
|
if (parent === undefined) {
|
|
124
|
-
|
|
125
|
-
message = message + (message ? '. ' : '') + itemMessage;
|
|
126
|
+
message = message + (message ? '. ' : '') + detail.message;
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
// Do not push intermediate errors, we're only interested in leafs
|
|
129
|
-
|
|
130
130
|
if (item.context.reason && item.context.reason.length) {
|
|
131
|
-
|
|
132
|
-
if (override) {
|
|
133
|
-
return override;
|
|
134
|
-
}
|
|
131
|
+
processErrors(item.context.reason, item.path);
|
|
135
132
|
}
|
|
136
133
|
else {
|
|
137
|
-
details.push(
|
|
138
|
-
message: itemMessage || item.toString(),
|
|
139
|
-
path: internals.getPath(item),
|
|
140
|
-
type: item.type,
|
|
141
|
-
context: item.context
|
|
142
|
-
});
|
|
134
|
+
details.push(detail);
|
|
143
135
|
}
|
|
144
136
|
}
|
|
145
137
|
};
|
|
146
138
|
|
|
147
|
-
|
|
148
|
-
if (override) {
|
|
149
|
-
return override;
|
|
150
|
-
}
|
|
139
|
+
processErrors(errors);
|
|
151
140
|
|
|
152
141
|
const error = new Error(message);
|
|
153
142
|
error.isJoi = true;
|
|
@@ -161,7 +150,17 @@ exports.process = function (errors, object) {
|
|
|
161
150
|
|
|
162
151
|
internals.getPath = function (item) {
|
|
163
152
|
|
|
164
|
-
|
|
153
|
+
const recursePath = (it) => {
|
|
154
|
+
|
|
155
|
+
const reachedItem = Hoek.reach(it, 'context.reason.0');
|
|
156
|
+
if (reachedItem && reachedItem.context) {
|
|
157
|
+
return recursePath(reachedItem);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return it.path;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return recursePath(item) || item.context.key;
|
|
165
164
|
};
|
|
166
165
|
|
|
167
166
|
|