joi 14.2.0 → 17.2.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.
Files changed (59) hide show
  1. package/LICENSE.md +10 -0
  2. package/README.md +9 -118
  3. package/dist/joi-browser.min.js +1 -0
  4. package/lib/annotate.js +175 -0
  5. package/lib/base.js +1068 -0
  6. package/lib/cache.js +143 -0
  7. package/lib/common.js +216 -0
  8. package/lib/compile.js +283 -0
  9. package/lib/errors.js +160 -269
  10. package/lib/extend.js +312 -0
  11. package/lib/index.d.ts +2200 -0
  12. package/lib/index.js +179 -347
  13. package/lib/manifest.js +476 -0
  14. package/lib/messages.js +178 -0
  15. package/lib/modify.js +267 -0
  16. package/lib/ref.js +386 -25
  17. package/lib/schemas.js +291 -15
  18. package/lib/state.js +152 -0
  19. package/lib/template.js +427 -0
  20. package/lib/trace.js +346 -0
  21. package/lib/types/alternatives.js +329 -0
  22. package/lib/types/any.js +174 -0
  23. package/lib/types/array.js +775 -0
  24. package/lib/types/binary.js +98 -0
  25. package/lib/types/boolean.js +150 -0
  26. package/lib/types/date.js +233 -0
  27. package/lib/types/function.js +93 -0
  28. package/lib/types/keys.js +1043 -0
  29. package/lib/types/link.js +168 -0
  30. package/lib/types/number.js +335 -0
  31. package/lib/types/object.js +22 -0
  32. package/lib/types/string.js +820 -0
  33. package/lib/types/symbol.js +102 -0
  34. package/lib/validator.js +650 -0
  35. package/lib/values.js +263 -0
  36. package/package.json +34 -29
  37. package/CHANGELOG.md +0 -3
  38. package/LICENSE +0 -25
  39. package/lib/cast.js +0 -64
  40. package/lib/language.js +0 -166
  41. package/lib/set.js +0 -191
  42. package/lib/types/alternatives/index.js +0 -218
  43. package/lib/types/any/index.js +0 -978
  44. package/lib/types/any/settings.js +0 -36
  45. package/lib/types/array/index.js +0 -707
  46. package/lib/types/binary/index.js +0 -100
  47. package/lib/types/boolean/index.js +0 -100
  48. package/lib/types/date/index.js +0 -182
  49. package/lib/types/func/index.js +0 -90
  50. package/lib/types/lazy/index.js +0 -82
  51. package/lib/types/number/index.js +0 -248
  52. package/lib/types/object/index.js +0 -957
  53. package/lib/types/state.js +0 -11
  54. package/lib/types/string/index.js +0 -703
  55. package/lib/types/string/ip.js +0 -54
  56. package/lib/types/string/rfc3986.js +0 -219
  57. package/lib/types/string/uri.js +0 -46
  58. package/lib/types/symbol/index.js +0 -93
  59. package/lib/types/symbols.js +0 -5
package/lib/schemas.js CHANGED
@@ -1,25 +1,301 @@
1
1
  'use strict';
2
2
 
3
- // Load modules
4
-
5
3
  const Joi = require('./index');
6
4
 
7
5
 
8
- // Declare internals
9
-
10
6
  const internals = {};
11
7
 
