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/messages.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const Clone = require('@hapi/hoek/lib/clone');
|
|
3
|
+
const { assert, clone } = require('@hapi/hoek');
|
|
5
4
|
|
|
6
5
|
const Template = require('./template');
|
|
7
6
|
|
|
@@ -14,22 +13,22 @@ exports.compile = function (messages, target) {
|
|
|
14
13
|
// Single value string ('plain error message', 'template {error} message')
|
|
15
14
|
|
|
16
15
|
if (typeof messages === 'string') {
|
|
17
|
-
|
|
16
|
+
assert(!target, 'Cannot set single message string');
|
|
18
17
|
return new Template(messages);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
// Single value template
|
|
22
21
|
|
|
23
22
|
if (Template.isTemplate(messages)) {
|
|
24
|
-
|
|
23
|
+
assert(!target, 'Cannot set single message template');
|
|
25
24
|
return messages;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
// By error code { 'number.min': <string | template> }
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
assert(typeof messages === 'object' && !Array.isArray(messages), 'Invalid message options');
|
|
31
30
|
|
|
32
|
-
target = target ?
|
|
31
|
+
target = target ? clone(target) : {};
|
|
33
32
|
|
|
34
33
|
for (let code in messages) {
|
|
35
34
|
const message = messages[code];
|
|
@@ -48,7 +47,7 @@ exports.compile = function (messages, target) {
|
|
|
48
47
|
|
|
49
48
|
// By language { english: { 'number.min': <string | template> } }
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
assert(typeof message === 'object' && !Array.isArray(message), 'Invalid message for', code);
|
|
52
51
|
|
|
53
52
|
const language = code;
|
|
54
53
|
target[language] = target[language] || {};
|
|
@@ -63,7 +62,7 @@ exports.compile = function (messages, target) {
|
|
|
63
62
|
continue;
|
|
64
63
|
}
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
assert(typeof localized === 'string', 'Invalid message for', code, 'in', language);
|
|
67
66
|
target[language][code] = new Template(localized);
|
|
68
67
|
}
|
|
69
68
|
}
|
|
@@ -135,7 +134,7 @@ exports.merge = function (base, extended) {
|
|
|
135
134
|
|
|
136
135
|
// By error code { 'number.min': <string | template> }
|
|
137
136
|
|
|
138
|
-
const target =
|
|
137
|
+
const target = clone(base);
|
|
139
138
|
|
|
140
139
|
for (let code in extended) {
|
|
141
140
|
const message = extended[code];
|
|
@@ -154,7 +153,7 @@ exports.merge = function (base, extended) {
|
|
|
154
153
|
|
|
155
154
|
// By language { english: { 'number.min': <string | template> } }
|
|
156
155
|
|
|
157
|
-
|
|
156
|
+
assert(typeof message === 'object' && !Array.isArray(message), 'Invalid message for', code);
|
|
158
157
|
|
|
159
158
|
const language = code;
|
|
160
159
|
target[language] = target[language] || {};
|
|
@@ -169,7 +168,7 @@ exports.merge = function (base, extended) {
|
|
|
169
168
|
continue;
|
|
170
169
|
}
|
|
171
170
|
|
|
172
|
-
|
|
171
|
+
assert(typeof localized === 'string', 'Invalid message for', code, 'in', language);
|
|
173
172
|
target[language][code] = new Template(localized);
|
|
174
173
|
}
|
|
175
174
|
}
|
package/lib/modify.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 Common = require('./common');
|
|
6
6
|
const Ref = require('./ref');
|
|
@@ -35,12 +35,12 @@ exports.Ids = internals.Ids = class {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
for (const [id, value] of source._byId.entries()) {
|
|
38
|
-
|
|
38
|
+
assert(!this._byKey.has(id), 'Schema id conflicts with existing key:', id);
|
|
39
39
|
this._byId.set(id, value);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
for (const [key, value] of source._byKey.entries()) {
|
|
43
|
-
|
|
43
|
+
assert(!this._byId.has(key), 'Schema key conflicts with existing id:', key);
|
|
44
44
|
this._byKey.set(key, value);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -52,7 +52,7 @@ exports.Ids = internals.Ids = class {
|
|
|
52
52
|
const tail = chain.shift();
|
|
53
53
|
let adjusted = { id: tail.id, schema: adjuster(tail.schema) };
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
assert(Common.isSchema(adjusted.schema), 'adjuster function failed to return a joi schema type');
|
|
56
56
|
|
|
57
57
|
for (const node of chain) {
|
|
58
58
|
adjusted = { id: node.id, schema: internals.fork(node.schema, adjusted.id, adjusted.schema) };
|
|
@@ -82,7 +82,7 @@ exports.Ids = internals.Ids = class {
|
|
|
82
82
|
|
|
83
83
|
const current = path[0];
|
|
84
84
|
const node = this._get(current);
|
|
85
|
-
|
|
85
|
+
assert(node, 'Schema does not contain path', [...behind, ...path].join('.'));
|
|
86
86
|
|
|
87
87
|
const forward = path.slice(1);
|
|
88
88
|
if (!forward.length) {
|
|
@@ -109,15 +109,15 @@ exports.Ids = internals.Ids = class {
|
|
|
109
109
|
const id = schema._flags.id;
|
|
110
110
|
if (id) {
|
|
111
111
|
const existing = this._byId.get(id);
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
assert(!existing || existing.schema === schema, 'Cannot add different schemas with the same id:', id);
|
|
113
|
+
assert(!this._byKey.has(id), 'Schema id conflicts with existing key:', id);
|
|
114
114
|
|
|
115
115
|
this._byId.set(id, { schema, id });
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
if (key) {
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
assert(!this._byKey.has(key), 'Schema already contains key:', key);
|
|
120
|
+
assert(!this._byId.has(key), 'Schema key conflicts with existing id:', key);
|
|
121
121
|
|
|
122
122
|
this._byKey.set(key, { schema, id: key });
|
|
123
123
|
}
|
|
@@ -134,7 +134,7 @@ exports.Ids = internals.Ids = class {
|
|
|
134
134
|
|
|
135
135
|
const current = path[0];
|
|
136
136
|
const node = this._get(current);
|
|
137
|
-
|
|
137
|
+
assert(node, 'Schema does not contain path', [...behind, ...path].join('.'));
|
|
138
138
|
|
|
139
139
|
nodes = [node, ...nodes];
|
|
140
140
|
|
package/lib/ref.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const Clone = require('@hapi/hoek/lib/clone');
|
|
5
|
-
const Reach = require('@hapi/hoek/lib/reach');
|
|
3
|
+
const { assert, clone, reach } = require('@hapi/hoek');
|
|
6
4
|
|
|
7
5
|
const Common = require('./common');
|
|
8
6
|
|
|
@@ -24,9 +22,9 @@ const internals = {
|
|
|
24
22
|
|
|
25
23
|
exports.create = function (key, options = {}) {
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
assert(typeof key === 'string', 'Invalid reference key:', key);
|
|
28
26
|
Common.assertOptions(options, ['adjust', 'ancestor', 'in', 'iterables', 'map', 'prefix', 'render', 'separator']);
|
|
29
|
-
|
|
27
|
+
assert(!options.prefix || typeof options.prefix === 'object', 'options.prefix must be of type object');
|
|
30
28
|
|
|
31
29
|
const ref = Object.assign({}, internals.defaults, options);
|
|
32
30
|
delete ref.prefix;
|
|
@@ -38,7 +36,7 @@ exports.create = function (key, options = {}) {
|
|
|
38
36
|
|
|
39
37
|
if (ref.type === 'value') {
|
|
40
38
|
if (context.root) {
|
|
41
|
-
|
|
39
|
+
assert(!separator || key[0] !== separator, 'Cannot specify relative path with root prefix');
|
|
42
40
|
ref.ancestor = 'root';
|
|
43
41
|
if (!key) {
|
|
44
42
|
key = null;
|
|
@@ -53,7 +51,7 @@ exports.create = function (key, options = {}) {
|
|
|
53
51
|
}
|
|
54
52
|
else {
|
|
55
53
|
if (ref.ancestor !== undefined) {
|
|
56
|
-
|
|
54
|
+
assert(!separator || !key || key[0] !== separator, 'Cannot combine prefix with ancestor option');
|
|
57
55
|
}
|
|
58
56
|
else {
|
|
59
57
|
const [ancestor, slice] = internals.ancestor(key, separator);
|
|
@@ -91,20 +89,20 @@ internals.Ref = class {
|
|
|
91
89
|
|
|
92
90
|
constructor(options) {
|
|
93
91
|
|
|
94
|
-
|
|
92
|
+
assert(typeof options === 'object', 'Invalid reference construction');
|
|
95
93
|
Common.assertOptions(options, [
|
|
96
94
|
'adjust', 'ancestor', 'in', 'iterables', 'map', 'path', 'render', 'separator', 'type', // Copied
|
|
97
95
|
'depth', 'key', 'root', 'display' // Overridden
|
|
98
96
|
]);
|
|
99
97
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
assert([false, undefined].includes(options.separator) || typeof options.separator === 'string' && options.separator.length === 1, 'Invalid separator');
|
|
99
|
+
assert(!options.adjust || typeof options.adjust === 'function', 'options.adjust must be a function');
|
|
100
|
+
assert(!options.map || Array.isArray(options.map), 'options.map must be an array');
|
|
101
|
+
assert(!options.map || !options.adjust, 'Cannot set both map and adjust options');
|
|
104
102
|
|
|
105
103
|
Object.assign(this, internals.defaults, options);
|
|
106
104
|
|
|
107
|
-
|
|
105
|
+
assert(this.type === 'value' || this.ancestor === undefined, 'Non-value references cannot reference ancestors');
|
|
108
106
|
|
|
109
107
|
if (Array.isArray(this.map)) {
|
|
110
108
|
this.map = new Map(this.map);
|
|
@@ -119,7 +117,7 @@ internals.Ref = class {
|
|
|
119
117
|
|
|
120
118
|
resolve(value, state, prefs, local, options = {}) {
|
|
121
119
|
|
|
122
|
-
|
|
120
|
+
assert(!this.in || options.in, 'Invalid in() reference usage');
|
|
123
121
|
|
|
124
122
|
if (this.type === 'global') {
|
|
125
123
|
return this._resolve(prefs.context, state, options);
|
|
@@ -137,7 +135,7 @@ internals.Ref = class {
|
|
|
137
135
|
return this._resolve(state.ancestors[state.ancestors.length - 1], state, options);
|
|
138
136
|
}
|
|
139
137
|
|
|
140
|
-
|
|
138
|
+
assert(this.ancestor <= state.ancestors.length, 'Invalid reference exceeds the schema root:', this.display);
|
|
141
139
|
return this._resolve(state.ancestors[this.ancestor - 1], state, options);
|
|
142
140
|
}
|
|
143
141
|
|
|
@@ -153,7 +151,7 @@ internals.Ref = class {
|
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
if (resolved === undefined) {
|
|
156
|
-
resolved =
|
|
154
|
+
resolved = reach(target, this.path, { iterables: this.iterables, functions: true });
|
|
157
155
|
}
|
|
158
156
|
|
|
159
157
|
if (this.adjust) {
|
|
@@ -398,7 +396,7 @@ exports.Manager = class {
|
|
|
398
396
|
clone() {
|
|
399
397
|
|
|
400
398
|
const copy = new exports.Manager();
|
|
401
|
-
copy.refs =
|
|
399
|
+
copy.refs = clone(this.refs);
|
|
402
400
|
return copy;
|
|
403
401
|
}
|
|
404
402
|
|
package/lib/state.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const Reach = require('@hapi/hoek/lib/reach');
|
|
3
|
+
const { clone, reach } = require('@hapi/hoek');
|
|
5
4
|
|
|
6
5
|
const Common = require('./common');
|
|
7
6
|
|
|
@@ -53,7 +52,7 @@ module.exports = internals.State = class {
|
|
|
53
52
|
snapshot() {
|
|
54
53
|
|
|
55
54
|
if (this.mainstay.shadow) {
|
|
56
|
-
this._snapshot =
|
|
55
|
+
this._snapshot = clone(this.mainstay.shadow.node(this.path));
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
this.mainstay.snapshot();
|
|
@@ -141,7 +140,7 @@ internals.Shadow = class {
|
|
|
141
140
|
return;
|
|
142
141
|
}
|
|
143
142
|
|
|
144
|
-
return
|
|
143
|
+
return reach(this._values, path, { iterables: true });
|
|
145
144
|
}
|
|
146
145
|
|
|
147
146
|
override(path, node) {
|
|
@@ -152,7 +151,7 @@ internals.Shadow = class {
|
|
|
152
151
|
|
|
153
152
|
const parents = path.slice(0, -1);
|
|
154
153
|
const own = path[path.length - 1];
|
|
155
|
-
const parent =
|
|
154
|
+
const parent = reach(this._values, parents, { iterables: true });
|
|
156
155
|
|
|
157
156
|
if (node) {
|
|
158
157
|
parent.set(own, node);
|
package/lib/template.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const EscapeHtml = require('@hapi/hoek/lib/escapeHtml');
|
|
6
|
-
const Formula = require('@sideway/formula');
|
|
3
|
+
const { assert, clone, escapeHtml } = require('@hapi/hoek');
|
|
4
|
+
const Formula = require('@hapi/formula');
|
|
7
5
|
|
|
8
6
|
const Common = require('./common');
|
|
9
7
|
const Errors = require('./errors');
|
|
@@ -30,8 +28,8 @@ module.exports = exports = internals.Template = class {
|
|
|
30
28
|
|
|
31
29
|
constructor(source, options) {
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
assert(typeof source === 'string', 'Template source must be a string');
|
|
32
|
+
assert(!source.includes('\u0000') && !source.includes('\u0001'), 'Template source cannot contain reserved control characters');
|
|
35
33
|
|
|
36
34
|
this.source = source;
|
|
37
35
|
this.rendered = source;
|
|
@@ -40,11 +38,11 @@ module.exports = exports = internals.Template = class {
|
|
|
40
38
|
|
|
41
39
|
if (options) {
|
|
42
40
|
const { functions, ...opts } = options;
|
|
43
|
-
this._settings = Object.keys(opts).length ?
|
|
41
|
+
this._settings = Object.keys(opts).length ? clone(opts) : undefined;
|
|
44
42
|
this._functions = functions;
|
|
45
43
|
if (this._functions) {
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
assert(Object.keys(this._functions).every((key) => typeof key === 'string'), 'Functions keys must be strings');
|
|
45
|
+
assert(Object.values(this._functions).every((key) => typeof key === 'function'), 'Functions values must be functions');
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
else {
|
|
@@ -208,7 +206,7 @@ module.exports = exports = internals.Template = class {
|
|
|
208
206
|
const rendered = this._part(part, /* context -> [*/ value, state, prefs, local, options /*] */);
|
|
209
207
|
const string = internals.stringify(rendered, value, state, prefs, local, options);
|
|
210
208
|
if (string !== undefined) {
|
|
211
|
-
const result = part.raw || (options.errors && options.errors.escapeHtml) === false ? string :
|
|
209
|
+
const result = part.raw || (options.errors && options.errors.escapeHtml) === false ? string : escapeHtml(string);
|
|
212
210
|
parts.push(internals.wrap(result, part.wrapped && prefs.errors.wrap.label));
|
|
213
211
|
}
|
|
214
212
|
}
|
package/lib/trace.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const Pinpoint = require('@
|
|
3
|
+
const { deepEqual } = require('@hapi/hoek');
|
|
4
|
+
const Pinpoint = require('@hapi/pinpoint');
|
|
5
5
|
|
|
6
6
|
const Errors = require('./errors');
|
|
7
7
|
|
|
@@ -232,7 +232,7 @@ internals.Store = class {
|
|
|
232
232
|
value(state, by, from, to, name) {
|
|
233
233
|
|
|
234
234
|
if (!state.mainstay.debug ||
|
|
235
|
-
|
|
235
|
+
deepEqual(from, to)) {
|
|
236
236
|
|
|
237
237
|
return;
|
|
238
238
|
}
|
|
@@ -327,7 +327,7 @@ internals.sub = function (paths, skipped) {
|
|
|
327
327
|
|
|
328
328
|
for (const path of paths) {
|
|
329
329
|
for (const skip of skipped) {
|
|
330
|
-
if (
|
|
330
|
+
if (deepEqual(path.slice(0, skip.length), skip)) {
|
|
331
331
|
return true;
|
|
332
332
|
}
|
|
333
333
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const Merge = require('@hapi/hoek/lib/merge');
|
|
3
|
+
const { assert, merge } = require('@hapi/hoek');
|
|
5
4
|
|
|
6
5
|
const Any = require('./any');
|
|
7
6
|
const Common = require('../common');
|
|
@@ -97,7 +96,7 @@ module.exports = Any.extend({
|
|
|
97
96
|
});
|
|
98
97
|
};
|
|
99
98
|
|
|
100
|
-
return isAnyObj(schema) ? { value: matched.reduce((acc, v) =>
|
|
99
|
+
return isAnyObj(schema) ? { value: matched.reduce((acc, v) => merge(acc, v, { mergeArrays: false })) } : { value: matched[matched.length - 1] };
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
// Match any
|
|
@@ -152,9 +151,9 @@ module.exports = Any.extend({
|
|
|
152
151
|
conditional: {
|
|
153
152
|
method(condition, options) {
|
|
154
153
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
assert(!this._flags._endedSwitch, 'Unreachable condition');
|
|
155
|
+
assert(!this._flags.match, 'Cannot combine match mode', this._flags.match, 'with conditional rule');
|
|
156
|
+
assert(options.break === undefined, 'Cannot use break option with alternatives conditional');
|
|
158
157
|
|
|
159
158
|
const obj = this.clone();
|
|
160
159
|
|
|
@@ -177,11 +176,11 @@ module.exports = Any.extend({
|
|
|
177
176
|
match: {
|
|
178
177
|
method(mode) {
|
|
179
178
|
|
|
180
|
-
|
|
179
|
+
assert(['any', 'one', 'all'].includes(mode), 'Invalid alternatives match mode', mode);
|
|
181
180
|
|
|
182
181
|
if (mode !== 'any') {
|
|
183
182
|
for (const match of this.$_terms.matches) {
|
|
184
|
-
|
|
183
|
+
assert(match.schema, 'Cannot combine match mode', mode, 'with conditional rules');
|
|
185
184
|
}
|
|
186
185
|
}
|
|
187
186
|
|
|
@@ -192,10 +191,10 @@ module.exports = Any.extend({
|
|
|
192
191
|
try: {
|
|
193
192
|
method(...schemas) {
|
|
194
193
|
|
|
195
|
-
|
|
194
|
+
assert(schemas.length, 'Missing alternative schemas');
|
|
196
195
|
Common.verifyFlat(schemas, 'try');
|
|
197
196
|
|
|
198
|
-
|
|
197
|
+
assert(!this._flags._endedSwitch, 'Unreachable condition');
|
|
199
198
|
|
|
200
199
|
const obj = this.clone();
|
|
201
200
|
for (const schema of schemas) {
|
|
@@ -218,6 +217,30 @@ module.exports = Any.extend({
|
|
|
218
217
|
};
|
|
219
218
|
|
|
220
219
|
return obj.$_modify({ each, ref: false });
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
isAsync() {
|
|
223
|
+
|
|
224
|
+
if (this.$_terms.externals?.length) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
for (const match of this.$_terms.matches) {
|
|
229
|
+
|
|
230
|
+
if (match.schema?.isAsync()) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (match.then?.isAsync()) {
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (match.otherwise?.isAsync()) {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return false;
|
|
221
244
|
}
|
|
222
245
|
},
|
|
223
246
|
|
|
@@ -328,10 +351,13 @@ internals.errors = function (failures, { error, state }) {
|
|
|
328
351
|
const [type, code] = report.code.split('.');
|
|
329
352
|
if (code !== 'base') {
|
|
330
353
|
complex.push({ type: schema.type, report });
|
|
331
|
-
continue;
|
|
332
354
|
}
|
|
333
|
-
|
|
334
|
-
|
|
355
|
+
else if (report.code === 'object.base') {
|
|
356
|
+
valids.add(report.local.type);
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
valids.add(type);
|
|
360
|
+
}
|
|
335
361
|
}
|
|
336
362
|
|
|
337
363
|
// All errors are base types or valids
|
package/lib/types/any.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 Base = require('../base');
|
|
6
6
|
const Common = require('../common');
|
|
@@ -36,8 +36,8 @@ module.exports = Base.extend({
|
|
|
36
36
|
custom: {
|
|
37
37
|
method(method, description) {
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
assert(typeof method === 'function', 'Method must be a function');
|
|
40
|
+
assert(description === undefined || description && typeof description === 'string', 'Description must be a non-empty string');
|
|
41
41
|
|
|
42
42
|
return this.$_addRule({ name: 'custom', args: { method, description } });
|
|
43
43
|
},
|
|
@@ -64,7 +64,7 @@ module.exports = Base.extend({
|
|
|
64
64
|
shared: {
|
|
65
65
|
method(schema) {
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
assert(Common.isSchema(schema) && schema._flags.id, 'Schema must be a schema with an id');
|
|
68
68
|
|
|
69
69
|
const obj = this.clone();
|
|
70
70
|
obj.$_terms.shared = obj.$_terms.shared || [];
|
|
@@ -77,7 +77,7 @@ module.exports = Base.extend({
|
|
|
77
77
|
warning: {
|
|
78
78
|
method(code, local) {
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
assert(code && typeof code === 'string', 'Invalid warning code');
|
|
81
81
|
|
|
82
82
|
return this.$_addRule({ name: 'warning', args: { code, local }, warn: true });
|
|
83
83
|
},
|
package/lib/types/array.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const DeepEqual = require('@hapi/hoek/lib/deepEqual');
|
|
5
|
-
const Reach = require('@hapi/hoek/lib/reach');
|
|
3
|
+
const { assert, deepEqual, reach } = require('@hapi/hoek');
|
|
6
4
|
|
|
7
5
|
const Any = require('./any');
|
|
8
6
|
const Common = require('../common');
|
|
@@ -417,7 +415,7 @@ module.exports = Any.extend({
|
|
|
417
415
|
method(enabled) {
|
|
418
416
|
|
|
419
417
|
const value = enabled === undefined ? true : !!enabled;
|
|
420
|
-
|
|
418
|
+
assert(!value || !this._flags._arrayItems, 'Cannot specify single rule when array has array items');
|
|
421
419
|
|
|
422
420
|
return this.$_setFlag('single', value);
|
|
423
421
|
}
|
|
@@ -434,7 +432,7 @@ module.exports = Any.extend({
|
|
|
434
432
|
|
|
435
433
|
if (options.by) {
|
|
436
434
|
settings.by = Compile.ref(options.by, { ancestor: 0 });
|
|
437
|
-
|
|
435
|
+
assert(!settings.by.ancestor, 'Cannot sort by ancestor');
|
|
438
436
|
}
|
|
439
437
|
|
|
440
438
|
return this.$_addRule({ name: 'sort', args: { options: settings } });
|
|
@@ -474,7 +472,7 @@ module.exports = Any.extend({
|
|
|
474
472
|
unique: {
|
|
475
473
|
method(comparator, options = {}) {
|
|
476
474
|
|
|
477
|
-
|
|
475
|
+
assert(!comparator || typeof comparator === 'function' || typeof comparator === 'string', 'comparator must be a function or a string');
|
|
478
476
|
Common.assertOptions(options, ['ignoreUndefined', 'separator']);
|
|
479
477
|
|
|
480
478
|
const rule = { name: 'unique', args: { options, comparator } };
|
|
@@ -504,13 +502,13 @@ module.exports = Any.extend({
|
|
|
504
502
|
custom: new Map()
|
|
505
503
|
};
|
|
506
504
|
|
|
507
|
-
const compare = comparator ||
|
|
505
|
+
const compare = comparator || deepEqual;
|
|
508
506
|
const ignoreUndefined = options.ignoreUndefined;
|
|
509
507
|
|
|
510
508
|
for (let i = 0; i < value.length; ++i) {
|
|
511
|
-
const item = path ?
|
|
509
|
+
const item = path ? reach(value[i], path) : value[i];
|
|
512
510
|
const records = comparator ? found.custom : found[typeof item];
|
|
513
|
-
|
|
511
|
+
assert(records, 'Failed to find unique map container for type', typeof item);
|
|
514
512
|
|
|
515
513
|
if (records instanceof Map) {
|
|
516
514
|
const entries = records.entries();
|
|
@@ -565,6 +563,30 @@ module.exports = Any.extend({
|
|
|
565
563
|
}
|
|
566
564
|
},
|
|
567
565
|
|
|
566
|
+
overrides: {
|
|
567
|
+
|
|
568
|
+
isAsync() {
|
|
569
|
+
|
|
570
|
+
if (this.$_terms.externals?.length) {
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
for (const item of this.$_terms.items) {
|
|
575
|
+
if (item.isAsync()) {
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
for (const item of this.$_terms.ordered) {
|
|
581
|
+
if (item.isAsync()) {
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
|
|
568
590
|
cast: {
|
|
569
591
|
set: {
|
|
570
592
|
from: Array.isArray,
|
|
@@ -727,7 +749,7 @@ internals.validateSingle = function (type, obj) {
|
|
|
727
749
|
if (type.type === 'array' ||
|
|
728
750
|
type._flags._arrayItems) {
|
|
729
751
|
|
|
730
|
-
|
|
752
|
+
assert(!obj._flags.single, 'Cannot specify array item with single rule enabled');
|
|
731
753
|
obj.$_setFlag('_arrayItems', true, { clone: false });
|
|
732
754
|
}
|
|
733
755
|
};
|
package/lib/types/binary.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');
|
|
@@ -21,7 +21,7 @@ module.exports = Any.extend({
|
|
|
21
21
|
try {
|
|
22
22
|
return { value: Buffer.from(value, schema._flags.encoding) };
|
|
23
23
|
}
|
|
24
|
-
catch
|
|
24
|
+
catch { }
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
},
|
|
@@ -37,7 +37,7 @@ module.exports = Any.extend({
|
|
|
37
37
|
encoding: {
|
|
38
38
|
method(encoding) {
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
assert(Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);
|
|
41
41
|
|
|
42
42
|
return this.$_setFlag('encoding', encoding);
|
|
43
43
|
}
|
package/lib/types/boolean.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');
|
|
@@ -76,7 +76,7 @@ module.exports = Any.extend({
|
|
|
76
76
|
for (let i = 0; i < values.length; ++i) {
|
|
77
77
|
const value = values[i];
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
assert(value !== undefined, 'Cannot call truthy with undefined');
|
|
80
80
|
obj.$_terms.truthy.add(value);
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -95,7 +95,7 @@ module.exports = Any.extend({
|
|
|
95
95
|
for (let i = 0; i < values.length; ++i) {
|
|
96
96
|
const value = values[i];
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
assert(value !== undefined, 'Cannot call falsy with undefined');
|
|
99
99
|
obj.$_terms.falsy.add(value);
|
|
100
100
|
}
|
|
101
101
|
|