joi 17.13.3 → 18.0.1
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 +2627 -2333
- 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 +33 -10
- 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/index.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 Cache = require('./cache');
|
|
7
6
|
const Common = require('./common');
|
|
@@ -54,7 +53,7 @@ internals.root = function () {
|
|
|
54
53
|
for (const type of root._types) {
|
|
55
54
|
root[type] = function (...args) {
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
assert(!args.length || ['alternatives', 'link', 'object'].includes(type), 'The', type, 'type does not allow arguments');
|
|
58
57
|
return internals.generate(this, internals.types[type], args);
|
|
59
58
|
};
|
|
60
59
|
}
|
|
@@ -109,7 +108,7 @@ internals.methods = {
|
|
|
109
108
|
|
|
110
109
|
build(desc) {
|
|
111
110
|
|
|
112
|
-
|
|
111
|
+
assert(typeof Manifest.build === 'function', 'Manifest functionality disabled');
|
|
113
112
|
return Manifest.build(this, desc);
|
|
114
113
|
},
|
|
115
114
|
|
|
@@ -125,12 +124,12 @@ internals.methods = {
|
|
|
125
124
|
|
|
126
125
|
defaults(modifier) {
|
|
127
126
|
|
|
128
|
-
|
|
127
|
+
assert(typeof modifier === 'function', 'modifier must be a function');
|
|
129
128
|
|
|
130
129
|
const joi = Object.assign({}, this);
|
|
131
130
|
for (const type of joi._types) {
|
|
132
131
|
const schema = modifier(joi[type]());
|
|
133
|
-
|
|
132
|
+
assert(Common.isSchema(schema), 'modifier must return a valid schema object');
|
|
134
133
|
|
|
135
134
|
joi[type] = function (...args) {
|
|
136
135
|
|
|
@@ -152,7 +151,7 @@ internals.methods = {
|
|
|
152
151
|
|
|
153
152
|
Schemas = Schemas || require('./schemas');
|
|
154
153
|
|
|
155
|
-
|
|
154
|
+
assert(extensions.length, 'You need to provide at least one extension');
|
|
156
155
|
this.assert(extensions, Schemas.extensions);
|
|
157
156
|
|
|
158
157
|
const joi = Object.assign({}, this);
|
|
@@ -167,7 +166,7 @@ internals.methods = {
|
|
|
167
166
|
|
|
168
167
|
const expanded = internals.expandExtension(extension, joi);
|
|
169
168
|
for (const item of expanded) {
|
|
170
|
-
|
|
169
|
+
assert(joi[item.type] === undefined || joi._types.has(item.type), 'Cannot override name', item.type);
|
|
171
170
|
|
|
172
171
|
const base = item.base || this.any();
|
|
173
172
|
const schema = Extend.type(base, item);
|
|
@@ -236,7 +235,7 @@ internals.assert = function (value, schema, annotate, args /* [message], [option
|
|
|
236
235
|
const display = annotate && typeof error.annotate === 'function' ? error.annotate() : error.message;
|
|
237
236
|
|
|
238
237
|
if (error instanceof Errors.ValidationError === false) {
|
|
239
|
-
error =
|
|
238
|
+
error = clone(error);
|
|
240
239
|
}
|
|
241
240
|
|
|
242
241
|
error.message = message ? `${message} ${display}` : display;
|
|
@@ -246,7 +245,7 @@ internals.assert = function (value, schema, annotate, args /* [message], [option
|
|
|
246
245
|
|
|
247
246
|
internals.generate = function (root, schema, args) {
|
|
248
247
|
|
|
249
|
-
|
|
248
|
+
assert(root, 'Must be invoked on a Joi instance.');
|
|
250
249
|
|
|
251
250
|
schema.$_root = root;
|
|
252
251
|
|
package/lib/manifest.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 Common = require('./common');
|
|
7
6
|
const Messages = require('./messages');
|
|
@@ -41,7 +40,7 @@ exports.describe = function (schema) {
|
|
|
41
40
|
// Preferences
|
|
42
41
|
|
|
43
42
|
if (schema._preferences) {
|
|
44
|
-
desc.preferences =
|
|
43
|
+
desc.preferences = clone(schema._preferences, { shallow: ['messages'] });
|
|
45
44
|
delete desc.preferences[Common.symbols.prefs];
|
|
46
45
|
if (desc.preferences.messages) {
|
|
47
46
|
desc.preferences.messages = Messages.decompile(desc.preferences.messages);
|
|
@@ -106,7 +105,7 @@ exports.describe = function (schema) {
|
|
|
106
105
|
continue;
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
assert(!desc[term], 'Cannot describe schema due to internal name conflict with', term);
|
|
110
109
|
|
|
111
110
|
const items = schema.$_terms[term];
|
|
112
111
|
if (!items) {
|
|
@@ -126,7 +125,7 @@ exports.describe = function (schema) {
|
|
|
126
125
|
continue;
|
|
127
126
|
}
|
|
128
127
|
|
|
129
|
-
|
|
128
|
+
assert(def.terms[term], 'Term', term, 'missing configuration');
|
|
130
129
|
const manifest = def.terms[term].manifest;
|
|
131
130
|
const mapped = typeof manifest === 'object';
|
|
132
131
|
if (!items.length &&
|
|
@@ -155,7 +154,7 @@ exports.describe = function (schema) {
|
|
|
155
154
|
// Single
|
|
156
155
|
|
|
157
156
|
if (manifest === 'single') {
|
|
158
|
-
|
|
157
|
+
assert(normalized.length === 1, 'Term', term, 'contains more than one item');
|
|
159
158
|
desc[term] = normalized[0];
|
|
160
159
|
continue;
|
|
161
160
|
}
|
|
@@ -187,7 +186,7 @@ internals.describe = function (item, options = {}) {
|
|
|
187
186
|
}
|
|
188
187
|
|
|
189
188
|
if (options.assign === 'options') {
|
|
190
|
-
return
|
|
189
|
+
return clone(item);
|
|
191
190
|
}
|
|
192
191
|
|
|
193
192
|
if (Buffer && Buffer.isBuffer(item)) { // $lab:coverage:ignore$
|
|
@@ -264,7 +263,7 @@ internals.Builder = class {
|
|
|
264
263
|
if (desc.flags) {
|
|
265
264
|
for (const flag in desc.flags) {
|
|
266
265
|
const setter = def.flags[flag] && def.flags[flag].setter || flag;
|
|
267
|
-
|
|
266
|
+
assert(typeof schema[setter] === 'function', 'Invalid flag', flag, 'for type', desc.type);
|
|
268
267
|
schema = schema[setter](this.build(desc.flags[flag]));
|
|
269
268
|
}
|
|
270
269
|
}
|
|
@@ -289,7 +288,7 @@ internals.Builder = class {
|
|
|
289
288
|
|
|
290
289
|
if (desc.rules) {
|
|
291
290
|
for (const rule of desc.rules) {
|
|
292
|
-
|
|
291
|
+
assert(typeof schema[rule.name] === 'function', 'Invalid rule', rule.name, 'for type', desc.type);
|
|
293
292
|
|
|
294
293
|
const args = [];
|
|
295
294
|
if (rule.args) {
|
|
@@ -301,13 +300,13 @@ internals.Builder = class {
|
|
|
301
300
|
const keys = Object.keys(built);
|
|
302
301
|
const definition = def.rules[rule.name].args;
|
|
303
302
|
if (definition) {
|
|
304
|
-
|
|
303
|
+
assert(keys.length <= definition.length, 'Invalid number of arguments for', desc.type, rule.name, '(expected up to', definition.length, ', found', keys.length, ')');
|
|
305
304
|
for (const { name } of definition) {
|
|
306
305
|
args.push(built[name]);
|
|
307
306
|
}
|
|
308
307
|
}
|
|
309
308
|
else {
|
|
310
|
-
|
|
309
|
+
assert(keys.length === 1, 'Invalid number of arguments for', desc.type, rule.name, '(expected up to 1, found', keys.length, ')');
|
|
311
310
|
args.push(built[keys[0]]);
|
|
312
311
|
}
|
|
313
312
|
}
|
|
@@ -339,7 +338,7 @@ internals.Builder = class {
|
|
|
339
338
|
continue;
|
|
340
339
|
}
|
|
341
340
|
|
|
342
|
-
|
|
341
|
+
assert(def.terms[key], 'Term', key, 'missing configuration');
|
|
343
342
|
const manifest = def.terms[key].manifest;
|
|
344
343
|
|
|
345
344
|
if (manifest === 'schema') {
|
|
@@ -394,7 +393,7 @@ internals.Builder = class {
|
|
|
394
393
|
}
|
|
395
394
|
|
|
396
395
|
if (options.assign === 'options') {
|
|
397
|
-
return
|
|
396
|
+
return clone(desc);
|
|
398
397
|
}
|
|
399
398
|
|
|
400
399
|
if (options.assign === 'regex') {
|
|
@@ -411,7 +410,7 @@ internals.Builder = class {
|
|
|
411
410
|
|
|
412
411
|
if (Object.keys(desc).length === 1) {
|
|
413
412
|
if (desc.buffer) {
|
|
414
|
-
|
|
413
|
+
assert(Buffer, 'Buffers are not supported');
|
|
415
414
|
return Buffer && Buffer.from(desc.buffer, 'binary'); // $lab:coverage:ignore$
|
|
416
415
|
}
|
|
417
416
|
|
|
@@ -432,12 +431,12 @@ internals.Builder = class {
|
|
|
432
431
|
}
|
|
433
432
|
|
|
434
433
|
if (desc.special) {
|
|
435
|
-
|
|
434
|
+
assert(['deep'].includes(desc.special), 'Unknown special value', desc.special);
|
|
436
435
|
return Common.symbols.deepDefault;
|
|
437
436
|
}
|
|
438
437
|
|
|
439
438
|
if (desc.value) {
|
|
440
|
-
return
|
|
439
|
+
return clone(desc.value);
|
|
441
440
|
}
|
|
442
441
|
}
|
|
443
442
|
|
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
|
|