json-2-joi 2.0.2 → 2.3.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ### 2.3.0
2
+
3
+ - If `noDefaults` is set `true`, `default()` will not be set to Joi schema and allow it overridable.
4
+
5
+ ### 2.2.0
6
+
7
+ - Add `forbidArrayNull`, `strictRequired` option.
8
+
9
+ ### 2.1.0
10
+
11
+ - Fix the issue that `enum` is only applied to `string` type or when missing type info.
12
+ - Add `strictEnum` and `enableEnum` option.
13
+ - Allow override options when calling `convert` api.
14
+
1
15
  ### 2.0.2
2
16
 
3
17
  - Remove `min` setting from JOI schema if `minLength` is not defined in JSON schema.
package/README.md CHANGED
@@ -6,7 +6,7 @@ Converts a JSON schema to a Joi schema for object validation.
6
6
 
7
7
  ## Change based on the forked version (enjoi):
8
8
 
9
- - Provided `refineDescription(schema)`, `allowNull` options
9
+ - Provided `refineDescription(schema)`, `allowNull`, `forbidArrayNull`, `strictRequired`, `strictEnum`, `enableEnum` options
10
10
  - Change cycle reference resovling without self-generating id and rely on $id if defined in JSON schema
11
11
  - Support `const` keyword in JSON schema
12
12
  - Support `example` setting for Joi based on JSON schema's `examples`, `default` or `enum`
@@ -49,11 +49,16 @@ Please file issues for other unsupported features.
49
49
  ### Options
50
50
 
51
51
  - `subSchemas` - an (optional) object with keys representing schema ids, and values representing schemas.
