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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Objective
4
4
 
5
- I have been using [joi](https://hapi.dev/family/joi/) a lot in different Node.js projects which guards the API.
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}`)
@@ -37,7 +37,13 @@ class JoiSpecConvertor {
37
37
  }
38
38
 
39
39
  _convertAlternatives(joiObj) {
40
- if (joiObj.base && joiObj.base.type === 'any') {
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
@@ -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 = _.get(joiSpec, `${this.optionsFieldName}.allowUnknown`, false)
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
- if (joiSpec.patterns) {
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 && joiSpec.matches[0].switch) {
358
- schema.oneOf = _.map(joiSpec.matches[0].switch, (condition) => {
359
- return this.parse(condition.then || condition.otherwise)
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.0",
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.6.3",
30
+ "ajv": "^8.11.0",
31
31
  "ajv-draft-04": "^1.0.0",
32
- "eslint": "^7.32.0",
33
- "jest": "^27.2.0",
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",