joi-to-json 2.6.0 → 2.6.1

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
@@ -95,6 +95,153 @@ const jsonSchema = parse(joiSchema)
95
95
  // const openApiSchema = parse(joiSchema, 'open-api')
96
96
  ```
97
97
 
98
+ ### Joi to OpenAPI
99
+
100
+ Most Joi specifications result in the expected OpenAPI schema.
101
+
102
+ E.g.,
103
+
104
+ ```js
105
+ const joi = require('joi')
106
+ const { dump } = require('js-yaml')
107
+ const { writeFile } = require('fs/promises')
108
+
109
+ const joiSchema = joi.object().keys({
110
+ uuid: joi.string().uuid({ version: ['uuidv3', 'uuidv5'] }),
111
+ nickName: joi.string().required().example('鹄思乱想').description('Hero Nickname').min(3).max(20).pattern(/^[a-z]+$/, { name: 'alpha', invert: true }),
112
+ avatar: joi.string().required().uri(),
113
+ email: joi.string().email(),
114
+ ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
115
+ hostname: joi.string().hostname().insensitive(),
116
+ gender: joi.string().valid('Male', 'Female', '', null).default('Male'),
117
+ isoDateString: joi.string().isoDate(),
118
+ isoDurationString: joi.string().isoDuration(),
119
+ birthday: joi.date().iso(),
120
+ certificate: joi.binary().encoding('base64'),
121
+ tags: joi.array().items(joi.string().required()).length(2),
122
+ nested: joi.object().keys({
123
+ key: joi.string()
124
+ }).unknown(true)
125
+ }).unknown(false)
126
+
127
+ async function writeYAML(targetPath) {
128
+ const openApiSchema = parse(joiSchema, 'open-api')
129
+
130
+ const openApiSchemaYAML = dump(openApiSchema, {lineWidth: 120, noCompatMode: true})
131
+ await writeFile(targetPath, openApiSchemaYAML)
132
+ }
133
+ ```
134
+
135
+ results in
136
+
137
+ ```yaml
138
+ type: object
139
+ required:
140
+ - nickName
141
+ - avatar
142
+ properties:
143
+ uuid:
144
+ type: string
145
+ format: uuid
146
+ nickName:
147
+ description: Hero Nickname
148
+ type: string
149
+ pattern: ^[a-z]+$
150
+ minLength: 3,
151
+ maxLength: 20,
152
+ example: 鹄思乱想
153
+ avatar:
154
+ type: string
155
+ format: uri
156
+ email:
157
+ type: string
158
+ format: email
159
+ ip:
160
+ type: string
161
+ oneOf:
162
+ - format: ipv4
163
+ - format: ipv6
164
+ hostname:
165
+ type: string
166
+ format: hostname
167
+ gender:
168
+ type: string
169
+ default: Male
170
+ enum:
171
+ - Male
172
+ - Female
173
+ - ''
174
+ - null
175
+ nullable: true
176
+ isoDateString:
177
+ type: string
178
+ format: date-time
179
+ isoDurationString:
180
+ type: string
181
+ format: duration
182
+ birthday:
183
+ type: string
184
+ format: date-time
185
+ certificate:
186
+ type: string
187
+ format: binary
188
+ tags:
189
+ type: array
190
+ items:
191
+ type: string
192
+ minItems: 2
193
+ maxItems: 2
194
+ nested:
195
+ type: object
196
+ properties:
197
+ key:
198
+ type: string
199
+ additionalProperties: true
200
+ additionalProperties: false
201
+ ```
202
+
203
+ Some OpenAPI features are not supported directly in Joi, but Joi schemas can be annotated with `joi.any().meta({…})`
204
+ to get them in the OpenAPI schema:
205
+
206
+ ```js
207
+
208
+
209
+ const joiSchema = joi.object().keys({
210
+ deprecatedProperty: joi.string().meta({ deprecated: true }).required(),
211
+ readOnlyProperty: joi.string().meta({ readOnly: true }),
212
+ writeOnlyProperty: joi.string().meta({ writeOnly: true }),
213
+ xMeta: joi.string().meta({ 'x-meta': 42 }),
214
+ unknownMetaProperty: joi.string().meta({ unknownMeta: 42 })
215
+ }).unknown(true)
216
+
217
+
218
+ ```
219
+
220
+ begets:
221
+
222
+ ```yaml
223
+ type: object
224
+ required:
225
+ - deprecatedProperty
226
+ properties:
227
+ deprecatedProperty:
228
+ type: string
229
+ deprecated: true
230
+ readOnlyProperty:
231
+ type: string
232
+ readOnly: true
233
+ writeOnlyProperty:
234
+ type: string
235
+ writeOnly: true
236
+ xMeta:
237
+ type: string
238
+ x-meta: 42
239
+ unknownMetaProperty:
240
+ type: string
241
+ # unknownMeta is not exported
242
+ additionalProperties: true
243
+ ```
244
+
98
245
  ## Browser support
99
246
  For generating JSON Schema in a browser you should use below import syntax for `joi` library in order to work because the `joi` browser minimized build does not have `describe` api which the `joi-to-json` relies on.
100
247
 
@@ -1,6 +1,24 @@
1
1
  /* eslint no-use-before-define: 'off' */
2
2
  const _ = require('lodash')
3
3
 
4
+ /**
5
+ * Recognize the `joi.override` representation in `describe()` output.
6
+ *
7
+ * `joi.override` is a Symbol that can be used in `joi.any().valid(…)`
8
+ * statements, to reset the list of valid values. In `describe()` output, it
9
+ * turns up as an object with 1 property:
10
+ *
11
+ * ```
12
+ * { override: true }
13
+ * ```
14
+ */
15
+ function isJoiOverride(e) {
16
+ return typeof e === 'object'
17
+ && e !== null
18
+ && Object.keys(e).length === 1
19
+ && e.override === true
20
+ }
21
+
4
22
  class JoiJsonSchemaParser {
5
23
  constructor() {
6
24
  this.childrenFieldName = this._getChildrenFieldName()
@@ -124,8 +142,9 @@ class JoiJsonSchemaParser {
124
142
 
125
143
  _getEnum(fieldDefn) {
126
144
  const enumList = fieldDefn[this.enumFieldName]
127
- if (fieldDefn.flags && fieldDefn.flags.only && _.size(enumList) > 1) {
128
- return _.uniq(enumList)
145
+ const filteredEnumList = enumList ? _.filter(enumList, e => !isJoiOverride(e)) : enumList
146
+ if (fieldDefn.flags && fieldDefn.flags.only && _.size(filteredEnumList) > 1) {
147
+ return _.uniq(filteredEnumList)
129
148
  }
130
149
  }
131
150
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joi-to-json",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "joi to JSON / OpenAPI Schema Converter",
5
5
  "main": "index.js",
6
6
  "repository": {