52
+ - `extensions` - an array of extensions to pass [joi.extend](https://github.com/hapijs/joi/blob/master/API.md#extendextension).
53
+ - `joiOptions` - Options directly passed to Joi for instance creation. If the `noDefaults` is set `true`, `default()` will NOT be called and applied to Joi schema.
52
54
  - `refineDescription(schema)` - an (optional) function to call to apply to the JSON schema so that it's possible to return customized description.
53
55
  - `refineType(type, format)` - an (optional) function to call to apply to type based on the type and format of the JSON schema.
54
56
  - `refineSchema(joiSchema, jsonSchema)` - an (optional) function to call to apply to adjust Joi schema base on the original JSON schema. Primary use case is handling `nullable` flag in OpenAPI 3.0
55
- - `extensions` - an array of extensions to pass [joi.extend](https://github.com/hapijs/joi/blob/master/API.md#extendextension).
56
- - `allowNull` - Allows null value when the field is NOT required with a default value of `false`.
57
+ - `allowNull` - Default as `false`. When `true` and the field has no `enum` setting, `null` value will be allowed.
58
+ - `forbidArrayNull` - Default as `true`. When `false` and `allowNull` is true, `null` value will be allowed for array type field.
59
+ - `strictRequired` - Default as `false`. When `true`, `null` (and empty string additionally for string type) will NOT be allowed for those `required` field in object.
60
+ - `strictEnum` - Default as `true`. When `false`, and `allowNull` is `true`, `null` (and empty string additionally for string type) will be added to `enum` list.
61
+ - `enableEnum` - Default as `true`. When `false`, `enum` restriction will not be added to Joi Schema.
57
62
 
58
63
  Example:
59
64
 
@@ -204,6 +209,67 @@ const lengthSchema = json2Joi.convert({
204
209
  });
205
210
  ```
206
211
 
212
+ #### Override options during conversion
213
+
214
+ When reusing the Resolver and calling `convert` API, it's possible that different schema might have different requirement.
215
+
216
+ It's possible to override these options for each conversion:
217
+
218
+ * refineType
219
+ * refineSchema
220
+ * refineDescription
221
+ * allowNull
222
+ * forbidArrayNull
223
+ * strictRequired
224
+ * strictEnum
225
+ * enableEnum
226
+ * noDefaults (Copied from `joiOptions` for the construction time)
227
+
228
+ However, the overriden options do not have impact on the `subSchemas` as they are preprocessed during Resolver construction.
229
+
230
+ ```javascript
231
+ const subSchemas = {
232
+ measurement: {
233
+ type: 'object',
234
+ properties: {
235
+ quantity: {
236
+ type: 'number',
237
+ enum: [0, 1]
238
+ }
239
+ }
240
+ }
241
+ };
242
+ const enjoi = Enjoi.resolver({
243
+ subSchemas,
244
+ enableEnum: false
245
+ });
246
+
247
+ const jsonSchema = {
248
+ type: 'object',
249
+ properties: {
250
+ weight: {
251
+ type: 'object',
252
+ properties: {
253
+ quantity: {
254
+ type: 'number',
255
+ enum: [0, 1]
256
+ }
257
+ }
258
+ },
259
+ length: {
260
+ $ref: 'measurement'
261
+ }
262
+ }
263
+ };
264
+
265
+ const schema1 = enjoi.convert(jsonSchema, { enableEnum: true });
266
+ const schema2 = enjoi.convert(jsonSchema);
267
+
268
+ t.ok(schema1.validate({ weight: { quantity: 2 } }).error, 'follow overridden options');
269
+ t.ok(!schema1.validate({ length: { quantity: 2 } }).error, 'no impact on subschemas');
270
+ t.ok(!schema2.validate({ weight: { quantity: 2 } }).error, 'still use original options');
271
+ ```
272
+
207
273
  ### Custom Types
208
274
 
209
275
  Custom types can be provided through the `extensions` option.
package/lib/resolver.js CHANGED
@@ -20,9 +20,38 @@ const optionsSchema = Joi.object({
20
20
  refineSchema: Joi.func().allow(null),
21
21
  refineDescription: Joi.func().allow(null),
22
22
  allowNull: Joi.boolean().default(false),
23
+ forbidArrayNull: Joi.boolean().default(true),
24
+ strictRequired: Joi.boolean().default(false),
25
+ strictEnum: Joi.boolean().default(true),
26
+ enableEnum: Joi.boolean().default(true),
23
27
  joiOptions: Joi.object().unknown(true).default({})
24
28
  });
25
29
 
30
+ const overridableOptions = {
31
+ refineType: Joi.func().allow(null),
32
+ refineSchema: Joi.func().allow(null),
33
+ refineDescription: Joi.func().allow(null),
34
+ allowNull: Joi.boolean(),
35
+ forbidArrayNull: Joi.boolean(),
36
+ strictRequired: Joi.boolean(),
37
+ noDefaults: Joi.boolean(),
38
+ strictEnum: Joi.boolean(),
39
+ enableEnum: Joi.boolean()
40
+ };
41
+ const overridableOptionKeys = Object.keys(overridableOptions);
42
+ const overrideOptionsSchema = Joi.object(overridableOptions);
43
+
44
+ function mergeOverridableOptions(target, ...sources) {
45
+ sources.forEach((src) => {
46
+ overridableOptionKeys.forEach((key) => {
47
+ if (typeof src[key] !== 'undefined') {
48
+ target[key] = src[key];
49
+ }
50
+ })
51
+ });
52
+ return target;
53
+ }
54
+
26
55
  function isNumber(value) {
27
56
  return typeof value === 'number';
28
57
  }
@@ -35,13 +64,36 @@ function isNotEmptyObject(value) {
35
64
  return isObject(value) && Object.keys(value).length > 0;
36
65
  }
37
66
 
38
- function allowNullIfNeeded(schema, allowNull = false) {
67
+ function allowNullIfNeeded(schema, { allowNull = false, forbidArrayNull = true }) {
39
68
  if (allowNull) {
69
+ const definition = schema.describe();
70
+ if (definition.flags && definition.flags.only && definition.allow) {
71
+ // Already has enum restriction
72
+ return schema;
73
+ }
74
+ if (forbidArrayNull && schema.type === 'array') {
75
+ return schema;
76
+ }
40
77
  return schema.allow(null);
41
78
  }
42
79
  return schema;
43
80
  }
44
81
 
82
+ function addEnumRestriction(joiSchema, enumList, { allowNull = false, strictEnum = true, enableEnum = true }) {
83
+ if (!enableEnum || !Array.isArray(enumList) || enumList.length === 0) {
84
+ return joiSchema;
85
+ }
86
+
87
+ const valids = [].concat(enumList);
88
+ if (allowNull && !strictEnum) {
89
+ valids.splice(0, 0, null);
90
+ if (joiSchema.type === 'string') {
91
+ valids.splice(0, 0, '');
92
+ }
93
+ }
94
+ return joiSchema.valid(...valids);
95
+ }
96
+
45
97
  function normalizedId(id) {
46
98
  return id.replace(/[^a-zA-Z0-9]/g, '_');
47
99
  }
@@ -104,15 +156,13 @@ class SchemaResolver {
104
156
 
105
157
  Hoek.assert(!validatedResult.error, validatedResult.error);
106
158
 
107
- const { subSchemas = {}, refineType, refineSchema, extensions = [], allowNull = false, refineDescription, joiOptions } = validatedResult.value;
159
+ const { subSchemas = {}, extensions = [], joiOptions } = validatedResult.value;
108
160
 
161
+ this.resolveOptions = mergeOverridableOptions({}, validatedResult.value);
109
162
  this.subSchemas = subSchemas;
110
- this.refineType = refineType;
111
- this.refineDescription = refineDescription;
112
- this.refineSchema = refineSchema;
113
- this.allowNull = allowNull;
114
163
  this.joiOptions = joiOptions;
115
164
  this.joiSharedSchemas = new Map();
165
+ this.resolveOptions.noDefaults = this.joiOptions.noDefaults;
116
166
 
117
167
  this.joi = getJoiInstance(joiOptions, extensions, joiInstance);
118
168
 
@@ -122,7 +172,7 @@ class SchemaResolver {
122
172
  // shorthand schema type does not need to set $id
123
173
  sharedSchema.$id = sharedSchemaId;
124
174
  }
125
- this.joiSharedSchemas.set(sharedSchemaId, this.resolve(sharedSchema));
175
+ this.joiSharedSchemas.set(sharedSchemaId, this.resolve(sharedSchema, this.resolveOptions));
126
176
  }
127
177
 
128
178
  const itr = this.joiSharedSchemas.keys();
@@ -132,26 +182,29 @@ class SchemaResolver {
132
182
  }
133
183
  }
134
184
 
135
- resolveShareSchemas(schema, baseUri = '', sharedProperties = '$defs') {
185
+ resolveShareSchemas(schema, resolveOptions, sharedProperties = '$defs', baseUri = '') {
136
186
  const localShared = schema[sharedProperties]
137
187
  if (localShared) {
138
188
  for (let sharedSchemaId in localShared) {
139
189
  this.joiSharedSchemas.set(
140
190
  `${baseUri}#/${sharedProperties}/${sharedSchemaId}`,
141
- this.resolve(localShared[sharedSchemaId], baseUri)
191
+ this.resolve(localShared[sharedSchemaId], resolveOptions, baseUri)
142
192
  );
143
193
  }
