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