joi-to-json 2.2.0 → 2.2.3
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 +5 -1
- package/index.js +1 -0
- package/lib/convertors/v12.js +7 -1
- package/lib/parsers/json.js +31 -10
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Objective
|
|
4
4
|
|
|
5
|
-
I have been using [joi](https://
|
|
5
|
+
I have been using [joi](https://joi.dev/) a lot in different Node.js projects to guard the API.
|
|
6
6
|
It's **The most powerful schema description language and data validator for JavaScript.** as it said.
|
|
7
7
|
|
|
8
8
|
Many times, we need to utilize this schema description to produce other output, such as Swagger OpenAPI doc.
|
|
@@ -103,6 +103,10 @@ You can optionally set below environment variables:
|
|
|
103
103
|
|
|
104
104
|
* `CASE_PATTERN=joi-obj-12` to control which version of joi obj to test
|
|
105
105
|
|
|
106
|
+
## Known Limitation
|
|
107
|
+
|
|
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
|
+
|
|
106
110
|
## License
|
|
107
111
|
|
|
108
112
|
MIT
|
package/index.js
CHANGED
|
@@ -51,6 +51,7 @@ function parse(joiObj, type = 'json') {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const joiBaseSpec = new convertor().toBaseSpec(joiObj.describe())
|
|
54
|
+
// fs.writeFileSync(`./internal_${convertor.getSupportVersion()}_${type}.json`, JSON.stringify(joiBaseSpec, null, 2))
|
|
54
55
|
const parser = parsers[type]
|
|
55
56
|
if (!parser) {
|
|
56
57
|
throw new Error(`No parser is registered for ${type}`)
|
package/lib/convertors/v12.js
CHANGED
|
@@ -37,7 +37,13 @@ class JoiSpecConvertor {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
_convertAlternatives(joiObj) {
|
|
40
|
-
|
|
40
|
+
let isWhenCase = false
|
|
41
|
+
if (joiObj.alternatives.length === 1) {
|
|
42
|
+
const condition = joiObj.alternatives[0]
|
|
43
|
+
isWhenCase = !!condition.then || !!condition.otherwise
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (isWhenCase) {
|
|
41
47
|
// when case
|
|
42
48
|
joiObj.type = 'any'
|
|
43
49
|
joiObj.whens = joiObj.alternatives
|
package/lib/parsers/json.js
CHANGED
|
@@ -106,6 +106,14 @@ class JoiJsonSchemaParser {
|
|
|
106
106
|
return _.isEmpty(enumList) ? undefined : enumList
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
_getUnknown(joiSpec) {
|
|
110
|
+
let allowUnknown = _.get(joiSpec, `${this.optionsFieldName}.allowUnknown`, false)
|
|
111
|
+
if (joiSpec.flags && typeof joiSpec.flags[this.allowUnknownFlagName] !== 'undefined') {
|
|
112
|
+
allowUnknown = joiSpec.flags[this.allowUnknownFlagName]
|
|
113
|
+
}
|
|
114
|
+
return allowUnknown
|
|
115
|
+
}
|
|
116
|
+
|
|
109
117
|
_setIfNotEmpty(schema, field, value) {
|
|
110
118
|
if (value !== null && value !== undefined) {
|
|
111
119
|
schema[field] = value
|
|
@@ -139,10 +147,7 @@ class JoiJsonSchemaParser {
|
|
|
139
147
|
schema.properties = {}
|
|
140
148
|
schema.required = []
|
|
141
149
|
|
|
142
|
-
schema.additionalProperties =
|
|
143
|
-
if (joiSpec.flags && typeof joiSpec.flags[this.allowUnknownFlagName] !== 'undefined') {
|
|
144
|
-
schema.additionalProperties = joiSpec.flags[this.allowUnknownFlagName]
|
|
145
|
-
}
|
|
150
|
+
schema.additionalProperties = this._getUnknown(joiSpec)
|
|
146
151
|
|
|
147
152
|
_.map(joiSpec[this.childrenFieldName], (fieldDefn, key) => {
|
|
148
153
|
const fieldSchema = this.parse(fieldDefn)
|
|
@@ -157,9 +162,9 @@ class JoiJsonSchemaParser {
|
|
|
157
162
|
* For dynamic key scenarios to store the pattern as key
|
|
158
163
|
* and have the properties be as with other examples
|
|
159
164
|
*/
|
|
160
|
-
|
|
165
|
+
if (joiSpec.patterns) {
|
|
161
166
|
_.each(joiSpec.patterns, patternObj => {
|
|
162
|
-
if (typeof patternObj.rule !== 'object') {
|
|
167
|
+
if (typeof patternObj.rule !== 'object' || typeof patternObj.regex === 'undefined') {
|
|
163
168
|
return
|
|
164
169
|
}
|
|
165
170
|
|
|
@@ -170,6 +175,7 @@ class JoiJsonSchemaParser {
|
|
|
170
175
|
schema.properties[patternObj.regex].required = []
|
|
171
176
|
|
|
172
177
|
const childKeys = patternObj.rule.keys || patternObj.rule.children
|
|
178
|
+
schema.properties[patternObj.regex].additionalProperties = this._getUnknown(patternObj.rule)
|
|
173
179
|
|
|
174
180
|
_.each(childKeys, (ruleObj, key) => {
|
|
175
181
|
schema.properties[patternObj.regex].properties[key] = this.parse(ruleObj)
|
|
@@ -178,6 +184,14 @@ class JoiJsonSchemaParser {
|
|
|
178
184
|
schema.properties[patternObj.regex].required.push(key)
|
|
179
185
|
}
|
|
180
186
|
})
|
|
187
|
+
|
|
188
|
+
schema.patternProperties = schema.patternProperties || {}
|
|
189
|
+
|
|
190
|
+
let regexString = patternObj.regex
|
|
191
|
+
regexString = regexString.indexOf('/') === 0 ? regexString.substring(1) : regexString
|
|
192
|
+
regexString = regexString.lastIndexOf('/') > -1 ? regexString.substring(0, regexString.length - 1) : regexString
|
|
193
|
+
|
|
194
|
+
schema.patternProperties[regexString] = schema.properties[patternObj.regex]
|
|
181
195
|
})
|
|
182
196
|
}
|
|
183
197
|
|
|
@@ -354,10 +368,17 @@ class JoiJsonSchemaParser {
|
|
|
354
368
|
return
|
|
355
369
|
}
|
|
356
370
|
|
|
357
|
-
if (joiSpec.matches.length === 1
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
371
|
+
if (joiSpec.matches.length === 1) {
|
|
372
|
+
const match = joiSpec.matches[0]
|
|
373
|
+
if (match.switch) {
|
|
374
|
+
schema.oneOf = _.map(match.switch, (condition) => {
|
|
375
|
+
return this.parse(condition.then || condition.otherwise)
|
|
376
|
+
})
|
|
377
|
+
} else if (match.then || match.otherwise) {
|
|
378
|
+
schema.oneOf = []
|
|
379
|
+
if (match.then) schema.oneOf.push(this.parse(match.then))
|
|
380
|
+
if (match.otherwise) schema.oneOf.push(this.parse(match.otherwise))
|
|
381
|
+
}
|
|
361
382
|
} else {
|
|
362
383
|
schema.oneOf = _.map(joiSpec.matches, (match) => {
|
|
363
384
|
return this.parse(match.schema)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "joi-to-json",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"description": "joi to JSON / OpenAPI Schema Converter",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"semver-compare": "^1.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"ajv": "^8.
|
|
30
|
+
"ajv": "^8.11.0",
|
|
31
31
|
"ajv-draft-04": "^1.0.0",
|
|
32
|
-
"eslint": "^
|
|
33
|
-
"jest": "^27.
|
|
32
|
+
"eslint": "^8.12.0",
|
|
33
|
+
"jest": "^27.5.1",
|
|
34
34
|
"joi-12": "npm:@commercial/joi@^12.1.0",
|
|
35
35
|
"joi-13": "npm:joi@^13.7.0",
|
|
36
36
|
"joi-14": "npm:joi@^14.3.1",
|