apify-schema-tools 2.0.1

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 (83) hide show
  1. package/.cspell/custom-dictionary.txt +4 -0
  2. package/.husky/pre-commit +33 -0
  3. package/.node-version +1 -0
  4. package/CHANGELOG.md +88 -0
  5. package/LICENSE +201 -0
  6. package/README.md +312 -0
  7. package/biome.json +31 -0
  8. package/dist/apify-schema-tools.d.ts +3 -0
  9. package/dist/apify-schema-tools.d.ts.map +1 -0
  10. package/dist/apify-schema-tools.js +197 -0
  11. package/dist/apify-schema-tools.js.map +1 -0
  12. package/dist/apify.d.ts +11 -0
  13. package/dist/apify.d.ts.map +1 -0
  14. package/dist/apify.js +107 -0
  15. package/dist/apify.js.map +1 -0
  16. package/dist/configuration.d.ts +43 -0
  17. package/dist/configuration.d.ts.map +1 -0
  18. package/dist/configuration.js +87 -0
  19. package/dist/configuration.js.map +1 -0
  20. package/dist/filesystem.d.ts +8 -0
  21. package/dist/filesystem.d.ts.map +1 -0
  22. package/dist/filesystem.js +16 -0
  23. package/dist/filesystem.js.map +1 -0
  24. package/dist/json-schemas.d.ts +34 -0
  25. package/dist/json-schemas.d.ts.map +1 -0
  26. package/dist/json-schemas.js +185 -0
  27. package/dist/json-schemas.js.map +1 -0
  28. package/dist/typescript.d.ts +26 -0
  29. package/dist/typescript.d.ts.map +1 -0
  30. package/dist/typescript.js +316 -0
  31. package/dist/typescript.js.map +1 -0
  32. package/package.json +60 -0
  33. package/samples/all-defaults/.actor/actor.json +15 -0
  34. package/samples/all-defaults/.actor/dataset_schema.json +32 -0
  35. package/samples/all-defaults/.actor/input_schema.json +53 -0
  36. package/samples/all-defaults/src/generated/dataset.ts +24 -0
  37. package/samples/all-defaults/src/generated/input-utils.ts +60 -0
  38. package/samples/all-defaults/src/generated/input.ts +42 -0
  39. package/samples/all-defaults/src-schemas/dataset-item.json +28 -0
  40. package/samples/all-defaults/src-schemas/input.json +73 -0
  41. package/samples/deep-merged-schemas/.actor/actor.json +15 -0
  42. package/samples/deep-merged-schemas/.actor/dataset_schema.json +37 -0
  43. package/samples/deep-merged-schemas/.actor/input_schema.json +61 -0
  44. package/samples/deep-merged-schemas/add-schemas/dataset-item.json +10 -0
  45. package/samples/deep-merged-schemas/add-schemas/input.json +33 -0
  46. package/samples/deep-merged-schemas/src/generated/dataset.ts +28 -0
  47. package/samples/deep-merged-schemas/src/generated/input-utils.ts +66 -0
  48. package/samples/deep-merged-schemas/src/generated/input.ts +47 -0
  49. package/samples/deep-merged-schemas/src-schemas/dataset-item.json +28 -0
  50. package/samples/deep-merged-schemas/src-schemas/input.json +73 -0
  51. package/samples/merged-schemas/.actor/actor.json +15 -0
  52. package/samples/merged-schemas/.actor/dataset_schema.json +37 -0
  53. package/samples/merged-schemas/.actor/input_schema.json +58 -0
  54. package/samples/merged-schemas/add-schemas/dataset-item.json +10 -0
  55. package/samples/merged-schemas/add-schemas/input.json +33 -0
  56. package/samples/merged-schemas/src/generated/dataset.ts +28 -0
  57. package/samples/merged-schemas/src/generated/input-utils.ts +57 -0
  58. package/samples/merged-schemas/src/generated/input.ts +42 -0
  59. package/samples/merged-schemas/src-schemas/dataset-item.json +28 -0
  60. package/samples/merged-schemas/src-schemas/input.json +73 -0
  61. package/samples/package-json-config/.actor/actor.json +15 -0
  62. package/samples/package-json-config/.actor/dataset_schema.json +32 -0
  63. package/samples/package-json-config/.actor/input_schema.json +53 -0
  64. package/samples/package-json-config/custom-src-schemas/dataset-item.json +28 -0
  65. package/samples/package-json-config/custom-src-schemas/input.json +73 -0
  66. package/samples/package-json-config/package.json +11 -0
  67. package/samples/package-json-config/src/custom-generated/dataset.ts +24 -0
  68. package/samples/package-json-config/src/custom-generated/input-utils.ts +60 -0
  69. package/samples/package-json-config/src/custom-generated/input.ts +42 -0
  70. package/src/apify-schema-tools.ts +302 -0
  71. package/src/apify.ts +124 -0
  72. package/src/configuration.ts +110 -0
  73. package/src/filesystem.ts +18 -0
  74. package/src/json-schemas.ts +252 -0
  75. package/src/typescript.ts +381 -0
  76. package/test/apify-schema-tools.test.ts +2064 -0
  77. package/test/apify.test.ts +28 -0
  78. package/test/common.ts +19 -0
  79. package/test/configuration.test.ts +642 -0
  80. package/test/json-schemas.test.ts +587 -0
  81. package/test/typescript.test.ts +817 -0
  82. package/tsconfig.json +18 -0
  83. package/update-samples.sh +27 -0
