@gitbook/react-openapi 1.1.9 → 1.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.
Files changed (177) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/InteractiveSection.d.ts +4 -0
  3. package/dist/InteractiveSection.jsx +14 -13
  4. package/dist/OpenAPICodeSample.d.ts +3 -2
  5. package/dist/OpenAPICodeSample.jsx +8 -12
  6. package/dist/OpenAPICodeSampleInteractive.d.ts +3 -0
  7. package/dist/OpenAPICodeSampleInteractive.jsx +37 -49
  8. package/dist/OpenAPICodeSampleSelector.d.ts +14 -0
  9. package/dist/OpenAPICodeSampleSelector.jsx +44 -0
  10. package/dist/OpenAPICopyButton.d.ts +2 -0
  11. package/dist/OpenAPICopyButton.jsx +5 -2
  12. package/dist/OpenAPIDisclosure.d.ts +4 -3
  13. package/dist/OpenAPIDisclosure.jsx +8 -11
  14. package/dist/OpenAPIDisclosureGroup.d.ts +7 -3
  15. package/dist/OpenAPIDisclosureGroup.jsx +18 -18
  16. package/dist/OpenAPIExample.d.ts +16 -0
  17. package/dist/OpenAPIExample.jsx +36 -0
  18. package/dist/OpenAPIMediaType.d.ts +21 -0
  19. package/dist/OpenAPIMediaType.jsx +61 -0
  20. package/dist/OpenAPIOperation.d.ts +3 -2
  21. package/dist/OpenAPIOperation.jsx +9 -72
  22. package/dist/OpenAPIOperationDescription.d.ts +9 -0
  23. package/dist/OpenAPIOperationDescription.jsx +22 -0
  24. package/dist/OpenAPIOperationStability.d.ts +9 -0
  25. package/dist/OpenAPIOperationStability.jsx +27 -0
  26. package/dist/OpenAPIPath.d.ts +12 -2
  27. package/dist/OpenAPIPath.jsx +10 -4
  28. package/dist/OpenAPIRequestBody.d.ts +3 -1
  29. package/dist/OpenAPIRequestBody.jsx +4 -3
  30. package/dist/OpenAPIResponse.d.ts +1 -1
  31. package/dist/OpenAPIResponse.jsx +1 -1
  32. package/dist/OpenAPIResponseExample.d.ts +4 -3
  33. package/dist/OpenAPIResponseExample.jsx +24 -154
  34. package/dist/OpenAPIResponseExampleContent.d.ts +19 -0
  35. package/dist/OpenAPIResponseExampleContent.jsx +57 -0
  36. package/dist/OpenAPIResponses.d.ts +1 -1
  37. package/dist/OpenAPIResponses.jsx +49 -36
  38. package/dist/OpenAPISchema.d.ts +1 -1
  39. package/dist/OpenAPISchema.jsx +121 -20
  40. package/dist/OpenAPISchemaName.d.ts +2 -0
  41. package/dist/OpenAPISchemaName.jsx +21 -17
  42. package/dist/OpenAPISchemaServer.d.ts +1 -1
  43. package/dist/OpenAPISecurities.d.ts +2 -1
  44. package/dist/OpenAPISecurities.jsx +11 -10
  45. package/dist/OpenAPISelect.d.ts +22 -0
  46. package/dist/OpenAPISelect.jsx +43 -0
  47. package/dist/OpenAPISpec.d.ts +3 -2
  48. package/dist/OpenAPISpec.jsx +11 -9
  49. package/dist/OpenAPITabs.jsx +9 -9
  50. package/dist/OpenAPIWebhook.d.ts +10 -0
  51. package/dist/OpenAPIWebhook.jsx +23 -0
  52. package/dist/OpenAPIWebhookExample.d.ts +6 -0
  53. package/dist/OpenAPIWebhookExample.jsx +41 -0
  54. package/dist/ScalarApiButton.d.ts +2 -0
  55. package/dist/ScalarApiButton.jsx +4 -3
  56. package/dist/StaticSection.d.ts +4 -1
  57. package/dist/StaticSection.jsx +13 -4
  58. package/dist/code-samples.js +57 -39
  59. package/dist/common/OpenAPIColumnSpec.d.ts +6 -0
  60. package/dist/common/OpenAPIColumnSpec.jsx +20 -0
  61. package/dist/common/OpenAPIOperationDescription.d.ts +6 -0
  62. package/dist/common/OpenAPIOperationDescription.jsx +19 -0
  63. package/dist/common/OpenAPIStability.d.ts +4 -0
  64. package/dist/common/OpenAPIStability.jsx +15 -0
  65. package/dist/common/OpenAPISummary.d.ts +6 -0
  66. package/dist/common/OpenAPISummary.jsx +30 -0
  67. package/dist/context.d.ts +75 -0
  68. package/dist/context.js +43 -0
  69. package/dist/generateSchemaExample.js +4 -0
  70. package/dist/getOrCreateStoreByKey.d.ts +10 -0
  71. package/dist/getOrCreateStoreByKey.js +19 -0
  72. package/dist/index.d.ts +5 -1
  73. package/dist/index.js +3 -0
  74. package/dist/resolveOpenAPIOperation.js +10 -5
  75. package/dist/resolveOpenAPIWebhook.d.ts +11 -0
  76. package/dist/resolveOpenAPIWebhook.js +127 -0
  77. package/dist/schemas/OpenAPISchemas.d.ts +5 -6
  78. package/dist/schemas/OpenAPISchemas.jsx +52 -49
  79. package/dist/schemas/resolveOpenAPISchemas.d.ts +4 -3
  80. package/dist/schemas/resolveOpenAPISchemas.js +0 -1
  81. package/dist/stringifyOpenAPI.d.ts +1 -1
  82. package/dist/stringifyOpenAPI.js +6 -3
  83. package/dist/translate.d.ts +10 -0
  84. package/dist/translate.jsx +75 -0
  85. package/dist/translations/de.d.ts +37 -0
  86. package/dist/translations/de.js +37 -0
  87. package/dist/translations/en.d.ts +37 -0
  88. package/dist/translations/en.js +37 -0
  89. package/dist/translations/es.d.ts +37 -0
  90. package/dist/translations/es.js +37 -0
  91. package/dist/translations/fr.d.ts +37 -0
  92. package/dist/translations/fr.js +37 -0
  93. package/dist/translations/index.d.ts +341 -0
  94. package/dist/translations/index.js +27 -0
  95. package/dist/translations/ja.d.ts +37 -0
  96. package/dist/translations/ja.js +37 -0
  97. package/dist/translations/nl.d.ts +37 -0
  98. package/dist/translations/nl.js +37 -0
  99. package/dist/translations/no.d.ts +37 -0
  100. package/dist/translations/no.js +37 -0
  101. package/dist/translations/pt-br.d.ts +37 -0
  102. package/dist/translations/pt-br.js +37 -0
  103. package/dist/translations/types.d.ts +5 -0
  104. package/dist/translations/types.js +1 -0
  105. package/dist/translations/zh.d.ts +37 -0
  106. package/dist/translations/zh.js +37 -0
  107. package/dist/tsconfig.build.tsbuildinfo +1 -1
  108. package/dist/types.d.ts +12 -48
  109. package/dist/util/example.d.ts +35 -0
  110. package/dist/util/example.jsx +103 -0
  111. package/dist/utils.d.ts +18 -0
  112. package/dist/utils.js +57 -0
  113. package/package.json +3 -3
  114. package/src/InteractiveSection.tsx +22 -18
  115. package/src/OpenAPICodeSample.tsx +26 -15
  116. package/src/OpenAPICodeSampleInteractive.tsx +67 -70
  117. package/src/OpenAPICodeSampleSelector.tsx +94 -0
  118. package/src/OpenAPICopyButton.tsx +7 -2
  119. package/src/OpenAPIDisclosure.tsx +20 -22
  120. package/src/OpenAPIDisclosureGroup.tsx +40 -22
  121. package/src/OpenAPIExample.tsx +55 -0
  122. package/src/OpenAPIMediaType.tsx +139 -0
  123. package/src/OpenAPIOperation.tsx +11 -104
  124. package/src/OpenAPIOperationDescription.tsx +34 -0
  125. package/src/OpenAPIOperationStability.tsx +39 -0
  126. package/src/OpenAPIPath.tsx +26 -6
  127. package/src/OpenAPIRequestBody.tsx +9 -4
  128. package/src/OpenAPIResponse.tsx +2 -2
  129. package/src/OpenAPIResponseExample.tsx +41 -215
  130. package/src/OpenAPIResponseExampleContent.tsx +123 -0
  131. package/src/OpenAPIResponses.tsx +83 -62
  132. package/src/OpenAPISchema.test.ts +80 -0
  133. package/src/OpenAPISchema.tsx +149 -25
  134. package/src/OpenAPISchemaName.tsx +28 -19
  135. package/src/OpenAPISchemaServer.tsx +1 -1
  136. package/src/OpenAPISecurities.tsx +46 -12
  137. package/src/OpenAPISelect.tsx +96 -0
  138. package/src/OpenAPISpec.tsx +21 -10
  139. package/src/OpenAPITabs.tsx +9 -9
  140. package/src/OpenAPIWebhook.tsx +33 -0
  141. package/src/OpenAPIWebhookExample.tsx +60 -0
  142. package/src/ScalarApiButton.tsx +6 -6
  143. package/src/StaticSection.tsx +37 -5
  144. package/src/code-samples.test.ts +3 -1
  145. package/src/code-samples.ts +67 -54
  146. package/src/common/OpenAPIColumnSpec.tsx +31 -0
  147. package/src/common/OpenAPIOperationDescription.tsx +31 -0
  148. package/src/common/OpenAPIStability.tsx +23 -0
  149. package/src/common/OpenAPISummary.tsx +45 -0
  150. package/src/context.ts +99 -0
  151. package/src/generateSchemaExample.test.ts +1020 -0
  152. package/src/generateSchemaExample.ts +5 -0
  153. package/src/getOrCreateStoreByKey.ts +33 -0
  154. package/src/index.ts +5 -1
  155. package/src/resolveOpenAPIOperation.ts +14 -3
  156. package/src/resolveOpenAPIWebhook.ts +99 -0
  157. package/src/schemas/OpenAPISchemas.tsx +76 -71
  158. package/src/schemas/resolveOpenAPISchemas.ts +4 -5
  159. package/src/stringifyOpenAPI.ts +11 -3
  160. package/src/translate.tsx +80 -0
  161. package/src/translations/de.ts +37 -0
  162. package/src/translations/en.ts +37 -0
  163. package/src/translations/es.ts +37 -0
  164. package/src/translations/fr.ts +37 -0
  165. package/src/translations/index.ts +33 -0
  166. package/src/translations/ja.ts +37 -0
  167. package/src/translations/nl.ts +37 -0
  168. package/src/translations/no.ts +37 -0
  169. package/src/translations/pt-br.ts +37 -0
  170. package/src/translations/types.ts +7 -0
  171. package/src/translations/zh.ts +37 -0
  172. package/src/types.ts +11 -46
  173. package/src/util/example.tsx +129 -0
  174. package/src/utils.ts +67 -0
  175. package/dist/useSyncedTabsGlobalState.d.ts +0 -10
  176. package/dist/useSyncedTabsGlobalState.js +0 -20
  177. package/src/useSyncedTabsGlobalState.ts +0 -35
