@scalar/json-magic 0.8.2 → 0.8.4

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 (84) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/bundle/index.d.ts +1 -0
  3. package/dist/bundle/index.d.ts.map +1 -1
  4. package/dist/bundle/index.js.map +1 -1
  5. package/dist/bundle/plugins/browser.js.map +1 -1
  6. package/dist/bundle/plugins/node.d.ts +1 -1
  7. package/dist/bundle/plugins/node.js +1 -1
  8. package/dist/bundle/plugins/node.js.map +1 -1
  9. package/dist/dereference/index.d.ts.map +1 -1
  10. package/dist/dereference/index.js.map +2 -2
  11. package/dist/diff/index.d.ts +1 -1
  12. package/dist/diff/index.d.ts.map +1 -1
  13. package/dist/diff/index.js +1 -1
  14. package/dist/diff/index.js.map +2 -2
  15. package/dist/helpers/escape-json-pointer.d.ts +1 -1
  16. package/dist/helpers/escape-json-pointer.js.map +1 -1
  17. package/dist/magic-proxy/index.d.ts.map +1 -1
  18. package/dist/magic-proxy/index.js.map +2 -2
  19. package/dist/magic-proxy/proxy.d.ts +0 -1
  20. package/dist/magic-proxy/proxy.d.ts.map +1 -1
  21. package/dist/magic-proxy/proxy.js +1 -2
  22. package/dist/magic-proxy/proxy.js.map +2 -2
  23. package/package.json +12 -13
  24. package/.turbo/turbo-build.log +0 -10
  25. package/esbuild.ts +0 -15
  26. package/src/bundle/bundle.test.ts +0 -2917
  27. package/src/bundle/bundle.ts +0 -916
  28. package/src/bundle/create-limiter.test.ts +0 -28
  29. package/src/bundle/create-limiter.ts +0 -52
  30. package/src/bundle/index.ts +0 -3
  31. package/src/bundle/plugins/browser.ts +0 -4
  32. package/src/bundle/plugins/fetch-urls/index.test.ts +0 -141
  33. package/src/bundle/plugins/fetch-urls/index.ts +0 -105
  34. package/src/bundle/plugins/node.ts +0 -5
  35. package/src/bundle/plugins/parse-json/index.test.ts +0 -24
  36. package/src/bundle/plugins/parse-json/index.ts +0 -32
  37. package/src/bundle/plugins/parse-yaml/index.test.ts +0 -26
  38. package/src/bundle/plugins/parse-yaml/index.ts +0 -34
  39. package/src/bundle/plugins/read-files/index.test.ts +0 -36
  40. package/src/bundle/plugins/read-files/index.ts +0 -58
  41. package/src/bundle/value-generator.test.ts +0 -165
  42. package/src/bundle/value-generator.ts +0 -143
  43. package/src/dereference/dereference.test.ts +0 -142
  44. package/src/dereference/dereference.ts +0 -84
  45. package/src/dereference/index.ts +0 -2
  46. package/src/diff/apply.test.ts +0 -262
  47. package/src/diff/apply.ts +0 -83
  48. package/src/diff/diff.test.ts +0 -328
  49. package/src/diff/diff.ts +0 -93
  50. package/src/diff/index.test.ts +0 -150
  51. package/src/diff/index.ts +0 -5
  52. package/src/diff/merge.test.ts +0 -1109
  53. package/src/diff/merge.ts +0 -136
  54. package/src/diff/trie.test.ts +0 -30
  55. package/src/diff/trie.ts +0 -113
  56. package/src/diff/utils.test.ts +0 -169
  57. package/src/diff/utils.ts +0 -111
  58. package/src/helpers/convert-to-local-ref.test.ts +0 -211
  59. package/src/helpers/convert-to-local-ref.ts +0 -43
  60. package/src/helpers/escape-json-pointer.test.ts +0 -13
  61. package/src/helpers/escape-json-pointer.ts +0 -8
  62. package/src/helpers/get-schemas.test.ts +0 -356
  63. package/src/helpers/get-schemas.ts +0 -80
  64. package/src/helpers/get-segments-from-path.test.ts +0 -17
  65. package/src/helpers/get-segments-from-path.ts +0 -17
  66. package/src/helpers/get-value-by-path.test.ts +0 -338
  67. package/src/helpers/get-value-by-path.ts +0 -44
  68. package/src/helpers/is-json-object.ts +0 -31
  69. package/src/helpers/is-object.test.ts +0 -27
  70. package/src/helpers/is-object.ts +0 -4
  71. package/src/helpers/is-yaml.ts +0 -18
  72. package/src/helpers/json-path-utils.test.ts +0 -57
  73. package/src/helpers/json-path-utils.ts +0 -50
  74. package/src/helpers/normalize.test.ts +0 -92
  75. package/src/helpers/normalize.ts +0 -35
  76. package/src/helpers/unescape-json-pointer.test.ts +0 -23
  77. package/src/helpers/unescape-json-pointer.ts +0 -9
  78. package/src/magic-proxy/index.ts +0 -2
  79. package/src/magic-proxy/proxy.test.ts +0 -1987
  80. package/src/magic-proxy/proxy.ts +0 -323
  81. package/src/types.ts +0 -1
  82. package/tsconfig.build.json +0 -12
  83. package/tsconfig.json +0 -16
  84. package/vite.config.ts +0 -8
