@gitbook/react-openapi 1.1.9 → 1.1.10

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 (60) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/InteractiveSection.jsx +7 -6
  3. package/dist/OpenAPICodeSample.d.ts +2 -2
  4. package/dist/OpenAPICodeSample.jsx +3 -8
  5. package/dist/OpenAPICodeSampleInteractive.jsx +31 -19
  6. package/dist/OpenAPICodeSampleSelector.d.ts +15 -0
  7. package/dist/OpenAPICodeSampleSelector.jsx +49 -0
  8. package/dist/OpenAPIExample.d.ts +34 -0
  9. package/dist/OpenAPIExample.jsx +103 -0
  10. package/dist/OpenAPIOperation.d.ts +2 -2
  11. package/dist/OpenAPIOperation.jsx +3 -7
  12. package/dist/OpenAPIPath.d.ts +10 -2
  13. package/dist/OpenAPIPath.jsx +9 -4
  14. package/dist/OpenAPIResponseExample.d.ts +2 -2
  15. package/dist/OpenAPIResponseExample.jsx +4 -95
  16. package/dist/OpenAPISchema.jsx +18 -5
  17. package/dist/OpenAPISchemaName.jsx +2 -7
  18. package/dist/OpenAPISecurities.jsx +6 -6
  19. package/dist/OpenAPISelect.d.ts +15 -0
  20. package/dist/OpenAPISelect.jsx +32 -0
  21. package/dist/OpenAPITabs.jsx +9 -9
  22. package/dist/context.d.ts +54 -0
  23. package/dist/context.js +11 -0
  24. package/dist/generateSchemaExample.js +4 -0
  25. package/dist/getOrCreateStoreByKey.d.ts +10 -0
  26. package/dist/getOrCreateStoreByKey.js +20 -0
  27. package/dist/index.d.ts +1 -1
  28. package/dist/resolveOpenAPIOperation.js +10 -5
  29. package/dist/schemas/OpenAPISchemas.d.ts +5 -6
  30. package/dist/schemas/OpenAPISchemas.jsx +45 -38
  31. package/dist/schemas/resolveOpenAPISchemas.d.ts +4 -3
  32. package/dist/schemas/resolveOpenAPISchemas.js +0 -1
  33. package/dist/tsconfig.build.tsbuildinfo +1 -1
  34. package/dist/types.d.ts +32 -26
  35. package/package.json +1 -1
  36. package/src/InteractiveSection.tsx +10 -8
  37. package/src/OpenAPICodeSample.tsx +8 -15
  38. package/src/OpenAPICodeSampleInteractive.tsx +43 -26
  39. package/src/OpenAPICodeSampleSelector.tsx +87 -0
  40. package/src/OpenAPIExample.tsx +129 -0
  41. package/src/OpenAPIOperation.tsx +6 -10
  42. package/src/OpenAPIPath.tsx +23 -6
  43. package/src/OpenAPIResponseExample.tsx +13 -118
  44. package/src/OpenAPISchema.tsx +26 -9
  45. package/src/OpenAPISchemaName.tsx +2 -8
  46. package/src/OpenAPISecurities.tsx +22 -9
  47. package/src/OpenAPISelect.tsx +70 -0
  48. package/src/OpenAPITabs.tsx +9 -9
  49. package/src/context.ts +64 -0
  50. package/src/generateSchemaExample.test.ts +1020 -0
  51. package/src/generateSchemaExample.ts +5 -0
  52. package/src/getOrCreateStoreByKey.ts +35 -0
  53. package/src/index.ts +1 -1
  54. package/src/resolveOpenAPIOperation.ts +14 -3
  55. package/src/schemas/OpenAPISchemas.tsx +75 -70
  56. package/src/schemas/resolveOpenAPISchemas.ts +4 -5
  57. package/src/types.ts +36 -29
  58. package/dist/useSyncedTabsGlobalState.d.ts +0 -10
  59. package/dist/useSyncedTabsGlobalState.js +0 -20
  60. 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
+ });