joi-to-json 4.3.0 → 4.3.2

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,346 +1,346 @@
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.
50
-
51
- Its signature is `parse(joiObj, type = 'json', definitions = {}, parserOptions = {})`
52
-
53
- ### Output Type
54
-
55
- * `json` - Default. Stands for JSON Schema Draft 07
56
- * `open-api` - Stands for OpenAPI 3.0 Schema - an extended subset of JSON Schema Specification Wright Draft 00 (aka Draft 5)
57
- * `open-api-3.1` - Stands for OpenAPI 3.1 Schema - a superset of JSON Schema Specification Draft 2020-12
58
- * `json-draft-04` - Stands for JSON Schema Draft 04
59
- * `json-draft-2019-09` - Stands for JSON Schema Draft 2019-09
60
-
61
- The output schema format are in [outputs](./outputs-parsers) under specific folders for different types.
62
-
63
- Sample code is as below:
64
-
65
- ```javascript
66
- const parse = require('joi-to-json')
67
-
68
- const joiSchema = joi.object().keys({
69
- nickName: joi.string().required().min(3).max(20).example('鹄思乱想').description('Hero Nickname')
70
- .regex(/^[a-z]+$/, { name: 'alpha', invert: true }),
71
- avatar: joi.string().required().uri(),
72
- email: joi.string().email(),
73
- ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
74
- hostname: joi.string().hostname().insensitive(),
75
- gender: joi.string().valid('Male', 'Female', '').default('Male'),
76
- height: joi.number().precision(2).positive().greater(0).less(200),
77
- birthday: joi.date().iso(),
78
- birthTime: joi.date().timestamp('unix'),
79
- skills: joi.array().items(joi.alternatives().try(
80
- joi.string(),
81
- joi.object().keys({
82
- name: joi.string().example('teleport').alphanum().lowercase().required().description('Skill Name'),
83
- level: joi.number().integer().min(10).max(100).default(50).multiple(10).example(10).description('Skill Level')
84
- })
85
- ).required()).min(1).max(3).unique().description('Skills'),
86
- tags: joi.array().items(joi.string().required()).length(2),
87
- retired: joi.boolean().truthy('yes').falsy('no').insensitive(false),
88
- certificate: joi.binary().encoding('base64'),
89
- notes: joi.any().meta({ 'x-supported-lang': ['zh-CN', 'en-US'], deprecated: true })
90
- })
91
-
92
- const jsonSchema = parse(joiSchema)
93
- // Or parsing to OpenAPI schema through:
94
- // const openApiSchema = parse(joiSchema, 'open-api')
95
- ```
96
-
97
- ### definitions
98
-
99
- This should be a JSON object containing all schemas referenced by the `joiObj` definition. It's useful if **Named Link** case is used but the referenced schemas are provided externally. This object uses the schema id as key and schema itself as value.
100
-
101
- ### parserOptions
102
-
103
- * `includeSchemaDialect`: Default to be `false`. `true` makes the parsed schema containing `$schema` field automatically. Value of the `$schema` is default for different output JSON format if it's not provided in options together.
104
- * `logicalOpParser`: Refer to **Special Joi Operator Support** below for detail usage.
105
-
106
- ## Features
107
-
108
- ### Special Joi Operator Support
109
-
110
- * [Logical Relation Operator](./docs/logical_rel_support.md)
111
-
112
- ### Named Link
113
-
114
- 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.
115
-
116
- ### Conditional Expression
117
-
118
- 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.
119
-
120
- 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': false })`, the JSON schema conversion will use the Composition approach using `allOf` and/or `anyOf` instead.
121
-
122
- **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.
123
-
124
-
125
- ## YAML File Generation
126
-
127
- Most Joi specifications result in the expected OpenAPI schema.
128
-
129
- E.g.,
130
-
131
- ```js
132
- const joi = require('joi')
133
- const { dump } = require('js-yaml')
134
- const { writeFile } = require('fs/promises')
135
-
136
- const joiSchema = joi.object().keys({
137
- uuid: joi.string().uuid({ version: ['uuidv3', 'uuidv5'] }),
138
- nickName: joi.string().required().example('鹄思乱想').description('Hero Nickname').min(3).max(20).pattern(/^[a-z]+$/, { name: 'alpha', invert: true }),
139
- avatar: joi.string().required().uri(),
140
- email: joi.string().email(),
141
- ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
142
- hostname: joi.string().hostname().insensitive(),
143
- gender: joi.string().valid('Male', 'Female', '', null).default('Male'),
144
- isoDateString: joi.string().isoDate(),
145
- isoDurationString: joi.string().isoDuration(),
146
- birthday: joi.date().iso(),
147
- certificate: joi.binary().encoding('base64'),
148
- tags: joi.array().items(joi.string().required()).length(2),
149
- nested: joi.object().keys({
150
- key: joi.string()
151
- }).unknown(true)
152
- }).unknown(false)
153
-
154
- async function writeYAML(targetPath) {
155
- const openApiSchema = parse(joiSchema, 'open-api')
156
-
157
- const openApiSchemaYAML = dump(openApiSchema, {lineWidth: 120, noCompatMode: true})
158
- await writeFile(targetPath, openApiSchemaYAML)
159
- }
160
- ```
161
-
162
- results in
163
-
164
- ```yaml
165
- type: object
166
- required:
167
- - nickName
168
- - avatar
169
- properties:
170
- uuid:
171
- type: string
172
- format: uuid
173
- nickName:
174
- description: Hero Nickname
175
- type: string
176
- pattern: ^[a-z]+$
177
- minLength: 3,
178
- maxLength: 20,
179
- example: 鹄思乱想
180
- avatar:
181
- type: string
182
- format: uri
183
- email:
184
- type: string
185
- format: email
186
- ip:
187
- type: string
188
- oneOf:
189
- - format: ipv4
190
- - format: ipv6
191
- hostname:
192
- type: string
193
- format: hostname
194
- gender:
195
- type: string
196
- default: Male
197
- enum:
198
- - Male
199
- - Female
200
- - ''
201
- - null
202
- nullable: true
203
- isoDateString:
204
- type: string
205
- format: date-time
206
- isoDurationString:
207
- type: string
208
- format: duration
209
- birthday:
210
- type: string
211
- format: date-time
212
- certificate:
213
- type: string
214
- format: binary
215
- tags:
216
- type: array
217
- items:
218
- type: string
219
- minItems: 2
220
- maxItems: 2
221
- nested:
222
- type: object
223
- properties:
224
- key:
225
- type: string
226
- additionalProperties: true
227
- additionalProperties: false
228
- ```
229
-
230
- Some OpenAPI features are not supported directly in Joi, but Joi schemas can be annotated with `joi.any().meta({…})`
231
- to get them in the OpenAPI schema:
232
-
233
- ```js
234
-
235
-
236
- const joiSchema = joi.object().keys({
237
- deprecatedProperty: joi.string().meta({ deprecated: true }).required(),
238
- readOnlyProperty: joi.string().meta({ readOnly: true }),
239
- writeOnlyProperty: joi.string().meta({ writeOnly: true }),
240
- xMeta: joi.string().meta({ 'x-meta': 42 }),
241
- unknownMetaProperty: joi.string().meta({ unknownMeta: 42 })
242
- }).unknown(true)
243
-
244
-
245
- ```
246
-
247
- begets:
248
-
249
- ```yaml
250
- type: object
251
- required:
252
- - deprecatedProperty
253
- properties:
254
- deprecatedProperty:
255
- type: string
256
- deprecated: true
257
- readOnlyProperty:
258
- type: string
259
- readOnly: true
260
- writeOnlyProperty:
261
- type: string
262
- writeOnly: true
263
- xMeta:
264
- type: string
265
- x-meta: 42
266
- unknownMetaProperty:
267
- type: string
268
- # unknownMeta is not exported
269
- additionalProperties: true
270
- ```
271
-
272
- ## Browser support
273
- 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.
274
-
275
- ```typescript
276
- import Joi from 'joi/lib/index';
277
- ```
278
-
279
- ## TypeScript support
280
-
281
- ```typescript
282
- import joi from 'joi';
283
- import * as Joi2Json from 'joi-to-json';
284
- import parse from 'joi-to-json';
285
-
286
- const logicalOpParser: Joi2Json.LogicalOpParserOpts = {
287
- with: function (a) {}
288
- };
289
-
290
- parse(joi.string()); // Default call
291
- parse(joi.string(), 'json', {}, { logicalOpParser: false }); // Completely disable Logical Relation Operator
292
- parse(joi.string(), 'open-api', {}, { logicalOpParser }); // Partially override Logical Relation Operator
293
- ```
294
-
295
- ## Test
296
-
297
- >npm run test
298
-
299
- ### Categories of Test Cases
300
-
301
- * JOI Standard Representation Conversion
302
-
303
- `fixtures-conversion` folder stores each JOI version's supported keyword for different data types.
304
- 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`.
305
-
306
- Standard converted results are stored in `outputs-conversion` folder.
307
-
308
- `test/conversion.spec.js` Test Spec handles all supported JOI versions' conversion verificaiton.
309
-
310
- * JSON output format Conversion
311
-
312
- `outputs-parsers` folder stores different output formats base on the JOI Standard Representation in `outputs-conversion` folder.
313
- The Test Spec under `test/parser/` are responsible for these area.
314
-
315
- * JSON schema (Draft 07) Validity Unit Test
316
-
317
- 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.
318
-
319
-
320
- ### Test Debug Approach
321
-
322
- When running `conversion.spec.js`, below environment variables can be set:
323
-
324
- * `TEST_CONVERTOR`: control which version of joi to test.
325
- Example: `TEST_CONVERTOR=v17`
326
- * `TEST_CASE`: control which test cases to verify. Name of the test cases is the key of the return object in `fixtures-conversion`.
327
- Example: `TEST_CASE=conditional,match_all` verifies the case in `alternatives.js`
328
- * `TEST_UPDATE_CONVERSION_BASELINE`: control whether writes the baseline file generated from the latest-version convertor (Currently `v17`).
329
- It is activated when setting to `true`.
330
-
331
- When runninng Test Spec under `test/parser`, below environment variables can be set:
332
-
333
- * `TEST_CASE`: control which test cases to verify.
334
- 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`.
335
- * `TEST_UPDATE_PARSER_BASELINE`: control whether writes the baseline file for the corresponding parser.
336
- It is activated when setting to `true`. For example, when running `json.spec.js`, it writes the baseline files under `outputs-parsers/json`.
337
-
338
-
339
- ## Known Limitation
340
-
341
- * For `object.pattern` usage in Joi, `pattern` parameter can only be a regular expression now as I cannot convert Joi object to regex yet.
342
- * `If-Then-Else` style output is not applicable for the condition referring to the other field.
343
-
344
- ## License
345
-
346
- 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.
50
+
51
+ Its signature is `parse(joiObj, type = 'json', definitions = {}, parserOptions = {})`
52
+
53
+ ### Output Type
54
+
55
+ * `json` - Default. Stands for JSON Schema Draft 07
56
+ * `open-api` - Stands for OpenAPI 3.0 Schema - an extended subset of JSON Schema Specification Wright Draft 00 (aka Draft 5)
57
+ * `open-api-3.1` - Stands for OpenAPI 3.1 Schema - a superset of JSON Schema Specification Draft 2020-12
58
+ * `json-draft-04` - Stands for JSON Schema Draft 04
59
+ * `json-draft-2019-09` - Stands for JSON Schema Draft 2019-09
60
+
61
+ The output schema format are in [outputs](./outputs-parsers) under specific folders for different types.
62
+
63
+ Sample code is as below:
64
+
65
+ ```javascript
66
+ const parse = require('joi-to-json')
67
+
68
+ const joiSchema = joi.object().keys({
69
+ nickName: joi.string().required().min(3).max(20).example('鹄思乱想').description('Hero Nickname')
70
+ .regex(/^[a-z]+$/, { name: 'alpha', invert: true }),
71
+ avatar: joi.string().required().uri(),
72
+ email: joi.string().email(),
73
+ ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
74
+ hostname: joi.string().hostname().insensitive(),
75
+ gender: joi.string().valid('Male', 'Female', '').default('Male'),
76
+ height: joi.number().precision(2).positive().greater(0).less(200),
77
+ birthday: joi.date().iso(),
78
+ birthTime: joi.date().timestamp('unix'),
79
+ skills: joi.array().items(joi.alternatives().try(
80
+ joi.string(),
81
+ joi.object().keys({
82
+ name: joi.string().example('teleport').alphanum().lowercase().required().description('Skill Name'),
83
+ level: joi.number().integer().min(10).max(100).default(50).multiple(10).example(10).description('Skill Level')
84
+ })
85
+ ).required()).min(1).max(3).unique().description('Skills'),
86
+ tags: joi.array().items(joi.string().required()).length(2),
87
+ retired: joi.boolean().truthy('yes').falsy('no').insensitive(false),
88
+ certificate: joi.binary().encoding('base64'),
89
+ notes: joi.any().meta({ 'x-supported-lang': ['zh-CN', 'en-US'], deprecated: true })
90
+ })
91
+
92
+ const jsonSchema = parse(joiSchema)
93
+ // Or parsing to OpenAPI schema through:
94
+ // const openApiSchema = parse(joiSchema, 'open-api')
95
+ ```
96
+
97
+ ### definitions
98
+
99
+ This should be a JSON object containing all schemas referenced by the `joiObj` definition. It's useful if **Named Link** case is used but the referenced schemas are provided externally. This object uses the schema id as key and schema itself as value.
100
+
101
+ ### parserOptions
102
+
103
+ * `includeSchemaDialect`: Default to be `false`. `true` makes the parsed schema containing `$schema` field automatically. Value of the `$schema` is default for different output JSON format if it's not provided in options together.
104
+ * `logicalOpParser`: Refer to **Special Joi Operator Support** below for detail usage.
105
+
106
+ ## Features
107
+
108
+ ### Special Joi Operator Support
109
+
110
+ * [Logical Relation Operator](./docs/logical_rel_support.md)
111
+
112
+ ### Named Link
113
+
114
+ 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.
115
+
116
+ ### Conditional Expression
117
+
118
+ 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.
119
+
120
+ 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': false })`, the JSON schema conversion will use the Composition approach using `allOf` and/or `anyOf` instead.
121
+
122
+ **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.
123
+
124
+
125
+ ## YAML File Generation
126
+
127
+ Most Joi specifications result in the expected OpenAPI schema.
128
+
129
+ E.g.,
130
+
131
+ ```js
132
+ const joi = require('joi')
133
+ const { dump } = require('js-yaml')
134
+ const { writeFile } = require('fs/promises')
135
+
136
+ const joiSchema = joi.object().keys({
137
+ uuid: joi.string().uuid({ version: ['uuidv3', 'uuidv5'] }),
138
+ nickName: joi.string().required().example('鹄思乱想').description('Hero Nickname').min(3).max(20).pattern(/^[a-z]+$/, { name: 'alpha', invert: true }),
139
+ avatar: joi.string().required().uri(),
140
+ email: joi.string().email(),
141
+ ip: joi.string().ip({ version: ['ipv4', 'ipv6'] }),
142
+ hostname: joi.string().hostname().insensitive(),
143
+ gender: joi.string().valid('Male', 'Female', '', null).default('Male'),
144
+ isoDateString: joi.string().isoDate(),
145
+ isoDurationString: joi.string().isoDuration(),
146
+ birthday: joi.date().iso(),
147
+ certificate: joi.binary().encoding('base64'),
148
+ tags: joi.array().items(joi.string().required()).length(2),
149
+ nested: joi.object().keys({
150
+ key: joi.string()
151
+ }).unknown(true)
152
+ }).unknown(false)
153
+
154
+ async function writeYAML(targetPath) {
155
+ const openApiSchema = parse(joiSchema, 'open-api')
156
+
157
+ const openApiSchemaYAML = dump(openApiSchema, {lineWidth: 120, noCompatMode: true})
158
+ await writeFile(targetPath, openApiSchemaYAML)
159
+ }
160
+ ```
161
+
162
+ results in
163
+
164
+ ```yaml
165
+ type: object
166
+ required:
167
+ - nickName
168
+ - avatar
169
+ properties:
170
+ uuid:
171
+ type: string
172
+ format: uuid
173
+ nickName:
174
+ description: Hero Nickname
175
+ type: string
176
+ pattern: ^[a-z]+$
177
+ minLength: 3,
178
+ maxLength: 20,
179
+ example: 鹄思乱想
180
+ avatar:
181
+ type: string
182
+ format: uri
183
+ email:
184
+ type: string
185
+ format: email
186
+ ip:
187
+ type: string
188
+ oneOf:
189
+ - format: ipv4
190
+ - format: ipv6
191
+ hostname:
192
+ type: string
193
+ format: hostname
194
+ gender:
195
+ type: string
196
+ default: Male
197
+ enum:
198
+ - Male
199
+ - Female
200
+ - ''
201
+ - null
202
+ nullable: true
203
+ isoDateString:
204
+ type: string
205
+ format: date-time
206
+ isoDurationString:
207
+ type: string
208
+ format: duration
209
+ birthday:
210
+ type: string
211
+ format: date-time
212
+ certificate:
213
+ type: string
214
+ format: binary
215
+ tags:
216
+ type: array
217
+ items:
218
+ type: string
219
+ minItems: 2
220
+ maxItems: 2
221
+ nested:
222
+ type: object
223
+ properties:
224
+ key:
225
+ type: string
226
+ additionalProperties: true
227
+ additionalProperties: false
228
+ ```
229
+
230
+ Some OpenAPI features are not supported directly in Joi, but Joi schemas can be annotated with `joi.any().meta({…})`
231
+ to get them in the OpenAPI schema:
232
+
233
+ ```js
234
+
235
+
236
+ const joiSchema = joi.object().keys({
237
+ deprecatedProperty: joi.string().meta({ deprecated: true }).required(),
238
+ readOnlyProperty: joi.string().meta({ readOnly: true }),
239
+ writeOnlyProperty: joi.string().meta({ writeOnly: true }),
240
+ xMeta: joi.string().meta({ 'x-meta': 42 }),
241
+ unknownMetaProperty: joi.string().meta({ unknownMeta: 42 })
242
+ }).unknown(true)
243
+
244
+
245
+ ```
246
+
247
+ begets:
248
+
249
+ ```yaml
250
+ type: object
251
+ required:
252
+ - deprecatedProperty
253
+ properties:
254
+ deprecatedProperty:
255
+ type: string
256
+ deprecated: true
257
+ readOnlyProperty:
258
+ type: string
259
+ readOnly: true
260
+ writeOnlyProperty:
261
+ type: string
262
+ writeOnly: true
263
+ xMeta:
264
+ type: string
265
+ x-meta: 42
266
+ unknownMetaProperty:
267
+ type: string
268
+ # unknownMeta is not exported
269
+ additionalProperties: true
270
+ ```
271
+
272
+ ## Browser support
273
+ 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.
274
+
275
+ ```typescript
276
+ import Joi from 'joi/lib/index';
277
+ ```
278
+
279
+ ## TypeScript support
280
+
281
+ ```typescript
282
+ import joi from 'joi';
283
+ import * as Joi2Json from 'joi-to-json';
284
+ import parse from 'joi-to-json';
285
+
286
+ const logicalOpParser: Joi2Json.LogicalOpParserOpts = {
287
+ with: function (a) {}
288
+ };
289
+
290
+ parse(joi.string()); // Default call
291
+ parse(joi.string(), 'json', {}, { logicalOpParser: false }); // Completely disable Logical Relation Operator
292
+ parse(joi.string(), 'open-api', {}, { logicalOpParser }); // Partially override Logical Relation Operator
293
+ ```
294
+
295
+ ## Test
296
+
297
+ >npm run test
298
+
299
+ ### Categories of Test Cases
300
+
301
+ * JOI Standard Representation Conversion
302
+
303
+ `fixtures-conversion` folder stores each JOI version's supported keyword for different data types.
304
+ 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`.
305
+
306
+ Standard converted results are stored in `outputs-conversion` folder.
307
+
308
+ `test/conversion.spec.js` Test Spec handles all supported JOI versions' conversion verificaiton.
309
+
310
+ * JSON output format Conversion
311
+
312
+ `outputs-parsers` folder stores different output formats base on the JOI Standard Representation in `outputs-conversion` folder.
313
+ The Test Spec under `test/parser/` are responsible for these area.
314
+
315
+ * JSON schema (Draft 07) Validity Unit Test
316
+
317
+ 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.
318
+
319
+
320
+ ### Test Debug Approach
321
+
322
+ When running `conversion.spec.js`, below environment variables can be set:
323
+
324
+ * `TEST_CONVERTOR`: control which version of joi to test.
325
+ Example: `TEST_CONVERTOR=v17`
326
+ * `TEST_CASE`: control which test cases to verify. Name of the test cases is the key of the return object in `fixtures-conversion`.
327
+ Example: `TEST_CASE=conditional,match_all` verifies the case in `alternatives.js`
328
+ * `TEST_UPDATE_CONVERSION_BASELINE`: control whether writes the baseline file generated from the latest-version convertor (Currently `v17`).
329
+ It is activated when setting to `true`.
330
+
331
+ When runninng Test Spec under `test/parser`, below environment variables can be set:
332
+
333
+ * `TEST_CASE`: control which test cases to verify.
334
+ 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`.
335
+ * `TEST_UPDATE_PARSER_BASELINE`: control whether writes the baseline file for the corresponding parser.
336
+ It is activated when setting to `true`. For example, when running `json.spec.js`, it writes the baseline files under `outputs-parsers/json`.
337
+
338
+
339
+ ## Known Limitation
340
+
341
+ * For `object.pattern` usage in Joi, `pattern` parameter can only be a regular expression now as I cannot convert Joi object to regex yet.
342
+ * `If-Then-Else` style output is not applicable for the condition referring to the other field.
343
+
344
+ ## License
345
+
346
+ MIT