@@ -0,0 +1,1020 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+
3
+ import type { OpenAPIV3 } from '@gitbook/openapi-parser';
4
+ import { generateSchemaExample } from './generateSchemaExample';
5
+
6
+ describe('generateSchemaExample', () => {
7
+ it('sets example values', () => {
8
+ expect(
9
+ generateSchemaExample({
10
+ example: 10,
11
+ })
12
+ ).toBe(10);
13
+ });
14
+
15
+ it('uses first example, if multiple are configured', () => {
16
+ expect(
17
+ generateSchemaExample({
18
+ examples: [10],
19
+ })
20
+ ).toBe(10);
21
+ });
22
+
23
+ it('takes the first enum as example', () => {
24
+ expect(
25
+ generateSchemaExample({
26
+ enum: ['available', 'pending', 'sold'],
27
+ })
28
+ ).toBe('available');
29
+ });
30
+
31
+ it('uses "text" as a fallback for strings', () => {
32
+ expect(
33
+ generateSchemaExample({
34
+ type: 'string',
35
+ })
36
+ ).toBe('text');
37
+ });
38
+
39
+ it('only includes required attributes and attributes with example values', () => {
40
+ expect(
41
+ generateSchemaExample(
42
+ {
43
+ type: 'object',
44
+ required: ['first_name'],
45
+ properties: {
46
+ first_name: {
47
+ type: 'string',
48
+ },
49
+ last_name: {
50
+ type: 'string',
51
+ required: true,
52
+ },
53
+ position: {
54
+ type: 'string',
55
+ examples: ['Developer'],
56
+ },
57
+ description: {
58
+ type: 'string',
59
+ example: 'A developer',
60
+ },
61
+ age: {
62
+ type: 'number',
63
+ },
64
+ },
65
+ },
66
+ {
67
+ omitEmptyAndOptionalProperties: true,
68
+ }
69
+ )
70
+ ).toStrictEqual({
71
+ first_name: 'text',
72
+ last_name: 'text',
73
+ position: 'Developer',
74
+ description: 'A developer',
75
+ });
76
+ });
77
+
78
+ it('includes every available attributes', () => {
79
+ expect(
80
+ generateSchemaExample(
81
+ {
82
+ type: 'object',
83
+ required: ['first_name'],
84
+ properties: {
85
+ first_name: {
86
+ type: 'string',
87
+ },
88
+ last_name: {
89
+ type: 'string',
90
+ required: true,
91
+ },
92
+ position: {
93
+ type: 'string',
94
+ examples: ['Developer'],
95
+ },
96
+ description: {
97
+ type: 'string',
98
+ example: 'A developer',
99
+ },
100
+ age: {
101
+ type: 'number',
102
+ },
103
+ },
104
+ },
105
+ {
106
+ omitEmptyAndOptionalProperties: false,
107
+ }
108
+ )
109
+ ).toStrictEqual({
110
+ first_name: 'text',
111
+ last_name: 'text',
112
+ position: 'Developer',
113
+ description: 'A developer',
114
+ age: 1,
115
+ });
116
+ });
117
+
118
+ it('uses example value for first type in non-null union types', () => {
119
+ expect(
120
+ generateSchemaExample({
121
+ type: ['string', 'number'],
122
+ } as OpenAPIV3.BaseSchemaObject)
123
+ ).toBe('text');
124
+ });
125
+
126
+ it('uses null for nullable union types', () => {
127
+ expect(
128
+ generateSchemaExample({
129
+ type: ['string', 'null'],
130
+ } as OpenAPIV3.BaseSchemaObject)
131
+ ).toBeNull();
132
+ });
133
+
134
+ it('sets example values', () => {
135
+ expect(
136
+ generateSchemaExample({
137
+ example: 10,
138
+ })
139
+ ).toBe(10);
140
+ });
141
+
142
+ it('goes through properties recursively with objects', () => {
143
+ expect(
144
+ generateSchemaExample({
145
+ type: 'object',
146
+ properties: {
147
+ category: {
148
+ type: 'object',
149
+ properties: {
150
+ id: {
151
+ example: 1,
152
+ },
153
+ name: {
154
+ example: 'Dogs',
155
+ },
156
+ attributes: {
157
+ type: 'object',
158
+ properties: {
159
+ size: {
160
+ enum: ['small', 'medium', 'large'],
161
+ },
162
+ },
163
+ },
164
+ },
165
+ },
166
+ },
167
+ })
168
+ ).toMatchObject({
169
+ category: {
170
+ id: 1,
171
+ name: 'Dogs',
172
+ attributes: {
173
+ size: 'small',
174
+ },
175
+ },
176
+ });
177
+ });
178
+
179
+ it('goes through properties recursively with arrays', () => {
180
+ expect(
181
+ generateSchemaExample({
182
+ type: 'object',
183
+ properties: {
184
+ tags: {
185
+ type: 'array',
186
+ items: {
187
+ type: 'object',
188
+ properties: {
189
+ id: {
190
+ example: 1,
191
+ },
192
+ },
193
+ },
194
+ },
195
+ },
196
+ })
197
+ ).toMatchObject({
198
+ tags: [
199
+ {
200
+ id: 1,
201
+ },
202
+ ],
203
+ });
204
+ });
205
+
206
+ it('uses empty [] as a fallback for arrays', () => {
207
+ expect(
208
+ generateSchemaExample({
209
+ type: 'object',
210
+ properties: {
211
+ title: {
212
+ type: 'array',
213
+ },
214
+ },
215
+ })
216
+ ).toMatchObject({
217
+ title: [],
218
+ });
219
+ });
220
+
221
+ // it('returns emails as an example value', () => {
222
+ // const result = generateSchemaExample({
223
+ // type: 'string',
224
+ // format: 'email',
225
+ // });
226
+
227
+ // function isEmail(text: string) {
228
+ // return !!text.match(/^.+@.+\..+$/);
229
+ // }
230
+
231
+ // expect(isEmail(result)).toBe(true);
232
+ // });
233
+
234
+ it('uses true as a fallback for booleans', () => {
235
+ expect(
236
+ generateSchemaExample({
237
+ type: 'boolean',
238
+ })
239
+ ).toBe(true);
240
+ });
241
+
242
+ it('uses 1 as a fallback for integers', () => {
243
+ expect(
244
+ generateSchemaExample({
245
+ type: 'integer',
246
+ })
247
+ ).toBe(1);
248
+ });
249
+
250
+ it('returns an array if the schema type is array', () => {
251
+ expect(
252
+ generateSchemaExample({
253
+ type: 'array',
254
+ })
255
+ ).toMatchObject([]);
256
+ });
257
+
258
+ it('uses array example values', () => {
259
+ expect(
260
+ generateSchemaExample({
261
+ type: 'array',
262
+ example: ['foobar'],
263
+ items: {
264
+ type: 'string',
265
+ },
266
+ })
267
+ ).toMatchObject(['foobar']);
268
+ });
269
+
270
+ it('uses specified object as array default', () => {
271
+ expect(
272
+ generateSchemaExample({
273
+ type: 'array',
274
+ items: {
275
+ type: 'object',
276
+ properties: {
277
+ foo: {
278
+ type: 'number',
279
+ },
280
+ bar: {
281
+ type: 'string',
282
+ },
283
+ },
284
+ },
285
+ })
286
+ ).toMatchObject([
287
+ {
288
+ foo: 1,
289
+ bar: 'text',
290
+ },
291
+ ]);
292
+ });
293
+
294
+ it('uses the first example in object anyOf', () => {
295
+ expect(
296
+ generateSchemaExample({
297
+ type: 'object',
298
+ anyOf: [
299
+ {
300
+ type: 'object',
301
+ properties: {
302
+ foo: { type: 'number' },
303
+ },
304
+ },
305
+ {
306
+ type: 'object',
307
+ properties: {
308
+ bar: { type: 'string' },
309
+ },
310
+ },
311
+ ],
312
+ })
313
+ ).toMatchObject({ foo: 1 });
314
+ });
315
+
316
+ it('uses the first example in object oneOf', () => {
317
+ expect(
318
+ generateSchemaExample({
319
+ type: 'object',
320
+ oneOf: [
321
+ {
322
+ type: 'object',
323
+ properties: {
324
+ foo: { type: 'number' },
325
+ },
326
+ },
327
+ {
328
+ type: 'object',
329
+ properties: {
330
+ bar: { type: 'string' },
331
+ },
332
+ },
333
+ ],
334
+ })
335
+ ).toMatchObject({ foo: 1 });
336
+ });
337
+
338
+ it('uses the first example in object anyOf when type is not defined', () => {
339
+ expect(
340
+ generateSchemaExample({
341
+ anyOf: [
342
+ {
343
+ type: 'object',
344
+ properties: {
345
+ foo: { type: 'number' },
346
+ },
347
+ },
348
+ {
349
+ type: 'object',
350
+ properties: {
351
+ bar: { type: 'string' },
352
+ },
353
+ },
354
+ ],
355
+ })
356
+ ).toMatchObject({ foo: 1 });
357
+ });
358
+
359
+ it('uses the first example in object oneOf when type is not defined', () => {
360
+ expect(
361
+ generateSchemaExample({
362
+ oneOf: [
363
+ {
364
+ type: 'object',
365
+ properties: {
366
+ foo: { type: 'number' },
367
+ },
368
+ },
369
+ {
370
+ type: 'object',
371
+ properties: {
372
+ bar: { type: 'string' },
373
+ },
374
+ },
375
+ ],
376
+ })
377
+ ).toMatchObject({ foo: 1 });
378
+ });
379
+
380
+ it('uses all examples in object allOf', () => {
381
+ expect(
382
+ generateSchemaExample({
383
+ allOf: [
384
+ {
385
+ type: 'object',
386
+ properties: {
387
+ foo: { type: 'number' },
388
+ },
389
+ },
390
+ {
391
+ type: 'object',
392
+ properties: {
393
+ bar: { type: 'string' },
394
+ },
395
+ },
396
+ ],
397
+ })
398
+ ).toMatchObject({ foo: 1, bar: 'text' });
399
+ });
400
+
401
+ it('merges allOf items in arrays', () => {
402
+ expect(
403
+ generateSchemaExample({
404
+ type: 'array',
405
+ items: {
406
+ allOf: [
407
+ {
408
+ type: 'object',
409
+ properties: {
410
+ foobar: { type: 'string' },
411
+ foo: { type: 'number' },
412
+ },
413
+ },
414
+ {
415
+ type: 'object',
416
+ properties: {
417
+ bar: { type: 'string' },
418
+ },
419
+ },
420
+ ],
421
+ },
422
+ })
423
+ ).toMatchObject([{ foobar: 'text', foo: 1, bar: 'text' }]);
424
+ });
425
+
426
+ it('handles array items with allOf containing objects', () => {
427
+ expect(
428
+ generateSchemaExample({
429
+ type: 'array',
430
+ items: {
431
+ allOf: [
432
+ {
433
+ type: 'object',
434
+ properties: {
435
+ id: { type: 'number', example: 1 },
436
+ },
437
+ },
438
+ {
439
+ type: 'object',
440
+ properties: {
441
+ name: { type: 'string', example: 'test' },
442
+ },
443
+ },
444
+ ],
445
+ },
446
+ })
447
+ ).toMatchObject([
448
+ {
449
+ id: 1,
450
+ name: 'test',
451
+ },
452
+ ]);
453
+ });
454
+
455
+ it('uses the first example in array anyOf', () => {
456
+ expect(
457
+ generateSchemaExample({
458
+ type: 'array',
459
+ items: {
460
+ anyOf: [
461
+ {
462
+ type: 'string',
463
+ example: 'foobar',
464
+ },
465
+ {
466
+ type: 'string',
467
+ example: 'barfoo',
468
+ },
469
+ ],
470
+ },
471
+ })
472
+ ).toMatchObject(['foobar']);
473
+ });
474
+
475
+ it('uses one example in array oneOf', () => {
476
+ expect(
477
+ generateSchemaExample({
478
+ type: 'array',
479
+ items: {
480
+ oneOf: [
481
+ {
482
+ type: 'string',
483
+ example: 'foobar',
484
+ },
485
+ {
486
+ type: 'string',
487
+ example: 'barfoo',
488
+ },
489
+ ],
490
+ },
491
+ })
492
+ ).toMatchObject(['foobar']);
493
+ });
494
+
495
+ it('uses all examples in array allOf', () => {
496
+ expect(
497
+ generateSchemaExample({
498
+ type: 'array',
499
+ items: {
500
+ allOf: [
501
+ {
502
+ type: 'string',
503
+ example: 'foobar',
504
+ },
505
+ {
506
+ type: 'string',
507
+ example: 'barfoo',
508
+ },
509
+ ],
510
+ },
511
+ })
512
+ ).toMatchObject(['foobar', 'barfoo']);
513
+ });
514
+
515
+ it('uses 1 as the default for a number', () => {
516
+ expect(
517
+ generateSchemaExample({
518
+ type: 'number',
519
+ })
520
+ ).toBe(1);
521
+ });
522
+
523
+ it('uses min as the default for a number', () => {
524
+ expect(
525
+ generateSchemaExample({
526
+ type: 'number',
527
+ min: 200,
528
+ })
529
+ ).toBe(200);
530
+ });
531
+
532
+ it('returns plaintext', () => {
533
+ expect(
534
+ generateSchemaExample({
535
+ type: 'string',
536
+ example: 'foobar',
537
+ })
538
+ ).toEqual('foobar');
539
+ });
540
+
541
+ it('converts a whole schema to an example response', () => {
542
+ const schema: OpenAPIV3.SchemaObject = {
543
+ required: ['name', 'photoUrls'],
544
+ type: 'object',
545
+ properties: {
546
+ id: {
547
+ type: 'integer',
548
+ format: 'int64',
549
+ example: 10,
550
+ },
551
+ name: {
552
+ type: 'string',
553
+ example: 'doggie',
554
+ },
555
+ category: {
556
+ type: 'object',
557
+ properties: {
558
+ id: {
559
+ type: 'integer',
560
+ format: 'int64',
561
+ example: 1,
562
+ },
563
+ name: {
564
+ type: 'string',
565
+ example: 'Dogs',
566
+ },
567
+ },
568
+ xml: {
569
+ name: 'category',
570
+ },
571
+ },
572
+ photoUrls: {
573
+ type: 'array',
574
+ xml: {
575
+ wrapped: true,
576
+ },
577
+ items: {
578
+ type: 'string',
579
+ xml: {
580
+ name: 'photoUrl',
581
+ },
582
+ },
583
+ },
584
+ tags: {
585
+ type: 'array',
586
+ xml: {
587
+ wrapped: true,
588
+ },
589
+ items: {
590
+ type: 'object',
591
+ properties: {
592
+ id: {
593
+ type: 'integer',
594
+ format: 'int64',
595
+ },
596
+ name: {
597
+ type: 'string',
598
+ },
599
+ },
600
+ xml: {
601
+ name: 'tag',
602
+ },
603
+ },
604
+ },
605
+ status: {
606
+ type: 'string',
607
+ description: 'pet status in the store',
608
+ enum: ['available', 'pending', 'sold'],
609
+ },
610
+ },
611
+ xml: {
612
+ name: 'pet',
613
+ },
614
+ };
615
+
616
+ expect(generateSchemaExample(schema)).toMatchObject({
617
+ id: 10,
618
+ name: 'doggie',
619
+ category: {
620
+ id: 1,
621
+ name: 'Dogs',
622
+ },
623
+ photoUrls: ['text'],
624
+ tags: [
625
+ {
626
+ id: 1,
627
+ name: 'text',
628
+ },
629
+ ],
630
+ status: 'available',
631
+ });
632
+ });
633
+
634
+ it('outputs XML', () => {
635
+ expect(
636
+ generateSchemaExample(
637
+ {
638
+ type: 'object',
639
+ properties: {
640
+ id: {
641
+ example: 1,
642
+ xml: {
643
+ name: 'foo',
644
+ },
645
+ },
646
+ },
647
+ },
648
+ { xml: true }
649
+ )
650
+ ).toMatchObject({
651
+ foo: 1,
652
+ });
653
+ });
654
+
655
+ it('add XML wrappers where needed', () => {
656
+ expect(
657
+ generateSchemaExample(
658
+ {
659
+ type: 'object',
660
+ properties: {
661
+ photoUrls: {
662
+ type: 'array',
663
+ xml: {
664
+ wrapped: true,
665
+ },
666
+ items: {
667
+ type: 'string',
668
+ example: 'https://example.com',
669
+ xml: {
670
+ name: 'photoUrl',
671
+ },
672
+ },
673
+ },
674
+ },
675
+ },
676
+ { xml: true }
677
+ )
678
+ ).toMatchObject({
679
+ photoUrls: [{ photoUrl: 'https://example.com' }],
680
+ });
681
+ });
682
+
683
+ it('doesn’t wrap items when not needed', () => {
684
+ expect(
685
+ generateSchemaExample(
686
+ {
687
+ type: 'object',
688
+ properties: {
689
+ photoUrls: {
690
+ type: 'array',
691
+ items: {
692
+ type: 'string',
693
+ example: 'https://example.com',
694
+ xml: {
695
+ name: 'photoUrl',
696
+ },
697
+ },
698
+ },
699
+ },
700
+ },
701
+ { xml: true }
702
+ )
703
+ ).toMatchObject({
704
+ photoUrls: ['https://example.com'],
705
+ });
706
+ });
707
+
708
+ it('use the first item of oneOf', () => {
709
+ expect(
710
+ generateSchemaExample({
711
+ oneOf: [
712
+ {
713
+ maxLength: 255,
714
+ type: 'string',
715
+ },
716
+ {
717
+ type: 'null',
718
+ },
719
+ ],
720
+ })
721
+ ).toBe('text');
722
+ });
723
+
724
+ it('works with allOf', () => {
725
+ expect(
726
+ generateSchemaExample({
727
+ allOf: [
728
+ {
729
+ type: 'string',
730
+ },
731
+ ],
732
+ })
733
+ ).toBe('text');
734
+ });
735
+
736
+ it('uses all schemas in allOf', () => {
737
+ expect(
738
+ generateSchemaExample({
739
+ allOf: [
740
+ {
741
+ type: 'object',
742
+ properties: {
743
+ id: {
744
+ example: 10,
745
+ },
746
+ },
747
+ },
748
+ {
749
+ type: 'object',
750
+ properties: {
751
+ title: {
752
+ example: 'Foobar',
753
+ },
754
+ },
755
+ },
756
+ ],
757
+ })
758
+ ).toMatchObject({
759
+ id: 10,
760
+ title: 'Foobar',
761
+ });
762
+ });
763
+
764
+ it('returns null for unknown types', () => {
765
+ expect(
766
+ generateSchemaExample({
767
+ type: 'fantasy',
768
+ } as OpenAPIV3.BaseSchemaObject)
769
+ ).toBe(null);
770
+ });
771
+
772
+ it('returns readOnly attributes by default', () => {
773
+ expect(
774
+ generateSchemaExample({
775
+ example: 'foobar',
776
+ readOnly: true,
777
+ })
778
+ ).toBe('foobar');
779
+ });
780
+
781
+ it('returns readOnly attributes in read mode', () => {
782
+ expect(
783
+ generateSchemaExample(
784
+ {
785
+ example: 'foobar',
786
+ readOnly: true,
787
+ },
788
+ {
789
+ mode: 'read',
790
+ }
791
+ )
792
+ ).toBe('foobar');
793
+ });
794
+
795
+ it('doesn’t return readOnly attributes in write mode', () => {
796
+ expect(
797
+ generateSchemaExample(
798
+ {
799
+ example: 'foobar',
800
+ readOnly: true,
801
+ },
802
+ {
803
+ mode: 'write',
804
+ }
805
+ )
806
+ ).toBeUndefined();
807
+ });
808
+
809
+ it('returns writeOnly attributes by default', () => {
810
+ expect(
811
+ generateSchemaExample({
812
+ example: 'foobar',
813
+ writeOnly: true,
814
+ })
815
+ ).toBe('foobar');
816
+ });
817
+
818
+ it('returns writeOnly attributes in write mode', () => {
819
+ expect(
820
+ generateSchemaExample(
821
+ {
822
+ example: 'foobar',
823
+ writeOnly: true,
824
+ },
825
+ {
826
+ mode: 'write',
827
+ }
828
+ )
829
+ ).toBe('foobar');
830
+ });
831
+
832
+ it('doesn’t return writeOnly attributes in read mode', () => {
833
+ expect(
834
+ generateSchemaExample(
835
+ {
836
+ example: 'foobar',
837
+ writeOnly: true,
838
+ },
839
+ {
840
+ mode: 'read',
841
+ }
842
+ )
843
+ ).toBeUndefined();
844
+ });
845
+
846
+ it('allows any additonalProperty', () => {
847
+ expect(
848
+ generateSchemaExample({
849
+ type: 'object',
850
+ additionalProperties: {},
851
+ })
852
+ ).toMatchObject({
853
+ ANY_ADDITIONAL_PROPERTY: 'anything',
854
+ });
855
+
856
+ expect(
857
+ generateSchemaExample({
858
+ type: 'object',
859
+ additionalProperties: true,
860
+ })
861
+ ).toMatchObject({
862
+ ANY_ADDITIONAL_PROPERTY: 'anything',
863
+ });
864
+ });
865
+
866
+ it('adds an additionalProperty with specific types', () => {
867
+ expect(
868
+ generateSchemaExample({
869
+ type: 'object',
870
+ additionalProperties: {
871
+ type: 'integer',
872
+ },
873
+ })
874
+ ).toMatchObject({
875
+ ANY_ADDITIONAL_PROPERTY: 1,
876
+ });
877
+
878
+ expect(
879
+ generateSchemaExample({
880
+ type: 'object',
881
+ additionalProperties: {
882
+ type: 'boolean',
883
+ },
884
+ })
885
+ ).toMatchObject({
886
+ ANY_ADDITIONAL_PROPERTY: true,
887
+ });
888
+
889
+ expect(
890
+ generateSchemaExample({
891
+ type: 'object',
892
+ additionalProperties: {
893
+ type: 'string',
894
+ },
895
+ })
896
+ ).toMatchObject({
897
+ ANY_ADDITIONAL_PROPERTY: 'text',
898
+ });
899
+
900
+ expect(
901
+ generateSchemaExample({
902
+ type: 'object',
903
+ additionalProperties: {
904
+ type: 'object',
905
+ properties: {
906
+ foo: {
907
+ type: 'string',
908
+ },
909
+ },
910
+ },
911
+ })
912
+ ).toMatchObject({
913
+ ANY_ADDITIONAL_PROPERTY: {
914
+ foo: 'text',
915
+ },
916
+ });
917
+ });
918
+
919
+ it('works with anyOf', () => {
920
+ expect(
921
+ generateSchemaExample({
922
+ title: 'Foo',
923
+ type: 'object',
924
+ anyOf: [
925
+ {
926
+ type: 'object',
927
+ required: ['a'],
928
+ properties: {
929
+ a: {
930
+ type: 'integer',
931
+ format: 'int32',
932
+ },
933
+ },
934
+ },
935
+ {
936
+ type: 'object',
937
+ required: ['b'],
938
+ properties: {
939
+ b: {
940
+ type: 'string',
941
+ },
942
+ },
943
+ },
944
+ ],
945
+ required: ['c'],
946
+ properties: {
947
+ c: {
948
+ type: 'boolean',
949
+ },
950
+ },
951
+ })
952
+ ).toStrictEqual({
953
+ a: 1,
954
+ c: true,
955
+ });
956
+ });
957
+
958
+ it('deals with circular references', () => {
959
+ const schema = {
960
+ type: 'object',
961
+ properties: {
962
+ foobar: {},
963
+ },
964
+ } satisfies OpenAPIV3.SchemaObject;
965
+
966
+ // Create a circular reference
967
+ schema.properties.foobar = schema;
968
+
969
+ // 10 levels deep, that’s enough. It should return null then.
970
+ expect(generateSchemaExample(schema)).toStrictEqual({
971
+ foobar: {
972
+ foobar: {
973
+ foobar: {
974
+ foobar: {
975
+ foobar: {
976
+ foobar: '[Circular Reference]',
977
+ },
978
+ },
979
+ },
980
+ },
981
+ },
982
+ });
983
+ });
984
+
985
+ it('handles patternProperties', () => {
986
+ expect(
987
+ generateSchemaExample({
988
+ type: 'object',
989
+ patternProperties: {
990
+ '^(.*)$': {
991
+ type: 'object',
992
+ properties: {
993
+ dataId: {
994
+ type: 'string',
995
+ },
996
+ link: {
997
+ anyOf: [
998
+ {
999
+ format: 'uri',
1000
+ type: 'string',
1001
+ example: 'https://example.com',
1002
+ },
1003
+ {
1004
+ type: 'null',
1005
+ },
1006
+ ],
1007
+ },
1008
+ },
1009
+ required: ['dataId', 'link'],
1010
+ },
1011
+ },
1012
+ })
1013
+ ).toStrictEqual({
1014
+ '^(.*)$': {
1015
+ dataId: 'text',
1016
+ link: 'https://example.com',
1017
+ },
1018
+ });
1019
+ });
1020
+ });