json-2-joi 2.5.0 → 3.0.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/README.md +1 -1
- package/lib/resolver.js +48 -27
- package/package.json +10 -11
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ const schema = Json2Joi.schema({
|
|
|
90
90
|
|
|
91
91
|
const { error, value } = schema.validate({firstName: 'John', lastName: 'Doe', age: 45});
|
|
92
92
|
```
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
### joiOptions
|
|
95
95
|
|
|
96
96
|
When this option is provided, a Joi instance will be created as `joiInstance = Joi.defaults((schema) => schema.options(joiOptions));` for building Joi Schema.
|
package/lib/resolver.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* global Map */
|
|
2
1
|
const Joi = require('joi');
|
|
3
2
|
const Hoek = require('@hapi/hoek');
|
|
4
3
|
const Bourne = require('@hapi/bourne');
|
|
@@ -124,7 +123,9 @@ function getJoiInstance(joiOptions, extensions, joiInstance) {
|
|
|
124
123
|
}
|
|
125
124
|
try {
|
|
126
125
|
return { value: Bourne.parse(value) };
|
|
127
|
-
} catch (ignoreErr) {
|
|
126
|
+
} catch (ignoreErr) { /* eslint-disable-line no-unused-vars */
|
|
127
|
+
// Purposefully ignoring error
|
|
128
|
+
}
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
},
|
|
@@ -139,7 +140,9 @@ function getJoiInstance(joiOptions, extensions, joiInstance) {
|
|
|
139
140
|
}
|
|
140
141
|
try {
|
|
141
142
|
return { value: Bourne.parse(value) };
|
|
142
|
-
} catch (ignoreErr) {
|
|
143
|
+
} catch (ignoreErr) { /* eslint-disable-line no-unused-vars */
|
|
144
|
+
// Purposefully ignoring error
|
|
145
|
+
}
|
|
143
146
|
}
|
|
144
147
|
}
|
|
145
148
|
},
|
|
@@ -222,7 +225,7 @@ class SchemaResolver {
|
|
|
222
225
|
return joiSchema;
|
|
223
226
|
}
|
|
224
227
|
|
|
225
|
-
resolve(schema, resolveOptions = {}, baseUri = (schema.$id || '')) {
|
|
228
|
+
resolve(schema, resolveOptions = {}, baseUri = (schema.$id || ''), isPropertyRequired = false) {
|
|
226
229
|
if (this.joi.isSchema(schema)) {
|
|
227
230
|
return schema;
|
|
228
231
|
}
|
|
@@ -242,17 +245,17 @@ class SchemaResolver {
|
|
|
242
245
|
|
|
243
246
|
if (typeof schema === 'string') {
|
|
244
247
|
// If schema is itself a string, interpret it as a type
|
|
245
|
-
resolvedSchema = this.resolveType({ type: schema }, resolveOptions, baseUri);
|
|
248
|
+
resolvedSchema = this.resolveType({ type: schema }, resolveOptions, baseUri, isPropertyRequired);
|
|
246
249
|
} else if (schema.$ref) {
|
|
247
250
|
if (schema.$ref.trim() === '#') {
|
|
248
251
|
return baseUri ? this.joi.link(`#${normalizedId(baseUri)}`) : this.joi.link('/');
|
|
249
252
|
}
|
|
250
253
|
|
|
251
|
-
resolvedSchema = this.resolve(this.resolveReference(schema.$ref, baseUri), resolveOptions, baseUri);
|
|
254
|
+
resolvedSchema = this.resolve(this.resolveReference(schema.$ref, baseUri), resolveOptions, baseUri, isPropertyRequired);
|
|
252
255
|
} else {
|
|
253
256
|
const partialSchemas = [];
|
|
254
257
|
if (schema.type) {
|
|
255
|
-
partialSchemas.push(this.resolveType(schema, resolveOptions, baseUri));
|
|
258
|
+
partialSchemas.push(this.resolveType(schema, resolveOptions, baseUri, isPropertyRequired));
|
|
256
259
|
} else if (schema.properties) {
|
|
257
260
|
// if no type is specified, just properties
|
|
258
261
|
partialSchemas.push(this.object(schema, resolveOptions, baseUri))
|
|
@@ -282,7 +285,6 @@ class SchemaResolver {
|
|
|
282
285
|
}
|
|
283
286
|
if (partialSchemas.length === 0) {
|
|
284
287
|
//Fall through to whatever.
|
|
285
|
-
//eslint-disable-next-line no-console
|
|
286
288
|
console.warn('WARNING: schema missing a \'type\' or \'$ref\' or \'enum\': \n%s', JSON.stringify(schema, null, 2));
|
|
287
289
|
//TODO: Handle better
|
|
288
290
|
partialSchemas.push(this.joi.any());
|
|
@@ -298,7 +300,9 @@ class SchemaResolver {
|
|
|
298
300
|
resolvedSchema = resolvedSchema.default(schema.default)
|
|
299
301
|
}
|
|
300
302
|
|
|
301
|
-
|
|
303
|
+
resolvedSchema = this.copyMetaAnnotations(schema, resolvedSchema);
|
|
304
|
+
|
|
305
|
+
if (schemaId && !(this.joiSharedSchemas.get(schemaId))) {
|
|
302
306
|
resolvedSchema = resolvedSchema.id(normalizedId(schemaId));
|
|
303
307
|
this.joiSharedSchemas.set(schemaId, resolvedSchema);
|
|
304
308
|
}
|
|
@@ -307,6 +311,15 @@ class SchemaResolver {
|
|
|
307
311
|
this.joiSharedSchemas.set(`${baseUri}#${schema.$anchor}`, resolvedSchema);
|
|
308
312
|
}
|
|
309
313
|
|
|
314
|
+
if (isPropertyRequired) {
|
|
315
|
+
resolvedSchema = resolvedSchema.required();
|
|
316
|
+
if (resolveOptions.strictRequired) {
|
|
317
|
+
resolvedSchema = resolvedSchema.invalid(null, '');
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
resolvedSchema = allowNullIfNeeded(resolvedSchema, resolveOptions);
|
|
321
|
+
}
|
|
322
|
+
|
|
310
323
|
return resolvedSchema;
|
|
311
324
|
}
|
|
312
325
|
|
|
@@ -358,7 +371,7 @@ class SchemaResolver {
|
|
|
358
371
|
return refSchema;
|
|
359
372
|
}
|
|
360
373
|
|
|
361
|
-
resolveType(schema, resolveOptions, baseUri) {
|
|
374
|
+
resolveType(schema, resolveOptions, baseUri, isPropertyRequired = false) {
|
|
362
375
|
let joischema;
|
|
363
376
|
|
|
364
377
|
const joitype = (type, options, format) => {
|
|
@@ -370,7 +383,7 @@ class SchemaResolver {
|
|
|
370
383
|
|
|
371
384
|
switch (type) {
|
|
372
385
|
case 'array':
|
|
373
|
-
joischema = this.array(schema, options, baseUri);
|
|
386
|
+
joischema = this.array(schema, options, baseUri, isPropertyRequired);
|
|
374
387
|
break;
|
|
375
388
|
case 'boolean':
|
|
376
389
|
joischema = this.joi.boolean();
|
|
@@ -460,6 +473,22 @@ class SchemaResolver {
|
|
|
460
473
|
return addEnumRestriction(joischema, schema.enum, resolveOptions);
|
|
461
474
|
}
|
|
462
475
|
|
|
476
|
+
copyMetaAnnotations(schema, joischema) {
|
|
477
|
+
const metaDataNames = ['title', 'deprecated', 'readOnly', 'writeOnly'];
|
|
478
|
+
const metas = {};
|
|
479
|
+
for (const metaName of metaDataNames) {
|
|
480
|
+
if (typeof schema[metaName] !== 'undefined') {
|
|
481
|
+
metas[metaName] = schema[metaName];
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (Object.keys(metas).length === 0) {
|
|
486
|
+
return joischema;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return joischema.meta(metas);
|
|
490
|
+
}
|
|
491
|
+
|
|
463
492
|
resolveOneOf(schema, resolveOptions, baseUri) {
|
|
464
493
|
Hoek.assert(Array.isArray(schema.oneOf), 'Expected oneOf to be an array.');
|
|
465
494
|
|
|
@@ -500,17 +529,9 @@ class SchemaResolver {
|
|
|
500
529
|
|
|
501
530
|
Object.keys(jsonSchema.properties).forEach((key) => {
|
|
502
531
|
const property = jsonSchema.properties[key];
|
|
532
|
+
const isPropertyRequired = Array.isArray(jsonSchema.required) && !!~jsonSchema.required.indexOf(key);
|
|
503
533
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if (Array.isArray(jsonSchema.required) && !!~jsonSchema.required.indexOf(key)) {
|
|
507
|
-
joischema = joischema.required();
|
|
508
|
-
if (resolveOptions.strictRequired) {
|
|
509
|
-
joischema = joischema.invalid(null, '');
|
|
510
|
-
}
|
|
511
|
-
} else {
|
|
512
|
-
joischema = allowNullIfNeeded(joischema, resolveOptions);
|
|
513
|
-
}
|
|
534
|
+
const joischema = this.resolve(property, resolveOptions, baseUri, isPropertyRequired);
|
|
514
535
|
|
|
515
536
|
schemas[key] = joischema;
|
|
516
537
|
});
|
|
@@ -533,26 +554,26 @@ class SchemaResolver {
|
|
|
533
554
|
return joischema;
|
|
534
555
|
}
|
|
535
556
|
|
|
536
|
-
resolveAsArray(value, resolveOptions, baseUri) {
|
|
557
|
+
resolveAsArray(value, resolveOptions, baseUri, isPropertyRequired = false) {
|
|
537
558
|
return [].concat(value).map((v) => {
|
|
538
559
|
const vSchema = this.resolve(v, resolveOptions, baseUri);
|
|
539
|
-
if (resolveOptions.strictArrayRequired) {
|
|
560
|
+
if (resolveOptions.strictArrayRequired && isPropertyRequired) {
|
|
540
561
|
return vSchema.invalid(...resolveOptions.customizedNullValues);
|
|
541
562
|
}
|
|
542
563
|
return allowNullIfNeeded(vSchema, resolveOptions)
|
|
543
564
|
});
|
|
544
565
|
}
|
|
545
566
|
|
|
546
|
-
array(schema, resolveOptions, baseUri) {
|
|
567
|
+
array(schema, resolveOptions, baseUri, isPropertyRequired = false) {
|
|
547
568
|
let joischema = this.joi.array();
|
|
548
569
|
let items;
|
|
549
570
|
|
|
550
571
|
if (schema.items) {
|
|
551
|
-
items = this.resolveAsArray(schema.items, resolveOptions, baseUri);
|
|
572
|
+
items = this.resolveAsArray(schema.items, resolveOptions, baseUri, isPropertyRequired);
|
|
552
573
|
|
|
553
574
|
joischema = joischema.items(...items);
|
|
554
575
|
} else if (schema.ordered) {
|
|
555
|
-
items = this.resolveAsArray(schema.ordered, resolveOptions, baseUri);
|
|
576
|
+
items = this.resolveAsArray(schema.ordered, resolveOptions, baseUri, isPropertyRequired);
|
|
556
577
|
joischema = joischema.ordered(...items);
|
|
557
578
|
}
|
|
558
579
|
|
|
@@ -560,7 +581,7 @@ class SchemaResolver {
|
|
|
560
581
|
joischema = joischema.max(items.length);
|
|
561
582
|
}
|
|
562
583
|
|
|
563
|
-
if (resolveOptions.strictArrayRequired && !schema.minItems) {
|
|
584
|
+
if (isPropertyRequired && resolveOptions.strictArrayRequired && !schema.minItems) {
|
|
564
585
|
schema.minItems = 1;
|
|
565
586
|
}
|
|
566
587
|
isNumber(schema.minItems) && (joischema = joischema.min(schema.minItems));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-2-joi",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"license": "Apache 2.0",
|
|
5
5
|
"description": "Converts json-schema to Joi schema. (Enhanced enjoi)",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -13,9 +13,6 @@
|
|
|
13
13
|
"type": "git",
|
|
14
14
|
"url": "git://github.com/kenspirit/json-2-joi.git"
|
|
15
15
|
},
|
|
16
|
-
"engines": {
|
|
17
|
-
"node": ">=12"
|
|
18
|
-
},
|
|
19
16
|
"keywords": [
|
|
20
17
|
"json-to-joi",
|
|
21
18
|
"json-2-joi",
|
|
@@ -35,17 +32,19 @@
|
|
|
35
32
|
"homepage": "https://github.com/kenspirit/json-2-joi",
|
|
36
33
|
"dependencies": {
|
|
37
34
|
"@hapi/bourne": "^3.0.0",
|
|
38
|
-
"@hapi/hoek": "^
|
|
39
|
-
"debug": "^4.3.
|
|
35
|
+
"@hapi/hoek": "^11.0.4",
|
|
36
|
+
"debug": "^4.3.5"
|
|
40
37
|
},
|
|
41
38
|
"peerDependencies": {
|
|
42
|
-
"joi": "^17.
|
|
39
|
+
"joi": "^17.13.3"
|
|
43
40
|
},
|
|
44
41
|
"devDependencies": {
|
|
45
|
-
"
|
|
46
|
-
"eslint": "^6.
|
|
47
|
-
"
|
|
48
|
-
"
|
|
42
|
+
"@eslint/js": "^9.6.0",
|
|
43
|
+
"eslint": "^9.6.0",
|
|
44
|
+
"globals": "^15.7.0",
|
|
45
|
+
"joi": "^17.13.3",
|
|
46
|
+
"nyc": "^17.0.0",
|
|
47
|
+
"tape": "^5.8.1"
|
|
49
48
|
},
|
|
50
49
|
"files": [
|
|
51
50
|
"lib/**/*.js",
|