@@ -1,1109 +0,0 @@
1
- import { merge } from '@/diff/merge'
2
- import { diff } from '@/diff/diff'
3
- import { describe, expect, test } from 'vitest'
4
-
5
- const deepClone = <T extends object>(obj: T) => JSON.parse(JSON.stringify(obj)) as T
6
-
7
- type DeepPartial<T> = T extends object
8
- ? {
9
- [P in keyof T]?: DeepPartial<T[P]>
10
- }
11
- : T
12
-
13
- describe('mergeDiff', () => {
14
- test('should correctly merge the diffs and get conflicting changes', () => {
15
- const baseDoc = {
16
- openapi: '3.0.0',
17
- info: {
18
- title: 'Simple API',
19
- description: 'A small OpenAPI specification example',
20
- version: '1.0.0',
21
- },
22
- }
23
-
24
- const doc1 = {
25
- ...baseDoc,
26
- info: {
27
- ...baseDoc.info,
28
- title: 'New title',
29
- },
30
- }
31
-
32
- const clonedBase = deepClone<Partial<typeof baseDoc>>(baseDoc)
33
- const deletedInformation = clonedBase.info
34
- delete clonedBase.info
35
-
36
- const doc2 = {
37
- ...clonedBase,
38
- }
39
-
40
- expect(merge(diff(baseDoc, doc1), diff(baseDoc, doc2))).toEqual({
41
- diffs: [],
42
- conflicts: [
43
- [
44
- [
45
- {
46
- path: ['info', 'title'],
47
- changes: doc1.info.title,
48
- type: 'update',
49
- },
50
- ],
51
- [{ path: ['info'], changes: deletedInformation, type: 'delete' }],
52
- ],
53
- ],
54
- })
55
-
56
- expect(merge(diff(baseDoc, doc2), diff(baseDoc, doc1))).toEqual({
57
- diffs: [],
58
- conflicts: [
59
- [
60
- [{ path: ['info'], changes: deletedInformation, type: 'delete' }],
61
- [
62
- {
63
- path: ['info', 'title'],
64
- changes: doc1.info.title,
65
- type: 'update',
66
- },
67
- ],
68
- ],
69
- ],
70
- })
71
- })
72
-
73
- test('should correctly merge the diffs and get deeply nested conflicting changes', () => {
74
- const baseDoc = {
75
- openapi: '3.0.0',
76
- info: {
77
- title: 'Simple API',
78
- description: 'A small OpenAPI specification example',
79
- version: '1.0.0',
80
- },
81
- paths: {
82
- '/users': {
83
- get: {
84
- summary: 'Get a list of users',
85
- operationId: 'getUsers',
86
- responses: {
87
- '200': {
88
- description: 'A list of users',
89
- content: {
90
- 'application/json': {
91
- schema: {
92
- type: 'array',
93
- items: {
94
- type: 'object',
95
- properties: {
96
- id: { type: 'integer' },
97
- name: { type: 'string' },
98
- },
99
- },
100
- },
101
- },
102
- },
103
- },
104
- },
105
- },
106
- },
107
- },
108
- }
109
-
110
- const doc1 = {
111
- ...baseDoc,
112
- paths: {
113
- ...baseDoc.paths,
114
- '/users': {
115
- ...baseDoc.paths?.['/users'],
116
- delete: {
117
- summary: 'Delete all users',
118
- operationId: 'delete',
119
- responses: {
120
- '200': {
121
- description: 'All users deleted successfully',
122
- },
123
- },
124
- },
125
- },
126
- '/users/{id}': {
127
- get: {
128
- summary: 'Get a user by ID',
129
- operationId: 'getUserById',
130
- parameters: [
131
- {
132
- name: 'id',
133
- in: 'path',
134
- required: true,
135
- schema: { type: 'integer' },
136
- },
137
- ],
138
- responses: {
139
- '200': {
140
- description: 'User details',
141
- content: {
142
- 'application/json': {
143
- schema: {
144
- type: 'object',
145
- properties: {
146
- id: { type: 'integer' },
147
- name: { type: 'string' },
148
- },
149
- },
150
- },
151
- },
152
- },
153
- '404': {
154
- description: 'User not found',
155
- },
156
- },
157
- },
158
- },
159
- },
160
- }
161
-
162
- const clonedBase = deepClone<DeepPartial<typeof baseDoc>>(baseDoc)
163
- const deletedDescription = clonedBase.info?.description
164
- delete clonedBase.info?.description
165
-
166
- const doc2 = {
167
- ...clonedBase,
168
- paths: {
169
- ...clonedBase.paths,
170
- '/users': {
171
- ...clonedBase.paths?.['/users'],
172
- delete: {
173
- summary: 'Delete all users',
174
- operationId: 'deleteUsers',
175
- responses: {
176
- '200': {
177
- description: 'All users deleted successfully',
178
- },
179
- },
180
- },
181
- },
182
- },
183
- }
184
-
185
- expect(merge(diff(baseDoc, doc1), diff(baseDoc, doc2))).toEqual({
186
- diffs: [
187
- {
188
- path: ['paths', '/users/{id}'],
189
- changes: doc1.paths['/users/{id}'],
190
- type: 'add',
191
- },
192
- {
193
- path: ['info', 'description'],
194
- changes: deletedDescription,
195
- type: 'delete',
196
- },
197
- ],
198
- conflicts: [
199
- [
200
- [
201
- {
202
- path: ['paths', '/users', 'delete'],
203
- changes: doc1.paths['/users'].delete,
204
- type: 'add',
205
- },
206
- ],
207
- [
208
- {
209
- path: ['paths', '/users', 'delete'],
210
- changes: doc2.paths['/users'].delete,
211
- type: 'add',
212
- },
213
- ],
214
- ],
215
- ],
216
- })
217
-
218
- expect(merge(diff(baseDoc, doc2), diff(baseDoc, doc1))).toEqual({
219
- diffs: [
220
- {
221
- path: ['info', 'description'],
222
- changes: deletedDescription,
223
- type: 'delete',
224
- },
225
- {
226
- path: ['paths', '/users/{id}'],
227
- changes: doc1.paths['/users/{id}'],
228
- type: 'add',
229
- },
230
- ],
231
- conflicts: [
232
- [
233
- [
234
- {
235
- path: ['paths', '/users', 'delete'],
236
- changes: doc2.paths['/users'].delete,
237
- type: 'add',
238
- },
239
- ],
240
- [
241
- {
242
- path: ['paths', '/users', 'delete'],
243
- changes: doc1.paths['/users'].delete,
244
- type: 'add',
245
- },
246
- ],
247
- ],
248
- ],
249
- })
250
- })
251
-
252
- test('non conflicting addition of paths', () => {
253
- const base = {
254
- openapi: '3.0.0',
255
- info: {
256
- title: 'Sample API',
257
- version: '1.0',
258
- },
259
- paths: {
260
- '/users': {
261
- get: {
262
- summary: 'Get users',
263
- responses: {
264
- 200: {
265
- description: 'Successful response',
266
- },
267
- },
268
- },
269
- },
270
- },
271
- }
272
-
273
- const doc1 = {
274
- ...base,
275
- paths: {
276
- ...base.paths,
277
- '/products': {
278
- get: {
279
- summary: 'Get products',
280
- responses: {
281
- 200: {
282
- description: 'Successful response',
283
- },
284
- },
285
- },
286
- },
287
- },
288
- }
289
-
290
- const doc2 = {
291
- ...base,
292
- paths: {
293
- ...base.paths,
294
- '/orders': {
295
- get: {
296
- summary: 'Get orders',
297
- responses: {
298
- 200: {
299
- description: 'Successful response',
300
- },
301
- },
302
- },
303
- },
304
- },
305
- }
306
-
307
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
308
- diffs: [
309
- {
310
- path: ['paths', '/products'],
311
- changes: doc1.paths['/products'],
312
- type: 'add',
313
- },
314
- {
315
- path: ['paths', '/orders'],
316
- changes: doc2.paths['/orders'],
317
- type: 'add',
318
- },
319
- ],
320
- conflicts: [],
321
- })
322
-
323
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
324
- diffs: [
325
- {
326
- path: ['paths', '/orders'],
327
- changes: doc2.paths['/orders'],
328
- type: 'add',
329
- },
330
- {
331
- path: ['paths', '/products'],
332
- changes: doc1.paths['/products'],
333
- type: 'add',
334
- },
335
- ],
336
- conflicts: [],
337
- })
338
- })
339
-
340
- test('updates in the same path', () => {
341
- const base = {
342
- openapi: '3.0.0',
343
- info: {
344
- title: 'Sample API',
345
- version: '1.0',
346
- },
347
- paths: {
348
- '/users': {
349
- get: {
350
- summary: 'Get users',
351
- responses: {
352
- 200: {
353
- description: 'Successful response',
354
- },
355
- },
356
- },
357
- },
358
- },
359
- }
360
-
361
- const doc1 = {
362
- ...base,
363
- paths: {
364
- ...base.paths,
365
- '/users': {
366
- get: {
367
- summary: 'Retrieve all users',
368
- responses: {
369
- 200: {
370
- description: 'Successful response',
371
- },
372
- },
373
- },
374
- },
375
- },
376
- }
377
-
378
- const doc2 = {
379
- ...base,
380
- paths: {
381
- ...base.paths,
382
- '/users': {
383
- get: {
384
- summary: 'List all users',
385
- responses: {
386
- 200: {
387
- description: 'Successful response',
388
- },
389
- },
390
- },
391
- },
392
- },
393
- }
394
-
395
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
396
- diffs: [],
397
- conflicts: [
398
- [
399
- [
400
- {
401
- path: ['paths', '/users', 'get', 'summary'],
402
- changes: doc1.paths['/users'].get.summary,
403
- type: 'update',
404
- },
405
- ],
406
- [
407
- {
408
- path: ['paths', '/users', 'get', 'summary'],
409
- changes: doc2.paths['/users'].get.summary,
410
- type: 'update',
411
- },
412
- ],
413
- ],
414
- ],
415
- })
416
-
417
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
418
- diffs: [],
419
- conflicts: [
420
- [
421
- [
422
- {
423
- path: ['paths', '/users', 'get', 'summary'],
424
- changes: doc2.paths['/users'].get.summary,
425
- type: 'update',
426
- },
427
- ],
428
- [
429
- {
430
- path: ['paths', '/users', 'get', 'summary'],
431
- changes: doc1.paths['/users'].get.summary,
432
- type: 'update',
433
- },
434
- ],
435
- ],
436
- ],
437
- })
438
- })
439
-
440
- test('removing and modifying the same path', () => {
441
- const base = {
442
- openapi: '3.0.0',
443
- info: {
444
- title: 'Sample API',
445
- version: '1.0',
446
- },
447
- paths: {
448
- '/users': {
449
- get: {
450
- summary: 'Get users',
451
- responses: {
452
- 200: {
453
- description: 'Successful response',
454
- },
455
- },
456
- },
457
- },
458
- },
459
- }
460
-
461
- const baseClone = deepClone<DeepPartial<typeof base>>(base)
462
- const removePaths = baseClone.paths?.['/users']?.get?.summary
463
- delete baseClone.paths?.['/users']?.get?.summary
464
-
465
- const doc1 = {
466
- ...baseClone,
467
- }
468
-
469
- const doc2 = {
470
- ...base,
471
- paths: {
472
- ...base.paths,
473
- '/users': {
474
- ...base.paths['/users'],
475
- get: {
476
- ...base.paths['/users'].get,
477
- summary: 'Get all registered users',
478
- },
479
- },
480
- },
481
- }
482
-
483
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
484
- diffs: [],
485
- conflicts: [
486
- [
487
- [
488
- {
489
- path: ['paths', '/users', 'get', 'summary'],
490
- changes: removePaths,
491
- type: 'delete',
492
- },
493
- ],
494
- [
495
- {
496
- path: ['paths', '/users', 'get', 'summary'],
497
- changes: doc2.paths['/users'].get.summary,
498
- type: 'update',
499
- },
500
- ],
501
- ],
502
- ],
503
- })
504
-
505
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
506
- diffs: [],
507
- conflicts: [
508
- [
509
- [
510
- {
511
- path: ['paths', '/users', 'get', 'summary'],
512
- changes: doc2.paths['/users'].get.summary,
513
- type: 'update',
514
- },
515
- ],
516
- [
517
- {
518
- path: ['paths', '/users', 'get', 'summary'],
519
- changes: removePaths,
520
- type: 'delete',
521
- },
522
- ],
523
- ],
524
- ],
525
- })
526
- })
527
-
528
- test('delete parent node and inner children node should only keep the higher level change', () => {
529
- const base = {
530
- openapi: '3.0.0',
531
- info: {
532
- title: 'Sample API',
533
- version: '1.0',
534
- },
535
- paths: {
536
- '/users': {
537
- get: {
538
- summary: 'Get users',
539
- responses: {
540
- 200: {
541
- description: 'Successful response',
542
- },
543
- },
544
- },
545
- },
546
- },
547
- }
548
-
549
- const doc1 = deepClone<DeepPartial<typeof base>>(base)
550
- delete doc1.paths?.['/users']?.get?.summary
551
-
552
- const doc2 = deepClone<DeepPartial<typeof base>>(base)
553
- const removePaths2 = doc2.paths?.['/users']
554
- delete doc2.paths?.['/users']
555
-
556
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
557
- diffs: [
558
- {
559
- path: ['paths', '/users'],
560
- changes: removePaths2,
561
- type: 'delete',
562
- },
563
- ],
564
- conflicts: [],
565
- })
566
-
567
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
568
- diffs: [
569
- {
570
- path: ['paths', '/users'],
571
- changes: removePaths2,
572
- type: 'delete',
573
- },
574
- ],
575
- conflicts: [],
576
- })
577
- })
578
-
579
- test('deleting the same path on both documents should not resolve in a conflict', () => {
580
- const base = {
581
- openapi: '3.0.0',
582
- info: {
583
- title: 'Sample API',
584
- version: '1.0',
585
- },
586
- paths: {
587
- '/users': {
588
- get: {
589
- summary: 'Get users',
590
- responses: {
591
- 200: {
592
- description: 'Successful response',
593
- },
594
- },
595
- },
596
- },
597
- },
598
- }
599
-
600
- const doc1 = deepClone<DeepPartial<typeof base>>(base)
601
- const doc2 = deepClone<DeepPartial<typeof base>>(base)
602
-
603
- delete doc1.paths?.['/users']?.get
604
- delete doc2.paths?.['/users']?.get
605
-
606
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
607
- diffs: [
608
- {
609
- type: 'delete',
610
- changes: base.paths['/users'].get,
611
- path: ['paths', '/users', 'get'],
612
- },
613
- ],
614
- conflicts: [],
615
- })
616
-
617
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
618
- diffs: [
619
- {
620
- type: 'delete',
621
- changes: base.paths['/users'].get,
622
- path: ['paths', '/users', 'get'],
623
- },
624
- ],
625
- conflicts: [],
626
- })
627
- })
628
-
629
- test('adding the same key should not resolve in a conflict', () => {
630
- const base = {
631
- openapi: '3.0.0',
632
- info: {
633
- title: 'Sample API',
634
- version: '1.0',
635
- },
636
- }
637
-
638
- const doc1 = {
639
- ...base,
640
- info: {
641
- ...base.info,
642
- description: 'Provides a way to interact with the playground',
643
- },
644
- }
645
-
646
- const doc2 = {
647
- ...base,
648
- info: {
649
- ...base.info,
650
- description: doc1.info.description,
651
- },
652
- }
653
-
654
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
655
- diffs: [
656
- {
657
- type: 'add',
658
- changes: doc1.info.description,
659
- path: ['info', 'description'],
660
- },
661
- ],
662
- conflicts: [],
663
- })
664
-
665
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
666
- diffs: [
667
- {
668
- type: 'add',
669
- changes: doc1.info.description,
670
- path: ['info', 'description'],
671
- },
672
- ],
673
- conflicts: [],
674
- })
675
- })
676
-
677
- test('adding the same object should not resolve in a conflict', () => {
678
- const base = {
679
- openapi: '3.0.0',
680
- }
681
-
682
- const doc1 = {
683
- ...base,
684
- info: {
685
- title: 'Sample API',
686
- version: '1.0',
687
- },
688
- }
689
-
690
- const doc2 = {
691
- ...base,
692
- info: {
693
- title: 'Sample API',
694
- version: '1.0',
695
- },
696
- }
697
-
698
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
699
- diffs: [
700
- {
701
- type: 'add',
702
- changes: doc1.info,
703
- path: ['info'],
704
- },
705
- ],
706
- conflicts: [],
707
- })
708
-
709
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
710
- diffs: [
711
- {
712
- type: 'add',
713
- changes: doc1.info,
714
- path: ['info'],
715
- },
716
- ],
717
- conflicts: [],
718
- })
719
- })
720
-
721
- test("adding similar object that can't be merged in the same path should result in a conflict", () => {
722
- const base = {
723
- openapi: '3.0.0',
724
- }
725
-
726
- const doc1 = {
727
- ...base,
728
- info: {
729
- title: 'Sample API',
730
- version: '1.0',
731
- },
732
- }
733
-
734
- const doc2 = {
735
- ...base,
736
- info: {
737
- title: 'Sample',
738
- version: '1.0',
739
- },
740
- }
741
-
742
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
743
- diffs: [],
744
- conflicts: [
745
- [
746
- [
747
- {
748
- type: 'add',
749
- changes: doc1.info,
750
- path: ['info'],
751
- },
752
- ],
753
- [
754
- {
755
- type: 'add',
756
- changes: doc2.info,
757
- path: ['info'],
758
- },
759
- ],
760
- ],
761
- ],
762
- })
763
-
764
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
765
- diffs: [],
766
- conflicts: [
767
- [
768
- [
769
- {
770
- type: 'add',
771
- changes: doc2.info,
772
- path: ['info'],
773
- },
774
- ],
775
- [
776
- {
777
- type: 'add',
778
- changes: doc1.info,
779
- path: ['info'],
780
- },
781
- ],
782
- ],
783
- ],
784
- })
785
- })
786
-
787
- test('adding the same value on the same path should not result in a conflict', () => {
788
- const base = {
789
- openapi: '3.0.0',
790
- info: {
791
- title: 'Sample API',
792
- },
793
- }
794
-
795
- const doc1 = {
796
- ...base,
797
- info: {
798
- ...base.info,
799
- version: '1.0',
800
- },
801
- }
802
-
803
- const doc2 = {
804
- ...base,
805
- info: {
806
- ...base.info,
807
- version: '1.0',
808
- },
809
- }
810
-
811
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
812
- diffs: [
813
- {
814
- type: 'add',
815
- changes: doc1.info.version,
816
- path: ['info', 'version'],
817
- },
818
- ],
819
- conflicts: [],
820
- })
821
-
822
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
823
- diffs: [
824
- {
825
- type: 'add',
826
- changes: doc1.info.version,
827
- path: ['info', 'version'],
828
- },
829
- ],
830
- conflicts: [],
831
- })
832
- })
833
-
834
- test('should return multiple one to many conflicts for the related conflicts', () => {
835
- const base = {
836
- openapi: '3.0.0',
837
- info: {
838
- title: 'Sample API',
839
- version: '1.0',
840
- },
841
- paths: {
842
- '/users': {
843
- get: {
844
- summary: 'Get users',
845
- responses: {
846
- 200: {
847
- description: 'Successful response',
848
- },
849
- },
850
- },
851
- },
852
- '/pets': {
853
- get: {
854
- summary: 'Get pets',
855
- responses: {
856
- 200: {
857
- description: 'Successful response',
858
- },
859
- },
860
- },
861
- },
862
- },
863
- }
864
-
865
- const doc1 = deepClone<DeepPartial<typeof base>>(base)
866
- const deletedUsersChanges = doc1.paths?.['/users']
867
- const deletedPetsChanges = doc1.paths?.['/pets']
868
- delete doc1.paths?.['/users']
869
- delete doc1.paths?.['/pets']
870
-
871
- const doc2 = {
872
- ...base,
873
- info: {
874
- ...base.info,
875
- },
876
- paths: {
877
- ...base.paths,
878
- '/users': {
879
- ...base.paths['/users'],
880
- get: {
881
- ...base.paths['/users'].get,
882
- summary: 'Updated summary',
883
- responses: {
884
- ...base.paths['/users'].get.responses,
885
- 200: {
886
- ...base.paths['/users'].get.responses[200],
887
- description: 'Updated Successful response',
888
- },
889
- 400: {
890
- description: 'Error response',
891
- },
892
- },
893
- },
894
- },
895
- '/pets': {
896
- ...base.paths['/pets'],
897
- get: {
898
- ...base.paths['/pets'].get,
899
- summary: 'Updated summary',
900
- responses: {
901
- ...base.paths['/pets'].get.responses,
902
- 200: {
903
- ...base.paths['/pets'].get.responses[200],
904
- description: 'Updated Successful response',
905
- },
906
- 400: {
907
- description: 'Error response',
908
- },
909
- },
910
- },
911
- },
912
- },
913
- }
914
-
915
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
916
- diffs: [],
917
- conflicts: [
918
- [
919
- [
920
- {
921
- type: 'delete',
922
- changes: deletedUsersChanges,
923
- path: ['paths', '/users'],
924
- },
925
- ],
926
- [
927
- {
928
- type: 'update',
929
- changes: doc2.paths['/users'].get.summary,
930
- path: ['paths', '/users', 'get', 'summary'],
931
- },
932
- {
933
- type: 'update',
934
- changes: doc2.paths['/users'].get.responses[200].description,
935
- path: ['paths', '/users', 'get', 'responses', '200', 'description'],
936
- },
937
- {
938
- type: 'add',
939
- changes: doc2.paths['/users'].get.responses[400],
940
- path: ['paths', '/users', 'get', 'responses', '400'],
941
- },
942
- ],
943
- ],
944
- [
945
- [
946
- {
947
- type: 'delete',
948
- changes: deletedPetsChanges,
949
- path: ['paths', '/pets'],
950
- },
951
- ],
952
- [
953
- {
954
- type: 'update',
955
- changes: doc2.paths['/pets'].get.summary,
956
- path: ['paths', '/pets', 'get', 'summary'],
957
- },
958
- {
959
- type: 'update',
960
- changes: doc2.paths['/pets'].get.responses[200].description,
961
- path: ['paths', '/pets', 'get', 'responses', '200', 'description'],
962
- },
963
- {
964
- type: 'add',
965
- changes: doc2.paths['/pets'].get.responses[400],
966
- path: ['paths', '/pets', 'get', 'responses', '400'],
967
- },
968
- ],
969
- ],
970
- ],
971
- })
972
-
973
- expect(merge(diff(base, doc2), diff(base, doc1))).toEqual({
974
- diffs: [],
975
- conflicts: [
976
- [
977
- [
978
- {
979
- type: 'update',
980
- changes: doc2.paths['/users'].get.summary,
981
- path: ['paths', '/users', 'get', 'summary'],
982
- },
983
- {
984
- type: 'update',
985
- changes: doc2.paths['/users'].get.responses[200].description,
986
- path: ['paths', '/users', 'get', 'responses', '200', 'description'],
987
- },
988
- {
989
- type: 'add',
990
- changes: doc2.paths['/users'].get.responses[400],
991
- path: ['paths', '/users', 'get', 'responses', '400'],
992
- },
993
- ],
994
- [
995
- {
996
- type: 'delete',
997
- changes: deletedUsersChanges,
998
- path: ['paths', '/users'],
999
- },
1000
- ],
1001
- ],
1002
- [
1003
- [
1004
- {
1005
- type: 'update',
1006
- changes: doc2.paths['/pets'].get.summary,
1007
- path: ['paths', '/pets', 'get', 'summary'],
1008
- },
1009
- {
1010
- type: 'update',
1011
- changes: doc2.paths['/pets'].get.responses[200].description,
1012
- path: ['paths', '/pets', 'get', 'responses', '200', 'description'],
1013
- },
1014
- {
1015
- type: 'add',
1016
- changes: doc2.paths['/pets'].get.responses[400],
1017
- path: ['paths', '/pets', 'get', 'responses', '400'],
1018
- },
1019
- ],
1020
- [
1021
- {
1022
- type: 'delete',
1023
- changes: deletedPetsChanges,
1024
- path: ['paths', '/pets'],
1025
- },
1026
- ],
1027
- ],
1028
- ],
1029
- })
1030
- })
1031
-
1032
- test('inner delete should not conflict with an outer update or addition', () => {
1033
- const base = {
1034
- openapi: '3.0.0',
1035
- info: {
1036
- title: 'Sample API',
1037
- version: '1.0',
1038
- },
1039
- paths: {
1040
- '/users': {
1041
- get: {
1042
- summary: 'Get users',
1043
- responses: {
1044
- 200: {
1045
- description: 'Successful response',
1046
- },
1047
- },
1048
- },
1049
- },
1050
- '/pets': {
1051
- get: {
1052
- summary: 'Get pets',
1053
- responses: {
1054
- 200: {
1055
- description: 'Successful response',
1056
- },
1057
- },
1058
- },
1059
- },
1060
- },
1061
- }
1062
-
1063
- const doc1 = deepClone<DeepPartial<typeof base>>(base)
1064
- const deletedUsersChanges = doc1.paths?.['/users']?.get?.responses
1065
- const deletedPetsChanges = doc1.paths?.['/pets']?.get?.responses
1066
- delete doc1.paths?.['/users']?.get?.responses
1067
- delete doc1.paths?.['/pets']?.get?.responses
1068
-
1069
- const doc2 = {
1070
- ...base,
1071
- info: {
1072
- ...base.info,
1073
- },
1074
- paths: {
1075
- ...base.paths,
1076
- '/users': {
1077
- ...base.paths['/users'],
1078
- post: {
1079
- summary: 'Create a new user',
1080
- },
1081
- },
1082
- '/pets': {
1083
- ...base.paths['/pets'],
1084
- },
1085
- },
1086
- }
1087
-
1088
- expect(merge(diff(base, doc1), diff(base, doc2))).toEqual({
1089
- diffs: [
1090
- {
1091
- type: 'delete',
1092
- changes: deletedUsersChanges,
1093
- path: ['paths', '/users', 'get', 'responses'],
1094
- },
1095
- {
1096
- type: 'delete',
1097
- changes: deletedPetsChanges,
1098
- path: ['paths', '/pets', 'get', 'responses'],
1099
- },
1100
- {
1101
- type: 'add',
1102
- changes: doc2.paths['/users'].post,
1103
- path: ['paths', '/users', 'post'],
1104
- },
1105
- ],
1106
- conflicts: [],
1107
- })
1108
- })
1109
- })