joi 11.3.2 → 12.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/README.md CHANGED
@@ -26,7 +26,7 @@ Imagine you run facebook and you want visitors to sign up on the website with re
26
26
  This is joi, joi allows you to create *blueprints* or *schemas* for JavaScript objects (an object that stores information) to ensure *validation* of key information.
27
27
 
28
28
  # API
29
- See the detailed [API Reference](https://github.com/hapijs/joi/blob/v11.3.2/API.md).
29
+ See the detailed [API Reference](https://github.com/hapijs/joi/blob/v12.0.0/API.md).
30
30
 
31
31
  # Example
32
32
 
package/lib/errors.js CHANGED
@@ -88,6 +88,10 @@ exports.Err = class {
88
88
 
89
89
  format = format || Hoek.reach(localized, this.type) || Hoek.reach(Language.errors, this.type);
90
90
 
91
+ if (format === undefined) {
92
+ return `Error code "${this.type}" is not defined, your custom type is missing the correct language definition`;
93
+ }
94
+
91
95
  let wrapArrays = Hoek.reach(localized, 'messages.wrapArrays');
92
96
  if (typeof wrapArrays !== 'boolean') {
93
97
  wrapArrays = Language.errors.messages.wrapArrays;
@@ -116,7 +120,7 @@ exports.Err = class {
116
120
 
117
121
  const value = Hoek.reach(this.context, name);
118
122
  const normalized = internals.stringify(value, wrapArrays);
119
- return (isSecure ? Hoek.escapeHtml(normalized) : normalized);
123
+ return (isSecure && this.options.escapeHtml ? Hoek.escapeHtml(normalized) : normalized);
120
124
  });
121
125
  }
122
126
 
package/lib/index.js CHANGED
@@ -26,6 +26,8 @@ const internals = {
26
26
 
27
27
  internals.applyDefaults = function (schema) {
28
28
 
29
+ Hoek.assert(this, 'Must be invoked on a Joi instance.');
30
+
29
31
  if (this._defaults) {
30
32
  schema = this._defaults(schema);
31
33
  }
@@ -47,12 +49,12 @@ internals.root = function () {
47
49
 
48
50
  Hoek.assert(arguments.length === 0, 'Joi.any() does not allow arguments.');
49
51
 
50
- return internals.applyDefaults.call(this || root, any);
52
+ return internals.applyDefaults.call(this, any);
51
53
  };
52
54
 
53
55
  root.alternatives = root.alt = function () {
54
56
 
55
- const alternatives = internals.applyDefaults.call(this || root, internals.alternatives);
57
+ const alternatives = internals.applyDefaults.call(this, internals.alternatives);
56
58
  return arguments.length ? alternatives.try.apply(alternatives, arguments) : alternatives;
57
59
  };
58
60
 
@@ -60,47 +62,47 @@ internals.root = function () {
60
62
 
61
63
  Hoek.assert(arguments.length === 0, 'Joi.array() does not allow arguments.');
62
64
 
63
- return internals.applyDefaults.call(this || root, internals.array);
65
+ return internals.applyDefaults.call(this, internals.array);
64
66
  };
65
67
 
66
68
  root.boolean = root.bool = function () {
67
69
 
68
70
  Hoek.assert(arguments.length === 0, 'Joi.boolean() does not allow arguments.');
69
71
 
70
- return internals.applyDefaults.call(this || root, internals.boolean);
72
+ return internals.applyDefaults.call(this, internals.boolean);
71
73
  };
72
74
 
73
75
  root.binary = function () {
74
76
 
75
77
  Hoek.assert(arguments.length === 0, 'Joi.binary() does not allow arguments.');
76
78
 
77
- return internals.applyDefaults.call(this || root, internals.binary);
79
+ return internals.applyDefaults.call(this, internals.binary);
78
80
  };
79
81
 
80
82
  root.date = function () {
81
83
 
82
84
  Hoek.assert(arguments.length === 0, 'Joi.date() does not allow arguments.');
83
85
 
84
- return internals.applyDefaults.call(this || root, internals.date);
86
+ return internals.applyDefaults.call(this, internals.date);
85
87
  };
86
88
 
87
89
  root.func = function () {
88
90
 
89
91
  Hoek.assert(arguments.length === 0, 'Joi.func() does not allow arguments.');
90
92
 
91
- return internals.applyDefaults.call(this || root, internals.func);
93
+ return internals.applyDefaults.call(this, internals.func);
92
94
  };
93
95
 
94
96
  root.number = function () {
95
97
 
96
98
  Hoek.assert(arguments.length === 0, 'Joi.number() does not allow arguments.');
97
99
 
98
- return internals.applyDefaults.call(this || root, internals.number);
100
+ return internals.applyDefaults.call(this, internals.number);
99
101
  };
100
102
 
101
103
  root.object = function () {
102
104
 
103
- const object = internals.applyDefaults.call(this || root, internals.object);
105
+ const object = internals.applyDefaults.call(this, internals.object);
104
106
  return arguments.length ? object.keys.apply(object, arguments) : object;
105
107
  };
106
108
 
@@ -108,7 +110,7 @@ internals.root = function () {
108
110
 
109
111
  Hoek.assert(arguments.length === 0, 'Joi.string() does not allow arguments.');
110
112
 
111
- return internals.applyDefaults.call(this || root, internals.string);
113
+ return internals.applyDefaults.call(this, internals.string);
112
114
  };
113
115
 
114
116
  root.ref = function () {
@@ -246,11 +248,10 @@ internals.root = function () {
246
248
  const extensions = Hoek.flatten(Array.prototype.slice.call(arguments));
247
249
  Hoek.assert(extensions.length > 0, 'You need to provide at least one extension');
248
250
 
249
- const currentJoi = this || root;
250
- currentJoi.assert(extensions, root.extensionsSchema);
251
+ this.assert(extensions, root.extensionsSchema);
251
252
 
252
- const joi = Object.create(currentJoi.any());
253
- Object.assign(joi, currentJoi);
253
+ const joi = Object.create(this.any());
254
+ Object.assign(joi, this);
254
255
 
255
256
  for (let i = 0; i < extensions.length; ++i) {
256
257
  let extension = extensions[i];
@@ -259,9 +260,9 @@ internals.root = function () {
259
260
  extension = extension(joi);
260
261
  }
261
262
 
262
- currentJoi.assert(extension, root.extensionSchema);
263
+ this.assert(extension, root.extensionSchema);
263
264
 
264
- const base = (extension.base || currentJoi.any()).clone(); // Cloning because we're going to override language afterwards
265
+ const base = (extension.base || this.any()).clone(); // Cloning because we're going to override language afterwards
265
266
  const ctor = base.constructor;
266
267
  const type = class extends ctor { // eslint-disable-line no-loop-func
267
268
 
@@ -333,7 +334,7 @@ internals.root = function () {
333
334
  const ruleArgs = rule.params ?
334
335
  (rule.params instanceof Any ? rule.params._inner.children.map((k) => k.key) : Object.keys(rule.params)) :
335
336
  [];
336
- const validateArgs = rule.params ? Cast.schema(currentJoi, rule.params) : null;
337
+ const validateArgs = rule.params ? Cast.schema(this, rule.params) : null;
337
338
 
338
339
  type.prototype[rule.name] = function () { // eslint-disable-line no-loop-func
339
340
 
@@ -396,7 +397,7 @@ internals.root = function () {
396
397
  const instance = new type();
397
398
  joi[extension.name] = function () {
398
399
 
399
- return internals.applyDefaults.call(this || joi, instance);
400
+ return internals.applyDefaults.call(this, instance);
400
401
  };
401
402
  }
402
403
 
package/lib/schemas.js CHANGED
@@ -20,5 +20,6 @@ exports.options = Joi.object({
20
20
  raw: Joi.boolean(),
21
21
  context: Joi.object(),
22
22
  strip: Joi.boolean(),
23
- noDefaults: Joi.boolean()
23
+ noDefaults: Joi.boolean(),
24
+ escapeHtml: Joi.boolean()
24
25
  }).strict();
@@ -31,9 +31,10 @@ internals.Alternatives = class extends Any {
31
31
 
32
32
  for (let i = 0; i < il; ++i) {
33
33
  const item = this._inner.matches[i];
34
- const schema = item.schema;
35
- if (!schema) {
36
- const failed = item.is._validate(item.ref(state.reference || state.parent, options), null, options, state.parent).errors;
34
+ if (!item.schema) {
35
+ const schema = item.peek || item.is;
36
+ const input = item.is ? item.ref(state.reference || state.parent, options) : value;
37
+ const failed = schema._validate(input, null, options, state.parent).errors;
37
38
 
38
39
  if (failed) {
39
40
  if (item.otherwise) {
@@ -51,7 +52,7 @@ internals.Alternatives = class extends Any {
51
52
  continue;
52
53
  }
53
54
 
54
- const result = schema._validate(value, state, options);
55
+ const result = item.schema._validate(value, state, options);
55
56
  if (!result.errors) { // Found a valid match
56
57
  return result;
57
58
  }
@@ -84,25 +85,35 @@ internals.Alternatives = class extends Any {
84
85
  return obj;
85
86
  }
86
87
 
87
- when(ref, options) {
88
+ when(condition, options) {
88
89
 
89
- Hoek.assert(Ref.isRef(ref) || typeof ref === 'string', 'Invalid reference:', ref);
90
+ let schemaCondition = false;
91
+ Hoek.assert(Ref.isRef(condition) || typeof condition === 'string' || (schemaCondition = condition instanceof Any), 'Invalid condition:', condition);
90
92
  Hoek.assert(options, 'Missing options');
91
93
  Hoek.assert(typeof options === 'object', 'Invalid options');
92
- Hoek.assert(options.hasOwnProperty('is'), 'Missing "is" directive');
94
+ if (schemaCondition) {
95
+ Hoek.assert(!options.hasOwnProperty('is'), '"is" can not be used with a schema condition');
96
+ }
97
+ else {
98
+ Hoek.assert(options.hasOwnProperty('is'), 'Missing "is" directive');
99
+ }
93
100
  Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
94
101
 
95
102
  const obj = this.clone();
96
- let is = Cast.schema(this._currentJoi, options.is);
103
+ let is;
104
+ if (!schemaCondition) {
105
+ is = Cast.schema(this._currentJoi, options.is);
97
106
 
98
- if (options.is === null || !(Ref.isRef(options.is) || options.is instanceof Any)) {
107
+ if (options.is === null || !(Ref.isRef(options.is) || options.is instanceof Any)) {
99
108
 
100
- // Only apply required if this wasn't already a schema or a ref, we'll suppose people know what they're doing
101
- is = is.required();
109
+ // Only apply required if this wasn't already a schema or a ref, we'll suppose people know what they're doing
110
+ is = is.required();
111
+ }
102
112
  }
103
113
 
104
114
  const item = {
105
- ref: Cast.ref(ref),
115
+ ref: schemaCondition ? null : Cast.ref(condition),
116
+ peek: schemaCondition ? condition : null,
106
117
  is,
107
118
  then: options.then !== undefined ? Cast.schema(this._currentJoi, options.then) : undefined,
108
119
  otherwise: options.otherwise !== undefined ? Cast.schema(this._currentJoi, options.otherwise) : undefined
@@ -114,8 +125,10 @@ internals.Alternatives = class extends Any {
114
125
  item.otherwise = item.otherwise && obj._baseType.concat(item.otherwise);
115
126
  }
116
127
 
117
- Ref.push(obj._refs, item.ref);
118
- obj._refs = obj._refs.concat(item.is._refs);
128
+ if (!schemaCondition) {
129
+ Ref.push(obj._refs, item.ref);
130
+ obj._refs = obj._refs.concat(item.is._refs);
131
+ }
119
132
 
120
133
  if (item.then && item.then._refs) {
121
134
  obj._refs = obj._refs.concat(item.then._refs);
@@ -146,9 +159,11 @@ internals.Alternatives = class extends Any {
146
159
 
147
160
  // when()
148
161
 
149
- const when = {
162
+ const when = item.is ? {
150
163
  ref: item.ref.toString(),
151
164
  is: item.is.describe()
165
+ } : {
166
+ peek: item.peek.describe()
152
167
  };
153
168
 
154
169
  if (item.then) {
@@ -25,7 +25,8 @@ internals.defaults = {
25
25
  language: {},
26
26
  presence: 'optional',
27
27
  strip: false,
28
- noDefaults: false
28
+ noDefaults: false,
29
+ escapeHtml: false
29
30
 
30
31
  // context: null
31
32
  };
@@ -385,7 +386,7 @@ module.exports = internals.Any = class {
385
386
  return obj;
386
387
  }
387
388
 
388
- when(ref, options) {
389
+ when(condition, options) {
389
390
 
390
391
  Hoek.assert(options && typeof options === 'object', 'Invalid options');
391
392
  Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
@@ -394,7 +395,12 @@ module.exports = internals.Any = class {
394
395
  const otherwise = options.hasOwnProperty('otherwise') ? this.concat(Cast.schema(this._currentJoi, options.otherwise)) : undefined;
395
396
 
396
397
  Alternatives = Alternatives || require('../alternatives');
397
- const obj = Alternatives.when(ref, { is: options.is, then, otherwise });
398
+
399
+ const alternativeOptions = { then, otherwise };
400
+ if (Object.prototype.hasOwnProperty.call(options, 'is')) {
401
+ alternativeOptions.is = options.is;
402
+ }
403
+ const obj = Alternatives.when(condition, alternativeOptions);
398
404
  obj._flags.presence = 'ignore';
399
405
  obj._baseType = this;
400
406
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "joi",
3
3
  "description": "Object schema validation",
4
- "version": "11.3.2",
4
+ "version": "12.0.0",
5
5
  "homepage": "https://github.com/hapijs/joi",
6
6
  "repository": "git://github.com/hapijs/joi",
7
7
  "main": "lib/index.js",