joi-to-json 2.2.4 → 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/README.md +7 -1
- package/index.js +1 -0
- package/lib/parsers/json-draft-04.js +6 -2
- package/lib/parsers/json-draft-2019-09.js +4 -4
- package/lib/parsers/json.js +49 -20
- package/lib/parsers/open-api.js +12 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,12 +101,18 @@ const jsonSchema = parse(joiSchema)
|
|
|
101
101
|
|
|
102
102
|
You can optionally set below environment variables:
|
|
103
103
|
|
|
104
|
-
* `CASE_PATTERN=joi-obj-
|
|
104
|
+
* `CASE_PATTERN=joi-obj-17` to control which version of joi obj to test
|
|
105
105
|
|
|
106
106
|
## Known Limitation
|
|
107
107
|
|
|
108
108
|
* For `object.pattern` usage in Joi, `pattern` parameter can only be a regular expression now as I cannot convert Joi object to regex yet.
|
|
109
109
|
|
|
110
|
+
## Updates
|
|
111
|
+
|
|
112
|
+
**Version 2.3.0**
|
|
113
|
+
|
|
114
|
+
* Supports named link for schema resuse, such as `.link('#person')`. **For `open-api` conversion**, as the shared schemas are located in `#/components/schemas` which is not self-contained, the conversion result contains an **extra `schemas`** field so that you can extract it when required.
|
|
115
|
+
|
|
110
116
|
## License
|
|
111
117
|
|
|
112
118
|
MIT
|
package/index.js
CHANGED
|
@@ -50,6 +50,7 @@ function parse(joiObj, type = 'json') {
|
|
|
50
50
|
convertor = convertors[0]
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// fs.writeFileSync('./joi_spec.json', JSON.stringify(joiObj.describe(), null, 2))
|
|
53
54
|
const joiBaseSpec = new convertor().toBaseSpec(joiObj.describe())
|
|
54
55
|
// fs.writeFileSync(`./internal_${convertor.getSupportVersion()}_${type}.json`, JSON.stringify(joiBaseSpec, null, 2))
|
|
55
56
|
const parser = parsers[type]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const _ = require('lodash')
|
|
2
2
|
const JoiJsonSchemaParser = require('./json')
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class JoiJsonDraftSchemaParser extends JoiJsonSchemaParser {
|
|
5
5
|
_setNumberFieldProperties(fieldSchema, fieldDefn) {
|
|
6
6
|
super._setNumberFieldProperties(fieldSchema, fieldDefn)
|
|
7
7
|
|
|
@@ -12,6 +12,10 @@ class JoiOpenApiSchemaParser extends JoiJsonSchemaParser {
|
|
|
12
12
|
fieldSchema.exclusiveMaximum = true
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
_getLocalSchemaBasePath() {
|
|
17
|
+
return '#/definitions'
|
|
18
|
+
}
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
module.exports =
|
|
21
|
+
module.exports = JoiJsonDraftSchemaParser
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
const _ = require('lodash')
|
|
2
2
|
const JoiJsonSchemaParser = require('./json')
|
|
3
3
|
|
|
4
|
-
class
|
|
5
|
-
parse(joiSpec) {
|
|
6
|
-
const schema = super.parse(joiSpec)
|
|
4
|
+
class JoiJsonDraftSchemaParser extends JoiJsonSchemaParser {
|
|
5
|
+
parse(joiSpec, definitions = {}, level = 0) {
|
|
6
|
+
const schema = super.parse(joiSpec, definitions, level)
|
|
7
7
|
|
|
8
8
|
if (!_.isEmpty(joiSpec.metas)) {
|
|
9
9
|
_.each(joiSpec.metas, meta => {
|
|
@@ -19,4 +19,4 @@ class JoiOpenApiSchemaParser extends JoiJsonSchemaParser {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
module.exports =
|
|
22
|
+
module.exports = JoiJsonDraftSchemaParser
|
package/lib/parsers/json.js
CHANGED
|
@@ -10,8 +10,8 @@ class JoiJsonSchemaParser {
|
|
|
10
10
|
this.allowUnknownFlagName = this._getAllowUnknownFlagName()
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
parse(joiSpec) {
|
|
14
|
-
|
|
13
|
+
parse(joiSpec, definitions = {}, level = 0) {
|
|
14
|
+
let schema = {}
|
|
15
15
|
|
|
16
16
|
if (this._getPresence(joiSpec) === 'forbidden') {
|
|
17
17
|
schema.not = {}
|
|
@@ -23,12 +23,24 @@ class JoiJsonSchemaParser {
|
|
|
23
23
|
this._setBinaryFieldProperties(schema, joiSpec)
|
|
24
24
|
this._setStringFieldProperties(schema, joiSpec)
|
|
25
25
|
this._setDateFieldProperties(schema, joiSpec)
|
|
26
|
-
this._setArrayFieldProperties(schema, joiSpec)
|
|
27
|
-
this._setObjectProperties(schema, joiSpec)
|
|
28
|
-
this._setAlternativesProperties(schema, joiSpec)
|
|
29
|
-
this._setAnyProperties(schema, joiSpec)
|
|
26
|
+
this._setArrayFieldProperties(schema, joiSpec, definitions, level)
|
|
27
|
+
this._setObjectProperties(schema, joiSpec, definitions, level)
|
|
28
|
+
this._setAlternativesProperties(schema, joiSpec, definitions, level)
|
|
29
|
+
this._setAnyProperties(schema, joiSpec, definitions, level)
|
|
30
30
|
this._addNullTypeIfNullable(schema, joiSpec)
|
|
31
31
|
this._setMetaProperties(schema, joiSpec)
|
|
32
|
+
this._setLinkFieldProperties(schema, joiSpec)
|
|
33
|
+
|
|
34
|
+
const schemaId = _.get(joiSpec, 'flags.id')
|
|
35
|
+
if (schemaId) {
|
|
36
|
+
definitions[schemaId] = schema
|
|
37
|
+
schema = {
|
|
38
|
+
$ref: `${this._getLocalSchemaBasePath()}/${schemaId}`
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (level === 0 && !_.isEmpty(definitions)) {
|
|
42
|
+
_.set(schema, `${this._getLocalSchemaBasePath().replace('#/', '').replace(/\//, '.')}`, definitions)
|
|
43
|
+
}
|
|
32
44
|
|
|
33
45
|
return schema
|
|
34
46
|
}
|
|
@@ -53,6 +65,10 @@ class JoiJsonSchemaParser {
|
|
|
53
65
|
return 'unknown'
|
|
54
66
|
}
|
|
55
67
|
|
|
68
|
+
_getLocalSchemaBasePath() {
|
|
69
|
+
return '#/$defs'
|
|
70
|
+
}
|
|
71
|
+
|
|
56
72
|
_getFieldDescription(fieldDefn) {
|
|
57
73
|
return _.get(fieldDefn, 'flags.description')
|
|
58
74
|
}
|
|
@@ -135,7 +151,7 @@ class JoiJsonSchemaParser {
|
|
|
135
151
|
fieldSchema.format = 'binary'
|
|
136
152
|
}
|
|
137
153
|
|
|
138
|
-
_setObjectProperties(schema, joiSpec) {
|
|
154
|
+
_setObjectProperties(schema, joiSpec, definitions, level) {
|
|
139
155
|
if (schema.type !== 'object') {
|
|
140
156
|
return
|
|
141
157
|
}
|
|
@@ -146,7 +162,7 @@ class JoiJsonSchemaParser {
|
|
|
146
162
|
schema.additionalProperties = this._getUnknown(joiSpec)
|
|
147
163
|
|
|
148
164
|
_.map(joiSpec[this.childrenFieldName], (fieldDefn, key) => {
|
|
149
|
-
const fieldSchema = this.parse(fieldDefn)
|
|
165
|
+
const fieldSchema = this.parse(fieldDefn, definitions, level + 1)
|
|
150
166
|
if (this._isRequired(fieldDefn)) {
|
|
151
167
|
schema.required.push(key)
|
|
152
168
|
}
|
|
@@ -174,7 +190,7 @@ class JoiJsonSchemaParser {
|
|
|
174
190
|
schema.properties[patternObj.regex].additionalProperties = this._getUnknown(patternObj.rule)
|
|
175
191
|
|
|
176
192
|
_.each(childKeys, (ruleObj, key) => {
|
|
177
|
-
schema.properties[patternObj.regex].properties[key] = this.parse(ruleObj)
|
|
193
|
+
schema.properties[patternObj.regex].properties[key] = this.parse(ruleObj, definitions, level + 1)
|
|
178
194
|
|
|
179
195
|
if (this._isRequired(ruleObj)) {
|
|
180
196
|
schema.properties[patternObj.regex].required.push(key)
|
|
@@ -301,7 +317,7 @@ class JoiJsonSchemaParser {
|
|
|
301
317
|
})
|
|
302
318
|
}
|
|
303
319
|
|
|
304
|
-
_setArrayFieldProperties(fieldSchema, fieldDefn) {
|
|
320
|
+
_setArrayFieldProperties(fieldSchema, fieldDefn, definitions, level) {
|
|
305
321
|
if (fieldSchema.type !== 'array') {
|
|
306
322
|
return
|
|
307
323
|
}
|
|
@@ -335,10 +351,12 @@ class JoiJsonSchemaParser {
|
|
|
335
351
|
}
|
|
336
352
|
|
|
337
353
|
if (fieldDefn.items.length === 1) {
|
|
338
|
-
fieldSchema.items = this.parse(fieldDefn.items[0])
|
|
354
|
+
fieldSchema.items = this.parse(fieldDefn.items[0], definitions, level + 1)
|
|
339
355
|
} else {
|
|
340
356
|
fieldSchema.items = {
|
|
341
|
-
anyOf: _.map(fieldDefn.items,
|
|
357
|
+
anyOf: _.map(fieldDefn.items, (itemSchema) => {
|
|
358
|
+
return this.parse(itemSchema, definitions, level + 1)
|
|
359
|
+
})
|
|
342
360
|
}
|
|
343
361
|
}
|
|
344
362
|
}
|
|
@@ -359,7 +377,7 @@ class JoiJsonSchemaParser {
|
|
|
359
377
|
}
|
|
360
378
|
}
|
|
361
379
|
|
|
362
|
-
_setAlternativesProperties(schema, joiSpec) {
|
|
380
|
+
_setAlternativesProperties(schema, joiSpec, definitions, level) {
|
|
363
381
|
if (schema.type !== 'alternatives') {
|
|
364
382
|
return
|
|
365
383
|
}
|
|
@@ -368,23 +386,23 @@ class JoiJsonSchemaParser {
|
|
|
368
386
|
const match = joiSpec.matches[0]
|
|
369
387
|
if (match.switch) {
|
|
370
388
|
schema.oneOf = _.map(match.switch, (condition) => {
|
|
371
|
-
return this.parse(condition.then || condition.otherwise)
|
|
389
|
+
return this.parse(condition.then || condition.otherwise, definitions, level + 1)
|
|
372
390
|
})
|
|
373
391
|
} else if (match.then || match.otherwise) {
|
|
374
392
|
schema.oneOf = []
|
|
375
|
-
if (match.then) schema.oneOf.push(this.parse(match.then))
|
|
376
|
-
if (match.otherwise) schema.oneOf.push(this.parse(match.otherwise))
|
|
393
|
+
if (match.then) schema.oneOf.push(this.parse(match.then, definitions, level + 1))
|
|
394
|
+
if (match.otherwise) schema.oneOf.push(this.parse(match.otherwise, definitions, level + 1))
|
|
377
395
|
}
|
|
378
396
|
} else {
|
|
379
397
|
schema.oneOf = _.map(joiSpec.matches, (match) => {
|
|
380
|
-
return this.parse(match.schema)
|
|
398
|
+
return this.parse(match.schema, definitions, level + 1)
|
|
381
399
|
})
|
|
382
400
|
}
|
|
383
401
|
|
|
384
402
|
delete schema.type
|
|
385
403
|
}
|
|
386
404
|
|
|
387
|
-
_setAnyProperties(schema, joiSpec) {
|
|
405
|
+
_setAnyProperties(schema, joiSpec, definitions, level) {
|
|
388
406
|
if (schema.type !== 'any') {
|
|
389
407
|
return
|
|
390
408
|
}
|
|
@@ -393,10 +411,10 @@ class JoiJsonSchemaParser {
|
|
|
393
411
|
const condition = joiSpec.whens[0]
|
|
394
412
|
schema.oneOf = []
|
|
395
413
|
if (condition.then) {
|
|
396
|
-
schema.oneOf.push(this.parse(condition.then))
|
|
414
|
+
schema.oneOf.push(this.parse(condition.then, definitions, level + 1))
|
|
397
415
|
}
|
|
398
416
|
if (condition.otherwise) {
|
|
399
|
-
schema.oneOf.push(this.parse(condition.otherwise))
|
|
417
|
+
schema.oneOf.push(this.parse(condition.otherwise, definitions, level + 1))
|
|
400
418
|
}
|
|
401
419
|
delete schema.type
|
|
402
420
|
return
|
|
@@ -422,6 +440,17 @@ class JoiJsonSchemaParser {
|
|
|
422
440
|
}
|
|
423
441
|
})
|
|
424
442
|
}
|
|
443
|
+
|
|
444
|
+
_setLinkFieldProperties(schema, joiSpec) {
|
|
445
|
+
if (schema.type !== 'link') {
|
|
446
|
+
return
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (_.get(joiSpec, 'link.ref.type') === 'local') {
|
|
450
|
+
schema.$ref = `${this._getLocalSchemaBasePath()}/${joiSpec.link.ref.path.join('/')}`
|
|
451
|
+
delete schema.type
|
|
452
|
+
}
|
|
453
|
+
}
|
|
425
454
|
}
|
|
426
455
|
|
|
427
456
|
module.exports = JoiJsonSchemaParser
|
package/lib/parsers/open-api.js
CHANGED
|
@@ -2,8 +2,10 @@ const _ = require('lodash')
|
|
|
2
2
|
const JoiJsonSchemaParser = require('./json-draft-04')
|
|
3
3
|
|
|
4
4
|
class JoiOpenApiSchemaParser extends JoiJsonSchemaParser {
|
|
5
|
-
parse(joiSpec) {
|
|
6
|
-
const
|
|
5
|
+
parse(joiSpec, definitions = {}, level = 0) {
|
|
6
|
+
const fullSchema = super.parse(joiSpec, definitions, level)
|
|
7
|
+
const schema = _.pick(fullSchema, [
|
|
8
|
+
'$ref',
|
|
7
9
|
'title',
|
|
8
10
|
'multipleOf',
|
|
9
11
|
'maximum',
|
|
@@ -47,9 +49,17 @@ class JoiOpenApiSchemaParser extends JoiJsonSchemaParser {
|
|
|
47
49
|
})
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
if (level === 0 && !_.isEmpty(definitions)) {
|
|
53
|
+
schema.schemas = definitions
|
|
54
|
+
}
|
|
55
|
+
|
|
50
56
|
return schema
|
|
51
57
|
}
|
|
52
58
|
|
|
59
|
+
_getLocalSchemaBasePath() {
|
|
60
|
+
return '#/components/schemas'
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
_setBasicProperties(fieldSchema, fieldDefn) {
|
|
54
64
|
super._setBasicProperties(fieldSchema, fieldDefn)
|
|
55
65
|
|