12
- exports.options = Joi.object({
13
- abortEarly: Joi.boolean(),
14
- convert: Joi.boolean(),
8
+
9
+ // Preferences
10
+
11
+ internals.wrap = Joi.string()
12
+ .min(1)
13
+ .max(2)
14
+ .allow(false);
15
+
16
+
17
+ exports.preferences = Joi.object({
15
18
  allowUnknown: Joi.boolean(),
16
- skipFunctions: Joi.boolean(),
17
- stripUnknown: [Joi.boolean(), Joi.object({ arrays: Joi.boolean(), objects: Joi.boolean() }).or('arrays', 'objects')],
18
- language: Joi.object(),
19
- presence: Joi.string().only('required', 'optional', 'forbidden', 'ignore'),
20
- raw: Joi.boolean(),
19
+ abortEarly: Joi.boolean(),
20
+ artifacts: Joi.boolean(),
21
+ cache: Joi.boolean(),
21
22
  context: Joi.object(),
22
- strip: Joi.boolean(),
23
+ convert: Joi.boolean(),
24
+ dateFormat: Joi.valid('date', 'iso', 'string', 'time', 'utc'),
25
+ debug: Joi.boolean(),
26
+ errors: {
27
+ escapeHtml: Joi.boolean(),
28
+ label: Joi.valid('path', 'key', false),
29
+ language: [
30
+ Joi.string(),
31
+ Joi.object().ref()
32
+ ],
33
+ render: Joi.boolean(),
34
+ stack: Joi.boolean(),
35
+ wrap: {
36
+ label: internals.wrap,
37
+ array: internals.wrap
38
+ }
39
+ },
40
+ externals: Joi.boolean(),
41
+ messages: Joi.object(),
23
42
  noDefaults: Joi.boolean(),
24
- escapeHtml: Joi.boolean()
25
- }).strict();
43
+ nonEnumerables: Joi.boolean(),
44
+ presence: Joi.valid('required', 'optional', 'forbidden'),
45
+ skipFunctions: Joi.boolean(),
46
+ stripUnknown: Joi.object({
47
+ arrays: Joi.boolean(),
48
+ objects: Joi.boolean()
49
+ })
50
+ .or('arrays', 'objects')
51
+ .allow(true, false),
52
+ warnings: Joi.boolean()
53
+ })
54
+ .strict();
55
+
56
+
57
+ // Extensions
58
+
59
+ internals.nameRx = /^[a-zA-Z0-9]\w*$/;
60
+
61
+
62
+ internals.rule = Joi.object({
63
+ alias: Joi.array().items(Joi.string().pattern(internals.nameRx)).single(),
64
+ args: Joi.array().items(
65
+ Joi.string(),
66
+ Joi.object({
67
+ name: Joi.string().pattern(internals.nameRx).required(),
68
+ ref: Joi.boolean(),
69
+ assert: Joi.alternatives([
70
+ Joi.function(),
71
+ Joi.object().schema()
72
+ ])
73
+ .conditional('ref', { is: true, then: Joi.required() }),
74
+ normalize: Joi.function(),
75
+ message: Joi.string().when('assert', { is: Joi.function(), then: Joi.required() })
76
+ })
77
+ ),
78
+ convert: Joi.boolean(),
79
+ manifest: Joi.boolean(),
80
+ method: Joi.function().allow(false),
81
+ multi: Joi.boolean(),
82
+ validate: Joi.function()
83
+ });
84
+
85
+
86
+ exports.extension = Joi.object({
87
+ type: Joi.alternatives([
88
+ Joi.string(),
89
+ Joi.object().regex()
90
+ ])
91
+ .required(),
92
+ args: Joi.function(),
93
+ cast: Joi.object().pattern(internals.nameRx, Joi.object({
94
+ from: Joi.function().maxArity(1).required(),
95
+ to: Joi.function().minArity(1).maxArity(2).required()
96
+ })),
97
+ base: Joi.object().schema()
98
+ .when('type', { is: Joi.object().regex(), then: Joi.forbidden() }),
99
+ coerce: [
100
+ Joi.function().maxArity(3),
101
+ Joi.object({ method: Joi.function().maxArity(3).required(), from: Joi.array().items(Joi.string()).single() })
102
+ ],
103
+ flags: Joi.object().pattern(internals.nameRx, Joi.object({
104
+ setter: Joi.string(),
105
+ default: Joi.any()
106
+ })),
107
+ manifest: {
108
+ build: Joi.function().arity(2)
109
+ },
110
+ messages: [Joi.object(), Joi.string()],
111
+ modifiers: Joi.object().pattern(internals.nameRx, Joi.function().minArity(1).maxArity(2)),
112
+ overrides: Joi.object().pattern(internals.nameRx, Joi.function()),
113
+ prepare: Joi.function().maxArity(3),
114
+ rebuild: Joi.function().arity(1),
115
+ rules: Joi.object().pattern(internals.nameRx, internals.rule),
116
+ terms: Joi.object().pattern(internals.nameRx, Joi.object({
117
+ init: Joi.array().allow(null).required(),
118
+ manifest: Joi.object().pattern(/.+/, [
119
+ Joi.valid('schema', 'single'),
120
+ Joi.object({
121
+ mapped: Joi.object({
122
+ from: Joi.string().required(),
123
+ to: Joi.string().required()
124
+ })
125
+ .required()
126
+ })
127
+ ])
128
+ })),
129
+ validate: Joi.function().maxArity(3)
130
+ })
131
+ .strict();
132
+
133
+
134
+ exports.extensions = Joi.array().items(Joi.object(), Joi.function().arity(1)).strict();
135
+
136
+
137
+ // Manifest
138
+
139
+ internals.desc = {
140
+
141
+ buffer: Joi.object({
142
+ buffer: Joi.string()
143
+ }),
144
+
145
+ func: Joi.object({
146
+ function: Joi.function().required(),
147
+ options: {
148
+ literal: true
149
+ }
150
+ }),
151
+
152
+ override: Joi.object({
153
+ override: true
154
+ }),
155
+
156
+ ref: Joi.object({
157
+ ref: Joi.object({
158
+ type: Joi.valid('value', 'global', 'local'),
159
+ path: Joi.array().required(),
160
+ separator: Joi.string().length(1).allow(false),
161
+ ancestor: Joi.number().min(0).integer().allow('root'),
162
+ map: Joi.array().items(Joi.array().length(2)).min(1),
163
+ adjust: Joi.function(),
164
+ iterables: Joi.boolean(),
165
+ in: Joi.boolean(),
166
+ render: Joi.boolean()
167
+ })
168
+ .required()
169
+ }),
170
+
171
+ regex: Joi.object({
172
+ regex: Joi.string().min(3)
173
+ }),
174
+
175
+ special: Joi.object({
176
+ special: Joi.valid('deep').required()
177
+ }),
178
+
179
+ template: Joi.object({
180
+ template: Joi.string().required(),
181
+ options: Joi.object()
182
+ }),
183
+
184
+ value: Joi.object({
185
+ value: Joi.alternatives([Joi.object(), Joi.array()]).required()
186
+ })
187
+ };
188
+
189
+
190
+ internals.desc.entity = Joi.alternatives([
191
+ Joi.array().items(Joi.link('...')),
192
+ Joi.boolean(),
193
+ Joi.function(),
194
+ Joi.number(),
195
+ Joi.string(),
196
+ internals.desc.buffer,
197
+ internals.desc.func,
198
+ internals.desc.ref,
199
+ internals.desc.regex,
200
+ internals.desc.special,
201
+ internals.desc.template,
202
+ internals.desc.value,
203
+ Joi.link('/')
204
+ ]);
205
+
206
+
207
+ internals.desc.values = Joi.array()
208
+ .items(
209
+ null,
210
+ Joi.boolean(),
211
+ Joi.function(),
212
+ Joi.number().allow(Infinity, -Infinity),
213
+ Joi.string().allow(''),
214
+ Joi.symbol(),
215
+ internals.desc.buffer,
216
+ internals.desc.func,
217
+ internals.desc.override,
218
+ internals.desc.ref,
219
+ internals.desc.regex,
220
+ internals.desc.template,
221
+ internals.desc.value
222
+ );
223
+
224
+
225
+ internals.desc.messages = Joi.object()
226
+ .pattern(/.+/, [
227
+ Joi.string(),
228
+ internals.desc.template,
229
+ Joi.object().pattern(/.+/, [Joi.string(), internals.desc.template])
230
+ ]);
231
+
232
+
233
+ exports.description = Joi.object({
234
+ type: Joi.string().required(),
235
+ flags: Joi.object({
236
+ cast: Joi.string(),
237
+ default: Joi.any(),
238
+ description: Joi.string(),
239
+ empty: Joi.link('/'),
240
+ failover: internals.desc.entity,
241
+ id: Joi.string(),
242
+ label: Joi.string(),
243
+ only: true,
244
+ presence: ['optional', 'required', 'forbidden'],
245
+ result: ['raw', 'strip'],
246
+ strip: Joi.boolean(),
247
+ unit: Joi.string()
248
+ })
249
+ .unknown(),
250
+ preferences: {
251
+ allowUnknown: Joi.boolean(),
252
+ abortEarly: Joi.boolean(),
253
+ artifacts: Joi.boolean(),
254
+ cache: Joi.boolean(),
255
+ convert: Joi.boolean(),
256
+ dateFormat: ['date', 'iso', 'string', 'time', 'utc'],
257
+ errors: {
258
+ escapeHtml: Joi.boolean(),
259
+ label: ['path', 'key'],
260
+ language: [
261
+ Joi.string(),
262
+ internals.desc.ref
263
+ ],
264
+ wrap: {
265
+ label: internals.wrap,
266
+ array: internals.wrap
267
+ }
268
+ },
269
+ externals: Joi.boolean(),
270
+ messages: internals.desc.messages,
271
+ noDefaults: Joi.boolean(),
272
+ nonEnumerables: Joi.boolean(),
273
+ presence: ['required', 'optional', 'forbidden'],
274
+ skipFunctions: Joi.boolean(),
275
+ stripUnknown: Joi.object({
276
+ arrays: Joi.boolean(),
277
+ objects: Joi.boolean()
278
+ })
279
+ .or('arrays', 'objects')
280
+ .allow(true, false),
281
+ warnings: Joi.boolean()
282
+ },
283
+ allow: internals.desc.values,
284
+ invalid: internals.desc.values,
285
+ rules: Joi.array().min(1).items({
286
+ name: Joi.string().required(),
287
+ args: Joi.object().min(1),
288
+ keep: Joi.boolean(),
289
+ message: [
290
+ Joi.string(),
291
+ internals.desc.messages
292
+ ],
293
+ warn: Joi.boolean()
294
+ }),
295
+
296
+ // Terms
297
+
298
+ keys: Joi.object().pattern(/.*/, Joi.link('/')),
299
+ link: internals.desc.ref
300
+ })
301
+ .pattern(/^[a-z]\w*$/, Joi.any());
package/lib/state.js ADDED
@@ -0,0 +1,152 @@
1
+ 'use strict';
2
+
3
+ const Clone = require('@hapi/hoek/lib/clone');
4
+ const Reach = require('@hapi/hoek/lib/reach');
5
+
6
+ const Common = require('./common');
7
+
8
+
9
+ const internals = {
10
+ value: Symbol('value')
11
+ };
12
+
13
+
14
+ module.exports = internals.State = class {
15
+
16
+ constructor(path, ancestors, state) {
17
+
18
+ this.path = path;
19
+ this.ancestors = ancestors; // [parent, ..., root]
20
+
21
+ this.mainstay = state.mainstay;
22
+ this.schemas = state.schemas; // [current, ..., root]
23
+ this.debug = null;
24
+ }
25
+
26
+ localize(path, ancestors = null, schema = null) {
27
+
28
+ const state = new internals.State(path, ancestors, this);
29
+
30
+ if (schema &&
31
+ state.schemas) {
32
+
33
+ state.schemas = [internals.schemas(schema), ...state.schemas];
34
+ }
35
+
36
+ return state;
37
+ }
38
+
39
+ nest(schema, debug) {
40
+
41
+ const state = new internals.State(this.path, this.ancestors, this);
42
+ state.schemas = state.schemas && [internals.schemas(schema), ...state.schemas];
43
+ state.debug = debug;
44
+ return state;
45
+ }
46
+
47
+ shadow(value, reason) {
48
+
49
+ this.mainstay.shadow = this.mainstay.shadow || new internals.Shadow();
50
+ this.mainstay.shadow.set(this.path, value, reason);
51
+ }
52
+
53
+ snapshot() {
54
+
55
+ if (this.mainstay.shadow) {
56
+ this._snapshot = Clone(this.mainstay.shadow.node(this.path));
57
+ }
58
+ }
59
+
60
+ restore() {
61
+
62
+ if (this.mainstay.shadow) {
63
+ this.mainstay.shadow.override(this.path, this._snapshot);
64
+ this._snapshot = undefined;
65
+ }
66
+ }
67
+ };
68
+
69
+
70
+ internals.schemas = function (schema) {
71
+
72
+ if (Common.isSchema(schema)) {
73
+ return { schema };
74
+ }
75
+
76
+ return schema;
77
+ };
78
+
79
+
80
+ internals.Shadow = class {
81
+
82
+ constructor() {
83
+
84
+ this._values = null;
85
+ }
86
+
87
+ set(path, value, reason) {
88
+
89
+ if (!path.length) { // No need to store root value
90
+ return;
91
+ }
92
+
93
+ if (reason === 'strip' &&
94
+ typeof path[path.length - 1] === 'number') { // Cannot store stripped array values (due to shift)
95
+
96
+ return;
97
+ }
98
+
99
+ this._values = this._values || new Map();
100
+
101
+ let node = this._values;
102
+ for (let i = 0; i < path.length; ++i) {
103
+ const segment = path[i];
104
+ let next = node.get(segment);
105
+ if (!next) {
106
+ next = new Map();
107
+ node.set(segment, next);
108
+ }
109
+
110
+ node = next;
111
+ }
112
+
113
+ node[internals.value] = value;
114
+ }
115
+
116
+ get(path) {
117
+
118
+ const node = this.node(path);
119
+ if (node) {
120
+ return node[internals.value];
121
+ }
122
+ }
123
+
124
+ node(path) {
125
+
126
+ if (!this._values) {
127
+ return;
128
+ }
129
+
130
+ return Reach(this._values, path, { iterables: true });
131
+ }
132
+
133
+ override(path, node) {
134
+
135
+ if (!this._values) {
136
+ return;
137
+ }
138
+
139
+ const parents = path.slice(0, -1);
140
+ const own = path[path.length - 1];
141
+ const parent = Reach(this._values, parents, { iterables: true });
142
+
143
+ if (node) {
144
+ parent.set(own, node);
145
+ return;
146
+ }
147
+
148
+ if (parent) {
149
+ parent.delete(own);
150
+ }
151
+ }
152
+ };