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