144
194
  }
145
195
  }
146
196
 
147
- convert(schema) {
197
+ convert(schema, options = {}) {
148
198
  const validateSchema = schemaSchema.validate(schema);
199
+ const { value: overrideOptions, error: overrideOptionsError } = overrideOptionsSchema.validate(options);
149
200
 
150
201
  Hoek.assert(!validateSchema.error, validateSchema.error);
202
+ Hoek.assert(!overrideOptionsError, overrideOptionsError);
151
203
 
152
204
  const schemaId = schema.$id || '';
153
205
  this.subSchemas[schemaId] = schema;
154
- const joiSchema = this.resolve(schema);
206
+
207
+ const joiSchema = this.resolve(schema, mergeOverridableOptions({}, this.resolveOptions, overrideOptions));
155
208
 
156
209
  // Cleanup all shared schema registered other than the initial shared ones
157
210
  delete this.subSchemas[schemaId];
@@ -165,7 +218,7 @@ class SchemaResolver {
165
218
  return joiSchema;
166
219
  }
167
220
 
168
- resolve(schema, baseUri = (schema.$id || '')) {
221
+ resolve(schema, resolveOptions = {}, baseUri = (schema.$id || '')) {
169
222
  if (this.joi.isSchema(schema)) {
170
223
  return schema;
171
224
  }
@@ -180,46 +233,48 @@ class SchemaResolver {
180
233
  }
181
234
  }
182
235
 
183
- this.resolveShareSchemas(schema, baseUri, '$defs');
184
- this.resolveShareSchemas(schema, baseUri, 'definitions');
236
+ this.resolveShareSchemas(schema, resolveOptions, '$defs', baseUri);
237
+ this.resolveShareSchemas(schema, resolveOptions, 'definitions', baseUri);
185
238
 
186
239
  if (typeof schema === 'string') {
187
240
  // If schema is itself a string, interpret it as a type
188
- resolvedSchema = this.resolveType({ type: schema });
241
+ resolvedSchema = this.resolveType({ type: schema }, resolveOptions, baseUri);
189
242
  } else if (schema.$ref) {
190
243
  if (schema.$ref.trim() === '#') {
191
244
  return baseUri ? this.joi.link(`#${normalizedId(baseUri)}`) : this.joi.link('/');
192
245
  }
193
246
 
194
- resolvedSchema = this.resolve(this.resolveReference(schema.$ref, baseUri), baseUri);
247
+ resolvedSchema = this.resolve(this.resolveReference(schema.$ref, baseUri), resolveOptions, baseUri);
195
248
  } else {
196
249
  const partialSchemas = [];
197
250
  if (schema.type) {
198
- partialSchemas.push(this.resolveType(schema, baseUri));
251
+ partialSchemas.push(this.resolveType(schema, resolveOptions, baseUri));
199
252
  } else if (schema.properties) {
200
253
  // if no type is specified, just properties
201
- partialSchemas.push(this.object(schema, baseUri))
254
+ partialSchemas.push(this.object(schema, resolveOptions, baseUri))
202
255
  } else if (schema.format) {
203
256
  // if no type is specified, just format
204
257
  partialSchemas.push(this.string(schema))
205
258
  } else if (schema.enum) {
206
259
  // If no type is specified, just enum
207
- partialSchemas.push(this.joi.any().valid(...schema.enum).example(schema.enum[0]));
260
+ partialSchemas.push(
261
+ addEnumRestriction(this.joi.any().example(schema.enum[0]), schema.enum, resolveOptions)
262
+ );
208
263
  } else if (schema.const) {
209
264
  // Constant value
210
265
  partialSchemas.push(this.getValueJoiType(schema.const).valid(schema.const));
211
266
  }
212
267
  if (schema.anyOf) {
213
- partialSchemas.push(this.resolveAnyOf(schema, baseUri));
268
+ partialSchemas.push(this.resolveAnyOf(schema, resolveOptions, baseUri));
214
269
  }
215
270
  if (schema.allOf) {
216
- partialSchemas.push(this.resolveAllOf(schema, baseUri));
271
+ partialSchemas.push(this.resolveAllOf(schema, resolveOptions, baseUri));
217
272
  }
218
273
  if (schema.oneOf) {
219
- partialSchemas.push(this.resolveOneOf(schema, baseUri));
274
+ partialSchemas.push(this.resolveOneOf(schema, resolveOptions, baseUri));
220
275
  }
221
276
  if (schema.not) {
222
- partialSchemas.push(this.resolveNot(schema, baseUri));
277
+ partialSchemas.push(this.resolveNot(schema, resolveOptions, baseUri));
223
278
  }
224
279
  if (partialSchemas.length === 0) {
225
280
  //Fall through to whatever.
@@ -231,11 +286,11 @@ class SchemaResolver {
231
286
  resolvedSchema = partialSchemas.length === 1 ? partialSchemas[0] : this.joi.alternatives(partialSchemas).match('all');
232
287
  }
233
288
 
234
- if (this.refineSchema) {
235
- resolvedSchema = this.refineSchema(resolvedSchema, schema);
289
+ if (resolveOptions.refineSchema) {
290
+ resolvedSchema = resolveOptions.refineSchema(resolvedSchema, schema);
236
291
  }
237
292
 
238
- if (schema.default !== undefined) {
293
+ if (schema.default !== undefined && !resolveOptions.noDefaults) {
239
294
  resolvedSchema = resolvedSchema.default(schema.default)
240
295
  }
241
296
 
@@ -299,24 +354,23 @@ class SchemaResolver {
299
354
  return refSchema;
300
355
  }
301
356
 
302
- resolveType(schema, baseUri) {
357
+ resolveType(schema, resolveOptions, baseUri) {
303
358
  let joischema;
304
359
 
305
360
  const typeDefinitionMap = {
306
- title: 'label',
307
- default: 'default'
361
+ title: 'label'
308
362
  };
309
363
 
310
- const joitype = (type, format) => {
364
+ const joitype = (type, options, format) => {
311
365
  let joischema;
312
366
 
313
- if (this.refineType) {
314
- type = this.refineType(type, format);
367
+ if (options.refineType) {
368
+ type = options.refineType(type, format);
315
369
  }
316
370
 
317
371
  switch (type) {
318
372
  case 'array':
319
- joischema = this.array(schema, baseUri);
373
+ joischema = this.array(schema, options, baseUri);
320
374
  break;
321
375
  case 'boolean':
322
376
  joischema = this.joi.boolean();
@@ -326,7 +380,7 @@ class SchemaResolver {
326
380
  joischema = this.number(schema);
327
381
  break;
328
382
  case 'object':
329
- joischema = this.object(schema, baseUri);
383
+ joischema = this.object(schema, options, baseUri);
330
384
  break;
331
385
  case 'string':
332
386
  joischema = this.string(schema);
@@ -347,12 +401,12 @@ class SchemaResolver {
347
401
  const schemas = [];
348
402
 
349
403
  for (let i = 0; i < schema.type.length; i++) {
350
- schemas.push(joitype(schema.type[i], schema.format));
404
+ schemas.push(joitype(schema.type[i], resolveOptions, schema.format));
351
405
  }
352
406
 
353
407
  joischema = this.joi.alternatives(schemas);
354
408
  } else {
355
- joischema = joitype(schema.type, schema.format);
409
+ joischema = joitype(schema.type, resolveOptions, schema.format);
356
410
  }
357
411
 
358
412
  Object.keys(typeDefinitionMap).forEach(function (key) {
@@ -362,8 +416,8 @@ class SchemaResolver {
362
416
  });
363
417
 
364
418
  let desc = schema.description;
365
- if (this.refineDescription) {
366
- desc = this.refineDescription(schema);
419
+ if (resolveOptions.refineDescription) {
420
+ desc = resolveOptions.refineDescription(schema);
367
421
  }
368
422
  if (desc) {
369
423
  joischema = joischema.description(desc);
@@ -383,70 +437,72 @@ class SchemaResolver {
383
437
  joischema = joischema.type === 'array' && !Array.isArray(example) ? joischema.example([example]) : joischema.example(example);
384
438
  }
385
439
 
386
- return joischema;
440
+ return addEnumRestriction(joischema, schema.enum, resolveOptions);
387
441
  }
388
442
 
389
- resolveOneOf(schema, baseUri) {
443
+ resolveOneOf(schema, resolveOptions, baseUri) {
390
444
  Hoek.assert(Array.isArray(schema.oneOf), 'Expected oneOf to be an array.');
391
445
 
392
- return this.joi.alternatives(schema.oneOf.map(schema => this.resolve(schema, baseUri))).match('one');
446
+ return this.joi.alternatives(schema.oneOf.map(schema => this.resolve(schema, resolveOptions, baseUri))).match('one');
393
447
  }
394
448
 
395
- resolveAnyOf(schema, baseUri) {
449
+ resolveAnyOf(schema, resolveOptions, baseUri) {
396
450
  Hoek.assert(Array.isArray(schema.anyOf), 'Expected anyOf to be an array.');
397
451
 
398
- return this.joi.alternatives(schema.anyOf.map(schema => this.resolve(schema, baseUri))).match('any');
452
+ return this.joi.alternatives(schema.anyOf.map(schema => this.resolve(schema, resolveOptions, baseUri))).match('any');
399
453
  }
400
454
 
401
- resolveAllOf(schema, baseUri) {
455
+ resolveAllOf(schema, resolveOptions, baseUri) {
402
456
  Hoek.assert(Array.isArray(schema.allOf), 'Expected allOf to be an array.');
403
457
 
404
- return this.joi.alternatives(schema.allOf.map(schema => this.resolve(schema, baseUri))).match('all');
458
+ return this.joi.alternatives(schema.allOf.map(schema => this.resolve(schema, resolveOptions, baseUri))).match('all');
405
459
  }
406
460
 
407
- resolveNot(schema, baseUri) {
461
+ resolveNot(schema, resolveOptions, baseUri) {
408
462
  Hoek.assert(isObject(schema.not), 'Expected Not to be an object.');
409
463
 
410
464
  return this.joi.alternatives().conditional(
411
465
  '.',
412
466
  {
413
- not: this.resolve(schema.not, baseUri),
467
+ not: this.resolve(schema.not, resolveOptions, baseUri),
414
468
  then: this.joi.any(),
415
469
  otherwise: this.joi.any().forbidden()
416
470
  }
417
471
  );
418
472
  }
419
473
 
420
- object(schema, baseUri) {
421
-
422
- const resolveproperties = () => {
423
- const schemas = {};
474
+ resolveProperties(jsonSchema, resolveOptions, baseUri) {
475
+ const schemas = {};
424
476
 
425
- if (!isObject(schema.properties)) {
426
- return;
427
- }
477
+ if (!isObject(jsonSchema.properties)) {
478
+ return;
479
+ }
428
480
 
429
- Object.keys(schema.properties).forEach((key) => {
430
- const property = schema.properties[key];
481
+ Object.keys(jsonSchema.properties).forEach((key) => {
482
+ const property = jsonSchema.properties[key];
431
483
 
432
- let joischema = this.resolve(property, baseUri);
484
+ let joischema = this.resolve(property, resolveOptions, baseUri);
433
485
 
434
- if (Array.isArray(schema.required) && !!~schema.required.indexOf(key)) {
435
- joischema = joischema.required();
436
- } else {
437
- joischema = allowNullIfNeeded(joischema, this.allowNull);
486
+ if (Array.isArray(jsonSchema.required) && !!~jsonSchema.required.indexOf(key)) {
487
+ joischema = joischema.required();
488
+ if (resolveOptions.strictRequired) {
489
+ joischema = joischema.invalid(null, '');
438
490
  }
491
+ } else {
492
+ joischema = allowNullIfNeeded(joischema, resolveOptions);
493
+ }
439
494
 
440
- schemas[key] = joischema;
441
- });
495
+ schemas[key] = joischema;
496
+ });
442
497
 
443
- return schemas;
444
- }
498
+ return schemas;
499
+ }
445
500
 
446
- let joischema = this.joi.object(resolveproperties(schema));
501
+ object(schema, resolveOptions, baseUri) {
502
+ let joischema = this.joi.object(this.resolveProperties(schema, resolveOptions, baseUri));
447
503
 
448
504
  if (isObject(schema.additionalProperties)) {
449
- joischema = joischema.pattern(/^/, this.resolve(schema.additionalProperties, baseUri));
505
+ joischema = joischema.pattern(/^/, this.resolve(schema.additionalProperties, resolveOptions, baseUri));
450
506
  } else if (typeof this.joiOptions.allowUnknown === 'undefined') {
451
507
  joischema = joischema.unknown(schema.additionalProperties !== false);
452
508
  }
@@ -457,25 +513,25 @@ class SchemaResolver {
457
513
  return joischema;
458
514
  }
459
515
 
460
- resolveAsArray(value, baseUri) {
516
+ resolveAsArray(value, resolveOptions, baseUri) {
461
517
  if (Array.isArray(value)) {
462
518
  // found an array, thus its _per type_
463
- return value.map((v) => allowNullIfNeeded(this.resolve(v, baseUri), this.allowNull));
519
+ return value.map((v) => allowNullIfNeeded(this.resolve(v, resolveOptions, baseUri), resolveOptions));
464
520
  }
465
521
  // it's a single entity, so just resolve it normally
466
- return [allowNullIfNeeded(this.resolve(value, baseUri), this.allowNull)];
522
+ return [allowNullIfNeeded(this.resolve(value, resolveOptions, baseUri), resolveOptions)];
467
523
  }
468
524
 
469
- array(schema, baseUri) {
525
+ array(schema, resolveOptions, baseUri) {
470
526
  let joischema = this.joi.array();
471
527
  let items;
472
528
 
473
529
  if (schema.items) {
474
- items = this.resolveAsArray(schema.items, baseUri);
530
+ items = this.resolveAsArray(schema.items, resolveOptions, baseUri);
475
531
 
476
532
  joischema = joischema.items(...items);
477
533
  } else if (schema.ordered) {
478
- items = this.resolveAsArray(schema.ordered, baseUri);
534
+ items = this.resolveAsArray(schema.ordered, resolveOptions, baseUri);
479
535
  joischema = joischema.ordered(...items);
480
536
  }
481
537
 
@@ -490,7 +546,7 @@ class SchemaResolver {
490
546
  joischema = joischema.unique();
491
547
  }
492
548
  if (schema.contains) {
493
- joischema = joischema.has(this.resolve(schema.contains, baseUri));
549
+ joischema = joischema.has(this.resolve(schema.contains, resolveOptions, baseUri));
494
550
  }
495
551
 
496
552
  return joischema;
@@ -519,10 +575,6 @@ class SchemaResolver {
519
575
  const timeRegex = '([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(.[0-9]+)?(Z|(\\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))';
520
576
  const dateTimeRegex = dateRegex + 'T' + timeRegex;
521
577
 
522
- if (schema.enum) {
523
- return this.joi.string().valid(...schema.enum);
524
- }
525
-
526
578
  switch (schema.format) {
527
579
  case 'date':
528
580
  return joischema.regex(new RegExp('^' + dateRegex + '$', 'i'), 'JsonSchema date format');
@@ -561,7 +613,7 @@ class SchemaResolver {
561
613
  regularString(schema, joischema) {
562
614
  schema.pattern && (joischema = joischema.regex(new RegExp(schema.pattern)));
563
615
 
564
- if ((typeof schema.minLength === 'undefined' || schema.minLength === 0) && !schema.pattern && !schema.format) {
616
+ if ((typeof schema.minLength === 'undefined' || schema.minLength === 0) && !schema.pattern && !schema.format && !schema.enum) {
565
617
  joischema = joischema.allow('');
566
618
  }
567
619
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-2-joi",
3
- "version": "2.0.2",
3
+ "version": "2.3.0",
4
4
  "license": "Apache 2.0",
5
5
  "description": "Converts json-schema to Joi schema. (Enhanced enjoi)",
6
6
  "main": "./index.js",