@@ -0,0 +1,817 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+
3
+ import { cleanupTestDirectory, getTestDir, setupTestDirectory } from "./common";
4
+
5
+ import path from "node:path";
6
+ import { readFile } from "../src/filesystem.js";
7
+ import type { ObjectSchema } from "../src/json-schemas";
8
+ import {
9
+ compareTypescriptInterfaces,
10
+ jsonSchemaToTypeScriptInterface,
11
+ parseTypeScriptInterface,
12
+ readGeneratedTypeScriptFile,
13
+ serializeTypeScriptInterface,
14
+ writeTypeScriptFile,
15
+ } from "../src/typescript.js";
16
+
17
+ const TEST_DIR = getTestDir("typescript");
18
+
19
+ describe("TypeScript files utilities", () => {
20
+ afterEach(() => {
21
+ cleanupTestDirectory(TEST_DIR);
22
+ });
23
+
24
+ describe("writeTypeScriptFile", () => {
25
+ it("should add a header to the TypeScript file", () => {
26
+ setupTestDirectory(TEST_DIR);
27
+
28
+ const content = "export const foo = 'bar';";
29
+ const filePath = path.join(TEST_DIR, "test.ts");
30
+ writeTypeScriptFile(filePath, content);
31
+
32
+ const fullContent = readFile(filePath);
33
+ expect(fullContent).toContain("generated by apify-schema-tools.");
34
+
35
+ const parsedContent = readGeneratedTypeScriptFile(filePath);
36
+ expect(parsedContent).toBe(content);
37
+ expect(parsedContent).not.toContain("generated by apify-schema-tools.");
38
+ });
39
+ });
40
+
41
+ describe("jsonSchemaToTypeScriptInterface", () => {
42
+ it("should convert JSON schema to TypeScript schema", () => {
43
+ const schema: ObjectSchema = {
44
+ description: "Test schema",
45
+ type: "object",
46
+ properties: {
47
+ name: { type: "string" },
48
+ colors: {
49
+ type: "array",
50
+ items: {
51
+ type: "object",
52
+ properties: {
53
+ name: {
54
+ type: "string",
55
+ enum: ["red", "green", "blue"],
56
+ },
57
+ value: {
58
+ type: ["integer", "string"],
59
+ description: "The hex color value",
60
+ },
61
+ },
62
+ required: ["name"],
63
+ },
64
+ },
65
+ features: {
66
+ type: "array",
67
+ items: {
68
+ type: "string",
69
+ enum: ["dotted", "striped", "solid"],
70
+ },
71
+ },
72
+ isNice: {
73
+ type: "boolean",
74
+ description: "Whether the shape is nice",
75
+ nullable: true,
76
+ },
77
+ },
78
+ required: ["name", "features", "isNice"],
79
+ };
80
+
81
+ const tsInterface = jsonSchemaToTypeScriptInterface(schema);
82
+
83
+ expect(tsInterface).toEqual({
84
+ doc: "Test schema",
85
+ isRequired: true,
86
+ isArray: false,
87
+ properties: {
88
+ name: {
89
+ doc: undefined,
90
+ isRequired: true,
91
+ isArray: false,
92
+ type: "string",
93
+ },
94
+ colors: {
95
+ doc: undefined,
96
+ isRequired: false,
97
+ isArray: true,
98
+ properties: {
99
+ name: {
100
+ doc: undefined,
101
+ isRequired: true,
102
+ isArray: false,
103
+ enum: ["red", "green", "blue"],
104
+ },
105
+ value: {
106
+ doc: "The hex color value",
107
+ isRequired: false,
108
+ isArray: false,
109
+ type: ["number", "string"],
110
+ },
111
+ },
112
+ },
113
+ features: {
114
+ doc: undefined,
115
+ isRequired: true,
116
+ isArray: true,
117
+ enum: ["dotted", "striped", "solid"],
118
+ },
119
+ isNice: {
120
+ doc: "Whether the shape is nice",
121
+ isRequired: true,
122
+ isArray: false,
123
+ type: ["boolean", "null"],
124
+ },
125
+ },
126
+ });
127
+ });
128
+ });
129
+
130
+ describe("serializeTypeScriptInterface", () => {
131
+ it("should serialize TypeScript interface to string", () => {
132
+ const tsSchema = {
133
+ doc: "Test schema",
134
+ isRequired: true,
135
+ isArray: false,
136
+ properties: {
137
+ name: {
138
+ doc: undefined,
139
+ isRequired: true,
140
+ isArray: false,
141
+ type: "string",
142
+ },
143
+ colors: {
144
+ doc: undefined,
145
+ isRequired: false,
146
+ isArray: true,
147
+ properties: {
148
+ name: {
149
+ doc: undefined,
150
+ isRequired: true,
151
+ isArray: false,
152
+ enum: ["red", "green", "blue"],
153
+ },
154
+ value: {
155
+ doc: "The hex color value",
156
+ isRequired: false,
157
+ isArray: false,
158
+ type: ["number", "string"],
159
+ },
160
+ },
161
+ },
162
+ features: {
163
+ doc: undefined,
164
+ isRequired: true,
165
+ isArray: true,
166
+ enum: ["dotted", "striped", "solid"],
167
+ },
168
+ isNice: {
169
+ doc: "Whether the shape is nice",
170
+ isRequired: true,
171
+ isArray: false,
172
+ type: ["boolean", "null"],
173
+ },
174
+ },
175
+ };
176
+
177
+ const serialized = serializeTypeScriptInterface("Shape", tsSchema);
178
+ expect(serialized).toBe(`\
179
+ /**
180
+ * Test schema
181
+ */
182
+ export interface Shape {
183
+ name: string;
184
+ colors?: {
185
+ name: "red" | "green" | "blue";
186
+ /**
187
+ * The hex color value
188
+ */
189
+ value?: number | string;
190
+ }[];
191
+ features: ("dotted" | "striped" | "solid")[];
192
+ /**
193
+ * Whether the shape is nice
194
+ */
195
+ isNice: boolean | null;
196
+ }`);
197
+ });
198
+ });
199
+
200
+ describe("parseTypeScriptInterface", () => {
201
+ it("should parse TypeScript interface from string", () => {
202
+ const tsInterface = `\
203
+ /**
204
+ * Test schema
205
+ */
206
+ export interface Shape {
207
+ name: string;
208
+ colors?: {
209
+ name: "red" | "green" | "blue";
210
+ /**
211
+ * The hex color value
212
+ */
213
+ value?: number | string;
214
+ }[];
215
+ features: ("dotted" | "striped" | "solid")[];
216
+ /**
217
+ * Whether the shape is nice
218
+ */
219
+ isNice: boolean | null;
220
+ }`;
221
+ const parsed = parseTypeScriptInterface(tsInterface);
222
+ expect(parsed).toEqual({
223
+ doc: "Test schema",
224
+ isRequired: true,
225
+ isArray: false,
226
+ properties: {
227
+ name: {
228
+ doc: undefined,
229
+ isRequired: true,
230
+ isArray: false,
231
+ type: "string",
232
+ },
233
+ colors: {
234
+ doc: undefined,
235
+ isRequired: false,
236
+ isArray: true,
237
+ properties: {
238
+ name: {
239
+ doc: undefined,
240
+ isRequired: true,
241
+ isArray: false,
242
+ enum: ["red", "green", "blue"],
243
+ },
244
+ value: {
245
+ doc: "The hex color value",
246
+ isRequired: false,
247
+ isArray: false,
248
+ type: ["number", "string"],
249
+ },
250
+ },
251
+ },
252
+ features: {
253
+ doc: undefined,
254
+ isRequired: true,
255
+ isArray: true,
256
+ enum: ["dotted", "striped", "solid"],
257
+ },
258
+ isNice: {
259
+ doc: "Whether the shape is nice",
260
+ isRequired: true,
261
+ isArray: false,
262
+ type: ["boolean", "null"],
263
+ },
264
+ },
265
+ });
266
+ });
267
+ });
268
+
269
+ describe("compareTypescriptInterfaces", () => {
270
+ const baseInterface = {
271
+ doc: "Base interface",
272
+ isRequired: true,
273
+ isArray: false,
274
+ properties: {
275
+ name: {
276
+ doc: "User name",
277
+ isRequired: true,
278
+ isArray: false,
279
+ type: "string",
280
+ },
281
+ age: {
282
+ doc: undefined,
283
+ isRequired: false,
284
+ isArray: false,
285
+ type: "number",
286
+ },
287
+ },
288
+ };
289
+
290
+ it("should return true for identical interfaces", () => {
291
+ const interfaceA = {
292
+ doc: "Test interface",
293
+ isRequired: true,
294
+ isArray: false,
295
+ properties: {
296
+ name: {
297
+ doc: "User name",
298
+ isRequired: true,
299
+ isArray: false,
300
+ type: "string",
301
+ },
302
+ age: {
303
+ doc: undefined,
304
+ isRequired: false,
305
+ isArray: false,
306
+ type: "number",
307
+ },
308
+ },
309
+ };
310
+ const interfaceB = {
311
+ doc: "Test interface",
312
+ isRequired: true,
313
+ isArray: false,
314
+ properties: {
315
+ name: {
316
+ doc: "User name",
317
+ isRequired: true,
318
+ isArray: false,
319
+ type: "string",
320
+ },
321
+ age: {
322
+ doc: undefined,
323
+ isRequired: false,
324
+ isArray: false,
325
+ type: "number",
326
+ },
327
+ },
328
+ };
329
+
330
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(true);
331
+ });
332
+
333
+ it("should return false for interfaces with different number of properties", () => {
334
+ const interfaceA = baseInterface;
335
+ const interfaceB = {
336
+ doc: "Test interface",
337
+ isRequired: true,
338
+ isArray: false,
339
+ properties: {
340
+ name: {
341
+ doc: "User name",
342
+ isRequired: true,
343
+ isArray: false,
344
+ type: "string",
345
+ },
346
+ age: {
347
+ doc: undefined,
348
+ isRequired: false,
349
+ isArray: false,
350
+ type: "number",
351
+ },
352
+ email: {
353
+ doc: undefined,
354
+ isRequired: true,
355
+ isArray: false,
356
+ type: "string",
357
+ },
358
+ },
359
+ };
360
+
361
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
362
+ });
363
+
364
+ it("should return false for interfaces with different property names", () => {
365
+ const interfaceA = baseInterface;
366
+ const interfaceB = {
367
+ doc: "Test interface",
368
+ isRequired: true,
369
+ isArray: false,
370
+ properties: {
371
+ fullName: {
372
+ doc: "User name",
373
+ isRequired: true,
374
+ isArray: false,
375
+ type: "string",
376
+ },
377
+ age: {
378
+ doc: undefined,
379
+ isRequired: false,
380
+ isArray: false,
381
+ type: "number",
382
+ },
383
+ },
384
+ };
385
+
386
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
387
+ });
388
+
389
+ it("should return false for properties with different types", () => {
390
+ const interfaceA = baseInterface;
391
+ const interfaceB = {
392
+ doc: "Test interface",
393
+ isRequired: true,
394
+ isArray: false,
395
+ properties: {
396
+ name: {
397
+ doc: "User name",
398
+ isRequired: true,
399
+ isArray: false,
400
+ type: "string",
401
+ },
402
+ age: {
403
+ doc: undefined,
404
+ isRequired: false,
405
+ isArray: false,
406
+ type: "string", // Different type
407
+ },
408
+ },
409
+ };
410
+
411
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
412
+ });
413
+
414
+ it("should return false for properties with different isRequired values", () => {
415
+ const interfaceA = baseInterface;
416
+ const interfaceB = {
417
+ doc: "Test interface",
418
+ isRequired: true,
419
+ isArray: false,
420
+ properties: {
421
+ name: {
422
+ doc: "User name",
423
+ isRequired: false, // Different isRequired
424
+ isArray: false,
425
+ type: "string",
426
+ },
427
+ age: {
428
+ doc: undefined,
429
+ isRequired: false,
430
+ isArray: false,
431
+ type: "number",
432
+ },
433
+ },
434
+ };
435
+
436
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
437
+ });
438
+
439
+ it("should return false for properties with different isArray values", () => {
440
+ const interfaceA = baseInterface;
441
+ const interfaceB = {
442
+ doc: "Test interface",
443
+ isRequired: true,
444
+ isArray: false,
445
+ properties: {
446
+ name: {
447
+ doc: "User name",
448
+ isRequired: true,
449
+ isArray: true, // Different isArray
450
+ type: "string",
451
+ },
452
+ age: {
453
+ doc: undefined,
454
+ isRequired: false,
455
+ isArray: false,
456
+ type: "number",
457
+ },
458
+ },
459
+ };
460
+
461
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
462
+ });
463
+
464
+ it("should return false for properties with different documentation when ignoreDocs is false", () => {
465
+ const interfaceA = baseInterface;
466
+ const interfaceB = {
467
+ doc: "Test interface",
468
+ isRequired: true,
469
+ isArray: false,
470
+ properties: {
471
+ name: {
472
+ doc: "Different documentation", // Different doc
473
+ isRequired: true,
474
+ isArray: false,
475
+ type: "string",
476
+ },
477
+ age: {
478
+ doc: undefined,
479
+ isRequired: false,
480
+ isArray: false,
481
+ type: "number",
482
+ },
483
+ },
484
+ };
485
+
486
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB, false)).toBe(false);
487
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false); // Default is false
488
+ });
489
+
490
+ it("should return true for properties with different documentation when ignoreDocs is true", () => {
491
+ const interfaceA = baseInterface;
492
+ const interfaceB = {
493
+ doc: "Test interface",
494
+ isRequired: true,
495
+ isArray: false,
496
+ properties: {
497
+ name: {
498
+ doc: "Different documentation", // Different doc
499
+ isRequired: true,
500
+ isArray: false,
501
+ type: "string",
502
+ },
503
+ age: {
504
+ doc: "Different age doc", // Different doc
505
+ isRequired: false,
506
+ isArray: false,
507
+ type: "number",
508
+ },
509
+ },
510
+ };
511
+
512
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB, true)).toBe(true);
513
+ });
514
+
515
+ it("should handle enum properties correctly", () => {
516
+ const interfaceA = {
517
+ doc: undefined,
518
+ isRequired: true,
519
+ isArray: false,
520
+ properties: {
521
+ status: {
522
+ doc: undefined,
523
+ isRequired: true,
524
+ isArray: false,
525
+ enum: ["active", "inactive", "pending"],
526
+ },
527
+ },
528
+ };
529
+ const interfaceB = {
530
+ doc: undefined,
531
+ isRequired: true,
532
+ isArray: false,
533
+ properties: {
534
+ status: {
535
+ doc: undefined,
536
+ isRequired: true,
537
+ isArray: false,
538
+ enum: ["active", "inactive", "pending"],
539
+ },
540
+ },
541
+ };
542
+
543
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(true);
544
+ });
545
+
546
+ it("should return false for enum properties with different values", () => {
547
+ const interfaceA = {
548
+ doc: undefined,
549
+ isRequired: true,
550
+ isArray: false,
551
+ properties: {
552
+ status: {
553
+ doc: undefined,
554
+ isRequired: true,
555
+ isArray: false,
556
+ enum: ["active", "inactive", "pending"],
557
+ },
558
+ },
559
+ };
560
+ const interfaceB = {
561
+ doc: undefined,
562
+ isRequired: true,
563
+ isArray: false,
564
+ properties: {
565
+ status: {
566
+ doc: undefined,
567
+ isRequired: true,
568
+ isArray: false,
569
+ enum: ["active", "inactive", "cancelled"], // Different enum value
570
+ },
571
+ },
572
+ };
573
+
574
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
575
+ });
576
+
577
+ it("should handle nested interface properties correctly", () => {
578
+ const interfaceA = {
579
+ doc: undefined,
580
+ isRequired: true,
581
+ isArray: false,
582
+ properties: {
583
+ user: {
584
+ doc: undefined,
585
+ isRequired: true,
586
+ isArray: false,
587
+ properties: {
588
+ name: {
589
+ doc: undefined,
590
+ isRequired: true,
591
+ isArray: false,
592
+ type: "string",
593
+ },
594
+ age: {
595
+ doc: undefined,
596
+ isRequired: false,
597
+ isArray: false,
598
+ type: "number",
599
+ },
600
+ },
601
+ },
602
+ },
603
+ };
604
+ const interfaceB = {
605
+ doc: undefined,
606
+ isRequired: true,
607
+ isArray: false,
608
+ properties: {
609
+ user: {
610
+ doc: undefined,
611
+ isRequired: true,
612
+ isArray: false,
613
+ properties: {
614
+ name: {
615
+ doc: undefined,
616
+ isRequired: true,
617
+ isArray: false,
618
+ type: "string",
619
+ },
620
+ age: {
621
+ doc: undefined,
622
+ isRequired: false,
623
+ isArray: false,
624
+ type: "number",
625
+ },
626
+ },
627
+ },
628
+ },
629
+ };
630
+
631
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(true);
632
+ });
633
+
634
+ it("should return false for nested interfaces with different structures", () => {
635
+ const interfaceA = {
636
+ doc: undefined,
637
+ isRequired: true,
638
+ isArray: false,
639
+ properties: {
640
+ user: {
641
+ doc: undefined,
642
+ isRequired: true,
643
+ isArray: false,
644
+ properties: {
645
+ name: {
646
+ doc: undefined,
647
+ isRequired: true,
648
+ isArray: false,
649
+ type: "string",
650
+ },
651
+ age: {
652
+ doc: undefined,
653
+ isRequired: false,
654
+ isArray: false,
655
+ type: "number",
656
+ },
657
+ },
658
+ },
659
+ },
660
+ };
661
+ const interfaceB = {
662
+ doc: undefined,
663
+ isRequired: true,
664
+ isArray: false,
665
+ properties: {
666
+ user: {
667
+ doc: undefined,
668
+ isRequired: true,
669
+ isArray: false,
670
+ properties: {
671
+ name: {
672
+ doc: undefined,
673
+ isRequired: true,
674
+ isArray: false,
675
+ type: "string",
676
+ },
677
+ // Missing age property
678
+ },
679
+ },
680
+ },
681
+ };
682
+
683
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
684
+ });
685
+
686
+ it("should handle union types correctly", () => {
687
+ const interfaceA = {
688
+ doc: undefined,
689
+ isRequired: true,
690
+ isArray: false,
691
+ properties: {
692
+ value: {
693
+ doc: undefined,
694
+ isRequired: true,
695
+ isArray: false,
696
+ type: ["string", "number"],
697
+ },
698
+ },
699
+ };
700
+ const interfaceB = {
701
+ doc: undefined,
702
+ isRequired: true,
703
+ isArray: false,
704
+ properties: {
705
+ value: {
706
+ doc: undefined,
707
+ isRequired: true,
708
+ isArray: false,
709
+ type: ["string", "number"],
710
+ },
711
+ },
712
+ };
713
+
714
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(true);
715
+ });
716
+
717
+ it("should return false for union types with different order", () => {
718
+ const interfaceA = {
719
+ doc: undefined,
720
+ isRequired: true,
721
+ isArray: false,
722
+ properties: {
723
+ value: {
724
+ doc: undefined,
725
+ isRequired: true,
726
+ isArray: false,
727
+ type: ["string", "number"],
728
+ },
729
+ },
730
+ };
731
+ const interfaceB = {
732
+ doc: undefined,
733
+ isRequired: true,
734
+ isArray: false,
735
+ properties: {
736
+ value: {
737
+ doc: undefined,
738
+ isRequired: true,
739
+ isArray: false,
740
+ type: ["number", "string"], // Different order
741
+ },
742
+ },
743
+ };
744
+
745
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
746
+ });
747
+
748
+ it("should return false when comparing interface property to basic type property", () => {
749
+ const interfaceA = {
750
+ doc: undefined,
751
+ isRequired: true,
752
+ isArray: false,
753
+ properties: {
754
+ data: {
755
+ doc: undefined,
756
+ isRequired: true,
757
+ isArray: false,
758
+ properties: {
759
+ name: {
760
+ doc: undefined,
761
+ isRequired: true,
762
+ isArray: false,
763
+ type: "string",
764
+ },
765
+ },
766
+ },
767
+ },
768
+ };
769
+ const interfaceB = {
770
+ doc: undefined,
771
+ isRequired: true,
772
+ isArray: false,
773
+ properties: {
774
+ data: {
775
+ doc: undefined,
776
+ isRequired: true,
777
+ isArray: false,
778
+ type: "string", // Basic type instead of interface
779
+ },
780
+ },
781
+ };
782
+
783
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
784
+ });
785
+
786
+ it("should return false when comparing enum property to basic type property", () => {
787
+ const interfaceA = {
788
+ doc: undefined,
789
+ isRequired: true,
790
+ isArray: false,
791
+ properties: {
792
+ status: {
793
+ doc: undefined,
794
+ isRequired: true,
795
+ isArray: false,
796
+ enum: ["active", "inactive"],
797
+ },
798
+ },
799
+ };
800
+ const interfaceB = {
801
+ doc: undefined,
802
+ isRequired: true,
803
+ isArray: false,
804
+ properties: {
805
+ status: {
806
+ doc: undefined,
807
+ isRequired: true,
808
+ isArray: false,
809
+ type: "string", // Basic type instead of enum
810
+ },
811
+ },
812
+ };
813
+
814
+ expect(compareTypescriptInterfaces(interfaceA, interfaceB)).toBe(false);
815
+ });
816
+ });
817
+ });