joi-to-json 4.0.1 → 4.1.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/lib/convertors/v12.js +330 -330
- package/lib/convertors/v16.js +32 -32
- package/lib/parsers/json-draft-04.js +10 -0
- package/lib/parsers/json-draft-2019-09.js +6 -0
- package/lib/parsers/json.js +13 -0
- package/lib/parsers/open-api.js +2 -0
- package/package.json +1 -1
package/lib/convertors/v12.js
CHANGED
|
@@ -1,330 +1,330 @@
|
|
|
1
|
-
const _ = require('lodash')
|
|
2
|
-
|
|
3
|
-
class JoiSpecConvertor {
|
|
4
|
-
constructor() {}
|
|
5
|
-
|
|
6
|
-
static getVersion(joiObj) {
|
|
7
|
-
return joiObj._currentJoi.version
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
static getSupportVersion() {
|
|
11
|
-
return '12'
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
_convertObject(joiObj) {
|
|
15
|
-
_.each(joiObj.rules, (rule, _idx) => {
|
|
16
|
-
const name = rule.name
|
|
17
|
-
if (['min', 'max', 'length'].includes(name)) {
|
|
18
|
-
rule.args = {
|
|
19
|
-
limit: rule.arg
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
delete rule.arg
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
if (joiObj.children) {
|
|
26
|
-
joiObj.keys = joiObj.children
|
|
27
|
-
delete joiObj.children
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
_.each(joiObj.keys, (value, _key) => {
|
|
31
|
-
this.toBaseSpec(value)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
_.each(joiObj.patterns, (pattern, _idx) => {
|
|
35
|
-
this.toBaseSpec(pattern.rule)
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
this._convertDependencies(joiObj)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
_convertDependencies(joiObj) {
|
|
42
|
-
_.each(joiObj.dependencies, (dependency) => {
|
|
43
|
-
if (dependency.key === null) {
|
|
44
|
-
delete dependency.key
|
|
45
|
-
}
|
|
46
|
-
if (dependency.type) {
|
|
47
|
-
dependency.rel = dependency.type
|
|
48
|
-
delete dependency.type
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
_convertDate(joiObj) {
|
|
54
|
-
if (joiObj.flags.timestamp) {
|
|
55
|
-
joiObj.flags.format = joiObj.flags.timestamp
|
|
56
|
-
delete joiObj.flags.timestamp
|
|
57
|
-
delete joiObj.flags.multiplier
|
|
58
|
-
} else if (joiObj.flags.format = {}) {
|
|
59
|
-
joiObj.flags.format = 'iso'
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
_convertAlternatives(joiObj) {
|
|
64
|
-
// backup alternatives setting
|
|
65
|
-
const alternatives = joiObj.alternatives
|
|
66
|
-
let fieldName = 'matches'
|
|
67
|
-
|
|
68
|
-
if (joiObj.base) {
|
|
69
|
-
// When case is based on one schema type
|
|
70
|
-
fieldName = 'whens'
|
|
71
|
-
|
|
72
|
-
const baseType = joiObj.base
|
|
73
|
-
delete joiObj.base
|
|
74
|
-
delete joiObj.alternatives
|
|
75
|
-
if (joiObj.flags && joiObj.flags.presence) {
|
|
76
|
-
delete joiObj.flags.presence
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
this.toBaseSpec(baseType)
|
|
80
|
-
|
|
81
|
-
_.merge(joiObj, baseType)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Convert alternatives
|
|
85
|
-
joiObj[fieldName] = _.map(alternatives, (alternative) => {
|
|
86
|
-
if (alternative.peek || alternative.ref) {
|
|
87
|
-
if (alternative.peek) {
|
|
88
|
-
alternative.is = alternative.peek
|
|
89
|
-
delete alternative.peek
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return _.mapValues(alternative, (value, condition) => {
|
|
93
|
-
switch (condition) {
|
|
94
|
-
case 'is':
|
|
95
|
-
this.toBaseSpec(value)
|
|
96
|
-
if (alternative.ref) {
|
|
97
|
-
// alternative field reference case
|
|
98
|
-
value.type = 'any'
|
|
99
|
-
value.allow.splice(0, 0, { 'override': true })
|
|
100
|
-
}
|
|
101
|
-
break
|
|
102
|
-
case 'otherwise':
|
|
103
|
-
this.toBaseSpec(value)
|
|
104
|
-
break
|
|
105
|
-
case 'then':
|
|
106
|
-
this.toBaseSpec(value)
|
|
107
|
-
break
|
|
108
|
-
case 'ref':
|
|
109
|
-
if (value.indexOf('ref:') === 0) {
|
|
110
|
-
value = {
|
|
111
|
-
path: value.replace('ref:', '').split('.')
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
break
|
|
115
|
-
}
|
|
116
|
-
return value
|
|
117
|
-
})
|
|
118
|
-
} else {
|
|
119
|
-
return {
|
|
120
|
-
schema: this.toBaseSpec(alternative)
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
// FIXME: Joi seems merging the `is` to `then` schema
|
|
126
|
-
_.forEach(joiObj[fieldName], (alternative) => {
|
|
127
|
-
if (alternative.is && alternative.then) {
|
|
128
|
-
if (alternative.is.type === 'object') {
|
|
129
|
-
const isKeys = Object.keys(alternative.is.keys)
|
|
130
|
-
_.forEach(isKeys, (key) => {
|
|
131
|
-
delete alternative.then.keys[key]
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
delete joiObj.alternatives
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
_convertBinary(joiObj) {
|
|
141
|
-
_.each(joiObj.rules, (rule, _idx) => {
|
|
142
|
-
const name = rule.name
|
|
143
|
-
if (['min', 'max', 'length'].includes(name)) {
|
|
144
|
-
rule.args = {
|
|
145
|
-
limit: rule.arg
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
delete rule.arg
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
_convertString(joiObj) {
|
|
153
|
-
delete joiObj.options
|
|
154
|
-
|
|
155
|
-
_.each(joiObj.rules, (rule, _idx) => {
|
|
156
|
-
const name = rule.name
|
|
157
|
-
if (['min', 'max'].includes(name)) {
|
|
158
|
-
rule.args = {
|
|
159
|
-
limit: rule.arg
|
|
160
|
-
}
|
|
161
|
-
} else if (['lowercase', 'uppercase'].includes(name)) {
|
|
162
|
-
rule.name = 'case'
|
|
163
|
-
rule.args = {
|
|
164
|
-
direction: name.replace('case', '')
|
|
165
|
-
}
|
|
166
|
-
delete joiObj.flags.case
|
|
167
|
-
} else if (rule.arg) {
|
|
168
|
-
rule.args = {
|
|
169
|
-
options: rule.arg
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (name === 'regex') {
|
|
173
|
-
rule.name = 'pattern'
|
|
174
|
-
rule.args.regex = rule.arg.pattern.toString()
|
|
175
|
-
delete rule.args.options.pattern
|
|
176
|
-
}
|
|
177
|
-
delete rule.arg
|
|
178
|
-
})
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
_convertNumber(joiObj) {
|
|
182
|
-
_.each(joiObj.rules, (rule, _idx) => {
|
|
183
|
-
const name = rule.name
|
|
184
|
-
if (['positive', 'negative'].includes(name)) {
|
|
185
|
-
rule.args = {
|
|
186
|
-
sign: name
|
|
187
|
-
}
|
|
188
|
-
rule.name = 'sign'
|
|
189
|
-
}
|
|
190
|
-
if (['greater', 'less', 'min', 'max', 'precision'].includes(name)) {
|
|
191
|
-
rule.args = {
|
|
192
|
-
limit: rule.arg
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
if (name === 'multiple') {
|
|
196
|
-
rule.args = {
|
|
197
|
-
base: rule.arg
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
delete rule.arg
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
if (joiObj.flags.precision) {
|
|
204
|
-
delete joiObj.flags.precision
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
_convertBoolean(joiObj) {
|
|
209
|
-
if (_.isArray(joiObj.truthy)) {
|
|
210
|
-
_.remove(joiObj.truthy, (i) => i === true)
|
|
211
|
-
if (joiObj.truthy.length === 0) {
|
|
212
|
-
delete joiObj.truthy
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
if (_.isArray(joiObj.falsy)) {
|
|
216
|
-
_.remove(joiObj.falsy, (i) => i === false)
|
|
217
|
-
if (joiObj.falsy.length === 0) {
|
|
218
|
-
delete joiObj.falsy
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (joiObj.flags.insensitive === false) {
|
|
222
|
-
joiObj.flags.sensitive = true
|
|
223
|
-
}
|
|
224
|
-
delete joiObj.flags.insensitive
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
_convertArray(joiObj) {
|
|
228
|
-
if (joiObj.flags.sparse === false) {
|
|
229
|
-
delete joiObj.flags.sparse
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
_.each(joiObj.rules, (rule, _idx) => {
|
|
233
|
-
const name = rule.name
|
|
234
|
-
if (['min', 'max', 'length'].includes(name)) {
|
|
235
|
-
rule.args = {
|
|
236
|
-
limit: rule.arg
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
if (name === 'has') {
|
|
240
|
-
this.toBaseSpec(rule.arg)
|
|
241
|
-
rule.args = {
|
|
242
|
-
schema: rule.arg
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
delete rule.arg
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
_.each(joiObj.items, (item, _idx) => {
|
|
249
|
-
this.toBaseSpec(item)
|
|
250
|
-
})
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
_convertExamples(_joiObj) {
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
toBaseSpec(joiObj) {
|
|
257
|
-
joiObj.flags = joiObj.flags || {}
|
|
258
|
-
|
|
259
|
-
if (joiObj.flags.allowOnly) {
|
|
260
|
-
joiObj.flags.only = joiObj.flags.allowOnly
|
|
261
|
-
}
|
|
262
|
-
delete joiObj.flags.allowOnly
|
|
263
|
-
if (joiObj.flags.allowUnknown) {
|
|
264
|
-
joiObj.flags.unknown = joiObj.flags.allowUnknown
|
|
265
|
-
}
|
|
266
|
-
delete joiObj.flags.allowUnknown
|
|
267
|
-
if (joiObj.description) {
|
|
268
|
-
joiObj.flags.description = joiObj.description
|
|
269
|
-
delete joiObj.description
|
|
270
|
-
}
|
|
271
|
-
if (joiObj.options) {
|
|
272
|
-
joiObj.preferences = joiObj.options
|
|
273
|
-
delete joiObj.options
|
|
274
|
-
}
|
|
275
|
-
if (joiObj.valids) {
|
|
276
|
-
joiObj.allow = joiObj.valids
|
|
277
|
-
delete joiObj.valids
|
|
278
|
-
}
|
|
279
|
-
if (joiObj.meta) {
|
|
280
|
-
joiObj.metas = joiObj.meta
|
|
281
|
-
delete joiObj.meta
|
|
282
|
-
}
|
|
283
|
-
if (joiObj.invalids) {
|
|
284
|
-
// FIXME Looks like before v16, joi spec default add [''] for string and [Infinity,-Infinity] for number
|
|
285
|
-
if (!(joiObj.invalids.length === 1 && joiObj.invalids[0] === '') &&
|
|
286
|
-
!(joiObj.invalids.length === 2 && joiObj.invalids[0] === Infinity && joiObj.invalids[1] === -Infinity)) {
|
|
287
|
-
joiObj.invalid = joiObj.invalids
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
delete joiObj.invalids
|
|
291
|
-
|
|
292
|
-
this._convertExamples(joiObj)
|
|
293
|
-
|
|
294
|
-
switch (joiObj.type) {
|
|
295
|
-
case 'object':
|
|
296
|
-
this._convertObject(joiObj)
|
|
297
|
-
break
|
|
298
|
-
case 'date':
|
|
299
|
-
this._convertDate(joiObj)
|
|
300
|
-
break
|
|
301
|
-
case 'alternatives':
|
|
302
|
-
this._convertAlternatives(joiObj)
|
|
303
|
-
break
|
|
304
|
-
case 'binary':
|
|
305
|
-
this._convertBinary(joiObj)
|
|
306
|
-
break
|
|
307
|
-
case 'string':
|
|
308
|
-
this._convertString(joiObj)
|
|
309
|
-
break
|
|
310
|
-
case 'number':
|
|
311
|
-
this._convertNumber(joiObj)
|
|
312
|
-
break
|
|
313
|
-
case 'boolean':
|
|
314
|
-
this._convertBoolean(joiObj)
|
|
315
|
-
break
|
|
316
|
-
case 'array':
|
|
317
|
-
this._convertArray(joiObj)
|
|
318
|
-
break
|
|
319
|
-
default:
|
|
320
|
-
break
|
|
321
|
-
}
|
|
322
|
-
if (_.isEmpty(joiObj.flags)) {
|
|
323
|
-
delete joiObj.flags
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return joiObj
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
module.exports = JoiSpecConvertor
|
|
1
|
+
const _ = require('lodash')
|
|
2
|
+
|
|
3
|
+
class JoiSpecConvertor {
|
|
4
|
+
constructor() {}
|
|
5
|
+
|
|
6
|
+
static getVersion(joiObj) {
|
|
7
|
+
return joiObj._currentJoi.version
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static getSupportVersion() {
|
|
11
|
+
return '12'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_convertObject(joiObj) {
|
|
15
|
+
_.each(joiObj.rules, (rule, _idx) => {
|
|
16
|
+
const name = rule.name
|
|
17
|
+
if (['min', 'max', 'length'].includes(name)) {
|
|
18
|
+
rule.args = {
|
|
19
|
+
limit: rule.arg
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
delete rule.arg
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
if (joiObj.children) {
|
|
26
|
+
joiObj.keys = joiObj.children
|
|
27
|
+
delete joiObj.children
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_.each(joiObj.keys, (value, _key) => {
|
|
31
|
+
this.toBaseSpec(value)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
_.each(joiObj.patterns, (pattern, _idx) => {
|
|
35
|
+
this.toBaseSpec(pattern.rule)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
this._convertDependencies(joiObj)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
_convertDependencies(joiObj) {
|
|
42
|
+
_.each(joiObj.dependencies, (dependency) => {
|
|
43
|
+
if (dependency.key === null) {
|
|
44
|
+
delete dependency.key
|
|
45
|
+
}
|
|
46
|
+
if (dependency.type) {
|
|
47
|
+
dependency.rel = dependency.type
|
|
48
|
+
delete dependency.type
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_convertDate(joiObj) {
|
|
54
|
+
if (joiObj.flags.timestamp) {
|
|
55
|
+
joiObj.flags.format = joiObj.flags.timestamp
|
|
56
|
+
delete joiObj.flags.timestamp
|
|
57
|
+
delete joiObj.flags.multiplier
|
|
58
|
+
} else if (joiObj.flags.format = {}) {
|
|
59
|
+
joiObj.flags.format = 'iso'
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_convertAlternatives(joiObj) {
|
|
64
|
+
// backup alternatives setting
|
|
65
|
+
const alternatives = joiObj.alternatives
|
|
66
|
+
let fieldName = 'matches'
|
|
67
|
+
|
|
68
|
+
if (joiObj.base) {
|
|
69
|
+
// When case is based on one schema type
|
|
70
|
+
fieldName = 'whens'
|
|
71
|
+
|
|
72
|
+
const baseType = joiObj.base
|
|
73
|
+
delete joiObj.base
|
|
74
|
+
delete joiObj.alternatives
|
|
75
|
+
if (joiObj.flags && joiObj.flags.presence) {
|
|
76
|
+
delete joiObj.flags.presence
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.toBaseSpec(baseType)
|
|
80
|
+
|
|
81
|
+
_.merge(joiObj, baseType)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Convert alternatives
|
|
85
|
+
joiObj[fieldName] = _.map(alternatives, (alternative) => {
|
|
86
|
+
if (alternative.peek || alternative.ref) {
|
|
87
|
+
if (alternative.peek) {
|
|
88
|
+
alternative.is = alternative.peek
|
|
89
|
+
delete alternative.peek
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return _.mapValues(alternative, (value, condition) => {
|
|
93
|
+
switch (condition) {
|
|
94
|
+
case 'is':
|
|
95
|
+
this.toBaseSpec(value)
|
|
96
|
+
if (alternative.ref) {
|
|
97
|
+
// alternative field reference case
|
|
98
|
+
value.type = 'any'
|
|
99
|
+
value.allow.splice(0, 0, { 'override': true })
|
|
100
|
+
}
|
|
101
|
+
break
|
|
102
|
+
case 'otherwise':
|
|
103
|
+
this.toBaseSpec(value)
|
|
104
|
+
break
|
|
105
|
+
case 'then':
|
|
106
|
+
this.toBaseSpec(value)
|
|
107
|
+
break
|
|
108
|
+
case 'ref':
|
|
109
|
+
if (value.indexOf('ref:') === 0) {
|
|
110
|
+
value = {
|
|
111
|
+
path: value.replace('ref:', '').split('.')
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
break
|
|
115
|
+
}
|
|
116
|
+
return value
|
|
117
|
+
})
|
|
118
|
+
} else {
|
|
119
|
+
return {
|
|
120
|
+
schema: this.toBaseSpec(alternative)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// FIXME: Joi seems merging the `is` to `then` schema
|
|
126
|
+
_.forEach(joiObj[fieldName], (alternative) => {
|
|
127
|
+
if (alternative.is && alternative.then) {
|
|
128
|
+
if (alternative.is.type === 'object') {
|
|
129
|
+
const isKeys = Object.keys(alternative.is.keys)
|
|
130
|
+
_.forEach(isKeys, (key) => {
|
|
131
|
+
delete alternative.then.keys[key]
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
delete joiObj.alternatives
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
_convertBinary(joiObj) {
|
|
141
|
+
_.each(joiObj.rules, (rule, _idx) => {
|
|
142
|
+
const name = rule.name
|
|
143
|
+
if (['min', 'max', 'length'].includes(name)) {
|
|
144
|
+
rule.args = {
|
|
145
|
+
limit: rule.arg
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
delete rule.arg
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
_convertString(joiObj) {
|
|
153
|
+
delete joiObj.options
|
|
154
|
+
|
|
155
|
+
_.each(joiObj.rules, (rule, _idx) => {
|
|
156
|
+
const name = rule.name
|
|
157
|
+
if (['min', 'max'].includes(name)) {
|
|
158
|
+
rule.args = {
|
|
159
|
+
limit: rule.arg
|
|
160
|
+
}
|
|
161
|
+
} else if (['lowercase', 'uppercase'].includes(name)) {
|
|
162
|
+
rule.name = 'case'
|
|
163
|
+
rule.args = {
|
|
164
|
+
direction: name.replace('case', '')
|
|
165
|
+
}
|
|
166
|
+
delete joiObj.flags.case
|
|
167
|
+
} else if (rule.arg) {
|
|
168
|
+
rule.args = {
|
|
169
|
+
options: rule.arg
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (name === 'regex') {
|
|
173
|
+
rule.name = 'pattern'
|
|
174
|
+
rule.args.regex = rule.arg.pattern.toString()
|
|
175
|
+
delete rule.args.options.pattern
|
|
176
|
+
}
|
|
177
|
+
delete rule.arg
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
_convertNumber(joiObj) {
|
|
182
|
+
_.each(joiObj.rules, (rule, _idx) => {
|
|
183
|
+
const name = rule.name
|
|
184
|
+
if (['positive', 'negative'].includes(name)) {
|
|
185
|
+
rule.args = {
|
|
186
|
+
sign: name
|
|
187
|
+
}
|
|
188
|
+
rule.name = 'sign'
|
|
189
|
+
}
|
|
190
|
+
if (['greater', 'less', 'min', 'max', 'precision'].includes(name)) {
|
|
191
|
+
rule.args = {
|
|
192
|
+
limit: rule.arg
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (name === 'multiple') {
|
|
196
|
+
rule.args = {
|
|
197
|
+
base: rule.arg
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
delete rule.arg
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
if (joiObj.flags.precision) {
|
|
204
|
+
delete joiObj.flags.precision
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
_convertBoolean(joiObj) {
|
|
209
|
+
if (_.isArray(joiObj.truthy)) {
|
|
210
|
+
_.remove(joiObj.truthy, (i) => i === true)
|
|
211
|
+
if (joiObj.truthy.length === 0) {
|
|
212
|
+
delete joiObj.truthy
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (_.isArray(joiObj.falsy)) {
|
|
216
|
+
_.remove(joiObj.falsy, (i) => i === false)
|
|
217
|
+
if (joiObj.falsy.length === 0) {
|
|
218
|
+
delete joiObj.falsy
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (joiObj.flags.insensitive === false) {
|
|
222
|
+
joiObj.flags.sensitive = true
|
|
223
|
+
}
|
|
224
|
+
delete joiObj.flags.insensitive
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
_convertArray(joiObj) {
|
|
228
|
+
if (joiObj.flags.sparse === false) {
|
|
229
|
+
delete joiObj.flags.sparse
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
_.each(joiObj.rules, (rule, _idx) => {
|
|
233
|
+
const name = rule.name
|
|
234
|
+
if (['min', 'max', 'length'].includes(name)) {
|
|
235
|
+
rule.args = {
|
|
236
|
+
limit: rule.arg
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (name === 'has') {
|
|
240
|
+
this.toBaseSpec(rule.arg)
|
|
241
|
+
rule.args = {
|
|
242
|
+
schema: rule.arg
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
delete rule.arg
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
_.each(joiObj.items, (item, _idx) => {
|
|
249
|
+
this.toBaseSpec(item)
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
_convertExamples(_joiObj) {
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
toBaseSpec(joiObj) {
|
|
257
|
+
joiObj.flags = joiObj.flags || {}
|
|
258
|
+
|
|
259
|
+
if (joiObj.flags.allowOnly) {
|
|
260
|
+
joiObj.flags.only = joiObj.flags.allowOnly
|
|
261
|
+
}
|
|
262
|
+
delete joiObj.flags.allowOnly
|
|
263
|
+
if (joiObj.flags.allowUnknown) {
|
|
264
|
+
joiObj.flags.unknown = joiObj.flags.allowUnknown
|
|
265
|
+
}
|
|
266
|
+
delete joiObj.flags.allowUnknown
|
|
267
|
+
if (joiObj.description) {
|
|
268
|
+
joiObj.flags.description = joiObj.description
|
|
269
|
+
delete joiObj.description
|
|
270
|
+
}
|
|
271
|
+
if (joiObj.options) {
|
|
272
|
+
joiObj.preferences = joiObj.options
|
|
273
|
+
delete joiObj.options
|
|
274
|
+
}
|
|
275
|
+
if (joiObj.valids) {
|
|
276
|
+
joiObj.allow = joiObj.valids
|
|
277
|
+
delete joiObj.valids
|
|
278
|
+
}
|
|
279
|
+
if (joiObj.meta) {
|
|
280
|
+
joiObj.metas = joiObj.meta
|
|
281
|
+
delete joiObj.meta
|
|
282
|
+
}
|
|
283
|
+
if (joiObj.invalids) {
|
|
284
|
+
// FIXME Looks like before v16, joi spec default add [''] for string and [Infinity,-Infinity] for number
|
|
285
|
+
if (!(joiObj.invalids.length === 1 && joiObj.invalids[0] === '') &&
|
|
286
|
+
!(joiObj.invalids.length === 2 && joiObj.invalids[0] === Infinity && joiObj.invalids[1] === -Infinity)) {
|
|
287
|
+
joiObj.invalid = joiObj.invalids
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
delete joiObj.invalids
|
|
291
|
+
|
|
292
|
+
this._convertExamples(joiObj)
|
|
293
|
+
|
|
294
|
+
switch (joiObj.type) {
|
|
295
|
+
case 'object':
|
|
296
|
+
this._convertObject(joiObj)
|
|
297
|
+
break
|
|
298
|
+
case 'date':
|
|
299
|
+
this._convertDate(joiObj)
|
|
300
|
+
break
|
|
301
|
+
case 'alternatives':
|
|
302
|
+
this._convertAlternatives(joiObj)
|
|
303
|
+
break
|
|
304
|
+
case 'binary':
|
|
305
|
+
this._convertBinary(joiObj)
|
|
306
|
+
break
|
|
307
|
+
case 'string':
|
|
308
|
+
this._convertString(joiObj)
|
|
309
|
+
break
|
|
310
|
+
case 'number':
|
|
311
|
+
this._convertNumber(joiObj)
|
|
312
|
+
break
|
|
313
|
+
case 'boolean':
|
|
314
|
+
this._convertBoolean(joiObj)
|
|
315
|
+
break
|
|
316
|
+
case 'array':
|
|
317
|
+
this._convertArray(joiObj)
|
|
318
|
+
break
|
|
319
|
+
default:
|
|
320
|
+
break
|
|
321
|
+
}
|
|
322
|
+
if (_.isEmpty(joiObj.flags)) {
|
|
323
|
+
delete joiObj.flags
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return joiObj
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
module.exports = JoiSpecConvertor
|
package/lib/convertors/v16.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
const BaseConverter = require('./v15')
|
|
2
|
-
|
|
3
|
-
class JoiSpecConvertor extends BaseConverter {
|
|
4
|
-
static getVersion(joiObj) {
|
|
5
|
-
return joiObj.$_root.version
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
static getSupportVersion() {
|
|
9
|
-
return '16'
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// All methods are overridden because the Joi v16.1.8 spec is closed to the latest version
|
|
13
|
-
_convertExamples(_joiObj) { }
|
|
14
|
-
|
|
15
|
-
_convertObject(_joiObj) { }
|
|
16
|
-
|
|
17
|
-
_convertDate(_joiObj) { }
|
|
18
|
-
|
|
19
|
-
_convertAlternatives(_joiObj) { }
|
|
20
|
-
|
|
21
|
-
_convertBinary(_joiObj) { }
|
|
22
|
-
|
|
23
|
-
_convertString(_joiObj) { }
|
|
24
|
-
|
|
25
|
-
_convertNumber(_joiObj) { }
|
|
26
|
-
|
|
27
|
-
_convertBoolean(_joiObj) { }
|
|
28
|
-
|
|
29
|
-
_convertArray(_joiObj) {}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
module.exports = JoiSpecConvertor
|
|
1
|
+
const BaseConverter = require('./v15')
|
|
2
|
+
|
|
3
|
+
class JoiSpecConvertor extends BaseConverter {
|
|
4
|
+
static getVersion(joiObj) {
|
|
5
|
+
return joiObj.$_root.version
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
static getSupportVersion() {
|
|
9
|
+
return '16'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// All methods are overridden because the Joi v16.1.8 spec is closed to the latest version
|
|
13
|
+
_convertExamples(_joiObj) { }
|
|
14
|
+
|
|
15
|
+
_convertObject(_joiObj) { }
|
|
16
|
+
|
|
17
|
+
_convertDate(_joiObj) { }
|
|
18
|
+
|
|
19
|
+
_convertAlternatives(_joiObj) { }
|
|
20
|
+
|
|
21
|
+
_convertBinary(_joiObj) { }
|
|
22
|
+
|
|
23
|
+
_convertString(_joiObj) { }
|
|
24
|
+
|
|
25
|
+
_convertNumber(_joiObj) { }
|
|
26
|
+
|
|
27
|
+
_convertBoolean(_joiObj) { }
|
|
28
|
+
|
|
29
|
+
_convertArray(_joiObj) {}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = JoiSpecConvertor
|
|
@@ -4,6 +4,7 @@ const JoiJsonSchemaParser = require('./json')
|
|
|
4
4
|
class JoiJsonDraftSchemaParser extends JoiJsonSchemaParser {
|
|
5
5
|
constructor(opts = {}) {
|
|
6
6
|
super(_.merge({
|
|
7
|
+
$schema: 'http://json-schema.org/draft-04/schema#',
|
|
7
8
|
logicalOpParser: {
|
|
8
9
|
xor: null,
|
|
9
10
|
with: function (schema, dependency) {
|
|
@@ -22,6 +23,15 @@ class JoiJsonDraftSchemaParser extends JoiJsonSchemaParser {
|
|
|
22
23
|
_setNumberFieldProperties(fieldSchema, fieldDefn) {
|
|
23
24
|
super._setNumberFieldProperties(fieldSchema, fieldDefn)
|
|
24
25
|
|
|
26
|
+
if (typeof fieldSchema.exclusiveMinimum !== 'undefined') {
|
|
27
|
+
fieldSchema.minimum = fieldSchema.exclusiveMinimum
|
|
28
|
+
fieldSchema.exclusiveMinimum = true
|
|
29
|
+
}
|
|
30
|
+
if (typeof fieldSchema.exclusiveMaximum !== 'undefined') {
|
|
31
|
+
fieldSchema.maximum = fieldSchema.exclusiveMaximum
|
|
32
|
+
fieldSchema.exclusiveMaximum = true
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
if (typeof fieldSchema.minimum !== 'undefined' && fieldSchema.minimum === fieldSchema.exclusiveMinimum) {
|
|
26
36
|
fieldSchema.exclusiveMinimum = true
|
|
27
37
|
}
|
|
@@ -2,6 +2,12 @@ const _ = require('lodash')
|
|
|
2
2
|
const JoiJsonSchemaParser = require('./json')
|
|
3
3
|
|
|
4
4
|
class JoiJsonDraftSchemaParser extends JoiJsonSchemaParser {
|
|
5
|
+
constructor(opts = {}) {
|
|
6
|
+
super(_.merge({
|
|
7
|
+
$schema: 'https://json-schema.org/draft/2019-09/schema'
|
|
8
|
+
}, opts))
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
parse(joiSpec, definitions = {}, level = 0) {
|
|
6
12
|
const schema = super.parse(joiSpec, definitions, level)
|
|
7
13
|
|
package/lib/parsers/json.js
CHANGED
|
@@ -82,6 +82,8 @@ function isJoiOverride(e) {
|
|
|
82
82
|
|
|
83
83
|
class JoiJsonSchemaParser {
|
|
84
84
|
constructor(opts = {}) {
|
|
85
|
+
this.$schema = opts.$schema || 'http://json-schema.org/draft-07/schema#'
|
|
86
|
+
this.includeSchemaDialect = opts.includeSchemaDialect || false
|
|
85
87
|
this.childrenFieldName = this._getChildrenFieldName()
|
|
86
88
|
this.optionsFieldName = this._getOptionsFieldName()
|
|
87
89
|
this.ruleArgFieldName = this._getRuleArgFieldName()
|
|
@@ -133,6 +135,10 @@ class JoiJsonSchemaParser {
|
|
|
133
135
|
_.set(schema, `${this._getLocalSchemaBasePath().replace('#/', '').replace(/\//, '.')}`, definitions)
|
|
134
136
|
}
|
|
135
137
|
|
|
138
|
+
if (this.includeSchemaDialect && level === 0 && this.$schema) {
|
|
139
|
+
schema.$schema = this.$schema
|
|
140
|
+
}
|
|
141
|
+
|
|
136
142
|
return schema
|
|
137
143
|
}
|
|
138
144
|
|
|
@@ -395,6 +401,13 @@ class JoiJsonSchemaParser {
|
|
|
395
401
|
case 'multiple':
|
|
396
402
|
fieldSchema.multipleOf = value.base
|
|
397
403
|
break
|
|
404
|
+
case 'sign':
|
|
405
|
+
if (rule.args.sign === 'positive') {
|
|
406
|
+
fieldSchema.exclusiveMinimum = 0
|
|
407
|
+
} else if (rule.args.sign === 'negative') {
|
|
408
|
+
fieldSchema.exclusiveMaximum = 0
|
|
409
|
+
}
|
|
410
|
+
break
|
|
398
411
|
default:
|
|
399
412
|
break
|
|
400
413
|
}
|
package/lib/parsers/open-api.js
CHANGED