joi-to-json 4.1.0 → 4.2.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 CHANGED
@@ -1,333 +1,334 @@
1
- # joi-to-json
2
-
3
- ## Objective
4
-
5
- I have been using [joi](https://joi.dev/) a lot in different Node.js projects to guard the API.
6
- It's **The most powerful schema description language and data validator for JavaScript.** as it said.
7
-
8
- Many times, we need to utilize this schema description to produce other output, such as Swagger OpenAPI doc.
9
- That is why I build [joi-route-to-swagger](https://github.com/kenspirit/joi-route-to-swagger) in the first place.
10
-
11
- At the beginning, `joi-route-to-swagger` relies on [joi-to-json-schema](https://github.com/lightsofapollo/joi-to-json-schema/) which utilizes many joi internal api or properties. Maybe joi did not provide the `describe` api way before, but I always feel uncomfortable of relying on internal api.
12
-
13
- The intention of `joi-to-json` is to support converting different version's joi schema to [JSON Schema](https://json-schema.org) using `describe` api.
14
-
15
- The implementation of this JOI to JSON conversion tool is simply a pipeline of two components:
16
-
17
- 1. Convertors
18
- - Each JOI version has one convertor implementation.
19
- - It converts the `joi.describe()` output to the baseline format (currently the v16 and v17 one)
20
-
21
- 2. Parsers
22
- - Each supported output JSON format (e.g. JSON Draft 07, OpenAPI) has one parser implementation.
23
- - All parsers converts the baseline format into its own format
24
-
25
-
26
- ## Joi Version Support
27
-
28
- * @commercial/joi
29
- * v12.1.0
30
- * joi
31
- * 13.7.0
32
- * 14.3.1
33
- * @hapi/joi
34
- * 15.1.1
35
- * 16.1.8
36
- * joi
37
- * 17.9.2
38
-
39
- Although the versions chosen are the latest one for each major version, It should support other minor versions as well.
40
-
41
-
42
- ## Installation
43
-
44
- >npm install joi-to-json
45
-
46
-
47
- ## Usage
48
-
49
- Only one API `parse` is available. It's signature is `parse(joiObj, type = 'json')`
50
-
51
- Currently supported output types:
52
- * `json` - Default. Stands for JSON Schema Draft 07
53
- * `open-api` - Stands for OpenAPI 3.0 Schema - an extended subset of JSON Schema Specification Wright Draft 00 (aka Draft 5)
54
- * `json-draft-04` - Stands for JSON Schema Draft 04
55
- * `json-draft-2019-09` - Stands for JSON Schema Draft 2019-09
56
-
57
- The output schema format are in [outputs](./outputs-parsers) under specific folders for different types.
58
-
59
- Sample code is as below:
60
-
61
- ```javascript
62
- const parse = require('joi-to-json')
63
-
64
- const joiSchema = joi.object().keys({
65
- nickName: joi.string().required().min(3).max(20).example('鹄思乱想').description('Hero Nickname')
66
- .regex(/^[a-z]+$/, { name: 'alpha', invert: true }),
67
- avatar: joi.string().required().uri(),
68
- email: joi.string().email(),
69
- ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
70
- hostname: joi.string().hostname().insensitive(),
71
- gender: joi.string().valid('Male', 'Female', '').default('Male'),
72
- height: joi.number().precision(2).positive().greater(0).less(200),
73
- birthday: joi.date().iso(),
74
- birthTime: joi.date().timestamp('unix'),
75
- skills: joi.array().items(joi.alternatives().try(
76
- joi.string(),
77
- joi.object().keys({
78
- name: joi.string().example('teleport').alphanum().lowercase().required().description('Skill Name'),
79
- level: joi.number().integer().min(10).max(100).default(50).multiple(10).example(10).description('Skill Level')
80
- })
81
- ).required()).min(1).max(3).unique().description('Skills'),
82
- tags: joi.array().items(joi.string().required()).length(2),
83
- retired: joi.boolean().truthy('yes').falsy('no').insensitive(false),
84
- certificate: joi.binary().encoding('base64'),
85
- notes: joi.any().meta({ 'x-supported-lang': ['zh-CN', 'en-US'], deprecated: true })
86
- })
87
-
88
- const jsonSchema = parse(joiSchema)
89
- // Or parsing to OpenAPI schema through:
90
- // const openApiSchema = parse(joiSchema, 'open-api')
91
- ```
92
-
93
- ## Features
94
-
95
- ### Special Joi Operator Support
96
-
97
- * [Logical Relation Operator](./docs/logical_rel_support.md)
98
-
99
- ### Named Link
100
-
101
- Supports named link for schema reuse, 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.
102
-
103
- ### Conditional Expression
104
-
105
- Starting from Draft 7, JSON Specification supports `If-Then-Else` style expression. Before that, we can also use something called [Implication](http://json-schema.org/understanding-json-schema/reference/conditionals.html#implication) using Schema Composition Approach to simulate that.
106
-
107
- By default, the `If-Then-Else` approach is used if the output spec supports it. However, if the joi conditional expression (`alternatives` or `when`) is annotated using Meta `.meta({ 'if-style': true })`, the JSON schema conversion will use the Composition approach using `allOf` and/or `anyOf` instead.
108
-
109
- **Limitation**: Currently, if the joi condition definition is referring to another field, the `If-Then-Else` style output is not supported. Instead, it simply uses the `anyOf` composing the `then` and `otherwise` on the defined field.
110
-
111
-
112
- ## YAML File Generation
113
-
114
- Most Joi specifications result in the expected OpenAPI schema.
115
-
116
- E.g.,
117
-
118
- ```js
119
- const joi = require('joi')
120
- const { dump } = require('js-yaml')
121
- const { writeFile } = require('fs/promises')
122
-
123
- const joiSchema = joi.object().keys({
124
- uuid: joi.string().uuid({ version: ['uuidv3', 'uuidv5'] }),
125
- nickName: joi.string().required().example('鹄思乱想').description('Hero Nickname').min(3).max(20).pattern(/^[a-z]+$/, { name: 'alpha', invert: true }),
126
- avatar: joi.string().required().uri(),
127
- email: joi.string().email(),
128
- ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
129
- hostname: joi.string().hostname().insensitive(),
130
- gender: joi.string().valid('Male', 'Female', '', null).default('Male'),
131
- isoDateString: joi.string().isoDate(),
132
- isoDurationString: joi.string().isoDuration(),
133
- birthday: joi.date().iso(),
134
- certificate: joi.binary().encoding('base64'),
135
- tags: joi.array().items(joi.string().required()).length(2),
136
- nested: joi.object().keys({
137
- key: joi.string()
138
- }).unknown(true)
139
- }).unknown(false)
140
-
141
- async function writeYAML(targetPath) {
142
- const openApiSchema = parse(joiSchema, 'open-api')
143
-
144
- const openApiSchemaYAML = dump(openApiSchema, {lineWidth: 120, noCompatMode: true})
145
- await writeFile(targetPath, openApiSchemaYAML)
146
- }
147
- ```
148
-
149
- results in
150
-
151
- ```yaml
152
- type: object
153
- required:
154
- - nickName
155
- - avatar
156
- properties:
157
- uuid:
158
- type: string
159
- format: uuid
160
- nickName:
161
- description: Hero Nickname
162
- type: string
163
- pattern: ^[a-z]+$
164
- minLength: 3,
165
- maxLength: 20,
166
- example: 鹄思乱想
167
- avatar:
168
- type: string
169
- format: uri
170
- email:
171
- type: string
172
- format: email
173
- ip:
174
- type: string
175
- oneOf:
176
- - format: ipv4
177
- - format: ipv6
178
- hostname:
179
- type: string
180
- format: hostname
181
- gender:
182
- type: string
183
- default: Male
184
- enum:
185
- - Male
186
- - Female
187
- - ''
188
- - null
189
- nullable: true
190
- isoDateString:
191
- type: string
192
- format: date-time
193
- isoDurationString:
194
- type: string
195
- format: duration
196
- birthday:
197
- type: string
198
- format: date-time
199
- certificate:
200
- type: string
201
- format: binary
202
- tags:
203
- type: array
204
- items:
205
- type: string
206
- minItems: 2
207
- maxItems: 2
208
- nested:
209
- type: object
210
- properties:
211
- key:
212
- type: string
213
- additionalProperties: true
214
- additionalProperties: false
215
- ```
216
-
217
- Some OpenAPI features are not supported directly in Joi, but Joi schemas can be annotated with `joi.any().meta({…})`
218
- to get them in the OpenAPI schema:
219
-
220
- ```js
221
-
222
-
223
- const joiSchema = joi.object().keys({
224
- deprecatedProperty: joi.string().meta({ deprecated: true }).required(),
225
- readOnlyProperty: joi.string().meta({ readOnly: true }),
226
- writeOnlyProperty: joi.string().meta({ writeOnly: true }),
227
- xMeta: joi.string().meta({ 'x-meta': 42 }),
228
- unknownMetaProperty: joi.string().meta({ unknownMeta: 42 })
229
- }).unknown(true)
230
-
231
-
232
- ```
233
-
234
- begets:
235
-
236
- ```yaml
237
- type: object
238
- required:
239
- - deprecatedProperty
240
- properties:
241
- deprecatedProperty:
242
- type: string
243
- deprecated: true
244
- readOnlyProperty:
245
- type: string
246
- readOnly: true
247
- writeOnlyProperty:
248
- type: string
249
- writeOnly: true
250
- xMeta:
251
- type: string
252
- x-meta: 42
253
- unknownMetaProperty:
254
- type: string
255
- # unknownMeta is not exported
256
- additionalProperties: true
257
- ```
258
-
259
- ## Browser support
260
- 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.
261
-
262
- ```typescript
263
- import Joi from 'joi/lib/index';
264
- ```
265
-
266
- ## TypeScript support
267
-
268
- ```typescript
269
- import joi from 'joi';
270
- import * as Joi2Json from 'joi-to-json';
271
- import parse from 'joi-to-json';
272
-
273
- const logicalOpParser: Joi2Json.LogicalOpParserOpts = {
274
- with: function (a) {}
275
- };
276
-
277
- parse(joi.string()); // Default call
278
- parse(joi.string(), 'json', {}, { logicalOpParser: false }); // Completely disable Logical Relation Operator
279
- parse(joi.string(), 'open-api', {}, { logicalOpParser }); // Partially override Logical Relation Operator
280
- ```
281
-
282
- ## Test
283
-
284
- >npm run test
285
-
286
- ### Categories of Test Cases
287
-
288
- * JOI Standard Representation Conversion
289
-
290
- `fixtures-conversion` folder stores each JOI version's supported keyword for different data types.
291
- In case any data type or keyword is not supported in historical JOI version, we can just create customized file to override the `base` version, such as `v15/link.js`.
292
-
293
- Standard converted results are stored in `outputs-conversion` folder.
294
-
295
- `test/conversion.spec.js` Test Spec handles all supported JOI versions' conversion verificaiton.
296
-
297
- * JSON output format Conversion
298
-
299
- `outputs-parsers` folder stores different output formats base on the JOI Standard Representation in `outputs-conversion` folder.
300
- The Test Spec under `test/parser/` are responsible for these area.
301
-
302
- * JSON schema (Draft 07) Validity Unit Test
303
-
304
- For special **Logical Relation Operator** and **Conditional Expression**, some Unit Tests are created to verify the JOI Spec and corresponding JSON Spec are valid of the same verification intention.
305
-
306
-
307
- ### Test Debug Approach
308
-
309
- When running `conversion.spec.js`, below environment variables can be set:
310
-
311
- * `TEST_CONVERTOR`: control which version of joi to test.
312
- Example: `TEST_CONVERTOR=v17`
313
- * `TEST_CASE`: control which test cases to verify. Name of the test cases is the key of the return object in `fixtures-conversion`.
314
- Example: `TEST_CASE=conditional,match_all` verifies the case in `alternatives.js`
315
- * `TEST_UPDATE_CONVERSION_BASELINE`: control whether writes the baseline file generated from the latest-version convertor (Currently `v17`).
316
- It is activated when setting to `true`.
317
-
318
- When runninng Test Spec under `test/parser`, below environment variables can be set:
319
-
320
- * `TEST_CASE`: control which test cases to verify.
321
- For example, when running `json.spec.js`, and set `TEST_CASE=conditional,match_all`, it verifies the corresponding JSON files in `outputs-parsers/json/alternatives`.
322
- * `TEST_UPDATE_PARSER_BASELINE`: control whether writes the baseline file for the corresponding parser.
323
- It is activated when setting to `true`. For example, when running `json.spec.js`, it writes the baseline files under `outputs-parsers/json`.
324
-
325
-
326
- ## Known Limitation
327
-
328
- * For `object.pattern` usage in Joi, `pattern` parameter can only be a regular expression now as I cannot convert Joi object to regex yet.
329
- * `If-Then-Else` style output is not applicable for the condition referring to the other field.
330
-
331
- ## License
332
-
333
- MIT
1
+ # joi-to-json
2
+
3
+ ## Objective
4
+
5
+ I have been using [joi](https://joi.dev/) a lot in different Node.js projects to guard the API.
6
+ It's **The most powerful schema description language and data validator for JavaScript.** as it said.
7
+
8
+ Many times, we need to utilize this schema description to produce other output, such as Swagger OpenAPI doc.
9
+ That is why I build [joi-route-to-swagger](https://github.com/kenspirit/joi-route-to-swagger) in the first place.
10
+
11
+ At the beginning, `joi-route-to-swagger` relies on [joi-to-json-schema](https://github.com/lightsofapollo/joi-to-json-schema/) which utilizes many joi internal api or properties. Maybe joi did not provide the `describe` api way before, but I always feel uncomfortable of relying on internal api.
12
+
13
+ The intention of `joi-to-json` is to support converting different version's joi schema to [JSON Schema](https://json-schema.org) using `describe` api.
14
+
15
+ The implementation of this JOI to JSON conversion tool is simply a pipeline of two components:
16
+
17
+ 1. Convertors
18
+ - Each JOI version has one convertor implementation.
19
+ - It converts the `joi.describe()` output to the baseline format (currently the v16 and v17 one)
20
+
21
+ 2. Parsers
22
+ - Each supported output JSON format (e.g. JSON Draft 07, OpenAPI) has one parser implementation.
23
+ - All parsers converts the baseline format into its own format
24
+
25
+
26
+ ## Joi Version Support
27
+
28
+ * @commercial/joi
29
+ * v12.1.0
30
+ * joi
31
+ * 13.7.0
32
+ * 14.3.1
33
+ * @hapi/joi
34
+ * 15.1.1
35
+ * 16.1.8
36
+ * joi
37
+ * 17.9.2
38
+
39
+ Although the versions chosen are the latest one for each major version, It should support other minor versions as well.
40
+
41
+
42
+ ## Installation
43
+
44
+ >npm install joi-to-json
45
+
46
+
47
+ ## Usage
48
+
49
+ Only one API `parse` is available. It's signature is `parse(joiObj, type = 'json')`
50
+
51
+ Currently supported output types:
52
+ * `json` - Default. Stands for JSON Schema Draft 07
53
+ * `open-api` - Stands for OpenAPI 3.0 Schema - an extended subset of JSON Schema Specification Wright Draft 00 (aka Draft 5)
54
+ * `open-api-3.1` - Stands for OpenAPI 3.1 Schema - a superset of JSON Schema Specification Draft 2020-12
55
+ * `json-draft-04` - Stands for JSON Schema Draft 04
56
+ * `json-draft-2019-09` - Stands for JSON Schema Draft 2019-09
57
+
58
+ The output schema format are in [outputs](./outputs-parsers) under specific folders for different types.
59
+
60
+ Sample code is as below:
61
+
62
+ ```javascript
63
+ const parse = require('joi-to-json')
64
+
65
+ const joiSchema = joi.object().keys({
66
+ nickName: joi.string().required().min(3).max(20).example('鹄思乱想').description('Hero Nickname')
67
+ .regex(/^[a-z]+$/, { name: 'alpha', invert: true }),
68
+ avatar: joi.string().required().uri(),
69
+ email: joi.string().email(),
70
+ ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
71
+ hostname: joi.string().hostname().insensitive(),
72
+ gender: joi.string().valid('Male', 'Female', '').default('Male'),
73
+ height: joi.number().precision(2).positive().greater(0).less(200),
74
+ birthday: joi.date().iso(),
75
+ birthTime: joi.date().timestamp('unix'),
76
+ skills: joi.array().items(joi.alternatives().try(
77
+ joi.string(),
78
+ joi.object().keys({
79
+ name: joi.string().example('teleport').alphanum().lowercase().required().description('Skill Name'),
80
+ level: joi.number().integer().min(10).max(100).default(50).multiple(10).example(10).description('Skill Level')
81
+ })
82
+ ).required()).min(1).max(3).unique().description('Skills'),
83
+ tags: joi.array().items(joi.string().required()).length(2),
84
+ retired: joi.boolean().truthy('yes').falsy('no').insensitive(false),
85
+ certificate: joi.binary().encoding('base64'),
86
+ notes: joi.any().meta({ 'x-supported-lang': ['zh-CN', 'en-US'], deprecated: true })
87
+ })
88
+
89
+ const jsonSchema = parse(joiSchema)
90
+ // Or parsing to OpenAPI schema through:
91
+ // const openApiSchema = parse(joiSchema, 'open-api')
92
+ ```
93
+
94
+ ## Features
95
+
96
+ ### Special Joi Operator Support
97
+
98
+ * [Logical Relation Operator](./docs/logical_rel_support.md)
99
+
100
+ ### Named Link
101
+
102
+ Supports named link for schema reuse, 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.
103
+
104
+ ### Conditional Expression
105
+
106
+ Starting from Draft 7, JSON Specification supports `If-Then-Else` style expression. Before that, we can also use something called [Implication](http://json-schema.org/understanding-json-schema/reference/conditionals.html#implication) using Schema Composition Approach to simulate that.
107
+
108
+ By default, the `If-Then-Else` approach is used if the output spec supports it. However, if the joi conditional expression (`alternatives` or `when`) is annotated using Meta `.meta({ 'if-style': true })`, the JSON schema conversion will use the Composition approach using `allOf` and/or `anyOf` instead.
109
+
110
+ **Limitation**: Currently, if the joi condition definition is referring to another field, the `If-Then-Else` style output is not supported. Instead, it simply uses the `anyOf` composing the `then` and `otherwise` on the defined field.
111
+
112
+
113
+ ## YAML File Generation
114
+
115
+ Most Joi specifications result in the expected OpenAPI schema.
116
+
117
+ E.g.,
118
+
119
+ ```js
120
+ const joi = require('joi')
121
+ const { dump } = require('js-yaml')
122
+ const { writeFile } = require('fs/promises')
123
+
124
+ const joiSchema = joi.object().keys({
125
+ uuid: joi.string().uuid({ version: ['uuidv3', 'uuidv5'] }),
126
+ nickName: joi.string().required().example('鹄思乱想').description('Hero Nickname').min(3).max(20).pattern(/^[a-z]+$/, { name: 'alpha', invert: true }),
127
+ avatar: joi.string().required().uri(),
128
+ email: joi.string().email(),
129
+ ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
130
+ hostname: joi.string().hostname().insensitive(),
131
+ gender: joi.string().valid('Male', 'Female', '', null).default('Male'),
132
+ isoDateString: joi.string().isoDate(),
133
+ isoDurationString: joi.string().isoDuration(),
134
+ birthday: joi.date().iso(),
135
+ certificate: joi.binary().encoding('base64'),
136
+ tags: joi.array().items(joi.string().required()).length(2),
137
+ nested: joi.object().keys({
138
+ key: joi.string()
139
+ }).unknown(true)
140
+ }).unknown(false)
141
+
142
+ async function writeYAML(targetPath) {
143
+ const openApiSchema = parse(joiSchema, 'open-api')
144
+
145
+ const openApiSchemaYAML = dump(openApiSchema, {lineWidth: 120, noCompatMode: true})
146
+ await writeFile(targetPath, openApiSchemaYAML)
147
+ }
148
+ ```
149
+
150
+ results in
151
+
152
+ ```yaml
153
+ type: object
154
+ required:
155
+ - nickName
156
+ - avatar
157
+ properties:
158
+ uuid:
159
+ type: string
160
+ format: uuid
161
+ nickName:
162
+ description: Hero Nickname
163
+ type: string
164
+ pattern: ^[a-z]+$
165
+ minLength: 3,
166
+ maxLength: 20,
167
+ example: 鹄思乱想
168
+ avatar:
169
+ type: string
170
+ format: uri
171
+ email:
172
+ type: string
173
+ format: email
174
+ ip:
175
+ type: string
176
+ oneOf:
177
+ - format: ipv4
178
+ - format: ipv6
179
+ hostname:
180
+ type: string
181
+ format: hostname
182
+ gender:
183
+ type: string
184
+ default: Male
185
+ enum:
186
+ - Male
187
+ - Female
188
+ - ''
189
+ - null
190
+ nullable: true
191
+ isoDateString:
192
+ type: string
193
+ format: date-time
194
+ isoDurationString:
195
+ type: string
196
+ format: duration
197
+ birthday:
198
+ type: string
199
+ format: date-time
200
+ certificate:
201
+ type: string
202
+ format: binary
203
+ tags:
204
+ type: array
205
+ items:
206
+ type: string
207
+ minItems: 2
208
+ maxItems: 2
209
+ nested:
210
+ type: object
211
+ properties:
212
+ key:
213
+ type: string
214
+ additionalProperties: true
215
+ additionalProperties: false
216
+ ```
217
+
218
+ Some OpenAPI features are not supported directly in Joi, but Joi schemas can be annotated with `joi.any().meta({…})`
219
+ to get them in the OpenAPI schema:
220
+
221
+ ```js
222
+
223
+
224
+ const joiSchema = joi.object().keys({
225
+ deprecatedProperty: joi.string().meta({ deprecated: true }).required(),
226
+ readOnlyProperty: joi.string().meta({ readOnly: true }),
227
+ writeOnlyProperty: joi.string().meta({ writeOnly: true }),
228
+ xMeta: joi.string().meta({ 'x-meta': 42 }),
229
+ unknownMetaProperty: joi.string().meta({ unknownMeta: 42 })
230
+ }).unknown(true)
231
+
232
+
233
+ ```
234
+
235
+ begets:
236
+
237
+ ```yaml
238
+ type: object
239
+ required:
240
+ - deprecatedProperty
241
+ properties:
242
+ deprecatedProperty:
243
+ type: string
244
+ deprecated: true
245
+ readOnlyProperty:
246
+ type: string
247
+ readOnly: true
248
+ writeOnlyProperty:
249
+ type: string
250
+ writeOnly: true
251
+ xMeta:
252
+ type: string
253
+ x-meta: 42
254
+ unknownMetaProperty:
255
+ type: string
256
+ # unknownMeta is not exported
257
+ additionalProperties: true
258
+ ```
259
+
260
+ ## Browser support
261
+ 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.
262
+
263
+ ```typescript
264
+ import Joi from 'joi/lib/index';
265
+ ```
266
+
267
+ ## TypeScript support
268
+
269
+ ```typescript
270
+ import joi from 'joi';
271
+ import * as Joi2Json from 'joi-to-json';
272
+ import parse from 'joi-to-json';
273
+
274
+ const logicalOpParser: Joi2Json.LogicalOpParserOpts = {
275
+ with: function (a) {}
276
+ };
277
+
278
+ parse(joi.string()); // Default call
279
+ parse(joi.string(), 'json', {}, { logicalOpParser: false }); // Completely disable Logical Relation Operator
280
+ parse(joi.string(), 'open-api', {}, { logicalOpParser }); // Partially override Logical Relation Operator
281
+ ```
282
+
283
+ ## Test
284
+
285
+ >npm run test
286
+
287
+ ### Categories of Test Cases
288
+
289
+ * JOI Standard Representation Conversion
290
+
291
+ `fixtures-conversion` folder stores each JOI version's supported keyword for different data types.
292
+ In case any data type or keyword is not supported in historical JOI version, we can just create customized file to override the `base` version, such as `v15/link.js`.
293
+
294
+ Standard converted results are stored in `outputs-conversion` folder.
295
+
296
+ `test/conversion.spec.js` Test Spec handles all supported JOI versions' conversion verificaiton.
297
+
298
+ * JSON output format Conversion
299
+
300
+ `outputs-parsers` folder stores different output formats base on the JOI Standard Representation in `outputs-conversion` folder.
301
+ The Test Spec under `test/parser/` are responsible for these area.
302
+
303
+ * JSON schema (Draft 07) Validity Unit Test
304
+
305
+ For special **Logical Relation Operator** and **Conditional Expression**, some Unit Tests are created to verify the JOI Spec and corresponding JSON Spec are valid of the same verification intention.
306
+
307
+
308
+ ### Test Debug Approach
309
+
310
+ When running `conversion.spec.js`, below environment variables can be set:
311
+
312
+ * `TEST_CONVERTOR`: control which version of joi to test.
313
+ Example: `TEST_CONVERTOR=v17`
314
+ * `TEST_CASE`: control which test cases to verify. Name of the test cases is the key of the return object in `fixtures-conversion`.
315
+ Example: `TEST_CASE=conditional,match_all` verifies the case in `alternatives.js`
316
+ * `TEST_UPDATE_CONVERSION_BASELINE`: control whether writes the baseline file generated from the latest-version convertor (Currently `v17`).
317
+ It is activated when setting to `true`.
318
+
319
+ When runninng Test Spec under `test/parser`, below environment variables can be set:
320
+
321
+ * `TEST_CASE`: control which test cases to verify.
322
+ For example, when running `json.spec.js`, and set `TEST_CASE=conditional,match_all`, it verifies the corresponding JSON files in `outputs-parsers/json/alternatives`.
323
+ * `TEST_UPDATE_PARSER_BASELINE`: control whether writes the baseline file for the corresponding parser.
324
+ It is activated when setting to `true`. For example, when running `json.spec.js`, it writes the baseline files under `outputs-parsers/json`.
325
+
326
+
327
+ ## Known Limitation
328
+
329
+ * For `object.pattern` usage in Joi, `pattern` parameter can only be a regular expression now as I cannot convert Joi object to regex yet.
330
+ * `If-Then-Else` style output is not applicable for the condition referring to the other field.
331
+
332
+ ## License
333
+
334
+ MIT