joi 10.4.2 → 10.6.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/LICENSE +1 -1
- package/README.md +1 -1
- package/lib/cast.js +7 -7
- package/lib/errors.js +5 -3
- package/lib/index.js +15 -11
- package/lib/language.js +1 -0
- package/lib/{alternatives.js → types/alternatives/index.js} +3 -3
- package/lib/{any.js → types/any/index.js} +6 -6
- package/lib/{array.js → types/array/index.js} +51 -8
- package/lib/{binary.js → types/binary/index.js} +1 -1
- package/lib/{boolean.js → types/boolean/index.js} +2 -2
- package/lib/{date.js → types/date/index.js} +2 -2
- package/lib/{lazy.js → types/lazy/index.js} +1 -1
- package/lib/{number.js → types/number/index.js} +2 -2
- package/lib/{object.js → types/object/index.js} +10 -4
- package/lib/{string.js → types/string/index.js} +49 -46
- package/lib/{string → types/string}/ip.js +0 -0
- package/lib/{string → types/string}/rfc3986.js +0 -0
- package/lib/{string → types/string}/uri.js +0 -0
- package/package.json +1 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -125,7 +125,7 @@ When validating a schema:
|
|
|
125
125
|
* Rules are defined in an additive fashion and evaluated in order after whitelist and blacklist checks.
|
|
126
126
|
|
|
127
127
|
# API
|
|
128
|
-
See the [API Reference](https://github.com/hapijs/joi/blob/v10.
|
|
128
|
+
See the [API Reference](https://github.com/hapijs/joi/blob/v10.6.0/API.md).
|
|
129
129
|
|
|
130
130
|
# Browsers
|
|
131
131
|
|
package/lib/cast.js
CHANGED
|
@@ -12,10 +12,10 @@ const Ref = require('./ref');
|
|
|
12
12
|
|
|
13
13
|
const internals = {
|
|
14
14
|
any: null,
|
|
15
|
-
date: require('./date'),
|
|
16
|
-
string: require('./string'),
|
|
17
|
-
number: require('./number'),
|
|
18
|
-
boolean: require('./boolean'),
|
|
15
|
+
date: require('./types/date'),
|
|
16
|
+
string: require('./types/string'),
|
|
17
|
+
number: require('./types/number'),
|
|
18
|
+
boolean: require('./types/boolean'),
|
|
19
19
|
alt: null,
|
|
20
20
|
object: null
|
|
21
21
|
};
|
|
@@ -23,9 +23,9 @@ const internals = {
|
|
|
23
23
|
|
|
24
24
|
exports.schema = function (config) {
|
|
25
25
|
|
|
26
|
-
internals.any = internals.any || new (require('./any'))();
|
|
27
|
-
internals.alt = internals.alt || require('./alternatives');
|
|
28
|
-
internals.object = internals.object || require('./object');
|
|
26
|
+
internals.any = internals.any || new (require('./types/any'))();
|
|
27
|
+
internals.alt = internals.alt || require('./types/alternatives');
|
|
28
|
+
internals.object = internals.object || require('./types/object');
|
|
29
29
|
|
|
30
30
|
if (config !== undefined && config !== null && typeof config === 'object') {
|
|
31
31
|
|
package/lib/errors.js
CHANGED
|
@@ -301,11 +301,13 @@ internals.annotate = function (stripColorCodes) {
|
|
|
301
301
|
const seg = path[j];
|
|
302
302
|
|
|
303
303
|
if (ref.isImmutable) {
|
|
304
|
-
//
|
|
305
|
-
ref = ref.clone();
|
|
304
|
+
ref = ref.clone(); // joi schemas are not cloned by hoek, we have to take this extra step
|
|
306
305
|
}
|
|
307
306
|
|
|
308
|
-
if (j + 1 < path.length &&
|
|
307
|
+
if (j + 1 < path.length &&
|
|
308
|
+
ref[seg] &&
|
|
309
|
+
typeof ref[seg] !== 'string') {
|
|
310
|
+
|
|
309
311
|
ref = ref[seg];
|
|
310
312
|
}
|
|
311
313
|
else {
|
package/lib/index.js
CHANGED
|
@@ -3,24 +3,24 @@
|
|
|
3
3
|
// Load modules
|
|
4
4
|
|
|
5
5
|
const Hoek = require('hoek');
|
|
6
|
-
const Any = require('./any');
|
|
6
|
+
const Any = require('./types/any');
|
|
7
7
|
const Cast = require('./cast');
|
|
8
8
|
const Errors = require('./errors');
|
|
9
|
-
const Lazy = require('./lazy');
|
|
9
|
+
const Lazy = require('./types/lazy');
|
|
10
10
|
const Ref = require('./ref');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
// Declare internals
|
|
14
14
|
|
|
15
15
|
const internals = {
|
|
16
|
-
alternatives: require('./alternatives'),
|
|
17
|
-
array: require('./array'),
|
|
18
|
-
boolean: require('./boolean'),
|
|
19
|
-
binary: require('./binary'),
|
|
20
|
-
date: require('./date'),
|
|
21
|
-
number: require('./number'),
|
|
22
|
-
object: require('./object'),
|
|
23
|
-
string: require('./string')
|
|
16
|
+
alternatives: require('./types/alternatives'),
|
|
17
|
+
array: require('./types/array'),
|
|
18
|
+
boolean: require('./types/boolean'),
|
|
19
|
+
binary: require('./types/binary'),
|
|
20
|
+
date: require('./types/date'),
|
|
21
|
+
number: require('./types/number'),
|
|
22
|
+
object: require('./types/object'),
|
|
23
|
+
string: require('./types/string')
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
|
|
@@ -330,7 +330,11 @@ internals.root = function () {
|
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
if (rule.setup) {
|
|
333
|
-
rule.setup.call(schema, arg);
|
|
333
|
+
const newSchema = rule.setup.call(schema, arg);
|
|
334
|
+
if (newSchema !== undefined) {
|
|
335
|
+
Hoek.assert(newSchema instanceof Any, `Setup of extension Joi.${this._type}().${rule.name}() must return undefined or a Joi object`);
|
|
336
|
+
schema = newSchema;
|
|
337
|
+
}
|
|
334
338
|
}
|
|
335
339
|
|
|
336
340
|
return schema;
|
package/lib/language.js
CHANGED
|
@@ -42,6 +42,7 @@ exports.errors = {
|
|
|
42
42
|
length: 'must contain {{limit}} items',
|
|
43
43
|
ordered: 'at position {{pos}} fails because {{reason}}',
|
|
44
44
|
orderedLength: 'at position {{pos}} fails because array must contain at most {{limit}} items',
|
|
45
|
+
ref: 'references "{{ref}}" which is not a positive integer',
|
|
45
46
|
sparse: 'must not be a sparse array',
|
|
46
47
|
unique: 'position {{pos}} contains a duplicate value'
|
|
47
48
|
},
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
// Load modules
|
|
4
4
|
|
|
5
5
|
const Hoek = require('hoek');
|
|
6
|
-
const Any = require('
|
|
7
|
-
const Cast = require('
|
|
8
|
-
const Ref = require('
|
|
6
|
+
const Any = require('../any');
|
|
7
|
+
const Cast = require('../../cast');
|
|
8
|
+
const Ref = require('../../ref');
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
// Declare internals
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// Load modules
|
|
4
4
|
|
|
5
5
|
const Hoek = require('hoek');
|
|
6
|
-
const Ref = require('
|
|
7
|
-
const Errors = require('
|
|
6
|
+
const Ref = require('../../ref');
|
|
7
|
+
const Errors = require('../../errors');
|
|
8
8
|
let Alternatives = null; // Delay-loaded to prevent circular dependencies
|
|
9
9
|
let Cast = null;
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ let Cast = null;
|
|
|
12
12
|
// Declare internals
|
|
13
13
|
|
|
14
14
|
const internals = {
|
|
15
|
-
Set: require('
|
|
15
|
+
Set: require('../../set')
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
|
|
@@ -35,7 +35,7 @@ module.exports = internals.Any = class {
|
|
|
35
35
|
|
|
36
36
|
constructor() {
|
|
37
37
|
|
|
38
|
-
Cast = Cast || require('
|
|
38
|
+
Cast = Cast || require('../../cast');
|
|
39
39
|
|
|
40
40
|
this.isJoi = true;
|
|
41
41
|
this._type = 'any';
|
|
@@ -83,7 +83,7 @@ module.exports = internals.Any = class {
|
|
|
83
83
|
|
|
84
84
|
checkOptions(options) {
|
|
85
85
|
|
|
86
|
-
const Schemas = require('
|
|
86
|
+
const Schemas = require('../../schemas');
|
|
87
87
|
const result = Schemas.options.validate(options);
|
|
88
88
|
if (result.error) {
|
|
89
89
|
throw new Error(result.error.details[0].message);
|
|
@@ -381,7 +381,7 @@ module.exports = internals.Any = class {
|
|
|
381
381
|
const then = options.hasOwnProperty('then') ? this.concat(Cast.schema(options.then)) : undefined;
|
|
382
382
|
const otherwise = options.hasOwnProperty('otherwise') ? this.concat(Cast.schema(options.otherwise)) : undefined;
|
|
383
383
|
|
|
384
|
-
Alternatives = Alternatives || require('
|
|
384
|
+
Alternatives = Alternatives || require('../alternatives');
|
|
385
385
|
const obj = Alternatives.when(ref, { is: options.is, then, otherwise });
|
|
386
386
|
obj._flags.presence = 'ignore';
|
|
387
387
|
obj._baseType = this;
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// Load modules
|
|
4
4
|
|
|
5
|
-
const Any = require('
|
|
6
|
-
const Cast = require('
|
|
5
|
+
const Any = require('../any');
|
|
6
|
+
const Cast = require('../../cast');
|
|
7
|
+
const Ref = require('../../ref');
|
|
7
8
|
const Hoek = require('hoek');
|
|
8
9
|
|
|
9
10
|
|
|
@@ -390,11 +391,25 @@ internals.Array = class extends Any {
|
|
|
390
391
|
|
|
391
392
|
min(limit) {
|
|
392
393
|
|
|
393
|
-
|
|
394
|
+
const isRef = Ref.isRef(limit);
|
|
395
|
+
|
|
396
|
+
Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
|
|
394
397
|
|
|
395
398
|
return this._test('min', limit, function (value, state, options) {
|
|
396
399
|
|
|
397
|
-
|
|
400
|
+
let compareTo;
|
|
401
|
+
if (isRef) {
|
|
402
|
+
compareTo = limit(state.reference || state.parent, options);
|
|
403
|
+
|
|
404
|
+
if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
|
|
405
|
+
return this.createError('array.ref', { ref: limit.key }, state, options);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
compareTo = limit;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (value.length >= compareTo) {
|
|
398
413
|
return value;
|
|
399
414
|
}
|
|
400
415
|
|
|
@@ -404,11 +419,25 @@ internals.Array = class extends Any {
|
|
|
404
419
|
|
|
405
420
|
max(limit) {
|
|
406
421
|
|
|
407
|
-
|
|
422
|
+
const isRef = Ref.isRef(limit);
|
|
423
|
+
|
|
424
|
+
Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
|
|
408
425
|
|
|
409
426
|
return this._test('max', limit, function (value, state, options) {
|
|
410
427
|
|
|
411
|
-
|
|
428
|
+
let compareTo;
|
|
429
|
+
if (isRef) {
|
|
430
|
+
compareTo = limit(state.reference || state.parent, options);
|
|
431
|
+
|
|
432
|
+
if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
|
|
433
|
+
return this.createError('array.ref', { ref: limit.key }, state, options);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
compareTo = limit;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (value.length <= compareTo) {
|
|
412
441
|
return value;
|
|
413
442
|
}
|
|
414
443
|
|
|
@@ -418,11 +447,25 @@ internals.Array = class extends Any {
|
|
|
418
447
|
|
|
419
448
|
length(limit) {
|
|
420
449
|
|
|
421
|
-
|
|
450
|
+
const isRef = Ref.isRef(limit);
|
|
451
|
+
|
|
452
|
+
Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
|
|
422
453
|
|
|
423
454
|
return this._test('length', limit, function (value, state, options) {
|
|
424
455
|
|
|
425
|
-
|
|
456
|
+
let compareTo;
|
|
457
|
+
if (isRef) {
|
|
458
|
+
compareTo = limit(state.reference || state.parent, options);
|
|
459
|
+
|
|
460
|
+
if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
|
|
461
|
+
return this.createError('array.ref', { ref: limit.key }, state, options);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
else {
|
|
465
|
+
compareTo = limit;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (value.length === compareTo) {
|
|
426
469
|
return value;
|
|
427
470
|
}
|
|
428
471
|
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
const Hoek = require('hoek');
|
|
6
6
|
const Topo = require('topo');
|
|
7
|
-
const Any = require('
|
|
8
|
-
const Errors = require('
|
|
9
|
-
const Cast = require('
|
|
10
|
-
const Ref = require('
|
|
7
|
+
const Any = require('../any');
|
|
8
|
+
const Errors = require('../../errors');
|
|
9
|
+
const Cast = require('../../cast');
|
|
10
|
+
const Ref = require('../../ref');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
// Declare internals
|
|
@@ -504,6 +504,12 @@ internals.Object = class extends Any {
|
|
|
504
504
|
return this.applyFunctionToChildren(children, 'optional');
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
+
forbiddenKeys(children) {
|
|
508
|
+
|
|
509
|
+
children = Hoek.flatten(Array.prototype.slice.call(arguments));
|
|
510
|
+
return this.applyFunctionToChildren(children, 'forbidden');
|
|
511
|
+
}
|
|
512
|
+
|
|
507
513
|
rename(from, to, options) {
|
|
508
514
|
|
|
509
515
|
Hoek.assert(typeof from === 'string', 'Rename missing the from argument');
|
|
@@ -4,18 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
const Net = require('net');
|
|
6
6
|
const Hoek = require('hoek');
|
|
7
|
-
|
|
8
|
-
const Any = require('
|
|
9
|
-
const Ref = require('
|
|
10
|
-
const JoiDate = require('
|
|
11
|
-
const Uri = require('./
|
|
12
|
-
const Ip = require('./
|
|
7
|
+
let Isemail; // Loaded on demand
|
|
8
|
+
const Any = require('../any');
|
|
9
|
+
const Ref = require('../../ref');
|
|
10
|
+
const JoiDate = require('../date');
|
|
11
|
+
const Uri = require('./uri');
|
|
12
|
+
const Ip = require('./ip');
|
|
13
13
|
|
|
14
14
|
// Declare internals
|
|
15
15
|
|
|
16
16
|
const internals = {
|
|
17
17
|
uriRegex: Uri.createUriRegex(),
|
|
18
|
-
ipRegex: Ip.createIpRegex(['ipv4', 'ipv6', 'ipvfuture'], 'optional')
|
|
18
|
+
ipRegex: Ip.createIpRegex(['ipv4', 'ipv6', 'ipvfuture'], 'optional'),
|
|
19
|
+
guidBrackets: {
|
|
20
|
+
'{': '}', '[': ']', '(': ')', '': ''
|
|
21
|
+
},
|
|
22
|
+
guidVersions: {
|
|
23
|
+
uuidv1: '1',
|
|
24
|
+
uuidv2: '2',
|
|
25
|
+
uuidv3: '3',
|
|
26
|
+
uuidv4: '4',
|
|
27
|
+
uuidv5: '5'
|
|
28
|
+
}
|
|
19
29
|
};
|
|
20
30
|
|
|
21
31
|
internals.String = class extends Any {
|
|
@@ -169,6 +179,8 @@ internals.String = class extends Any {
|
|
|
169
179
|
|
|
170
180
|
return this._test('email', isEmailOptions, function (value, state, options) {
|
|
171
181
|
|
|
182
|
+
Isemail = Isemail || require('isemail');
|
|
183
|
+
|
|
172
184
|
try {
|
|
173
185
|
const result = Isemail.validate(value, isEmailOptions);
|
|
174
186
|
if (result === true || result === 0) {
|
|
@@ -324,19 +336,7 @@ internals.String = class extends Any {
|
|
|
324
336
|
|
|
325
337
|
guid(guidOptions) {
|
|
326
338
|
|
|
327
|
-
|
|
328
|
-
'{': '}', '[': ']', '(': ')', '': ''
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
const uuids = {
|
|
332
|
-
'uuidv1': '1',
|
|
333
|
-
'uuidv2': '2',
|
|
334
|
-
'uuidv3': '3',
|
|
335
|
-
'uuidv4': '4',
|
|
336
|
-
'uuidv5': '5'
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
const versions = [];
|
|
339
|
+
let versionNumbers = '';
|
|
340
340
|
|
|
341
341
|
if (guidOptions && guidOptions.version) {
|
|
342
342
|
if (!Array.isArray(guidOptions.version)) {
|
|
@@ -344,50 +344,36 @@ internals.String = class extends Any {
|
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
Hoek.assert(guidOptions.version.length >= 1, 'version must have at least 1 valid version specified');
|
|
347
|
+
const versions = new Set();
|
|
347
348
|
|
|
348
349
|
for (let i = 0; i < guidOptions.version.length; ++i) {
|
|
349
350
|
let version = guidOptions.version[i];
|
|
350
351
|
Hoek.assert(typeof version === 'string', 'version at position ' + i + ' must be a string');
|
|
351
352
|
version = version.toLowerCase();
|
|
352
|
-
|
|
353
|
-
Hoek.assert(
|
|
354
|
-
versions.
|
|
353
|
+
const versionNumber = internals.guidVersions[version];
|
|
354
|
+
Hoek.assert(versionNumber, 'version at position ' + i + ' must be one of ' + Object.keys(internals.guidVersions).join(', '));
|
|
355
|
+
Hoek.assert(!(versions.has(versionNumber)), 'version at position ' + i + ' must not be a duplicate.');
|
|
356
|
+
|
|
357
|
+
versionNumbers += versionNumber;
|
|
358
|
+
versions.add(versionNumber);
|
|
355
359
|
}
|
|
356
360
|
}
|
|
357
361
|
|
|
358
|
-
const
|
|
362
|
+
const guidRegex = new RegExp(`^([\\[{\\(]?)[0-9A-F]{8}([:-]?)[0-9A-F]{4}\\2?[${versionNumbers || '0-9A-F'}][0-9A-F]{3}\\2?[${versionNumbers ? '89AB' : '0-9A-F'}][0-9A-F]{3}\\2?[0-9A-F]{12}([\\]}\\)]?)$`, 'i');
|
|
359
363
|
|
|
360
364
|
return this._test('guid', guidOptions, function (value, state, options) {
|
|
361
365
|
|
|
362
|
-
const results =
|
|
366
|
+
const results = guidRegex.exec(value);
|
|
363
367
|
|
|
364
368
|
if (!results) {
|
|
365
369
|
return this.createError('string.guid', { value }, state, options);
|
|
366
370
|
}
|
|
367
371
|
|
|
368
372
|
// Matching braces
|
|
369
|
-
if (
|
|
373
|
+
if (internals.guidBrackets[results[1]] !== results[results.length - 1]) {
|
|
370
374
|
return this.createError('string.guid', { value }, state, options);
|
|
371
375
|
}
|
|
372
376
|
|
|
373
|
-
// Matching separators
|
|
374
|
-
if (results[3] !== results[5] || results[3] !== results[7] || results[3] !== results[9]) {
|
|
375
|
-
return this.createError('string.guid', { value }, state, options);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// Specific UUID versions
|
|
379
|
-
if (versions.length) {
|
|
380
|
-
const validVersions = versions.some((uuidVersion) => {
|
|
381
|
-
|
|
382
|
-
return results[6][0] === uuids[uuidVersion];
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
// Valid version and 89AB check
|
|
386
|
-
if (!(validVersions && /[89AB]/i.test(results[8][0]))) {
|
|
387
|
-
return this.createError('string.guid', { value }, state, options);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
377
|
return value;
|
|
392
378
|
});
|
|
393
379
|
}
|
|
@@ -406,9 +392,26 @@ internals.String = class extends Any {
|
|
|
406
392
|
});
|
|
407
393
|
}
|
|
408
394
|
|
|
409
|
-
base64() {
|
|
395
|
+
base64(base64Options) {
|
|
396
|
+
|
|
397
|
+
base64Options = base64Options || {};
|
|
398
|
+
|
|
399
|
+
// Validation.
|
|
400
|
+
Hoek.assert(typeof base64Options === 'object', 'base64 options must be an object');
|
|
401
|
+
Hoek.assert(typeof base64Options.paddingRequired === 'undefined' || typeof base64Options.paddingRequired === 'boolean',
|
|
402
|
+
'paddingRequired must be boolean');
|
|
403
|
+
|
|
404
|
+
// Determine if padding is required.
|
|
405
|
+
const paddingRequired = base64Options.paddingRequired === false ?
|
|
406
|
+
base64Options.paddingRequired
|
|
407
|
+
: base64Options.paddingRequired || true;
|
|
410
408
|
|
|
411
|
-
|
|
409
|
+
// Set validation based on preference.
|
|
410
|
+
const regex = paddingRequired ?
|
|
411
|
+
// Padding is required.
|
|
412
|
+
/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/
|
|
413
|
+
// Padding is optional.
|
|
414
|
+
: /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}(==)?|[A-Za-z0-9+\/]{3}=?)?$/;
|
|
412
415
|
|
|
413
416
|
return this._test('base64', regex, function (value, state, options) {
|
|
414
417
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|