joi 8.3.0 → 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/lib/object.js CHANGED
@@ -6,6 +6,7 @@ const Hoek = require('hoek');
6
6
  const Topo = require('topo');
7
7
  const Any = require('./any');
8
8
  const Cast = require('./cast');
9
+ const Ref = require('./ref');
9
10
 
10
11
 
11
12
  // Declare internals
@@ -217,15 +218,10 @@ internals.Object.prototype._base = function (value, state, options) {
217
218
  if (options.stripUnknown ||
218
219
  options.skipFunctions) {
219
220
 
220
- const stripUnknown = options.stripUnknown
221
- ? (options.stripUnknown === true ? true : !!options.stripUnknown.objects)
222
- : false;
223
-
224
-
225
221
  for (let i = 0; i < unprocessedKeys.length; ++i) {
226
222
  const key = unprocessedKeys[i];
227
223
 
228
- if (stripUnknown) {
224
+ if (options.stripUnknown) {
229
225
  delete target[key];
230
226
  delete unprocessed[key];
231
227
  }
@@ -817,4 +813,17 @@ internals.Object.prototype.type = function (constructor, name) {
817
813
  };
818
814
 
819
815
 
816
+ internals.Object.prototype.ref = function () {
817
+
818
+ return this._test('ref', null, (value, state, options) => {
819
+
820
+ if (Ref.isRef(value)) {
821
+ return null;
822
+ }
823
+
824
+ return this.createError('function.ref', null, state, options);
825
+ });
826
+ };
827
+
828
+
820
829
  module.exports = new internals.Object();
package/lib/string.js CHANGED
@@ -79,16 +79,6 @@ internals.String.prototype._base = function (value, state, options) {
79
79
  value = value.replace(replacement.pattern, replacement.replacement);
80
80
  }
81
81
  }
82
-
83
- if (this._flags.truncate) {
84
- for (let i = 0; i < this._tests.length; ++i) {
85
- const test = this._tests[i];
86
- if (test.name === 'max') {
87
- value = value.slice(0, test.arg);
88
- break;
89
- }
90
- }
91
- }
92
82
  }
93
83
 
94
84
  return {
@@ -481,11 +471,4 @@ internals.String.prototype.replace = function (pattern, replacement) {
481
471
  return obj;
482
472
  };
483
473
 
484
- internals.String.prototype.truncate = function (enabled) {
485
-
486
- const obj = this.clone();
487
- obj._flags.truncate = enabled === undefined ? true : !!enabled;
488
- return obj;
489
- };
490
-
491
474
  module.exports = new internals.String();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "joi",
3
3
  "description": "Object schema validation",
4
- "version": "8.3.0",
4
+ "version": "9.0.0-0",
5
5
  "homepage": "https://github.com/hapijs/joi",
6
6
  "repository": "git://github.com/hapijs/joi",
7
7
  "main": "lib/index.js",
@@ -15,22 +15,21 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "hoek": "4.x.x",
18
- "topo": "2.x.x",
19
18
  "isemail": "2.x.x",
20
- "moment": "2.x.x"
19
+ "items": "2.x.x",
20
+ "moment": "2.x.x",
21
+ "topo": "2.x.x"
21
22
  },
22
23
  "devDependencies": {
23
24
  "code": "2.x.x",
24
25
  "lab": "10.x.x",
25
- "markdown-toc": "0.12.x",
26
- "npmignore": "0.2.x"
26
+ "markdown-toc": "0.12.x"
27
27
  },
28
28
  "scripts": {
29
29
  "test": "lab -t 100 -a code -L",
30
30
  "test-cov-html": "lab -r html -o coverage.html -a code",
31
31
  "toc": "node generate-readme-toc.js",
32
- "update-npmignore": "npmignore",
33
- "version": "npm run toc && npm run update-npmignore && git add API.md README.md .npmignore"
32
+ "version": "npm run toc && git add API.md README.md"
34
33
  },
35
34
  "license": "BSD-3-Clause"
36
35
  }
@@ -0,0 +1,490 @@
1
+ 'use strict';
2
+
3
+ // Load modules
4
+
5
+ const Lab = require('lab');
6
+ const Code = require('code');
7
+ const Joi = require('..');
8
+ const Helper = require('./helper');
9
+
10
+
11
+ // Declare internals
12
+
13
+ const internals = {};
14
+
15
+
16
+ // Test shortcuts
17
+
18
+ const lab = exports.lab = Lab.script();
19
+ const describe = lab.describe;
20
+ const it = lab.it;
21
+ const expect = Code.expect;
22
+
23
+
24
+ describe('alternatives', () => {
25
+
26
+ it('fails when no alternatives are provided', (done) => {
27
+
28
+ Joi.alternatives().validate('a', (err, value) => {
29
+
30
+ expect(err).to.exist();
31
+ expect(err.message).to.equal('"value" not matching any of the allowed alternatives');
32
+ done();
33
+ });
34
+ });
35
+
36
+ it('allows undefined when no alternatives are provided', (done) => {
37
+
38
+ Joi.alternatives().validate(undefined, (err, value) => {
39
+
40
+ expect(err).to.not.exist();
41
+ done();
42
+ });
43
+ });
44
+
45
+ it('applies modifiers when higher priority converts', (done) => {
46
+
47
+ const schema = Joi.object({
48
+ a: [
49
+ Joi.number(),
50
+ Joi.string()
51
+ ]
52
+ });
53
+
54
+ schema.validate({ a: '5' }, (err, value) => {
55
+
56
+ expect(err).to.not.exist();
57
+ expect(value.a).to.equal(5);
58
+ done();
59
+ });
60
+ });
61
+
62
+ it('applies modifiers when lower priority valid is a match', (done) => {
63
+
64
+ const schema = Joi.object({
65
+ a: [
66
+ Joi.number(),
67
+ Joi.valid('5')
68
+ ]
69
+ });
70
+
71
+ schema.validate({ a: '5' }, (err, value) => {
72
+
73
+ expect(err).to.not.exist();
74
+ expect(value.a).to.equal(5);
75
+ done();
76
+ });
77
+ });
78
+
79
+ it('does not apply modifier if alternative fails', (done) => {
80
+
81
+ const schema = Joi.object({
82
+ a: [
83
+ Joi.object({ c: Joi.any(), d: Joi.number() }).rename('b', 'c'),
84
+ { b: Joi.any(), d: Joi.string() }
85
+ ]
86
+ });
87
+
88
+ const input = { a: { b: 'any', d: 'string' } };
89
+ schema.validate(input, (err, value) => {
90
+
91
+ expect(err).to.not.exist();
92
+ expect(value.a.b).to.equal('any');
93
+ done();
94
+ });
95
+ });
96
+
97
+ describe('try()', () => {
98
+
99
+ it('throws when missing alternatives', (done) => {
100
+
101
+ expect(() => {
102
+
103
+ Joi.alternatives().try();
104
+ }).to.throw('Cannot add other alternatives without at least one schema');
105
+ done();
106
+ });
107
+ });
108
+
109
+ describe('when()', () => {
110
+
111
+ it('throws on invalid ref (not string)', (done) => {
112
+
113
+ expect(() => {
114
+
115
+ Joi.alternatives().when(5, { is: 6, then: Joi.number() });
116
+ }).to.throw('Invalid reference: 5');
117
+ done();
118
+ });
119
+
120
+ it('validates conditional alternatives', (done) => {
121
+
122
+ const schema = {
123
+ a: Joi.alternatives().when('b', { is: 5, then: 'x', otherwise: 'y' })
124
+ .try('z'),
125
+ b: Joi.any()
126
+ };
127
+
128
+ Helper.validate(schema, [
129
+ [{ a: 'x', b: 5 }, true],
130
+ [{ a: 'x', b: 6 }, false],
131
+ [{ a: 'y', b: 5 }, false],
132
+ [{ a: 'y', b: 6 }, true],
133
+ [{ a: 'z', b: 5 }, false],
134
+ [{ a: 'z', b: 6 }, false]
135
+ ], done);
136
+ });
137
+
138
+ it('validates conditional alternatives (empty key)', (done) => {
139
+
140
+ const schema = {
141
+ a: Joi.alternatives().when('', { is: 5, then: 'x', otherwise: 'y' })
142
+ .try('z'),
143
+ '': Joi.any()
144
+ };
145
+
146
+ Helper.validate(schema, [
147
+ [{ a: 'x', '': 5 }, true],
148
+ [{ a: 'x', '': 6 }, false],
149
+ [{ a: 'y', '': 5 }, false],
150
+ [{ a: 'y', '': 6 }, true],
151
+ [{ a: 'z', '': 5 }, false],
152
+ [{ a: 'z', '': 6 }, false]
153
+ ], done);
154
+ });
155
+
156
+ it('validates only then', (done) => {
157
+
158
+ const schema = {
159
+ a: Joi.alternatives().when(Joi.ref('b'), { is: 5, then: 'x' })
160
+ .try('z'),
161
+ b: Joi.any()
162
+ };
163
+
164
+ Helper.validate(schema, [
165
+ [{ a: 'x', b: 5 }, true],
166
+ [{ a: 'x', b: 6 }, false],
167
+ [{ a: 'y', b: 5 }, false],
168
+ [{ a: 'y', b: 6 }, false],
169
+ [{ a: 'z', b: 5 }, false],
170
+ [{ a: 'z', b: 6 }, true]
171
+ ], done);
172
+ });
173
+
174
+ it('validates only otherwise', (done) => {
175
+
176
+ const schema = {
177
+ a: Joi.alternatives().when('b', { is: 5, otherwise: 'y' })
178
+ .try('z'),
179
+ b: Joi.any()
180
+ };
181
+
182
+ Helper.validate(schema, [
183
+ [{ a: 'x', b: 5 }, false],
184
+ [{ a: 'x', b: 6 }, false],
185
+ [{ a: 'y', b: 5 }, false],
186
+ [{ a: 'y', b: 6 }, true],
187
+ [{ a: 'z', b: 5 }, true],
188
+ [{ a: 'z', b: 6 }, false]
189
+ ], done);
190
+ });
191
+
192
+ it('validates when is is null', (done) => {
193
+
194
+ const schema = {
195
+ a: Joi.alternatives().when('b', { is: null, then: 'x', otherwise: Joi.number() }),
196
+ b: Joi.any()
197
+ };
198
+
199
+ Helper.validate(schema, [
200
+ [{ a: 1 }, true],
201
+ [{ a: 'y' }, false],
202
+ [{ a: 'x', b: null }, true],
203
+ [{ a: 'y', b: null }, false],
204
+ [{ a: 1, b: null }, false]
205
+ ], done);
206
+ });
207
+
208
+ it('validates when is has ref', (done) => {
209
+
210
+ const schema = {
211
+ a: Joi.alternatives().when('b', { is: Joi.ref('c'), then: 'x' }),
212
+ b: Joi.any(),
213
+ c: Joi.number()
214
+ };
215
+
216
+ Helper.validate(schema, [
217
+ [{ a: 'x', b: 5, c: '5' }, true],
218
+ [{ a: 'x', b: 5, c: '1' }, false],
219
+ [{ a: 'x', b: '5', c: '5' }, false],
220
+ [{ a: 'y', b: 5, c: 5 }, false],
221
+ [{ a: 'y' }, false]
222
+ ], done);
223
+ });
224
+
225
+ it('validates when then has ref', (done) => {
226
+
227
+ const schema = {
228
+ a: Joi.alternatives().when('b', { is: 5, then: Joi.ref('c') }),
229
+ b: Joi.any(),
230
+ c: Joi.number()
231
+ };
232
+
233
+ Helper.validate(schema, [
234
+ [{ a: 'x', b: 5, c: '1' }, false],
235
+ [{ a: 1, b: 5, c: '1' }, true],
236
+ [{ a: '1', b: 5, c: '1' }, false]
237
+ ], done);
238
+ });
239
+
240
+ it('validates when otherwise has ref', (done) => {
241
+
242
+ const schema = {
243
+ a: Joi.alternatives().when('b', { is: 6, otherwise: Joi.ref('c') }),
244
+ b: Joi.any(),
245
+ c: Joi.number()
246
+ };
247
+
248
+ Helper.validate(schema, [
249
+ [{ a: 'x', b: 5, c: '1' }, false],
250
+ [{ a: 1, b: 5, c: '1' }, true],
251
+ [{ a: '1', b: 5, c: '1' }, false]
252
+ ], done);
253
+ });
254
+
255
+ it('validates when empty value', (done) => {
256
+
257
+ const schema = {
258
+ a: Joi.alternatives().when('b', { is: true, then: Joi.required() }),
259
+ b: Joi.boolean().default(false)
260
+ };
261
+
262
+ Helper.validate(schema, [
263
+ [{ b: false }, true],
264
+ [{ b: true }, true] // true because required() only applies to the one alternative
265
+ ], done);
266
+ });
267
+
268
+ it('validates when missing value', (done) => {
269
+
270
+ const schema = Joi.object({
271
+ a: Joi.alternatives().when('b', { is: 5, then: Joi.optional(), otherwise: Joi.required() }).required(),
272
+ b: Joi.number()
273
+ });
274
+
275
+ Helper.validate(schema, [
276
+ [{ a: 1 }, true],
277
+ [{}, false],
278
+ [{ b: 1 }, false],
279
+ [{ a: 1, b: 1 }, true],
280
+ [{ a: 1, b: 5 }, true],
281
+ [{ b: 5 }, false]
282
+ ], done);
283
+ });
284
+ });
285
+
286
+ describe('describe()', () => {
287
+
288
+ it('describes when', (done) => {
289
+
290
+ const schema = {
291
+ a: Joi.alternatives().when('b', { is: 5, then: 'x', otherwise: 'y' })
292
+ .try('z'),
293
+ b: Joi.any()
294
+ };
295
+
296
+ const outcome = {
297
+ type: 'object',
298
+ children: {
299
+ b: {
300
+ type: 'any'
301
+ },
302
+ a: {
303
+ type: 'alternatives',
304
+ alternatives: [
305
+ {
306
+ ref: 'ref:b',
307
+ is: {
308
+ type: 'number',
309
+ flags: {
310
+ allowOnly: true,
311
+ presence: 'required'
312
+ },
313
+ valids: [5],
314
+ invalids: [Infinity, -Infinity]
315
+ },
316
+ then: {
317
+ type: 'string',
318
+ flags: {
319
+ allowOnly: true
320
+ },
321
+ valids: ['x'],
322
+ invalids: ['']
323
+ },
324
+ otherwise: {
325
+ type: 'string',
326
+ flags: {
327
+ allowOnly: true
328
+ },
329
+ valids: ['y'],
330
+ invalids: ['']
331
+ }
332
+ },
333
+ {
334
+ type: 'string',
335
+ flags: {
336
+ allowOnly: true
337
+ },
338
+ valids: ['z'],
339
+ invalids: ['']
340
+ }
341
+ ]
342
+ }
343
+ }
344
+ };
345
+
346
+ expect(Joi.describe(schema)).to.deep.equal(outcome);
347
+ done();
348
+ });
349
+
350
+ it('describes when (only then)', (done) => {
351
+
352
+ const schema = {
353
+ a: Joi.alternatives().when('b', { is: 5, then: 'x' })
354
+ .try('z'),
355
+ b: Joi.any()
356
+ };
357
+
358
+ const outcome = {
359
+ type: 'object',
360
+ children: {
361
+ b: {
362
+ type: 'any'
363
+ },
364
+ a: {
365
+ type: 'alternatives',
366
+ alternatives: [
367
+ {
368
+ ref: 'ref:b',
369
+ is: {
370
+ type: 'number',
371
+ flags: {
372
+ allowOnly: true,
373
+ presence: 'required'
374
+ },
375
+ valids: [5],
376
+ invalids: [Infinity, -Infinity]
377
+ },
378
+ then: {
379
+ type: 'string',
380
+ flags: {
381
+ allowOnly: true
382
+ },
383
+ valids: ['x'],
384
+ invalids: ['']
385
+ }
386
+ },
387
+ {
388
+ type: 'string',
389
+ flags: {
390
+ allowOnly: true
391
+ },
392
+ valids: ['z'],
393
+ invalids: ['']
394
+ }
395
+ ]
396
+ }
397
+ }
398
+ };
399
+
400
+ expect(Joi.describe(schema)).to.deep.equal(outcome);
401
+ done();
402
+ });
403
+
404
+ it('describes when (only otherwise)', (done) => {
405
+
406
+ const schema = {
407
+ a: Joi.alternatives().when('b', { is: 5, otherwise: 'y' })
408
+ .try('z'),
409
+ b: Joi.any()
410
+ };
411
+
412
+ const outcome = {
413
+ type: 'object',
414
+ children: {
415
+ b: {
416
+ type: 'any'
417
+ },
418
+ a: {
419
+ type: 'alternatives',
420
+ alternatives: [
421
+ {
422
+ ref: 'ref:b',
423
+ is: {
424
+ type: 'number',
425
+ flags: {
426
+ allowOnly: true,
427
+ presence: 'required'
428
+ },
429
+ valids: [5],
430
+ invalids: [Infinity, -Infinity]
431
+ },
432
+ otherwise: {
433
+ type: 'string',
434
+ flags: {
435
+ allowOnly: true
436
+ },
437
+ valids: ['y'],
438
+ invalids: ['']
439
+ }
440
+ },
441
+ {
442
+ type: 'string',
443
+ flags: {
444
+ allowOnly: true
445
+ },
446
+ valids: ['z'],
447
+ invalids: ['']
448
+ }
449
+ ]
450
+ }
451
+ }
452
+ };
453
+
454
+ expect(Joi.describe(schema)).to.deep.equal(outcome);
455
+ done();
456
+ });
457
+
458
+ it('describes inherited fields (from any)', (done) => {
459
+
460
+ const schema = Joi.alternatives()
461
+ .try('a')
462
+ .description('d')
463
+ .example('a')
464
+ .meta('b')
465
+ .meta('c')
466
+ .notes('f')
467
+ .tags('g');
468
+
469
+ const outcome = {
470
+ type: 'alternatives',
471
+ description: 'd',
472
+ notes: ['f'],
473
+ tags: ['g'],
474
+ meta: ['b', 'c'],
475
+ examples: ['a'],
476
+ alternatives: [{
477
+ type: 'string',
478
+ flags: {
479
+ allowOnly: true
480
+ },
481
+ valids: ['a'],
482
+ invalids: ['']
483
+ }]
484
+ };
485
+
486
+ expect(Joi.describe(schema)).to.deep.equal(outcome);
487
+ done();
488
+ });
489
+ });
490
+ });