@depup/joi 18.1.1-depup.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/errors.js ADDED
@@ -0,0 +1,271 @@
1
+ 'use strict';
2
+
3
+ const Annotate = require('./annotate');
4
+ const Common = require('./common');
5
+ const Template = require('./template');
6
+
7
+
8
+ const internals = {};
9
+
10
+
11
+ exports.Report = class {
12
+
13
+ constructor(code, value, local, flags, messages, state, prefs) {
14
+
15
+ this.code = code;
16
+ this.flags = flags;
17
+ this.messages = messages;
18
+ this.path = state.path;
19
+ this.prefs = prefs;
20
+ this.state = state;
21
+ this.value = value;
22
+
23
+ this.message = null;
24
+ this.template = null;
25
+
26
+ this.local = local || {};
27
+ this.local.label = exports.label(this.flags, this.state, this.prefs, this.messages);
28
+
29
+ if (this.value !== undefined &&
30
+ !this.local.hasOwnProperty('value')) {
31
+
32
+ this.local.value = this.value;
33
+ }
34
+
35
+ if (this.path.length) {
36
+ const key = this.path[this.path.length - 1];
37
+ if (typeof key !== 'object') {
38
+ this.local.key = key;
39
+ }
40
+ }
41
+ }
42
+
43
+ _setTemplate(template) {
44
+
45
+ this.template = template;
46
+
47
+ if (!this.flags.label &&
48
+ this.path.length === 0) {
49
+
50
+ const localized = this._template(this.template, 'root');
51
+ if (localized) {
52
+ this.local.label = localized;
53
+ }
54
+ }
55
+ }
56
+
57
+ toString() {
58
+
59
+ if (this.message) {
60
+ return this.message;
61
+ }
62
+
63
+ const code = this.code;
64
+
65
+ if (!this.prefs.errors.render) {
66
+ return this.code;
67
+ }
68
+
69
+ const template = this._template(this.template) ||
70
+ this._template(this.prefs.messages) ||
71
+ this._template(this.messages);
72
+
73
+ if (template === undefined) {
74
+ return `Error code "${code}" is not defined, your custom type is missing the correct messages definition`;
75
+ }
76
+
77
+ // Render and cache result
78
+
79
+ this.message = template.render(this.value, this.state, this.prefs, this.local, { errors: this.prefs.errors, messages: [this.prefs.messages, this.messages] });
80
+ if (!this.prefs.errors.label) {
81
+ this.message = this.message.replace(/^"" /, '').trim();
82
+ }
83
+
84
+ return this.message;
85
+ }
86
+
87
+ _template(messages, code) {
88
+
89
+ return exports.template(this.value, messages, code || this.code, this.state, this.prefs);
90
+ }
91
+ };
92
+
93
+
94
+ exports.path = function (path) {
95
+
96
+ let label = '';
97
+ for (const segment of path) {
98
+ if (typeof segment === 'object') { // Exclude array single path segment
99
+ continue;
100
+ }
101
+
102
+ if (typeof segment === 'string') {
103
+ if (label) {
104
+ label += '.';
105
+ }
106
+
107
+ label += segment;
108
+ }
109
+ else {
110
+ label += `[${segment}]`;
111
+ }
112
+ }
113
+
114
+ return label;
115
+ };
116
+
117
+
118
+ exports.template = function (value, messages, code, state, prefs) {
119
+
120
+ if (!messages) {
121
+ return;
122
+ }
123
+
124
+ if (Template.isTemplate(messages)) {
125
+ return code !== 'root' ? messages : null;
126
+ }
127
+
128
+ let lang = prefs.errors.language;
129
+ if (Common.isResolvable(lang)) {
130
+ lang = lang.resolve(value, state, prefs);
131
+ }
132
+
133
+ if (lang &&
134
+ messages[lang]) {
135
+
136
+ if (messages[lang][code] !== undefined) {
137
+ return messages[lang][code];
138
+ }
139
+
140
+ if (messages[lang]['*'] !== undefined) {
141
+ return messages[lang]['*'];
142
+ }
143
+ }
144
+
145
+ if (!messages[code]) {
146
+ return messages['*'];
147
+ }
148
+
149
+ return messages[code];
150
+ };
151
+
152
+
153
+ exports.label = function (flags, state, prefs, messages) {
154
+
155
+ if (!prefs.errors.label) {
156
+ return '';
157
+ }
158
+
159
+ if (flags.label) {
160
+ return flags.label;
161
+ }
162
+
163
+ let path = state.path;
164
+ if (prefs.errors.label === 'key' &&
165
+ state.path.length > 1) {
166
+
167
+ path = state.path.slice(-1);
168
+ }
169
+
170
+ const normalized = exports.path(path);
171
+ if (normalized) {
172
+ return normalized;
173
+ }
174
+
175
+ return exports.template(null, prefs.messages, 'root', state, prefs) ||
176
+ messages && exports.template(null, messages, 'root', state, prefs) ||
177
+ 'value';
178
+ };
179
+
180
+
181
+ exports.process = function (errors, original, prefs) {
182
+
183
+ if (!errors) {
184
+ return null;
185
+ }
186
+
187
+ const { override, message, details } = exports.details(errors);
188
+ if (override) {
189
+ return override;
190
+ }
191
+
192
+ if (prefs.errors.stack) {
193
+ return new exports.ValidationError(message, details, original);
194
+ }
195
+
196
+ const limit = Error.stackTraceLimit;
197
+ Error.stackTraceLimit = 0;
198
+ const validationError = new exports.ValidationError(message, details, original);
199
+ Error.stackTraceLimit = limit;
200
+ return validationError;
201
+ };
202
+
203
+
204
+ exports.details = function (errors, options = {}) {
205
+
206
+ let messages = [];
207
+ const details = [];
208
+
209
+ for (const item of errors) {
210
+
211
+ // Override
212
+
213
+ if (item instanceof Error) {
214
+ if (options.override !== false) {
215
+ return { override: item };
216
+ }
217
+
218
+ const message = item.toString();
219
+ messages.push(message);
220
+
221
+ details.push({
222
+ message,
223
+ type: 'override',
224
+ context: { error: item }
225
+ });
226
+
227
+ continue;
228
+ }
229
+
230
+ // Report
231
+
232
+ const message = item.toString();
233
+ messages.push(message);
234
+
235
+ details.push({
236
+ message,
237
+ path: item.path.filter((v) => typeof v !== 'object'),
238
+ type: item.code,
239
+ context: item.local
240
+ });
241
+ }
242
+
243
+ if (messages.length > 1) {
244
+ messages = [...new Set(messages)];
245
+ }
246
+
247
+ return { message: messages.join('. '), details };
248
+ };
249
+
250
+
251
+ exports.ValidationError = class extends Error {
252
+
253
+ constructor(message, details, original) {
254
+
255
+ super(message);
256
+ this._original = original;
257
+ this.details = details;
258
+ }
259
+
260
+ static isError(err) {
261
+
262
+ return err instanceof exports.ValidationError;
263
+ }
264
+ };
265
+
266
+
267
+ exports.ValidationError.prototype.isJoi = true;
268
+
269
+ exports.ValidationError.prototype.name = 'ValidationError';
270
+
271
+ exports.ValidationError.prototype.annotate = Annotate.error;
package/lib/extend.js ADDED
@@ -0,0 +1,317 @@
1
+ 'use strict';
2
+
3
+ const { assert, clone } = require('@hapi/hoek');
4
+
5
+ const Common = require('./common');
6
+ const Messages = require('./messages');
7
+
8
+
9
+ const internals = {};
10
+
11
+
12
+ exports.type = function (from, options) {
13
+
14
+ const base = Object.getPrototypeOf(from);
15
+ const prototype = clone(base);
16
+ const schema = from._assign(Object.create(prototype));
17
+ const def = Object.assign({}, options); // Shallow cloned
18
+ delete def.base;
19
+
20
+ prototype._definition = def;
21
+
22
+ const parent = base._definition || {};
23
+ def.messages = Messages.merge(parent.messages, def.messages);
24
+ def.properties = Object.assign({}, parent.properties, def.properties);
25
+
26
+ // Type
27
+
28
+ schema.type = def.type;
29
+
30
+ // Flags
31
+
32
+ def.flags = Object.assign({}, parent.flags, def.flags);
33
+
34
+ // Terms
35
+
36
+ const terms = Object.assign({}, parent.terms);
37
+ if (def.terms) {
38
+ for (const name in def.terms) { // Only apply own terms
39
+ const term = def.terms[name];
40
+ assert(schema.$_terms[name] === undefined, 'Invalid term override for', def.type, name);
41
+ schema.$_terms[name] = term.init;
42
+ terms[name] = term;
43
+ }
44
+ }
45
+
46
+ def.terms = terms;
47
+
48
+ // Constructor arguments
49
+
50
+ if (!def.args) {
51
+ def.args = parent.args;
52
+ }
53
+
54
+ // Prepare
55
+
56
+ def.prepare = internals.prepare(def.prepare, parent.prepare);
57
+
58
+ // Coerce
59
+
60
+ if (def.coerce) {
61
+ if (typeof def.coerce === 'function') {
62
+ def.coerce = { method: def.coerce };
63
+ }
64
+
65
+ if (def.coerce.from &&
66
+ !Array.isArray(def.coerce.from)) {
67
+
68
+ def.coerce = { method: def.coerce.method, from: [].concat(def.coerce.from) };
69
+ }
70
+ }
71
+
72
+ def.coerce = internals.coerce(def.coerce, parent.coerce);
73
+
74
+ // Validate
75
+
76
+ def.validate = internals.validate(def.validate, parent.validate);
77
+
78
+ // Rules
79
+
80
+ const rules = Object.assign({}, parent.rules);
81
+ if (def.rules) {
82
+ for (const name in def.rules) {
83
+ const rule = def.rules[name];
84
+ assert(typeof rule === 'object', 'Invalid rule definition for', def.type, name);
85
+
86
+ let method = rule.method;
87
+ if (method === undefined) {
88
+ method = function () {
89
+
90
+ return this.$_addRule(name);
91
+ };
92
+ }
93
+
94
+ if (method) {
95
+ assert(!prototype[name], 'Rule conflict in', def.type, name);
96
+ prototype[name] = method;
97
+ }
98
+
99
+ assert(!rules[name], 'Rule conflict in', def.type, name);
100
+ rules[name] = rule;
101
+
102
+ if (rule.alias) {
103
+ const aliases = [].concat(rule.alias);
104
+ for (const alias of aliases) {
105
+ prototype[alias] = rule.method;
106
+ }
107
+ }
108
+
109
+ if (rule.args) {
110
+ rule.argsByName = new Map();
111
+ rule.args = rule.args.map((arg) => {
112
+
113
+ if (typeof arg === 'string') {
114
+ arg = { name: arg };
115
+ }
116
+
117
+ assert(!rule.argsByName.has(arg.name), 'Duplicated argument name', arg.name);
118
+
119
+ if (Common.isSchema(arg.assert)) {
120
+ arg.assert = arg.assert.strict().label(arg.name);
121
+ }
122
+
123
+ rule.argsByName.set(arg.name, arg);
124
+ return arg;
125
+ });
126
+ }
127
+ }
128
+ }
129
+
130
+ def.rules = rules;
131
+
132
+ // JSON Schema
133
+
134
+ if (!def.jsonSchema) {
135
+ def.jsonSchema = parent.jsonSchema;
136
+ }
137
+
138
+ // Modifiers
139
+
140
+ const modifiers = Object.assign({}, parent.modifiers);
141
+ if (def.modifiers) {
142
+ for (const name in def.modifiers) {
143
+ assert(!prototype[name], 'Rule conflict in', def.type, name);
144
+
145
+ const modifier = def.modifiers[name];
146
+ assert(typeof modifier === 'function', 'Invalid modifier definition for', def.type, name);
147
+
148
+ const method = function (arg) {
149
+
150
+ return this.rule({ [name]: arg });
151
+ };
152
+
153
+ prototype[name] = method;
154
+ modifiers[name] = modifier;
155
+ }
156
+ }
157
+
158
+ def.modifiers = modifiers;
159
+
160
+ // Overrides
161
+
162
+ if (def.overrides) {
163
+ prototype._super = base;
164
+ schema.$_super = {}; // Backwards compatibility
165
+ for (const override in def.overrides) {
166
+ assert(base[override], 'Cannot override missing', override);
167
+ def.overrides[override][Common.symbols.parent] = base[override];
168
+ schema.$_super[override] = base[override].bind(schema); // Backwards compatibility
169
+ }
170
+
171
+ Object.assign(prototype, def.overrides);
172
+ }
173
+
174
+ // Casts
175
+
176
+ def.cast = Object.assign({}, parent.cast, def.cast);
177
+
178
+ // Manifest
179
+
180
+ const manifest = Object.assign({}, parent.manifest, def.manifest);
181
+ manifest.build = internals.build(def.manifest && def.manifest.build, parent.manifest && parent.manifest.build);
182
+ def.manifest = manifest;
183
+
184
+ // Rebuild
185
+
186
+ def.rebuild = internals.rebuild(def.rebuild, parent.rebuild);
187
+
188
+ return schema;
189
+ };
190
+
191
+
192
+ // Helpers
193
+
194
+ internals.build = function (child, parent) {
195
+
196
+ if (!child ||
197
+ !parent) {
198
+
199
+ return child || parent;
200
+ }
201
+
202
+ return function (obj, desc) {
203
+
204
+ return parent(child(obj, desc), desc);
205
+ };
206
+ };
207
+
208
+
209
+ internals.coerce = function (child, parent) {
210
+
211
+ if (!child ||
212
+ !parent) {
213
+
214
+ return child || parent;
215
+ }
216
+
217
+ return {
218
+ from: child.from && parent.from ? [...new Set([...child.from, ...parent.from])] : null,
219
+ method(value, helpers) {
220
+
221
+ let coerced;
222
+ if (!parent.from ||
223
+ parent.from.includes(typeof value)) {
224
+
225
+ coerced = parent.method(value, helpers);
226
+ if (coerced) {
227
+ if (coerced.errors ||
228
+ coerced.value === undefined) {
229
+
230
+ return coerced;
231
+ }
232
+
233
+ value = coerced.value;
234
+ }
235
+ }
236
+
237
+ if (!child.from ||
238
+ child.from.includes(typeof value)) {
239
+
240
+ const own = child.method(value, helpers);
241
+ if (own) {
242
+ return own;
243
+ }
244
+ }
245
+
246
+ return coerced;
247
+ }
248
+ };
249
+ };
250
+
251
+
252
+ internals.prepare = function (child, parent) {
253
+
254
+ if (!child ||
255
+ !parent) {
256
+
257
+ return child || parent;
258
+ }
259
+
260
+ return function (value, helpers) {
261
+
262
+ const prepared = child(value, helpers);
263
+ if (prepared) {
264
+ if (prepared.errors ||
265
+ prepared.value === undefined) {
266
+
267
+ return prepared;
268
+ }
269
+
270
+ value = prepared.value;
271
+ }
272
+
273
+ return parent(value, helpers) || prepared;
274
+ };
275
+ };
276
+
277
+
278
+ internals.rebuild = function (child, parent) {
279
+
280
+ if (!child ||
281
+ !parent) {
282
+
283
+ return child || parent;
284
+ }
285
+
286
+ return function (schema) {
287
+
288
+ parent(schema);
289
+ child(schema);
290
+ };
291
+ };
292
+
293
+
294
+ internals.validate = function (child, parent) {
295
+
296
+ if (!child ||
297
+ !parent) {
298
+
299
+ return child || parent;
300
+ }
301
+
302
+ return function (value, helpers) {
303
+
304
+ const result = parent(value, helpers);
305
+ if (result) {
306
+ if (result.errors &&
307
+ (!Array.isArray(result.errors) || result.errors.length)) {
308
+
309
+ return result;
310
+ }
311
+
312
+ value = result.value;
313
+ }
314
+
315
+ return child(value, helpers) || result;
316
+ };
317
+ };