joi 17.13.2 → 18.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/dist/joi-browser.min.js +1 -1
- package/lib/annotate.js +2 -2
- package/lib/base.js +151 -74
- package/lib/cache.js +3 -4
- package/lib/common.js +1 -2
- package/lib/compile.js +23 -23
- package/lib/extend.js +10 -11
- package/lib/index.d.ts +78 -20
- package/lib/index.js +9 -10
- package/lib/manifest.js +15 -16
- package/lib/messages.js +10 -11
- package/lib/modify.js +10 -10
- package/lib/ref.js +15 -17
- package/lib/state.js +4 -5
- package/lib/template.js +8 -10
- package/lib/trace.js +4 -4
- package/lib/types/alternatives.js +39 -13
- package/lib/types/any.js +5 -5
- package/lib/types/array.js +32 -10
- package/lib/types/binary.js +3 -3
- package/lib/types/boolean.js +3 -3
- package/lib/types/date.js +3 -3
- package/lib/types/function.js +4 -4
- package/lib/types/keys.js +39 -16
- package/lib/types/link.js +11 -11
- package/lib/types/number.js +4 -4
- package/lib/types/string.js +84 -52
- package/lib/types/symbol.js +5 -5
- package/lib/validator.js +26 -18
- package/lib/values.js +4 -5
- package/package.json +21 -12
package/lib/types/date.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { assert } = require('@hapi/hoek');
|
|
4
4
|
|
|
5
5
|
const Any = require('./any');
|
|
6
6
|
const Common = require('../common');
|
|
@@ -78,7 +78,7 @@ module.exports = Any.extend({
|
|
|
78
78
|
format: {
|
|
79
79
|
method(format) {
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
assert(['iso', 'javascript', 'unix'].includes(format), 'Unknown date format', format);
|
|
82
82
|
|
|
83
83
|
return this.$_setFlag('format', format);
|
|
84
84
|
}
|
|
@@ -122,7 +122,7 @@ module.exports = Any.extend({
|
|
|
122
122
|
timestamp: {
|
|
123
123
|
method(type = 'javascript') {
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
assert(['javascript', 'unix'].includes(type), '"type" must be one of "javascript, unix"');
|
|
126
126
|
|
|
127
127
|
return this.format(type);
|
|
128
128
|
}
|
package/lib/types/function.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { assert } = require('@hapi/hoek');
|
|
4
4
|
|
|
5
5
|
const Keys = require('./keys');
|
|
6
6
|
|
|
@@ -20,7 +20,7 @@ module.exports = Keys.extend({
|
|
|
20
20
|
arity: {
|
|
21
21
|
method(n) {
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
assert(Number.isSafeInteger(n) && n >= 0, 'n must be a positive integer');
|
|
24
24
|
|
|
25
25
|
return this.$_addRule({ name: 'arity', args: { n } });
|
|
26
26
|
},
|
|
@@ -52,7 +52,7 @@ module.exports = Keys.extend({
|
|
|
52
52
|
minArity: {
|
|
53
53
|
method(n) {
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
assert(Number.isSafeInteger(n) && n > 0, 'n must be a strict positive integer');
|
|
56
56
|
|
|
57
57
|
return this.$_addRule({ name: 'minArity', args: { n } });
|
|
58
58
|
},
|
|
@@ -69,7 +69,7 @@ module.exports = Keys.extend({
|
|
|
69
69
|
maxArity: {
|
|
70
70
|
method(n) {
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
assert(Number.isSafeInteger(n) && n >= 0, 'n must be a positive integer');
|
|
73
73
|
|
|
74
74
|
return this.$_addRule({ name: 'maxArity', args: { n } });
|
|
75
75
|
},
|
package/lib/types/keys.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const Assert = require('@hapi/hoek/lib/assert');
|
|
5
|
-
const Clone = require('@hapi/hoek/lib/clone');
|
|
3
|
+
const { applyToDefaults, assert, clone: Clone } = require('@hapi/hoek');
|
|
6
4
|
const Topo = require('@hapi/topo');
|
|
7
5
|
|
|
8
6
|
const Any = require('./any');
|
|
@@ -199,7 +197,7 @@ module.exports = Any.extend({
|
|
|
199
197
|
subject = Compile.ref(subject);
|
|
200
198
|
}
|
|
201
199
|
|
|
202
|
-
|
|
200
|
+
assert(message === undefined || typeof message === 'string', 'Message must be a string');
|
|
203
201
|
|
|
204
202
|
schema = this.$_compile(schema, { appendPath: true });
|
|
205
203
|
|
|
@@ -225,7 +223,7 @@ module.exports = Any.extend({
|
|
|
225
223
|
instance: {
|
|
226
224
|
method(constructor, name) {
|
|
227
225
|
|
|
228
|
-
|
|
226
|
+
assert(typeof constructor === 'function', 'constructor must be a function');
|
|
229
227
|
|
|
230
228
|
name = name || constructor.name;
|
|
231
229
|
|
|
@@ -245,8 +243,8 @@ module.exports = Any.extend({
|
|
|
245
243
|
keys: {
|
|
246
244
|
method(schema) {
|
|
247
245
|
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
assert(schema === undefined || typeof schema === 'object', 'Object schema must be a valid object');
|
|
247
|
+
assert(!Common.isSchema(schema), 'Object schema cannot be a joi schema');
|
|
250
248
|
|
|
251
249
|
const obj = this.clone();
|
|
252
250
|
|
|
@@ -337,11 +335,11 @@ module.exports = Any.extend({
|
|
|
337
335
|
pattern = this.$_compile(pattern, { appendPath: true });
|
|
338
336
|
}
|
|
339
337
|
|
|
340
|
-
|
|
338
|
+
assert(schema !== undefined, 'Invalid rule');
|
|
341
339
|
Common.assertOptions(options, ['fallthrough', 'matches']);
|
|
342
340
|
|
|
343
341
|
if (isRegExp) {
|
|
344
|
-
|
|
342
|
+
assert(!pattern.flags.includes('g') && !pattern.flags.includes('y'), 'pattern should not use global or sticky mode');
|
|
345
343
|
}
|
|
346
344
|
|
|
347
345
|
schema = this.$_compile(schema, { appendPath: true });
|
|
@@ -402,9 +400,9 @@ module.exports = Any.extend({
|
|
|
402
400
|
rename: {
|
|
403
401
|
method(from, to, options = {}) {
|
|
404
402
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
403
|
+
assert(typeof from === 'string' || from instanceof RegExp, 'Rename missing the from argument');
|
|
404
|
+
assert(typeof to === 'string' || to instanceof Template, 'Invalid rename to argument');
|
|
405
|
+
assert(to !== from, 'Cannot rename key to same name:', from);
|
|
408
406
|
|
|
409
407
|
Common.assertOptions(options, ['alias', 'ignoreUndefined', 'override', 'multiple']);
|
|
410
408
|
|
|
@@ -412,7 +410,7 @@ module.exports = Any.extend({
|
|
|
412
410
|
|
|
413
411
|
obj.$_terms.renames = obj.$_terms.renames || [];
|
|
414
412
|
for (const rename of obj.$_terms.renames) {
|
|
415
|
-
|
|
413
|
+
assert(rename.from !== from, 'Cannot rename the same key multiple times');
|
|
416
414
|
}
|
|
417
415
|
|
|
418
416
|
if (to instanceof Template) {
|
|
@@ -422,7 +420,7 @@ module.exports = Any.extend({
|
|
|
422
420
|
obj.$_terms.renames.push({
|
|
423
421
|
from,
|
|
424
422
|
to,
|
|
425
|
-
options:
|
|
423
|
+
options: applyToDefaults(internals.renameDefaults, options)
|
|
426
424
|
});
|
|
427
425
|
|
|
428
426
|
return obj;
|
|
@@ -486,6 +484,31 @@ module.exports = Any.extend({
|
|
|
486
484
|
}
|
|
487
485
|
|
|
488
486
|
return this.$_parent('default', value, options);
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
isAsync() {
|
|
490
|
+
|
|
491
|
+
if (this.$_terms.externals?.length) {
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (this.$_terms.keys?.length) {
|
|
496
|
+
for (const key of this.$_terms.keys) {
|
|
497
|
+
if (key.schema.isAsync()) {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (this.$_terms.patterns?.length) {
|
|
504
|
+
for (const pattern of this.$_terms.patterns) {
|
|
505
|
+
if (pattern.rule.isAsync()) {
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return false;
|
|
489
512
|
}
|
|
490
513
|
},
|
|
491
514
|
|
|
@@ -589,7 +612,7 @@ internals.clone = function (value, prefs) {
|
|
|
589
612
|
|
|
590
613
|
internals.dependency = function (schema, rel, key, peers, options) {
|
|
591
614
|
|
|
592
|
-
|
|
615
|
+
assert(key === null || typeof key === 'string', rel, 'key must be a strings');
|
|
593
616
|
|
|
594
617
|
// Extract options from peers array
|
|
595
618
|
|
|
@@ -606,7 +629,7 @@ internals.dependency = function (schema, rel, key, peers, options) {
|
|
|
606
629
|
const separator = Common.default(options.separator, '.');
|
|
607
630
|
const paths = [];
|
|
608
631
|
for (const peer of peers) {
|
|
609
|
-
|
|
632
|
+
assert(typeof peer === 'string', rel, 'peers must be strings');
|
|
610
633
|
paths.push(Compile.ref(peer, { separator, ancestor: 0, prefix: false }));
|
|
611
634
|
}
|
|
612
635
|
|
package/lib/types/link.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { assert } = require('@hapi/hoek');
|
|
4
4
|
|
|
5
5
|
const Any = require('./any');
|
|
6
6
|
const Common = require('../common');
|
|
@@ -31,7 +31,7 @@ module.exports = Any.extend({
|
|
|
31
31
|
|
|
32
32
|
validate(value, { schema, state, prefs }) {
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
assert(schema.$_terms.link, 'Uninitialized link schema');
|
|
35
35
|
|
|
36
36
|
const linked = internals.generate(schema, value, state, prefs);
|
|
37
37
|
const ref = schema.$_terms.link[0].ref;
|
|
@@ -48,12 +48,12 @@ module.exports = Any.extend({
|
|
|
48
48
|
ref: {
|
|
49
49
|
method(ref) {
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
assert(!this.$_terms.link, 'Cannot reinitialize schema');
|
|
52
52
|
|
|
53
53
|
ref = Compile.ref(ref);
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
assert(ref.type === 'value' || ref.type === 'local', 'Invalid reference type:', ref.type);
|
|
56
|
+
assert(ref.type === 'local' || ref.ancestor === 'root' || ref.ancestor > 0, 'Link cannot reference itself');
|
|
57
57
|
|
|
58
58
|
const obj = this.clone();
|
|
59
59
|
obj.$_terms.link = [{ ref }];
|
|
@@ -73,9 +73,9 @@ module.exports = Any.extend({
|
|
|
73
73
|
|
|
74
74
|
concat(source) {
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
assert(this.$_terms.link, 'Uninitialized link schema');
|
|
77
|
+
assert(Common.isSchema(source), 'Invalid schema object');
|
|
78
|
+
assert(source.type !== 'link', 'Cannot merge type link with another link');
|
|
79
79
|
|
|
80
80
|
const obj = this.clone();
|
|
81
81
|
|
|
@@ -92,7 +92,7 @@ module.exports = Any.extend({
|
|
|
92
92
|
|
|
93
93
|
build(obj, desc) {
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
assert(desc.link, 'Invalid link description missing link');
|
|
96
96
|
return obj.ref(desc.link);
|
|
97
97
|
}
|
|
98
98
|
}
|
|
@@ -115,7 +115,7 @@ internals.generate = function (schema, value, state, prefs) {
|
|
|
115
115
|
try {
|
|
116
116
|
linked = path.length ? perspective.$_reach(path) : perspective;
|
|
117
117
|
}
|
|
118
|
-
catch
|
|
118
|
+
catch {
|
|
119
119
|
internals.assert(false, 'to non-existing schema', ref, schema, state, prefs);
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -164,5 +164,5 @@ internals.assert = function (condition, message, ref, schema, state, prefs) {
|
|
|
164
164
|
return;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
assert(false, `"${Errors.label(schema._flags, state, prefs)}" contains link reference "${ref.display}" ${message}`);
|
|
168
168
|
};
|
package/lib/types/number.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { assert } = require('@hapi/hoek');
|
|
4
4
|
|
|
5
5
|
const Any = require('./any');
|
|
6
6
|
const Common = require('../common');
|
|
@@ -251,7 +251,7 @@ module.exports = Any.extend({
|
|
|
251
251
|
precision: {
|
|
252
252
|
method(limit) {
|
|
253
253
|
|
|
254
|
-
|
|
254
|
+
assert(Number.isSafeInteger(limit), 'limit must be an integer');
|
|
255
255
|
|
|
256
256
|
return this.$_addRule({ name: 'precision', args: { limit } });
|
|
257
257
|
},
|
|
@@ -271,7 +271,7 @@ module.exports = Any.extend({
|
|
|
271
271
|
sign: {
|
|
272
272
|
method(sign) {
|
|
273
273
|
|
|
274
|
-
|
|
274
|
+
assert(['negative', 'positive'].includes(sign), 'Invalid sign', sign);
|
|
275
275
|
|
|
276
276
|
return this.$_addRule({ name: 'sign', args: { sign } });
|
|
277
277
|
},
|
|
@@ -290,7 +290,7 @@ module.exports = Any.extend({
|
|
|
290
290
|
unsafe: {
|
|
291
291
|
method(enabled = true) {
|
|
292
292
|
|
|
293
|
-
|
|
293
|
+
assert(typeof enabled === 'boolean', 'enabled must be a boolean');
|
|
294
294
|
|
|
295
295
|
return this.$_setFlag('unsafe', enabled);
|
|
296
296
|
}
|
package/lib/types/string.js
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const Ip = require('@sideway/address/lib/ip');
|
|
7
|
-
const EscapeRegex = require('@hapi/hoek/lib/escapeRegex');
|
|
8
|
-
const Tlds = require('@sideway/address/lib/tlds');
|
|
9
|
-
const Uri = require('@sideway/address/lib/uri');
|
|
3
|
+
const { assert, escapeRegex } = require('@hapi/hoek');
|
|
4
|
+
const { isDomainValid, isEmailValid, ipRegex, uriRegex } = require('@hapi/address');
|
|
5
|
+
const Tlds = require('@hapi/tlds');
|
|
10
6
|
|
|
11
7
|
const Any = require('./any');
|
|
12
8
|
const Common = require('../common');
|
|
13
9
|
|
|
14
10
|
|
|
15
11
|
const internals = {
|
|
16
|
-
tlds: Tlds instanceof Set ? { tlds: { allow: Tlds, deny: null } } : false, // $lab:coverage:ignore$
|
|
12
|
+
tlds: Tlds.tlds instanceof Set ? { tlds: { allow: Tlds.tlds, deny: null } } : false, // $lab:coverage:ignore$
|
|
17
13
|
base64Regex: {
|
|
18
14
|
// paddingRequired
|
|
19
15
|
true: {
|
|
@@ -32,7 +28,7 @@ const internals = {
|
|
|
32
28
|
withOptionalPrefix: /^(?:0x)?[0-9a-f]+$/i,
|
|
33
29
|
withoutPrefix: /^[0-9a-f]+$/i
|
|
34
30
|
},
|
|
35
|
-
ipRegex:
|
|
31
|
+
ipRegex: ipRegex({ cidr: 'forbidden' }).regex,
|
|
36
32
|
isoDurationRegex: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/,
|
|
37
33
|
|
|
38
34
|
guidBrackets: {
|
|
@@ -171,8 +167,8 @@ module.exports = Any.extend({
|
|
|
171
167
|
Common.assertOptions(options, ['paddingRequired', 'urlSafe']);
|
|
172
168
|
|
|
173
169
|
options = { urlSafe: false, paddingRequired: true, ...options };
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
assert(typeof options.paddingRequired === 'boolean', 'paddingRequired must be boolean');
|
|
171
|
+
assert(typeof options.urlSafe === 'boolean', 'urlSafe must be boolean');
|
|
176
172
|
|
|
177
173
|
return this.$_addRule({ name: 'base64', args: { options } });
|
|
178
174
|
},
|
|
@@ -190,7 +186,7 @@ module.exports = Any.extend({
|
|
|
190
186
|
case: {
|
|
191
187
|
method(direction) {
|
|
192
188
|
|
|
193
|
-
|
|
189
|
+
assert(['lower', 'upper'].includes(direction), 'Invalid case:', direction);
|
|
194
190
|
|
|
195
191
|
return this.$_addRule({ name: 'case', args: { direction } });
|
|
196
192
|
},
|
|
@@ -240,7 +236,7 @@ module.exports = Any.extend({
|
|
|
240
236
|
Common.assertOptions(options, ['paddingRequired']);
|
|
241
237
|
|
|
242
238
|
options = { paddingRequired: true, ...options };
|
|
243
|
-
|
|
239
|
+
assert(typeof options.paddingRequired === 'boolean', 'paddingRequired must be boolean');
|
|
244
240
|
|
|
245
241
|
return this.$_addRule({ name: 'dataUri', args: { options } });
|
|
246
242
|
},
|
|
@@ -271,7 +267,7 @@ module.exports = Any.extend({
|
|
|
271
267
|
method(options) {
|
|
272
268
|
|
|
273
269
|
if (options) {
|
|
274
|
-
Common.assertOptions(options, ['allowFullyQualified', 'allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
|
|
270
|
+
Common.assertOptions(options, ['allowFullyQualified', 'allowUnicode', 'allowUnderscore', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
|
|
275
271
|
}
|
|
276
272
|
|
|
277
273
|
const address = internals.addressOptions(options);
|
|
@@ -279,7 +275,7 @@ module.exports = Any.extend({
|
|
|
279
275
|
},
|
|
280
276
|
validate(value, helpers, args, { address }) {
|
|
281
277
|
|
|
282
|
-
if (
|
|
278
|
+
if (isDomainValid(value, address)) {
|
|
283
279
|
return value;
|
|
284
280
|
}
|
|
285
281
|
|
|
@@ -291,10 +287,10 @@ module.exports = Any.extend({
|
|
|
291
287
|
method(options = {}) {
|
|
292
288
|
|
|
293
289
|
Common.assertOptions(options, ['allowFullyQualified', 'allowUnicode', 'ignoreLength', 'maxDomainSegments', 'minDomainSegments', 'multiple', 'separator', 'tlds']);
|
|
294
|
-
|
|
290
|
+
assert(options.multiple === undefined || typeof options.multiple === 'boolean', 'multiple option must be an boolean');
|
|
295
291
|
|
|
296
292
|
const address = internals.addressOptions(options);
|
|
297
|
-
const regex = new RegExp(`\\s*[${options.separator ?
|
|
293
|
+
const regex = new RegExp(`\\s*[${options.separator ? escapeRegex(options.separator) : ','}]\\s*`);
|
|
298
294
|
|
|
299
295
|
return this.$_addRule({ name: 'email', args: { options }, regex, address });
|
|
300
296
|
},
|
|
@@ -303,7 +299,7 @@ module.exports = Any.extend({
|
|
|
303
299
|
const emails = options.multiple ? value.split(regex) : [value];
|
|
304
300
|
const invalids = [];
|
|
305
301
|
for (const email of emails) {
|
|
306
|
-
if (!
|
|
302
|
+
if (!isEmailValid(email, address)) {
|
|
307
303
|
invalids.push(email);
|
|
308
304
|
}
|
|
309
305
|
}
|
|
@@ -320,37 +316,72 @@ module.exports = Any.extend({
|
|
|
320
316
|
alias: 'uuid',
|
|
321
317
|
method(options = {}) {
|
|
322
318
|
|
|
323
|
-
Common.assertOptions(options, ['version', 'separator']);
|
|
319
|
+
Common.assertOptions(options, ['version', 'separator', 'wrapper']);
|
|
320
|
+
|
|
321
|
+
assert(
|
|
322
|
+
options.wrapper === undefined ||
|
|
323
|
+
typeof options.wrapper === 'boolean' ||
|
|
324
|
+
(typeof options.wrapper === 'string' && typeof internals.guidBrackets[options.wrapper] === 'string'),
|
|
325
|
+
`"wrapper" must be true, false, or one of "${Object.keys(internals.guidBrackets).filter(Boolean).join('", "')}"`
|
|
326
|
+
);
|
|
324
327
|
|
|
325
328
|
let versionNumbers = '';
|
|
326
329
|
|
|
327
330
|
if (options.version) {
|
|
328
331
|
const versions = [].concat(options.version);
|
|
329
332
|
|
|
330
|
-
|
|
333
|
+
assert(versions.length >= 1, 'version must have at least 1 valid version specified');
|
|
331
334
|
const set = new Set();
|
|
332
335
|
|
|
333
336
|
for (let i = 0; i < versions.length; ++i) {
|
|
334
337
|
const version = versions[i];
|
|
335
|
-
|
|
338
|
+
assert(typeof version === 'string', 'version at position ' + i + ' must be a string');
|
|
336
339
|
const versionNumber = internals.guidVersions[version.toLowerCase()];
|
|
337
|
-
|
|
338
|
-
|
|
340
|
+
assert(versionNumber, 'version at position ' + i + ' must be one of ' + Object.keys(internals.guidVersions).join(', '));
|
|
341
|
+
assert(!set.has(versionNumber), 'version at position ' + i + ' must not be a duplicate');
|
|
339
342
|
|
|
340
343
|
versionNumbers += versionNumber;
|
|
341
344
|
set.add(versionNumber);
|
|
342
345
|
}
|
|
343
346
|
}
|
|
344
347
|
|
|
345
|
-
|
|
348
|
+
assert(internals.guidSeparators.has(options.separator), 'separator must be one of true, false, "-", or ":"');
|
|
346
349
|
const separator = options.separator === undefined ? '[:-]?' :
|
|
347
350
|
options.separator === true ? '[:-]' :
|
|
348
351
|
options.separator === false ? '[]?' : `\\${options.separator}`;
|
|
349
352
|
|
|
350
|
-
|
|
353
|
+
let wrapperStart;
|
|
354
|
+
let wrapperEnd;
|
|
355
|
+
|
|
356
|
+
if (options.wrapper === undefined) {
|
|
357
|
+
wrapperStart = '[\\[{\\(]?';
|
|
358
|
+
wrapperEnd = '[\\]}\\)]?';
|
|
359
|
+
}
|
|
360
|
+
else if (options.wrapper === true) {
|
|
361
|
+
wrapperStart = '[\\[{\\(]';
|
|
362
|
+
wrapperEnd = '[\\]}\\)]';
|
|
363
|
+
}
|
|
364
|
+
else if (options.wrapper === false) {
|
|
365
|
+
wrapperStart = '';
|
|
366
|
+
wrapperEnd = '';
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
wrapperStart = escapeRegex(options.wrapper);
|
|
370
|
+
wrapperEnd = escapeRegex(internals.guidBrackets[options.wrapper]);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const regex = new RegExp(
|
|
374
|
+
`^(${wrapperStart})[0-9A-F]{8}(${separator})[0-9A-F]{4}\\2?[${
|
|
375
|
+
versionNumbers || '0-9A-F'
|
|
376
|
+
}][0-9A-F]{3}\\2?[${
|
|
377
|
+
versionNumbers ? '89AB' : '0-9A-F'
|
|
378
|
+
}][0-9A-F]{3}\\2?[0-9A-F]{12}(${wrapperEnd})$`,
|
|
379
|
+
'i'
|
|
380
|
+
);
|
|
351
381
|
|
|
352
382
|
return this.$_addRule({ name: 'guid', args: { options }, regex });
|
|
353
383
|
},
|
|
384
|
+
|
|
354
385
|
validate(value, helpers, args, { regex }) {
|
|
355
386
|
|
|
356
387
|
const results = regex.exec(value);
|
|
@@ -359,9 +390,10 @@ module.exports = Any.extend({
|
|
|
359
390
|
return helpers.error('string.guid');
|
|
360
391
|
}
|
|
361
392
|
|
|
362
|
-
|
|
393
|
+
const open = results[1];
|
|
394
|
+
const close = results[results.length - 1];
|
|
363
395
|
|
|
364
|
-
if (internals.guidBrackets[
|
|
396
|
+
if ((open || close) && internals.guidBrackets[open] !== close) {
|
|
365
397
|
return helpers.error('string.guid');
|
|
366
398
|
}
|
|
367
399
|
|
|
@@ -375,8 +407,8 @@ module.exports = Any.extend({
|
|
|
375
407
|
Common.assertOptions(options, ['byteAligned', 'prefix']);
|
|
376
408
|
|
|
377
409
|
options = { byteAligned: false, prefix: false, ...options };
|
|
378
|
-
|
|
379
|
-
|
|
410
|
+
assert(typeof options.byteAligned === 'boolean', 'byteAligned must be boolean');
|
|
411
|
+
assert(typeof options.prefix === 'boolean' || options.prefix === 'optional', 'prefix must be boolean or "optional"');
|
|
380
412
|
|
|
381
413
|
return this.$_addRule({ name: 'hex', args: { options } });
|
|
382
414
|
},
|
|
@@ -408,7 +440,7 @@ module.exports = Any.extend({
|
|
|
408
440
|
},
|
|
409
441
|
validate(value, helpers) {
|
|
410
442
|
|
|
411
|
-
if (
|
|
443
|
+
if (isDomainValid(value, { minDomainSegments: 1 }) ||
|
|
412
444
|
internals.ipRegex.test(value)) {
|
|
413
445
|
|
|
414
446
|
return value;
|
|
@@ -430,7 +462,7 @@ module.exports = Any.extend({
|
|
|
430
462
|
|
|
431
463
|
Common.assertOptions(options, ['cidr', 'version']);
|
|
432
464
|
|
|
433
|
-
const { cidr, versions, regex } =
|
|
465
|
+
const { cidr, versions, regex } = ipRegex(options);
|
|
434
466
|
const version = options.version ? versions : undefined;
|
|
435
467
|
return this.$_addRule({ name: 'ip', args: { options: { cidr, version } }, regex });
|
|
436
468
|
},
|
|
@@ -529,7 +561,7 @@ module.exports = Any.extend({
|
|
|
529
561
|
normalize: {
|
|
530
562
|
method(form = 'NFC') {
|
|
531
563
|
|
|
532
|
-
|
|
564
|
+
assert(internals.normalizationForms.includes(form), 'normalization form must be one of ' + internals.normalizationForms.join(', '));
|
|
533
565
|
|
|
534
566
|
return this.$_addRule({ name: 'normalize', args: { form } });
|
|
535
567
|
},
|
|
@@ -548,8 +580,8 @@ module.exports = Any.extend({
|
|
|
548
580
|
alias: 'regex',
|
|
549
581
|
method(regex, options = {}) {
|
|
550
582
|
|
|
551
|
-
|
|
552
|
-
|
|
583
|
+
assert(regex instanceof RegExp, 'regex must be a RegExp');
|
|
584
|
+
assert(!regex.flags.includes('g') && !regex.flags.includes('y'), 'regex should not use global or sticky mode');
|
|
553
585
|
|
|
554
586
|
if (typeof options === 'string') {
|
|
555
587
|
options = { name: options };
|
|
@@ -578,11 +610,11 @@ module.exports = Any.extend({
|
|
|
578
610
|
method(pattern, replacement) {
|
|
579
611
|
|
|
580
612
|
if (typeof pattern === 'string') {
|
|
581
|
-
pattern = new RegExp(
|
|
613
|
+
pattern = new RegExp(escapeRegex(pattern), 'g');
|
|
582
614
|
}
|
|
583
615
|
|
|
584
|
-
|
|
585
|
-
|
|
616
|
+
assert(pattern instanceof RegExp, 'pattern must be a RegExp');
|
|
617
|
+
assert(typeof replacement === 'string', 'replacement must be a String');
|
|
586
618
|
|
|
587
619
|
const obj = this.clone();
|
|
588
620
|
|
|
@@ -613,7 +645,7 @@ module.exports = Any.extend({
|
|
|
613
645
|
trim: {
|
|
614
646
|
method(enabled = true) {
|
|
615
647
|
|
|
616
|
-
|
|
648
|
+
assert(typeof enabled === 'boolean', 'enabled must be a boolean');
|
|
617
649
|
|
|
618
650
|
return this.$_addRule({ name: 'trim', args: { enabled } });
|
|
619
651
|
},
|
|
@@ -633,7 +665,7 @@ module.exports = Any.extend({
|
|
|
633
665
|
truncate: {
|
|
634
666
|
method(enabled = true) {
|
|
635
667
|
|
|
636
|
-
|
|
668
|
+
assert(typeof enabled === 'boolean', 'enabled must be a boolean');
|
|
637
669
|
|
|
638
670
|
return this.$_setFlag('truncate', enabled);
|
|
639
671
|
}
|
|
@@ -655,7 +687,7 @@ module.exports = Any.extend({
|
|
|
655
687
|
Common.assertOptions(options.domain, ['allowFullyQualified', 'allowUnicode', 'maxDomainSegments', 'minDomainSegments', 'tlds']);
|
|
656
688
|
}
|
|
657
689
|
|
|
658
|
-
const { regex, scheme } =
|
|
690
|
+
const { regex, scheme } = uriRegex(options);
|
|
659
691
|
const domain = options.domain ? internals.addressOptions(options.domain) : null;
|
|
660
692
|
return this.$_addRule({ name: 'uri', args: { options }, regex, domain, scheme });
|
|
661
693
|
},
|
|
@@ -679,7 +711,7 @@ module.exports = Any.extend({
|
|
|
679
711
|
const matched = match[1] || match[2];
|
|
680
712
|
if (domain &&
|
|
681
713
|
(!options.allowRelative || matched) &&
|
|
682
|
-
!
|
|
714
|
+
!isDomainValid(matched, domain)) {
|
|
683
715
|
|
|
684
716
|
return helpers.error('string.domain', { value: matched });
|
|
685
717
|
}
|
|
@@ -760,12 +792,12 @@ internals.addressOptions = function (options) {
|
|
|
760
792
|
|
|
761
793
|
// minDomainSegments
|
|
762
794
|
|
|
763
|
-
|
|
795
|
+
assert(options.minDomainSegments === undefined ||
|
|
764
796
|
Number.isSafeInteger(options.minDomainSegments) && options.minDomainSegments > 0, 'minDomainSegments must be a positive integer');
|
|
765
797
|
|
|
766
798
|
// maxDomainSegments
|
|
767
799
|
|
|
768
|
-
|
|
800
|
+
assert(options.maxDomainSegments === undefined ||
|
|
769
801
|
Number.isSafeInteger(options.maxDomainSegments) && options.maxDomainSegments > 0, 'maxDomainSegments must be a positive integer');
|
|
770
802
|
|
|
771
803
|
// tlds
|
|
@@ -777,11 +809,11 @@ internals.addressOptions = function (options) {
|
|
|
777
809
|
if (options.tlds === true ||
|
|
778
810
|
options.tlds === undefined) {
|
|
779
811
|
|
|
780
|
-
|
|
812
|
+
assert(internals.tlds, 'Built-in TLD list disabled');
|
|
781
813
|
return Object.assign({}, options, internals.tlds);
|
|
782
814
|
}
|
|
783
815
|
|
|
784
|
-
|
|
816
|
+
assert(typeof options.tlds === 'object', 'tlds must be true, false, or an object');
|
|
785
817
|
|
|
786
818
|
const deny = options.tlds.deny;
|
|
787
819
|
if (deny) {
|
|
@@ -789,19 +821,19 @@ internals.addressOptions = function (options) {
|
|
|
789
821
|
options = Object.assign({}, options, { tlds: { deny: new Set(deny) } });
|
|
790
822
|
}
|
|
791
823
|
|
|
792
|
-
|
|
793
|
-
|
|
824
|
+
assert(options.tlds.deny instanceof Set, 'tlds.deny must be an array, Set, or boolean');
|
|
825
|
+
assert(!options.tlds.allow, 'Cannot specify both tlds.allow and tlds.deny lists');
|
|
794
826
|
internals.validateTlds(options.tlds.deny, 'tlds.deny');
|
|
795
827
|
return options;
|
|
796
828
|
}
|
|
797
829
|
|
|
798
830
|
const allow = options.tlds.allow;
|
|
799
831
|
if (!allow) {
|
|
800
|
-
return options;
|
|
832
|
+
return { ...options, tlds: false };
|
|
801
833
|
}
|
|
802
834
|
|
|
803
835
|
if (allow === true) {
|
|
804
|
-
|
|
836
|
+
assert(internals.tlds, 'Built-in TLD list disabled');
|
|
805
837
|
return Object.assign({}, options, internals.tlds);
|
|
806
838
|
}
|
|
807
839
|
|
|
@@ -809,7 +841,7 @@ internals.addressOptions = function (options) {
|
|
|
809
841
|
options = Object.assign({}, options, { tlds: { allow: new Set(allow) } });
|
|
810
842
|
}
|
|
811
843
|
|
|
812
|
-
|
|
844
|
+
assert(options.tlds.allow instanceof Set, 'tlds.allow must be an array, Set, or boolean');
|
|
813
845
|
internals.validateTlds(options.tlds.allow, 'tlds.allow');
|
|
814
846
|
return options;
|
|
815
847
|
};
|
|
@@ -818,7 +850,7 @@ internals.addressOptions = function (options) {
|
|
|
818
850
|
internals.validateTlds = function (set, source) {
|
|
819
851
|
|
|
820
852
|
for (const tld of set) {
|
|
821
|
-
|
|
853
|
+
assert(isDomainValid(tld, { minDomainSegments: 1, maxDomainSegments: 1 }), `${source} must contain valid top level domain names`);
|
|
822
854
|
}
|
|
823
855
|
};
|
|
824
856
|
|
|
@@ -844,7 +876,7 @@ internals.isoDate = function (value) {
|
|
|
844
876
|
|
|
845
877
|
internals.length = function (schema, name, limit, operator, encoding) {
|
|
846
878
|
|
|
847
|
-
|
|
879
|
+
assert(!encoding || Buffer && Buffer.isEncoding(encoding), 'Invalid encoding:', encoding); // $lab:coverage:ignore$
|
|
848
880
|
|
|
849
881
|
return schema.$_addRule({ name, method: 'length', args: { limit, encoding }, operator });
|
|
850
882
|
};
|