agency-lang 0.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 (76) hide show
  1. package/README.md +7 -0
  2. package/dist/backends/baseGenerator.js +194 -0
  3. package/dist/backends/graphGenerator.integration.test.js +119 -0
  4. package/dist/backends/graphGenerator.js +308 -0
  5. package/dist/backends/index.js +3 -0
  6. package/dist/backends/typescriptGenerator/builtins.js +46 -0
  7. package/dist/backends/typescriptGenerator/typeToString.js +36 -0
  8. package/dist/backends/typescriptGenerator/typeToZodSchema.js +54 -0
  9. package/dist/backends/typescriptGenerator.integration.test.js +119 -0
  10. package/dist/backends/typescriptGenerator.js +340 -0
  11. package/dist/backends/typescriptGenerator.test.js +763 -0
  12. package/dist/backends/utils.js +6 -0
  13. package/dist/generate-graph-file.js +25 -0
  14. package/dist/generate-ts-file.js +26 -0
  15. package/dist/index.js +3 -0
  16. package/dist/parser.js +38 -0
  17. package/dist/parser.test.js +306 -0
  18. package/dist/parsers/access.js +19 -0
  19. package/dist/parsers/access.test.js +929 -0
  20. package/dist/parsers/assignment.js +8 -0
  21. package/dist/parsers/body.test.js +106 -0
  22. package/dist/parsers/comment.js +6 -0
  23. package/dist/parsers/comment.test.js +100 -0
  24. package/dist/parsers/dataStructures.js +14 -0
  25. package/dist/parsers/dataStructures.test.js +660 -0
  26. package/dist/parsers/function.js +22 -0
  27. package/dist/parsers/function.test.js +591 -0
  28. package/dist/parsers/functionCall.js +10 -0
  29. package/dist/parsers/functionCall.test.js +119 -0
  30. package/dist/parsers/importStatement.js +3 -0
  31. package/dist/parsers/importStatement.test.js +290 -0
  32. package/dist/parsers/literals.js +12 -0
  33. package/dist/parsers/literals.test.js +639 -0
  34. package/dist/parsers/matchBlock.js +24 -0
  35. package/dist/parsers/matchBlock.test.js +506 -0
  36. package/dist/parsers/parserUtils.js +2 -0
  37. package/dist/parsers/returnStatement.js +8 -0
  38. package/dist/parsers/tools.js +3 -0
  39. package/dist/parsers/tools.test.js +170 -0
  40. package/dist/parsers/typeHints.js +59 -0
  41. package/dist/parsers/typeHints.test.js +2754 -0
  42. package/dist/parsers/utils.js +5 -0
  43. package/dist/parsers/whileLoop.test.js +342 -0
  44. package/dist/templates/backends/graphGenerator/builtinTools.js +36 -0
  45. package/dist/templates/backends/graphGenerator/conditionalEdge.js +10 -0
  46. package/dist/templates/backends/graphGenerator/edge.js +10 -0
  47. package/dist/templates/backends/graphGenerator/goToNode.js +9 -0
  48. package/dist/templates/backends/graphGenerator/graphNode.js +15 -0
  49. package/dist/templates/backends/graphGenerator/imports.js +47 -0
  50. package/dist/templates/backends/graphGenerator/node.js +18 -0
  51. package/dist/templates/backends/graphGenerator/promptNode.js +16 -0
  52. package/dist/templates/backends/graphGenerator/startNode.js +10 -0
  53. package/dist/templates/backends/typescriptGenerator/builtinFunctions/fetch.js +17 -0
  54. package/dist/templates/backends/typescriptGenerator/builtinFunctions/fetchJSON.js +17 -0
  55. package/dist/templates/backends/typescriptGenerator/builtinFunctions/input.js +21 -0
  56. package/dist/templates/backends/typescriptGenerator/builtinFunctions/read.js +13 -0
  57. package/dist/templates/backends/typescriptGenerator/builtinTools.js +36 -0
  58. package/dist/templates/backends/typescriptGenerator/functionDefinition.js +11 -0
  59. package/dist/templates/backends/typescriptGenerator/imports.js +25 -0
  60. package/dist/templates/backends/typescriptGenerator/promptFunction.js +76 -0
  61. package/dist/templates/backends/typescriptGenerator/tool.js +23 -0
  62. package/dist/templates/backends/typescriptGenerator/toolCall.js +35 -0
  63. package/dist/types/access.js +1 -0
  64. package/dist/types/dataStructures.js +1 -0
  65. package/dist/types/function.js +1 -0
  66. package/dist/types/graphNode.js +1 -0
  67. package/dist/types/importStatement.js +1 -0
  68. package/dist/types/literals.js +1 -0
  69. package/dist/types/matchBlock.js +1 -0
  70. package/dist/types/returnStatement.js +1 -0
  71. package/dist/types/tools.js +1 -0
  72. package/dist/types/typeHints.js +1 -0
  73. package/dist/types/whileLoop.js +1 -0
  74. package/dist/types.js +11 -0
  75. package/dist/utils.js +18 -0
  76. package/package.json +52 -0
@@ -0,0 +1,2754 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { primitiveTypeParser, arrayTypeParser, angleBracketsArrayTypeParser, stringLiteralTypeParser, numberLiteralTypeParser, booleanLiteralTypeParser, objectPropertyParser, objectPropertyDescriptionParser, objectPropertyWithDescriptionParser, objectTypeParser, typeAliasParser, typeAliasVariableParser, variableTypeParser, unionTypeParser, typeHintParser, } from "./typeHints.js";
3
+ describe("primitiveTypeParser", () => {
4
+ const testCases = [
5
+ {
6
+ input: "number",
7
+ expected: {
8
+ success: true,
9
+ result: { type: "primitiveType", value: "number" },
10
+ },
11
+ },
12
+ {
13
+ input: "string",
14
+ expected: {
15
+ success: true,
16
+ result: { type: "primitiveType", value: "string" },
17
+ },
18
+ },
19
+ {
20
+ input: "boolean",
21
+ expected: {
22
+ success: true,
23
+ result: { type: "primitiveType", value: "boolean" },
24
+ },
25
+ },
26
+ {
27
+ input: "invalid",
28
+ expected: { success: false },
29
+ },
30
+ {
31
+ input: "",
32
+ expected: { success: false },
33
+ },
34
+ ];
35
+ testCases.forEach(({ input, expected }) => {
36
+ if (expected.success) {
37
+ it(`should parse "${input}" successfully`, () => {
38
+ const result = primitiveTypeParser(input);
39
+ expect(result.success).toBe(true);
40
+ if (result.success) {
41
+ expect(result.result).toEqual(expected.result);
42
+ }
43
+ });
44
+ }
45
+ else {
46
+ it(`should fail to parse "${input}"`, () => {
47
+ const result = primitiveTypeParser(input);
48
+ expect(result.success).toBe(false);
49
+ });
50
+ }
51
+ });
52
+ });
53
+ describe("arrayTypeParser", () => {
54
+ const testCases = [
55
+ {
56
+ input: "number[]",
57
+ expected: {
58
+ success: true,
59
+ result: {
60
+ type: "arrayType",
61
+ elementType: { type: "primitiveType", value: "number" },
62
+ },
63
+ },
64
+ },
65
+ {
66
+ input: "string[]",
67
+ expected: {
68
+ success: true,
69
+ result: {
70
+ type: "arrayType",
71
+ elementType: { type: "primitiveType", value: "string" },
72
+ },
73
+ },
74
+ },
75
+ {
76
+ input: "boolean[]",
77
+ expected: {
78
+ success: true,
79
+ result: {
80
+ type: "arrayType",
81
+ elementType: { type: "primitiveType", value: "boolean" },
82
+ },
83
+ },
84
+ },
85
+ {
86
+ // nested array
87
+ input: "boolean[][]",
88
+ expected: {
89
+ success: true,
90
+ result: {
91
+ type: "arrayType",
92
+ elementType: {
93
+ type: "arrayType",
94
+ elementType: { type: "primitiveType", value: "boolean" },
95
+ },
96
+ },
97
+ },
98
+ },
99
+ {
100
+ // array of objects
101
+ input: "{ name: string; age: number }[]",
102
+ expected: {
103
+ success: true,
104
+ result: {
105
+ type: "arrayType",
106
+ elementType: {
107
+ type: "objectType",
108
+ properties: [
109
+ {
110
+ key: "name",
111
+ value: { type: "primitiveType", value: "string" },
112
+ },
113
+ {
114
+ key: "age",
115
+ value: { type: "primitiveType", value: "number" },
116
+ },
117
+ ],
118
+ },
119
+ },
120
+ },
121
+ },
122
+ {
123
+ input: "number",
124
+ expected: { success: false },
125
+ },
126
+ {
127
+ input: "invalid[]",
128
+ expected: { success: false },
129
+ },
130
+ {
131
+ input: "[]",
132
+ expected: { success: false },
133
+ },
134
+ ];
135
+ testCases.forEach(({ input, expected }) => {
136
+ if (expected.success) {
137
+ it(`should parse "${input}" successfully`, () => {
138
+ const result = arrayTypeParser(input);
139
+ expect(result.success).toBe(true);
140
+ if (result.success) {
141
+ expect(result.result).toEqual(expected.result);
142
+ }
143
+ });
144
+ }
145
+ else {
146
+ it(`should fail to parse "${input}"`, () => {
147
+ const result = arrayTypeParser(input);
148
+ expect(result.success).toBe(false);
149
+ });
150
+ }
151
+ });
152
+ });
153
+ describe("angleBracketsArrayTypeParser", () => {
154
+ const testCases = [
155
+ {
156
+ input: "array<number>",
157
+ expected: {
158
+ success: true,
159
+ result: {
160
+ type: "arrayType",
161
+ elementType: { type: "primitiveType", value: "number" },
162
+ },
163
+ },
164
+ },
165
+ {
166
+ input: "array<string>",
167
+ expected: {
168
+ success: true,
169
+ result: {
170
+ type: "arrayType",
171
+ elementType: { type: "primitiveType", value: "string" },
172
+ },
173
+ },
174
+ },
175
+ {
176
+ input: "array<boolean>",
177
+ expected: {
178
+ success: true,
179
+ result: {
180
+ type: "arrayType",
181
+ elementType: { type: "primitiveType", value: "boolean" },
182
+ },
183
+ },
184
+ },
185
+ {
186
+ input: "array<invalid>",
187
+ expected: { success: false },
188
+ },
189
+ {
190
+ input: "array<>",
191
+ expected: { success: false },
192
+ },
193
+ ];
194
+ testCases.forEach(({ input, expected }) => {
195
+ if (expected.success) {
196
+ it(`should parse "${input}" successfully`, () => {
197
+ const result = angleBracketsArrayTypeParser(input);
198
+ expect(result.success).toBe(true);
199
+ if (result.success) {
200
+ expect(result.result).toEqual(expected.result);
201
+ }
202
+ });
203
+ }
204
+ else {
205
+ it(`should fail to parse "${input}"`, () => {
206
+ const result = angleBracketsArrayTypeParser(input);
207
+ expect(result.success).toBe(false);
208
+ });
209
+ }
210
+ });
211
+ });
212
+ describe("stringLiteralTypeParser", () => {
213
+ const testCases = [
214
+ {
215
+ input: '"hello"',
216
+ expected: {
217
+ success: true,
218
+ result: { type: "stringLiteralType", value: "hello" },
219
+ },
220
+ },
221
+ {
222
+ input: '"world"',
223
+ expected: {
224
+ success: true,
225
+ result: { type: "stringLiteralType", value: "world" },
226
+ },
227
+ },
228
+ {
229
+ input: '""',
230
+ expected: { success: false },
231
+ },
232
+ {
233
+ input: '"unterminated',
234
+ expected: { success: false },
235
+ },
236
+ {
237
+ input: 'unterminated"',
238
+ expected: { success: false },
239
+ },
240
+ {
241
+ input: "hello",
242
+ expected: { success: false },
243
+ },
244
+ ];
245
+ testCases.forEach(({ input, expected }) => {
246
+ if (expected.success) {
247
+ it(`should parse ${input} successfully`, () => {
248
+ const result = stringLiteralTypeParser(input);
249
+ expect(result.success).toBe(true);
250
+ if (result.success) {
251
+ expect(result.result).toEqual(expected.result);
252
+ }
253
+ });
254
+ }
255
+ else {
256
+ it(`should fail to parse ${input}`, () => {
257
+ const result = stringLiteralTypeParser(input);
258
+ expect(result.success).toBe(false);
259
+ });
260
+ }
261
+ });
262
+ });
263
+ describe("numberLiteralTypeParser", () => {
264
+ const testCases = [
265
+ {
266
+ input: "42",
267
+ expected: {
268
+ success: true,
269
+ result: { type: "numberLiteralType", value: "42" },
270
+ },
271
+ },
272
+ {
273
+ input: "0",
274
+ expected: {
275
+ success: true,
276
+ result: { type: "numberLiteralType", value: "0" },
277
+ },
278
+ },
279
+ {
280
+ input: "123456",
281
+ expected: {
282
+ success: true,
283
+ result: { type: "numberLiteralType", value: "123456" },
284
+ },
285
+ },
286
+ {
287
+ input: "-10",
288
+ expected: {
289
+ success: true,
290
+ result: { type: "numberLiteralType", value: "-10" },
291
+ },
292
+ },
293
+ {
294
+ input: "10.15",
295
+ expected: {
296
+ success: true,
297
+ result: { type: "numberLiteralType", value: "10.15" },
298
+ },
299
+ },
300
+ {
301
+ input: "abc",
302
+ expected: { success: false },
303
+ },
304
+ {
305
+ input: "",
306
+ expected: { success: false },
307
+ },
308
+ ];
309
+ testCases.forEach(({ input, expected }) => {
310
+ if (expected.success) {
311
+ it(`should parse "${input}" successfully`, () => {
312
+ const result = numberLiteralTypeParser(input);
313
+ expect(result.success).toBe(true);
314
+ if (result.success) {
315
+ expect(result.result).toEqual(expected.result);
316
+ }
317
+ });
318
+ }
319
+ else {
320
+ it(`should fail to parse "${input}"`, () => {
321
+ const result = numberLiteralTypeParser(input);
322
+ expect(result.success).toBe(false);
323
+ });
324
+ }
325
+ });
326
+ });
327
+ describe("booleanLiteralTypeParser", () => {
328
+ const testCases = [
329
+ {
330
+ input: "true",
331
+ expected: {
332
+ success: true,
333
+ result: { type: "booleanLiteralType", value: "true" },
334
+ },
335
+ },
336
+ {
337
+ input: "false",
338
+ expected: {
339
+ success: true,
340
+ result: { type: "booleanLiteralType", value: "false" },
341
+ },
342
+ },
343
+ {
344
+ input: "True",
345
+ expected: { success: false },
346
+ },
347
+ {
348
+ input: "FALSE",
349
+ expected: { success: false },
350
+ },
351
+ {
352
+ input: "1",
353
+ expected: { success: false },
354
+ },
355
+ {
356
+ input: "",
357
+ expected: { success: false },
358
+ },
359
+ ];
360
+ testCases.forEach(({ input, expected }) => {
361
+ if (expected.success) {
362
+ it(`should parse "${input}" successfully`, () => {
363
+ const result = booleanLiteralTypeParser(input);
364
+ expect(result.success).toBe(true);
365
+ if (result.success) {
366
+ expect(result.result).toEqual(expected.result);
367
+ }
368
+ });
369
+ }
370
+ else {
371
+ it(`should fail to parse "${input}"`, () => {
372
+ const result = booleanLiteralTypeParser(input);
373
+ expect(result.success).toBe(false);
374
+ });
375
+ }
376
+ });
377
+ });
378
+ describe("typeAliasParser", () => {
379
+ const testCases = [
380
+ // Basic type aliases with primitives
381
+ {
382
+ input: "type Name = string",
383
+ expected: {
384
+ success: true,
385
+ result: {
386
+ type: "typeAlias",
387
+ aliasName: "Name",
388
+ aliasedType: { type: "primitiveType", value: "string" },
389
+ },
390
+ },
391
+ },
392
+ {
393
+ input: "type Count = number",
394
+ expected: {
395
+ success: true,
396
+ result: {
397
+ type: "typeAlias",
398
+ aliasName: "Count",
399
+ aliasedType: { type: "primitiveType", value: "number" },
400
+ },
401
+ },
402
+ },
403
+ {
404
+ input: "type Flag = boolean",
405
+ expected: {
406
+ success: true,
407
+ result: {
408
+ type: "typeAlias",
409
+ aliasName: "Flag",
410
+ aliasedType: { type: "primitiveType", value: "boolean" },
411
+ },
412
+ },
413
+ },
414
+ // Object type aliases
415
+ {
416
+ input: "type Point = { x: number; y: number }",
417
+ expected: {
418
+ success: true,
419
+ result: {
420
+ type: "typeAlias",
421
+ aliasName: "Point",
422
+ aliasedType: {
423
+ type: "objectType",
424
+ properties: [
425
+ {
426
+ key: "x",
427
+ value: { type: "primitiveType", value: "number" },
428
+ },
429
+ {
430
+ key: "y",
431
+ value: { type: "primitiveType", value: "number" },
432
+ },
433
+ ],
434
+ },
435
+ },
436
+ },
437
+ },
438
+ {
439
+ input: "type User = { name: string; age: number; active: boolean }",
440
+ expected: {
441
+ success: true,
442
+ result: {
443
+ type: "typeAlias",
444
+ aliasName: "User",
445
+ aliasedType: {
446
+ type: "objectType",
447
+ properties: [
448
+ {
449
+ key: "name",
450
+ value: { type: "primitiveType", value: "string" },
451
+ },
452
+ {
453
+ key: "age",
454
+ value: { type: "primitiveType", value: "number" },
455
+ },
456
+ {
457
+ key: "active",
458
+ value: { type: "primitiveType", value: "boolean" },
459
+ },
460
+ ],
461
+ },
462
+ },
463
+ },
464
+ },
465
+ // Array type aliases
466
+ {
467
+ input: "type Numbers = number[]",
468
+ expected: {
469
+ success: true,
470
+ result: {
471
+ type: "typeAlias",
472
+ aliasName: "Numbers",
473
+ aliasedType: {
474
+ type: "arrayType",
475
+ elementType: { type: "primitiveType", value: "number" },
476
+ },
477
+ },
478
+ },
479
+ },
480
+ {
481
+ input: "type Items = array<string>",
482
+ expected: {
483
+ success: true,
484
+ result: {
485
+ type: "typeAlias",
486
+ aliasName: "Items",
487
+ aliasedType: {
488
+ type: "arrayType",
489
+ elementType: { type: "primitiveType", value: "string" },
490
+ },
491
+ },
492
+ },
493
+ },
494
+ // Literal type aliases
495
+ {
496
+ input: 'type Status = "active"',
497
+ expected: {
498
+ success: true,
499
+ result: {
500
+ type: "typeAlias",
501
+ aliasName: "Status",
502
+ aliasedType: { type: "stringLiteralType", value: "active" },
503
+ },
504
+ },
505
+ },
506
+ {
507
+ input: "type Level = 42",
508
+ expected: {
509
+ success: true,
510
+ result: {
511
+ type: "typeAlias",
512
+ aliasName: "Level",
513
+ aliasedType: { type: "numberLiteralType", value: "42" },
514
+ },
515
+ },
516
+ },
517
+ {
518
+ input: "type Enabled = true",
519
+ expected: {
520
+ success: true,
521
+ result: {
522
+ type: "typeAlias",
523
+ aliasName: "Enabled",
524
+ aliasedType: { type: "booleanLiteralType", value: "true" },
525
+ },
526
+ },
527
+ },
528
+ // Union type aliases
529
+ {
530
+ input: "type StringOrNumber = string | number",
531
+ expected: {
532
+ success: true,
533
+ result: {
534
+ type: "typeAlias",
535
+ aliasName: "StringOrNumber",
536
+ aliasedType: {
537
+ type: "unionType",
538
+ types: [
539
+ { type: "primitiveType", value: "string" },
540
+ { type: "primitiveType", value: "number" },
541
+ ],
542
+ },
543
+ },
544
+ },
545
+ },
546
+ {
547
+ input: 'type Result = "success" | "error"',
548
+ expected: {
549
+ success: true,
550
+ result: {
551
+ type: "typeAlias",
552
+ aliasName: "Result",
553
+ aliasedType: {
554
+ type: "unionType",
555
+ types: [
556
+ { type: "stringLiteralType", value: "success" },
557
+ { type: "stringLiteralType", value: "error" },
558
+ ],
559
+ },
560
+ },
561
+ },
562
+ },
563
+ {
564
+ input: "type Mixed = string | 42 | true",
565
+ expected: {
566
+ success: true,
567
+ result: {
568
+ type: "typeAlias",
569
+ aliasName: "Mixed",
570
+ aliasedType: {
571
+ type: "unionType",
572
+ types: [
573
+ { type: "primitiveType", value: "string" },
574
+ { type: "numberLiteralType", value: "42" },
575
+ { type: "booleanLiteralType", value: "true" },
576
+ ],
577
+ },
578
+ },
579
+ },
580
+ },
581
+ // Nested/Complex type aliases
582
+ {
583
+ input: "type Nested = { coords: { x: number; y: number } }",
584
+ expected: {
585
+ success: true,
586
+ result: {
587
+ type: "typeAlias",
588
+ aliasName: "Nested",
589
+ aliasedType: {
590
+ type: "objectType",
591
+ properties: [
592
+ {
593
+ key: "coords",
594
+ value: {
595
+ type: "objectType",
596
+ properties: [
597
+ {
598
+ key: "x",
599
+ value: { type: "primitiveType", value: "number" },
600
+ },
601
+ {
602
+ key: "y",
603
+ value: { type: "primitiveType", value: "number" },
604
+ },
605
+ ],
606
+ },
607
+ },
608
+ ],
609
+ },
610
+ },
611
+ },
612
+ },
613
+ {
614
+ input: "type Complex = { value: string | number }",
615
+ expected: {
616
+ success: true,
617
+ result: {
618
+ type: "typeAlias",
619
+ aliasName: "Complex",
620
+ aliasedType: {
621
+ type: "objectType",
622
+ properties: [
623
+ {
624
+ key: "value",
625
+ value: {
626
+ type: "unionType",
627
+ types: [
628
+ { type: "primitiveType", value: "string" },
629
+ { type: "primitiveType", value: "number" },
630
+ ],
631
+ },
632
+ },
633
+ ],
634
+ },
635
+ },
636
+ },
637
+ },
638
+ // Whitespace variations
639
+ {
640
+ input: "type A=number",
641
+ expected: {
642
+ success: true,
643
+ result: {
644
+ type: "typeAlias",
645
+ aliasName: "A",
646
+ aliasedType: { type: "primitiveType", value: "number" },
647
+ },
648
+ },
649
+ },
650
+ {
651
+ input: "type B = number",
652
+ expected: {
653
+ success: true,
654
+ result: {
655
+ type: "typeAlias",
656
+ aliasName: "B",
657
+ aliasedType: { type: "primitiveType", value: "number" },
658
+ },
659
+ },
660
+ },
661
+ {
662
+ input: "type C = number",
663
+ expected: {
664
+ success: true,
665
+ result: {
666
+ type: "typeAlias",
667
+ aliasName: "C",
668
+ aliasedType: { type: "primitiveType", value: "number" },
669
+ },
670
+ },
671
+ },
672
+ {
673
+ input: "type D = number[]",
674
+ expected: {
675
+ success: true,
676
+ result: {
677
+ type: "typeAlias",
678
+ aliasName: "D",
679
+ aliasedType: {
680
+ type: "arrayType",
681
+ elementType: { type: "primitiveType", value: "number" },
682
+ },
683
+ },
684
+ },
685
+ },
686
+ // Different naming styles
687
+ {
688
+ input: "type MyType = string",
689
+ expected: {
690
+ success: true,
691
+ result: {
692
+ type: "typeAlias",
693
+ aliasName: "MyType",
694
+ aliasedType: { type: "primitiveType", value: "string" },
695
+ },
696
+ },
697
+ },
698
+ {
699
+ input: "type x = number",
700
+ expected: {
701
+ success: true,
702
+ result: {
703
+ type: "typeAlias",
704
+ aliasName: "x",
705
+ aliasedType: { type: "primitiveType", value: "number" },
706
+ },
707
+ },
708
+ },
709
+ {
710
+ input: "type ABC = boolean",
711
+ expected: {
712
+ success: true,
713
+ result: {
714
+ type: "typeAlias",
715
+ aliasName: "ABC",
716
+ aliasedType: { type: "primitiveType", value: "boolean" },
717
+ },
718
+ },
719
+ },
720
+ // Failure cases
721
+ {
722
+ input: "type",
723
+ expected: { success: false },
724
+ },
725
+ {
726
+ input: "type A",
727
+ expected: { success: false },
728
+ },
729
+ {
730
+ input: "type A =",
731
+ expected: { success: false },
732
+ },
733
+ {
734
+ input: "type = number",
735
+ expected: { success: false },
736
+ },
737
+ {
738
+ input: "A = number",
739
+ expected: { success: false },
740
+ },
741
+ {
742
+ input: "type A number",
743
+ expected: { success: false },
744
+ },
745
+ {
746
+ input: "",
747
+ expected: { success: false },
748
+ },
749
+ ];
750
+ testCases.forEach(({ input, expected }) => {
751
+ if (expected.success) {
752
+ it(`should parse "${input}" successfully`, () => {
753
+ const result = typeAliasParser(input);
754
+ expect(result.success).toBe(true);
755
+ if (result.success) {
756
+ expect(result.result).toEqual(expected.result);
757
+ }
758
+ });
759
+ }
760
+ else {
761
+ it(`should fail to parse "${input}"`, () => {
762
+ const result = typeAliasParser(input);
763
+ expect(result.success).toBe(false);
764
+ });
765
+ }
766
+ });
767
+ });
768
+ describe("typeAliasVariableParser", () => {
769
+ const testCases = [
770
+ // Simple references
771
+ {
772
+ input: "Point",
773
+ expected: {
774
+ success: true,
775
+ result: {
776
+ type: "typeAliasVariable",
777
+ aliasName: "Point",
778
+ },
779
+ },
780
+ },
781
+ {
782
+ input: "MyType",
783
+ expected: {
784
+ success: true,
785
+ result: {
786
+ type: "typeAliasVariable",
787
+ aliasName: "MyType",
788
+ },
789
+ },
790
+ },
791
+ {
792
+ input: "UserData",
793
+ expected: {
794
+ success: true,
795
+ result: {
796
+ type: "typeAliasVariable",
797
+ aliasName: "UserData",
798
+ },
799
+ },
800
+ },
801
+ {
802
+ input: "x",
803
+ expected: {
804
+ success: true,
805
+ result: {
806
+ type: "typeAliasVariable",
807
+ aliasName: "x",
808
+ },
809
+ },
810
+ },
811
+ // Edge cases
812
+ {
813
+ input: "a123",
814
+ expected: {
815
+ success: true,
816
+ result: {
817
+ type: "typeAliasVariable",
818
+ aliasName: "a123",
819
+ },
820
+ },
821
+ },
822
+ {
823
+ input: "ABC",
824
+ expected: {
825
+ success: true,
826
+ result: {
827
+ type: "typeAliasVariable",
828
+ aliasName: "ABC",
829
+ },
830
+ },
831
+ },
832
+ {
833
+ input: "longtypename",
834
+ expected: {
835
+ success: true,
836
+ result: {
837
+ type: "typeAliasVariable",
838
+ aliasName: "longtypename",
839
+ },
840
+ },
841
+ },
842
+ // Failure cases
843
+ {
844
+ input: "",
845
+ expected: { success: false },
846
+ },
847
+ ];
848
+ testCases.forEach(({ input, expected }) => {
849
+ if (expected.success) {
850
+ it(`should parse "${input}" successfully`, () => {
851
+ const result = typeAliasVariableParser(input);
852
+ expect(result.success).toBe(true);
853
+ if (result.success) {
854
+ expect(result.result).toEqual(expected.result);
855
+ }
856
+ });
857
+ }
858
+ else {
859
+ it(`should fail to parse "${input}"`, () => {
860
+ const result = typeAliasVariableParser(input);
861
+ expect(result.success).toBe(false);
862
+ });
863
+ }
864
+ });
865
+ });
866
+ describe("objectPropertyParser", () => {
867
+ const testCases = [
868
+ {
869
+ input: "x: number",
870
+ expected: {
871
+ success: true,
872
+ result: {
873
+ key: "x",
874
+ value: { type: "primitiveType", value: "number" },
875
+ },
876
+ },
877
+ },
878
+ {
879
+ input: "name: string",
880
+ expected: {
881
+ success: true,
882
+ result: {
883
+ key: "name",
884
+ value: { type: "primitiveType", value: "string" },
885
+ },
886
+ },
887
+ },
888
+ {
889
+ input: "active: boolean",
890
+ expected: {
891
+ success: true,
892
+ result: {
893
+ key: "active",
894
+ value: { type: "primitiveType", value: "boolean" },
895
+ },
896
+ },
897
+ },
898
+ {
899
+ input: "items: number[]",
900
+ expected: {
901
+ success: true,
902
+ result: {
903
+ key: "items",
904
+ value: {
905
+ type: "arrayType",
906
+ elementType: { type: "primitiveType", value: "number" },
907
+ },
908
+ },
909
+ },
910
+ },
911
+ {
912
+ input: 'status: "active"',
913
+ expected: {
914
+ success: true,
915
+ result: {
916
+ key: "status",
917
+ value: { type: "stringLiteralType", value: "active" },
918
+ },
919
+ },
920
+ },
921
+ {
922
+ input: "count: 42",
923
+ expected: {
924
+ success: true,
925
+ result: {
926
+ key: "count",
927
+ value: { type: "numberLiteralType", value: "42" },
928
+ },
929
+ },
930
+ },
931
+ {
932
+ input: "x:number",
933
+ expected: {
934
+ success: true,
935
+ result: {
936
+ key: "x",
937
+ value: { type: "primitiveType", value: "number" },
938
+ },
939
+ },
940
+ },
941
+ {
942
+ input: "x : number",
943
+ expected: {
944
+ success: true,
945
+ result: {
946
+ key: "x",
947
+ value: { type: "primitiveType", value: "number" },
948
+ },
949
+ },
950
+ },
951
+ {
952
+ input: "x number",
953
+ expected: { success: false },
954
+ },
955
+ {
956
+ input: "x:",
957
+ expected: { success: false },
958
+ },
959
+ {
960
+ input: ": number",
961
+ expected: { success: false },
962
+ },
963
+ {
964
+ input: "",
965
+ expected: { success: false },
966
+ },
967
+ ];
968
+ testCases.forEach(({ input, expected }) => {
969
+ if (expected.success) {
970
+ it(`should parse "${input}" successfully`, () => {
971
+ const result = objectPropertyParser(input);
972
+ expect(result.success).toBe(true);
973
+ if (result.success) {
974
+ expect(result.result).toEqual(expected.result);
975
+ }
976
+ });
977
+ }
978
+ else {
979
+ it(`should fail to parse "${input}"`, () => {
980
+ const result = objectPropertyParser(input);
981
+ expect(result.success).toBe(false);
982
+ });
983
+ }
984
+ });
985
+ });
986
+ describe("objectPropertyDescriptionParser", () => {
987
+ const testCases = [
988
+ {
989
+ input: "# this is a description;",
990
+ expected: {
991
+ success: true,
992
+ result: {
993
+ description: "this is a description",
994
+ },
995
+ },
996
+ },
997
+ {
998
+ input: "# hostname of a url;",
999
+ expected: {
1000
+ success: true,
1001
+ result: {
1002
+ description: "hostname of a url",
1003
+ },
1004
+ },
1005
+ },
1006
+ {
1007
+ input: "#simple;",
1008
+ expected: {
1009
+ success: true,
1010
+ result: {
1011
+ description: "simple",
1012
+ },
1013
+ },
1014
+ },
1015
+ {
1016
+ input: "# with extra spaces ;",
1017
+ expected: {
1018
+ success: true,
1019
+ result: {
1020
+ description: "with extra spaces ",
1021
+ },
1022
+ },
1023
+ },
1024
+ {
1025
+ input: "# description with, punctuation!;",
1026
+ expected: {
1027
+ success: true,
1028
+ result: {
1029
+ description: "description with, punctuation!",
1030
+ },
1031
+ },
1032
+ },
1033
+ {
1034
+ input: "# description with numbers 123;",
1035
+ expected: {
1036
+ success: true,
1037
+ result: {
1038
+ description: "description with numbers 123",
1039
+ },
1040
+ },
1041
+ },
1042
+ // Failure cases
1043
+ {
1044
+ input: "no hash;",
1045
+ expected: { success: false },
1046
+ },
1047
+ {
1048
+ input: "#;",
1049
+ expected: { success: false },
1050
+ },
1051
+ {
1052
+ input: "",
1053
+ expected: { success: false },
1054
+ },
1055
+ ];
1056
+ testCases.forEach(({ input, expected }) => {
1057
+ if (expected.success) {
1058
+ it(`should parse "${input}" successfully`, () => {
1059
+ const result = objectPropertyDescriptionParser(input);
1060
+ expect(result.success).toBe(true);
1061
+ if (result.success) {
1062
+ expect(result.result).toEqual(expected.result);
1063
+ }
1064
+ });
1065
+ }
1066
+ else {
1067
+ it(`should fail to parse "${input}"`, () => {
1068
+ const result = objectPropertyDescriptionParser(input);
1069
+ expect(result.success).toBe(false);
1070
+ });
1071
+ }
1072
+ });
1073
+ });
1074
+ describe("objectPropertyWithDescriptionParser", () => {
1075
+ const testCases = [
1076
+ {
1077
+ input: "hostname: string # hostname of a url;",
1078
+ expected: {
1079
+ success: true,
1080
+ result: {
1081
+ key: "hostname",
1082
+ value: { type: "primitiveType", value: "string" },
1083
+ description: "hostname of a url",
1084
+ },
1085
+ },
1086
+ },
1087
+ {
1088
+ input: "x: number # x coordinate;",
1089
+ expected: {
1090
+ success: true,
1091
+ result: {
1092
+ key: "x",
1093
+ value: { type: "primitiveType", value: "number" },
1094
+ description: "x coordinate",
1095
+ },
1096
+ },
1097
+ },
1098
+ {
1099
+ input: "active: boolean # whether user is active;",
1100
+ expected: {
1101
+ success: true,
1102
+ result: {
1103
+ key: "active",
1104
+ value: { type: "primitiveType", value: "boolean" },
1105
+ description: "whether user is active",
1106
+ },
1107
+ },
1108
+ },
1109
+ {
1110
+ input: "items: number[] # list of item ids;",
1111
+ expected: {
1112
+ success: true,
1113
+ result: {
1114
+ key: "items",
1115
+ value: {
1116
+ type: "arrayType",
1117
+ elementType: { type: "primitiveType", value: "number" },
1118
+ },
1119
+ description: "list of item ids",
1120
+ },
1121
+ },
1122
+ },
1123
+ {
1124
+ input: 'status: "active" # current status;',
1125
+ expected: {
1126
+ success: true,
1127
+ result: {
1128
+ key: "status",
1129
+ value: { type: "stringLiteralType", value: "active" },
1130
+ description: "current status",
1131
+ },
1132
+ },
1133
+ },
1134
+ {
1135
+ input: "count: 42 # default count;",
1136
+ expected: {
1137
+ success: true,
1138
+ result: {
1139
+ key: "count",
1140
+ value: { type: "numberLiteralType", value: "42" },
1141
+ description: "default count",
1142
+ },
1143
+ },
1144
+ },
1145
+ // Without extra spaces
1146
+ {
1147
+ input: "name: string #user name;",
1148
+ expected: {
1149
+ success: true,
1150
+ result: {
1151
+ key: "name",
1152
+ value: { type: "primitiveType", value: "string" },
1153
+ description: "user name",
1154
+ },
1155
+ },
1156
+ },
1157
+ // Failure cases
1158
+ {
1159
+ input: "x: number",
1160
+ expected: { success: false },
1161
+ },
1162
+ {
1163
+ input: "",
1164
+ expected: { success: false },
1165
+ },
1166
+ ];
1167
+ testCases.forEach(({ input, expected }) => {
1168
+ if (expected.success) {
1169
+ it(`should parse "${input}" successfully`, () => {
1170
+ const result = objectPropertyWithDescriptionParser(input);
1171
+ expect(result.success).toBe(true);
1172
+ if (result.success) {
1173
+ expect(result.result).toEqual(expected.result);
1174
+ }
1175
+ });
1176
+ }
1177
+ else {
1178
+ it(`should fail to parse "${input}"`, () => {
1179
+ const result = objectPropertyWithDescriptionParser(input);
1180
+ expect(result.success).toBe(false);
1181
+ });
1182
+ }
1183
+ });
1184
+ });
1185
+ describe("objectTypeParser", () => {
1186
+ const testCases = [
1187
+ // Single property
1188
+ {
1189
+ input: "{ x: number }",
1190
+ expected: {
1191
+ success: true,
1192
+ result: {
1193
+ type: "objectType",
1194
+ properties: [
1195
+ {
1196
+ key: "x",
1197
+ value: { type: "primitiveType", value: "number" },
1198
+ },
1199
+ ],
1200
+ },
1201
+ },
1202
+ },
1203
+ // Multiple properties
1204
+ {
1205
+ input: "{ x: number; y: number }",
1206
+ expected: {
1207
+ success: true,
1208
+ result: {
1209
+ type: "objectType",
1210
+ properties: [
1211
+ {
1212
+ key: "x",
1213
+ value: { type: "primitiveType", value: "number" },
1214
+ },
1215
+ {
1216
+ key: "y",
1217
+ value: { type: "primitiveType", value: "number" },
1218
+ },
1219
+ ],
1220
+ },
1221
+ },
1222
+ },
1223
+ {
1224
+ input: "{ name: string; age: number; active: boolean }",
1225
+ expected: {
1226
+ success: true,
1227
+ result: {
1228
+ type: "objectType",
1229
+ properties: [
1230
+ {
1231
+ key: "name",
1232
+ value: { type: "primitiveType", value: "string" },
1233
+ },
1234
+ {
1235
+ key: "age",
1236
+ value: { type: "primitiveType", value: "number" },
1237
+ },
1238
+ {
1239
+ key: "active",
1240
+ value: { type: "primitiveType", value: "boolean" },
1241
+ },
1242
+ ],
1243
+ },
1244
+ },
1245
+ },
1246
+ // With different value types
1247
+ {
1248
+ input: "{ items: number[]; tags: string[] }",
1249
+ expected: {
1250
+ success: true,
1251
+ result: {
1252
+ type: "objectType",
1253
+ properties: [
1254
+ {
1255
+ key: "items",
1256
+ value: {
1257
+ type: "arrayType",
1258
+ elementType: { type: "primitiveType", value: "number" },
1259
+ },
1260
+ },
1261
+ {
1262
+ key: "tags",
1263
+ value: {
1264
+ type: "arrayType",
1265
+ elementType: { type: "primitiveType", value: "string" },
1266
+ },
1267
+ },
1268
+ ],
1269
+ },
1270
+ },
1271
+ },
1272
+ {
1273
+ input: '{ status: "active"; count: 42 }',
1274
+ expected: {
1275
+ success: true,
1276
+ result: {
1277
+ type: "objectType",
1278
+ properties: [
1279
+ {
1280
+ key: "status",
1281
+ value: { type: "stringLiteralType", value: "active" },
1282
+ },
1283
+ {
1284
+ key: "count",
1285
+ value: { type: "numberLiteralType", value: "42" },
1286
+ },
1287
+ ],
1288
+ },
1289
+ },
1290
+ },
1291
+ // Whitespace variations
1292
+ {
1293
+ input: "{x:number}",
1294
+ expected: {
1295
+ success: true,
1296
+ result: {
1297
+ type: "objectType",
1298
+ properties: [
1299
+ {
1300
+ key: "x",
1301
+ value: { type: "primitiveType", value: "number" },
1302
+ },
1303
+ ],
1304
+ },
1305
+ },
1306
+ },
1307
+ {
1308
+ input: "{ x: number }",
1309
+ expected: {
1310
+ success: true,
1311
+ result: {
1312
+ type: "objectType",
1313
+ properties: [
1314
+ {
1315
+ key: "x",
1316
+ value: { type: "primitiveType", value: "number" },
1317
+ },
1318
+ ],
1319
+ },
1320
+ },
1321
+ },
1322
+ {
1323
+ input: "{ x: number ; y: number }",
1324
+ expected: {
1325
+ success: true,
1326
+ result: {
1327
+ type: "objectType",
1328
+ properties: [
1329
+ {
1330
+ key: "x",
1331
+ value: { type: "primitiveType", value: "number" },
1332
+ },
1333
+ {
1334
+ key: "y",
1335
+ value: { type: "primitiveType", value: "number" },
1336
+ },
1337
+ ],
1338
+ },
1339
+ },
1340
+ },
1341
+ // Empty object
1342
+ {
1343
+ input: "{}",
1344
+ expected: {
1345
+ success: true,
1346
+ result: {
1347
+ type: "objectType",
1348
+ properties: [],
1349
+ },
1350
+ },
1351
+ },
1352
+ {
1353
+ input: "{ }",
1354
+ expected: {
1355
+ success: true,
1356
+ result: {
1357
+ type: "objectType",
1358
+ properties: [],
1359
+ },
1360
+ },
1361
+ },
1362
+ // Object with union type values
1363
+ {
1364
+ input: "{ value: string | number }",
1365
+ expected: {
1366
+ success: true,
1367
+ result: {
1368
+ type: "objectType",
1369
+ properties: [
1370
+ {
1371
+ key: "value",
1372
+ value: {
1373
+ type: "unionType",
1374
+ types: [
1375
+ { type: "primitiveType", value: "string" },
1376
+ { type: "primitiveType", value: "number" },
1377
+ ],
1378
+ },
1379
+ },
1380
+ ],
1381
+ },
1382
+ },
1383
+ },
1384
+ {
1385
+ input: '{ status: "active" | "inactive"; count: number }',
1386
+ expected: {
1387
+ success: true,
1388
+ result: {
1389
+ type: "objectType",
1390
+ properties: [
1391
+ {
1392
+ key: "status",
1393
+ value: {
1394
+ type: "unionType",
1395
+ types: [
1396
+ { type: "stringLiteralType", value: "active" },
1397
+ { type: "stringLiteralType", value: "inactive" },
1398
+ ],
1399
+ },
1400
+ },
1401
+ {
1402
+ key: "count",
1403
+ value: { type: "primitiveType", value: "number" },
1404
+ },
1405
+ ],
1406
+ },
1407
+ },
1408
+ },
1409
+ {
1410
+ input: "{ data: string | number | boolean }",
1411
+ expected: {
1412
+ success: true,
1413
+ result: {
1414
+ type: "objectType",
1415
+ properties: [
1416
+ {
1417
+ key: "data",
1418
+ value: {
1419
+ type: "unionType",
1420
+ types: [
1421
+ { type: "primitiveType", value: "string" },
1422
+ { type: "primitiveType", value: "number" },
1423
+ { type: "primitiveType", value: "boolean" },
1424
+ ],
1425
+ },
1426
+ },
1427
+ ],
1428
+ },
1429
+ },
1430
+ },
1431
+ // Nested object types
1432
+ {
1433
+ input: "{ coords: { x: number; y: number } }",
1434
+ expected: {
1435
+ success: true,
1436
+ result: {
1437
+ type: "objectType",
1438
+ properties: [
1439
+ {
1440
+ key: "coords",
1441
+ value: {
1442
+ type: "objectType",
1443
+ properties: [
1444
+ {
1445
+ key: "x",
1446
+ value: { type: "primitiveType", value: "number" },
1447
+ },
1448
+ {
1449
+ key: "y",
1450
+ value: { type: "primitiveType", value: "number" },
1451
+ },
1452
+ ],
1453
+ },
1454
+ },
1455
+ ],
1456
+ },
1457
+ },
1458
+ },
1459
+ {
1460
+ input: "{ user: { name: string; age: number }; active: boolean }",
1461
+ expected: {
1462
+ success: true,
1463
+ result: {
1464
+ type: "objectType",
1465
+ properties: [
1466
+ {
1467
+ key: "user",
1468
+ value: {
1469
+ type: "objectType",
1470
+ properties: [
1471
+ {
1472
+ key: "name",
1473
+ value: { type: "primitiveType", value: "string" },
1474
+ },
1475
+ {
1476
+ key: "age",
1477
+ value: { type: "primitiveType", value: "number" },
1478
+ },
1479
+ ],
1480
+ },
1481
+ },
1482
+ {
1483
+ key: "active",
1484
+ value: { type: "primitiveType", value: "boolean" },
1485
+ },
1486
+ ],
1487
+ },
1488
+ },
1489
+ },
1490
+ {
1491
+ input: "{ outer: { inner: { value: string } } }",
1492
+ expected: {
1493
+ success: true,
1494
+ result: {
1495
+ type: "objectType",
1496
+ properties: [
1497
+ {
1498
+ key: "outer",
1499
+ value: {
1500
+ type: "objectType",
1501
+ properties: [
1502
+ {
1503
+ key: "inner",
1504
+ value: {
1505
+ type: "objectType",
1506
+ properties: [
1507
+ {
1508
+ key: "value",
1509
+ value: { type: "primitiveType", value: "string" },
1510
+ },
1511
+ ],
1512
+ },
1513
+ },
1514
+ ],
1515
+ },
1516
+ },
1517
+ ],
1518
+ },
1519
+ },
1520
+ },
1521
+ // Object with type alias properties
1522
+ {
1523
+ input: "{ coord: Point }",
1524
+ expected: {
1525
+ success: true,
1526
+ result: {
1527
+ type: "objectType",
1528
+ properties: [
1529
+ {
1530
+ key: "coord",
1531
+ value: {
1532
+ type: "typeAliasVariable",
1533
+ aliasName: "Point",
1534
+ },
1535
+ },
1536
+ ],
1537
+ },
1538
+ },
1539
+ },
1540
+ {
1541
+ input: "{ start: Point; end: Point }",
1542
+ expected: {
1543
+ success: true,
1544
+ result: {
1545
+ type: "objectType",
1546
+ properties: [
1547
+ {
1548
+ key: "start",
1549
+ value: {
1550
+ type: "typeAliasVariable",
1551
+ aliasName: "Point",
1552
+ },
1553
+ },
1554
+ {
1555
+ key: "end",
1556
+ value: {
1557
+ type: "typeAliasVariable",
1558
+ aliasName: "Point",
1559
+ },
1560
+ },
1561
+ ],
1562
+ },
1563
+ },
1564
+ },
1565
+ {
1566
+ input: "{ data: Point | Line }",
1567
+ expected: {
1568
+ success: true,
1569
+ result: {
1570
+ type: "objectType",
1571
+ properties: [
1572
+ {
1573
+ key: "data",
1574
+ value: {
1575
+ type: "unionType",
1576
+ types: [
1577
+ {
1578
+ type: "typeAliasVariable",
1579
+ aliasName: "Point",
1580
+ },
1581
+ {
1582
+ type: "typeAliasVariable",
1583
+ aliasName: "Line",
1584
+ },
1585
+ ],
1586
+ },
1587
+ },
1588
+ ],
1589
+ },
1590
+ },
1591
+ },
1592
+ // Failure cases
1593
+ {
1594
+ input: "{ x number }",
1595
+ expected: { success: false },
1596
+ },
1597
+ {
1598
+ input: "{ x: }",
1599
+ expected: { success: false },
1600
+ },
1601
+ {
1602
+ input: "{ : number }",
1603
+ expected: { success: false },
1604
+ },
1605
+ {
1606
+ input: "{ x: number",
1607
+ expected: { success: false },
1608
+ },
1609
+ {
1610
+ input: "x: number }",
1611
+ expected: { success: false },
1612
+ },
1613
+ {
1614
+ input: "",
1615
+ expected: { success: false },
1616
+ },
1617
+ // With descriptions
1618
+ {
1619
+ input: "{ hostname: string # hostname of a url; }",
1620
+ expected: {
1621
+ success: true,
1622
+ result: {
1623
+ type: "objectType",
1624
+ properties: [
1625
+ {
1626
+ key: "hostname",
1627
+ value: { type: "primitiveType", value: "string" },
1628
+ description: "hostname of a url",
1629
+ },
1630
+ ],
1631
+ },
1632
+ },
1633
+ },
1634
+ {
1635
+ input: "{ x: number # x coordinate; y: number # y coordinate; }",
1636
+ expected: {
1637
+ success: true,
1638
+ result: {
1639
+ type: "objectType",
1640
+ properties: [
1641
+ {
1642
+ key: "x",
1643
+ value: { type: "primitiveType", value: "number" },
1644
+ description: "x coordinate",
1645
+ },
1646
+ {
1647
+ key: "y",
1648
+ value: { type: "primitiveType", value: "number" },
1649
+ description: "y coordinate",
1650
+ },
1651
+ ],
1652
+ },
1653
+ },
1654
+ },
1655
+ {
1656
+ input: "{ name: string # user name; age: number; active: boolean # is active; }",
1657
+ expected: {
1658
+ success: true,
1659
+ result: {
1660
+ type: "objectType",
1661
+ properties: [
1662
+ {
1663
+ key: "name",
1664
+ value: { type: "primitiveType", value: "string" },
1665
+ description: "user name",
1666
+ },
1667
+ {
1668
+ key: "age",
1669
+ value: { type: "primitiveType", value: "number" },
1670
+ },
1671
+ {
1672
+ key: "active",
1673
+ value: { type: "primitiveType", value: "boolean" },
1674
+ description: "is active",
1675
+ },
1676
+ ],
1677
+ },
1678
+ },
1679
+ },
1680
+ {
1681
+ input: "{ items: number[] # list of ids; }",
1682
+ expected: {
1683
+ success: true,
1684
+ result: {
1685
+ type: "objectType",
1686
+ properties: [
1687
+ {
1688
+ key: "items",
1689
+ value: {
1690
+ type: "arrayType",
1691
+ elementType: { type: "primitiveType", value: "number" },
1692
+ },
1693
+ description: "list of ids",
1694
+ },
1695
+ ],
1696
+ },
1697
+ },
1698
+ },
1699
+ ];
1700
+ testCases.forEach(({ input, expected }) => {
1701
+ if (expected.success) {
1702
+ it(`should parse "${input}" successfully`, () => {
1703
+ const result = objectTypeParser(input);
1704
+ expect(result.success).toBe(true);
1705
+ if (result.success) {
1706
+ expect(result.result).toEqual(expected.result);
1707
+ }
1708
+ });
1709
+ }
1710
+ else {
1711
+ it(`should fail to parse "${input}"`, () => {
1712
+ const result = objectTypeParser(input);
1713
+ expect(result.success).toBe(false);
1714
+ });
1715
+ }
1716
+ });
1717
+ });
1718
+ describe("unionTypeParser", () => {
1719
+ const testCases = [
1720
+ // Basic union types
1721
+ {
1722
+ input: "string | number",
1723
+ expected: {
1724
+ success: true,
1725
+ result: {
1726
+ type: "unionType",
1727
+ types: [
1728
+ { type: "primitiveType", value: "string" },
1729
+ { type: "primitiveType", value: "number" },
1730
+ ],
1731
+ },
1732
+ },
1733
+ },
1734
+ {
1735
+ input: "number | string",
1736
+ expected: {
1737
+ success: true,
1738
+ result: {
1739
+ type: "unionType",
1740
+ types: [
1741
+ { type: "primitiveType", value: "number" },
1742
+ { type: "primitiveType", value: "string" },
1743
+ ],
1744
+ },
1745
+ },
1746
+ },
1747
+ {
1748
+ input: "string | boolean",
1749
+ expected: {
1750
+ success: true,
1751
+ result: {
1752
+ type: "unionType",
1753
+ types: [
1754
+ { type: "primitiveType", value: "string" },
1755
+ { type: "primitiveType", value: "boolean" },
1756
+ ],
1757
+ },
1758
+ },
1759
+ },
1760
+ // Union with literal types
1761
+ {
1762
+ input: '"hello" | "world"',
1763
+ expected: {
1764
+ success: true,
1765
+ result: {
1766
+ type: "unionType",
1767
+ types: [
1768
+ { type: "stringLiteralType", value: "hello" },
1769
+ { type: "stringLiteralType", value: "world" },
1770
+ ],
1771
+ },
1772
+ },
1773
+ },
1774
+ {
1775
+ input: "42 | 100",
1776
+ expected: {
1777
+ success: true,
1778
+ result: {
1779
+ type: "unionType",
1780
+ types: [
1781
+ { type: "numberLiteralType", value: "42" },
1782
+ { type: "numberLiteralType", value: "100" },
1783
+ ],
1784
+ },
1785
+ },
1786
+ },
1787
+ {
1788
+ input: "true | false",
1789
+ expected: {
1790
+ success: true,
1791
+ result: {
1792
+ type: "unionType",
1793
+ types: [
1794
+ { type: "booleanLiteralType", value: "true" },
1795
+ { type: "booleanLiteralType", value: "false" },
1796
+ ],
1797
+ },
1798
+ },
1799
+ },
1800
+ // Mixed literals and primitives
1801
+ {
1802
+ input: '"hello" | number',
1803
+ expected: {
1804
+ success: true,
1805
+ result: {
1806
+ type: "unionType",
1807
+ types: [
1808
+ { type: "stringLiteralType", value: "hello" },
1809
+ { type: "primitiveType", value: "number" },
1810
+ ],
1811
+ },
1812
+ },
1813
+ },
1814
+ {
1815
+ input: "42 | string",
1816
+ expected: {
1817
+ success: true,
1818
+ result: {
1819
+ type: "unionType",
1820
+ types: [
1821
+ { type: "numberLiteralType", value: "42" },
1822
+ { type: "primitiveType", value: "string" },
1823
+ ],
1824
+ },
1825
+ },
1826
+ },
1827
+ // Multiple types (more than 2)
1828
+ {
1829
+ input: "string | number | boolean",
1830
+ expected: {
1831
+ success: true,
1832
+ result: {
1833
+ type: "unionType",
1834
+ types: [
1835
+ { type: "primitiveType", value: "string" },
1836
+ { type: "primitiveType", value: "number" },
1837
+ { type: "primitiveType", value: "boolean" },
1838
+ ],
1839
+ },
1840
+ },
1841
+ },
1842
+ {
1843
+ input: '"a" | "b" | "c"',
1844
+ expected: {
1845
+ success: true,
1846
+ result: {
1847
+ type: "unionType",
1848
+ types: [
1849
+ { type: "stringLiteralType", value: "a" },
1850
+ { type: "stringLiteralType", value: "b" },
1851
+ { type: "stringLiteralType", value: "c" },
1852
+ ],
1853
+ },
1854
+ },
1855
+ },
1856
+ // Whitespace variations
1857
+ {
1858
+ input: "string|number",
1859
+ expected: {
1860
+ success: true,
1861
+ result: {
1862
+ type: "unionType",
1863
+ types: [
1864
+ { type: "primitiveType", value: "string" },
1865
+ { type: "primitiveType", value: "number" },
1866
+ ],
1867
+ },
1868
+ },
1869
+ },
1870
+ {
1871
+ input: "string | number",
1872
+ expected: {
1873
+ success: true,
1874
+ result: {
1875
+ type: "unionType",
1876
+ types: [
1877
+ { type: "primitiveType", value: "string" },
1878
+ { type: "primitiveType", value: "number" },
1879
+ ],
1880
+ },
1881
+ },
1882
+ },
1883
+ // Union with array types
1884
+ {
1885
+ input: "string[] | number[]",
1886
+ expected: {
1887
+ success: true,
1888
+ result: {
1889
+ type: "unionType",
1890
+ types: [
1891
+ {
1892
+ type: "arrayType",
1893
+ elementType: { type: "primitiveType", value: "string" },
1894
+ },
1895
+ {
1896
+ type: "arrayType",
1897
+ elementType: { type: "primitiveType", value: "number" },
1898
+ },
1899
+ ],
1900
+ },
1901
+ },
1902
+ },
1903
+ {
1904
+ input: "array<string> | array<number>",
1905
+ expected: {
1906
+ success: true,
1907
+ result: {
1908
+ type: "unionType",
1909
+ types: [
1910
+ {
1911
+ type: "arrayType",
1912
+ elementType: { type: "primitiveType", value: "string" },
1913
+ },
1914
+ {
1915
+ type: "arrayType",
1916
+ elementType: { type: "primitiveType", value: "number" },
1917
+ },
1918
+ ],
1919
+ },
1920
+ },
1921
+ },
1922
+ // Union of object types
1923
+ {
1924
+ input: "{ x: number } | { y: string }",
1925
+ expected: {
1926
+ success: true,
1927
+ result: {
1928
+ type: "unionType",
1929
+ types: [
1930
+ {
1931
+ type: "objectType",
1932
+ properties: [
1933
+ {
1934
+ key: "x",
1935
+ value: { type: "primitiveType", value: "number" },
1936
+ },
1937
+ ],
1938
+ },
1939
+ {
1940
+ type: "objectType",
1941
+ properties: [
1942
+ {
1943
+ key: "y",
1944
+ value: { type: "primitiveType", value: "string" },
1945
+ },
1946
+ ],
1947
+ },
1948
+ ],
1949
+ },
1950
+ },
1951
+ },
1952
+ {
1953
+ input: "{ name: string; age: number } | { id: number; active: boolean }",
1954
+ expected: {
1955
+ success: true,
1956
+ result: {
1957
+ type: "unionType",
1958
+ types: [
1959
+ {
1960
+ type: "objectType",
1961
+ properties: [
1962
+ {
1963
+ key: "name",
1964
+ value: { type: "primitiveType", value: "string" },
1965
+ },
1966
+ {
1967
+ key: "age",
1968
+ value: { type: "primitiveType", value: "number" },
1969
+ },
1970
+ ],
1971
+ },
1972
+ {
1973
+ type: "objectType",
1974
+ properties: [
1975
+ {
1976
+ key: "id",
1977
+ value: { type: "primitiveType", value: "number" },
1978
+ },
1979
+ {
1980
+ key: "active",
1981
+ value: { type: "primitiveType", value: "boolean" },
1982
+ },
1983
+ ],
1984
+ },
1985
+ ],
1986
+ },
1987
+ },
1988
+ },
1989
+ {
1990
+ input: "{ x: number } | { y: number } | { z: number }",
1991
+ expected: {
1992
+ success: true,
1993
+ result: {
1994
+ type: "unionType",
1995
+ types: [
1996
+ {
1997
+ type: "objectType",
1998
+ properties: [
1999
+ {
2000
+ key: "x",
2001
+ value: { type: "primitiveType", value: "number" },
2002
+ },
2003
+ ],
2004
+ },
2005
+ {
2006
+ type: "objectType",
2007
+ properties: [
2008
+ {
2009
+ key: "y",
2010
+ value: { type: "primitiveType", value: "number" },
2011
+ },
2012
+ ],
2013
+ },
2014
+ {
2015
+ type: "objectType",
2016
+ properties: [
2017
+ {
2018
+ key: "z",
2019
+ value: { type: "primitiveType", value: "number" },
2020
+ },
2021
+ ],
2022
+ },
2023
+ ],
2024
+ },
2025
+ },
2026
+ },
2027
+ // Union of objects with union properties
2028
+ {
2029
+ input: '{ status: "active" | "inactive" } | { code: number }',
2030
+ expected: {
2031
+ success: true,
2032
+ result: {
2033
+ type: "unionType",
2034
+ types: [
2035
+ {
2036
+ type: "objectType",
2037
+ properties: [
2038
+ {
2039
+ key: "status",
2040
+ value: {
2041
+ type: "unionType",
2042
+ types: [
2043
+ { type: "stringLiteralType", value: "active" },
2044
+ { type: "stringLiteralType", value: "inactive" },
2045
+ ],
2046
+ },
2047
+ },
2048
+ ],
2049
+ },
2050
+ {
2051
+ type: "objectType",
2052
+ properties: [
2053
+ {
2054
+ key: "code",
2055
+ value: { type: "primitiveType", value: "number" },
2056
+ },
2057
+ ],
2058
+ },
2059
+ ],
2060
+ },
2061
+ },
2062
+ },
2063
+ {
2064
+ input: "{ value: string | number } | { data: boolean | number }",
2065
+ expected: {
2066
+ success: true,
2067
+ result: {
2068
+ type: "unionType",
2069
+ types: [
2070
+ {
2071
+ type: "objectType",
2072
+ properties: [
2073
+ {
2074
+ key: "value",
2075
+ value: {
2076
+ type: "unionType",
2077
+ types: [
2078
+ { type: "primitiveType", value: "string" },
2079
+ { type: "primitiveType", value: "number" },
2080
+ ],
2081
+ },
2082
+ },
2083
+ ],
2084
+ },
2085
+ {
2086
+ type: "objectType",
2087
+ properties: [
2088
+ {
2089
+ key: "data",
2090
+ value: {
2091
+ type: "unionType",
2092
+ types: [
2093
+ { type: "primitiveType", value: "boolean" },
2094
+ { type: "primitiveType", value: "number" },
2095
+ ],
2096
+ },
2097
+ },
2098
+ ],
2099
+ },
2100
+ ],
2101
+ },
2102
+ },
2103
+ },
2104
+ {
2105
+ input: '{ type: "user"; name: string } | { type: "admin"; level: number }',
2106
+ expected: {
2107
+ success: true,
2108
+ result: {
2109
+ type: "unionType",
2110
+ types: [
2111
+ {
2112
+ type: "objectType",
2113
+ properties: [
2114
+ {
2115
+ key: "type",
2116
+ value: { type: "stringLiteralType", value: "user" },
2117
+ },
2118
+ {
2119
+ key: "name",
2120
+ value: { type: "primitiveType", value: "string" },
2121
+ },
2122
+ ],
2123
+ },
2124
+ {
2125
+ type: "objectType",
2126
+ properties: [
2127
+ {
2128
+ key: "type",
2129
+ value: { type: "stringLiteralType", value: "admin" },
2130
+ },
2131
+ {
2132
+ key: "level",
2133
+ value: { type: "primitiveType", value: "number" },
2134
+ },
2135
+ ],
2136
+ },
2137
+ ],
2138
+ },
2139
+ },
2140
+ },
2141
+ // Union with type aliases
2142
+ {
2143
+ input: "Point | Line",
2144
+ expected: {
2145
+ success: true,
2146
+ result: {
2147
+ type: "unionType",
2148
+ types: [
2149
+ {
2150
+ type: "typeAliasVariable",
2151
+ aliasName: "Point",
2152
+ },
2153
+ {
2154
+ type: "typeAliasVariable",
2155
+ aliasName: "Line",
2156
+ },
2157
+ ],
2158
+ },
2159
+ },
2160
+ },
2161
+ {
2162
+ input: "string | Point",
2163
+ expected: {
2164
+ success: true,
2165
+ result: {
2166
+ type: "unionType",
2167
+ types: [
2168
+ { type: "primitiveType", value: "string" },
2169
+ {
2170
+ type: "typeAliasVariable",
2171
+ aliasName: "Point",
2172
+ },
2173
+ ],
2174
+ },
2175
+ },
2176
+ },
2177
+ {
2178
+ input: "Point | { x: number }",
2179
+ expected: {
2180
+ success: true,
2181
+ result: {
2182
+ type: "unionType",
2183
+ types: [
2184
+ {
2185
+ type: "typeAliasVariable",
2186
+ aliasName: "Point",
2187
+ },
2188
+ {
2189
+ type: "objectType",
2190
+ properties: [
2191
+ {
2192
+ key: "x",
2193
+ value: { type: "primitiveType", value: "number" },
2194
+ },
2195
+ ],
2196
+ },
2197
+ ],
2198
+ },
2199
+ },
2200
+ },
2201
+ {
2202
+ input: "Point | Line | Circle",
2203
+ expected: {
2204
+ success: true,
2205
+ result: {
2206
+ type: "unionType",
2207
+ types: [
2208
+ {
2209
+ type: "typeAliasVariable",
2210
+ aliasName: "Point",
2211
+ },
2212
+ {
2213
+ type: "typeAliasVariable",
2214
+ aliasName: "Line",
2215
+ },
2216
+ {
2217
+ type: "typeAliasVariable",
2218
+ aliasName: "Circle",
2219
+ },
2220
+ ],
2221
+ },
2222
+ },
2223
+ },
2224
+ // Failure cases
2225
+ {
2226
+ input: "string",
2227
+ expected: { success: false },
2228
+ },
2229
+ {
2230
+ input: "string number",
2231
+ expected: { success: false },
2232
+ },
2233
+ {
2234
+ input: "",
2235
+ expected: { success: false },
2236
+ },
2237
+ {
2238
+ input: "|",
2239
+ expected: { success: false },
2240
+ },
2241
+ {
2242
+ input: "string |",
2243
+ expected: { success: false },
2244
+ },
2245
+ {
2246
+ input: "| string",
2247
+ expected: { success: false },
2248
+ },
2249
+ ];
2250
+ testCases.forEach(({ input, expected }) => {
2251
+ if (expected.success) {
2252
+ it(`should parse "${input}" successfully`, () => {
2253
+ const result = unionTypeParser(input);
2254
+ expect(result.success).toBe(true);
2255
+ if (result.success) {
2256
+ expect(result.result).toEqual(expected.result);
2257
+ }
2258
+ });
2259
+ }
2260
+ else {
2261
+ it(`should fail to parse "${input}"`, () => {
2262
+ const result = unionTypeParser(input);
2263
+ expect(result.success).toBe(false);
2264
+ });
2265
+ }
2266
+ });
2267
+ });
2268
+ describe("variableTypeParser", () => {
2269
+ const testCases = [
2270
+ {
2271
+ input: "number",
2272
+ expected: {
2273
+ success: true,
2274
+ result: { type: "primitiveType", value: "number" },
2275
+ },
2276
+ },
2277
+ {
2278
+ input: "string[]",
2279
+ expected: {
2280
+ success: true,
2281
+ result: {
2282
+ type: "arrayType",
2283
+ elementType: { type: "primitiveType", value: "string" },
2284
+ },
2285
+ },
2286
+ },
2287
+ {
2288
+ input: "array<boolean>",
2289
+ expected: {
2290
+ success: true,
2291
+ result: {
2292
+ type: "arrayType",
2293
+ elementType: { type: "primitiveType", value: "boolean" },
2294
+ },
2295
+ },
2296
+ },
2297
+ {
2298
+ input: '"hello"',
2299
+ expected: {
2300
+ success: true,
2301
+ result: { type: "stringLiteralType", value: "hello" },
2302
+ },
2303
+ },
2304
+ {
2305
+ input: "42",
2306
+ expected: {
2307
+ success: true,
2308
+ result: { type: "numberLiteralType", value: "42" },
2309
+ },
2310
+ },
2311
+ {
2312
+ input: "true",
2313
+ expected: {
2314
+ success: true,
2315
+ result: { type: "booleanLiteralType", value: "true" },
2316
+ },
2317
+ },
2318
+ {
2319
+ input: "{ x: number }",
2320
+ expected: {
2321
+ success: true,
2322
+ result: {
2323
+ type: "objectType",
2324
+ properties: [
2325
+ {
2326
+ key: "x",
2327
+ value: { type: "primitiveType", value: "number" },
2328
+ },
2329
+ ],
2330
+ },
2331
+ },
2332
+ },
2333
+ {
2334
+ input: "{ x: number; y: string }",
2335
+ expected: {
2336
+ success: true,
2337
+ result: {
2338
+ type: "objectType",
2339
+ properties: [
2340
+ {
2341
+ key: "x",
2342
+ value: { type: "primitiveType", value: "number" },
2343
+ },
2344
+ {
2345
+ key: "y",
2346
+ value: { type: "primitiveType", value: "string" },
2347
+ },
2348
+ ],
2349
+ },
2350
+ },
2351
+ },
2352
+ // Type alias references
2353
+ {
2354
+ input: "Point",
2355
+ expected: {
2356
+ success: true,
2357
+ result: {
2358
+ type: "typeAliasVariable",
2359
+ aliasName: "Point",
2360
+ },
2361
+ },
2362
+ },
2363
+ {
2364
+ input: "",
2365
+ expected: { success: false },
2366
+ },
2367
+ ];
2368
+ testCases.forEach(({ input, expected }) => {
2369
+ if (expected.success) {
2370
+ it(`should parse "${input}" successfully`, () => {
2371
+ const result = variableTypeParser(input);
2372
+ expect(result.success).toBe(true);
2373
+ if (result.success) {
2374
+ expect(result.result).toEqual(expected.result);
2375
+ }
2376
+ });
2377
+ }
2378
+ else {
2379
+ it(`should fail to parse "${input}"`, () => {
2380
+ const result = variableTypeParser(input);
2381
+ expect(result.success).toBe(false);
2382
+ });
2383
+ }
2384
+ });
2385
+ });
2386
+ describe("typeHintParser", () => {
2387
+ const testCases = [
2388
+ {
2389
+ input: "bar :: number",
2390
+ expected: {
2391
+ success: true,
2392
+ result: {
2393
+ type: "typeHint",
2394
+ variableName: "bar",
2395
+ variableType: { type: "primitiveType", value: "number" },
2396
+ },
2397
+ },
2398
+ },
2399
+ {
2400
+ input: "test :: string",
2401
+ expected: {
2402
+ success: true,
2403
+ result: {
2404
+ type: "typeHint",
2405
+ variableName: "test",
2406
+ variableType: { type: "primitiveType", value: "string" },
2407
+ },
2408
+ },
2409
+ },
2410
+ {
2411
+ input: "items :: number[]",
2412
+ expected: {
2413
+ success: true,
2414
+ result: {
2415
+ type: "typeHint",
2416
+ variableName: "items",
2417
+ variableType: {
2418
+ type: "arrayType",
2419
+ elementType: { type: "primitiveType", value: "number" },
2420
+ },
2421
+ },
2422
+ },
2423
+ },
2424
+ {
2425
+ input: "list :: array<string>",
2426
+ expected: {
2427
+ success: true,
2428
+ result: {
2429
+ type: "typeHint",
2430
+ variableName: "list",
2431
+ variableType: {
2432
+ type: "arrayType",
2433
+ elementType: { type: "primitiveType", value: "string" },
2434
+ },
2435
+ },
2436
+ },
2437
+ },
2438
+ {
2439
+ input: 'name :: "Alice"',
2440
+ expected: {
2441
+ success: true,
2442
+ result: {
2443
+ type: "typeHint",
2444
+ variableName: "name",
2445
+ variableType: { type: "stringLiteralType", value: "Alice" },
2446
+ },
2447
+ },
2448
+ },
2449
+ {
2450
+ input: "count :: 42",
2451
+ expected: {
2452
+ success: true,
2453
+ result: {
2454
+ type: "typeHint",
2455
+ variableName: "count",
2456
+ variableType: { type: "numberLiteralType", value: "42" },
2457
+ },
2458
+ },
2459
+ },
2460
+ {
2461
+ input: "flag :: true",
2462
+ expected: {
2463
+ success: true,
2464
+ result: {
2465
+ type: "typeHint",
2466
+ variableName: "flag",
2467
+ variableType: { type: "booleanLiteralType", value: "true" },
2468
+ },
2469
+ },
2470
+ },
2471
+ {
2472
+ input: "x :: number",
2473
+ expected: {
2474
+ success: true,
2475
+ result: {
2476
+ type: "typeHint",
2477
+ variableName: "x",
2478
+ variableType: { type: "primitiveType", value: "number" },
2479
+ },
2480
+ },
2481
+ },
2482
+ // Union types
2483
+ {
2484
+ input: "foo :: string | number",
2485
+ expected: {
2486
+ success: true,
2487
+ result: {
2488
+ type: "typeHint",
2489
+ variableName: "foo",
2490
+ variableType: {
2491
+ type: "unionType",
2492
+ types: [
2493
+ { type: "primitiveType", value: "string" },
2494
+ { type: "primitiveType", value: "number" },
2495
+ ],
2496
+ },
2497
+ },
2498
+ },
2499
+ },
2500
+ {
2501
+ input: "value :: number | string | boolean",
2502
+ expected: {
2503
+ success: true,
2504
+ result: {
2505
+ type: "typeHint",
2506
+ variableName: "value",
2507
+ variableType: {
2508
+ type: "unionType",
2509
+ types: [
2510
+ { type: "primitiveType", value: "number" },
2511
+ { type: "primitiveType", value: "string" },
2512
+ { type: "primitiveType", value: "boolean" },
2513
+ ],
2514
+ },
2515
+ },
2516
+ },
2517
+ },
2518
+ {
2519
+ input: 'status :: "success" | "error"',
2520
+ expected: {
2521
+ success: true,
2522
+ result: {
2523
+ type: "typeHint",
2524
+ variableName: "status",
2525
+ variableType: {
2526
+ type: "unionType",
2527
+ types: [
2528
+ { type: "stringLiteralType", value: "success" },
2529
+ { type: "stringLiteralType", value: "error" },
2530
+ ],
2531
+ },
2532
+ },
2533
+ },
2534
+ },
2535
+ {
2536
+ input: "mixed :: 42 | string",
2537
+ expected: {
2538
+ success: true,
2539
+ result: {
2540
+ type: "typeHint",
2541
+ variableName: "mixed",
2542
+ variableType: {
2543
+ type: "unionType",
2544
+ types: [
2545
+ { type: "numberLiteralType", value: "42" },
2546
+ { type: "primitiveType", value: "string" },
2547
+ ],
2548
+ },
2549
+ },
2550
+ },
2551
+ },
2552
+ {
2553
+ input: "arrays :: string[] | number[]",
2554
+ expected: {
2555
+ success: true,
2556
+ result: {
2557
+ type: "typeHint",
2558
+ variableName: "arrays",
2559
+ variableType: {
2560
+ type: "unionType",
2561
+ types: [
2562
+ {
2563
+ type: "arrayType",
2564
+ elementType: { type: "primitiveType", value: "string" },
2565
+ },
2566
+ {
2567
+ type: "arrayType",
2568
+ elementType: { type: "primitiveType", value: "number" },
2569
+ },
2570
+ ],
2571
+ },
2572
+ },
2573
+ },
2574
+ },
2575
+ // Object types
2576
+ {
2577
+ input: "point :: { x: number; y: number }",
2578
+ expected: {
2579
+ success: true,
2580
+ result: {
2581
+ type: "typeHint",
2582
+ variableName: "point",
2583
+ variableType: {
2584
+ type: "objectType",
2585
+ properties: [
2586
+ {
2587
+ key: "x",
2588
+ value: { type: "primitiveType", value: "number" },
2589
+ },
2590
+ {
2591
+ key: "y",
2592
+ value: { type: "primitiveType", value: "number" },
2593
+ },
2594
+ ],
2595
+ },
2596
+ },
2597
+ },
2598
+ },
2599
+ {
2600
+ input: "user :: { name: string; age: number; active: boolean }",
2601
+ expected: {
2602
+ success: true,
2603
+ result: {
2604
+ type: "typeHint",
2605
+ variableName: "user",
2606
+ variableType: {
2607
+ type: "objectType",
2608
+ properties: [
2609
+ {
2610
+ key: "name",
2611
+ value: { type: "primitiveType", value: "string" },
2612
+ },
2613
+ {
2614
+ key: "age",
2615
+ value: { type: "primitiveType", value: "number" },
2616
+ },
2617
+ {
2618
+ key: "active",
2619
+ value: { type: "primitiveType", value: "boolean" },
2620
+ },
2621
+ ],
2622
+ },
2623
+ },
2624
+ },
2625
+ },
2626
+ {
2627
+ input: "coords :: { items: number[]; tags: string[] }",
2628
+ expected: {
2629
+ success: true,
2630
+ result: {
2631
+ type: "typeHint",
2632
+ variableName: "coords",
2633
+ variableType: {
2634
+ type: "objectType",
2635
+ properties: [
2636
+ {
2637
+ key: "items",
2638
+ value: {
2639
+ type: "arrayType",
2640
+ elementType: { type: "primitiveType", value: "number" },
2641
+ },
2642
+ },
2643
+ {
2644
+ key: "tags",
2645
+ value: {
2646
+ type: "arrayType",
2647
+ elementType: { type: "primitiveType", value: "string" },
2648
+ },
2649
+ },
2650
+ ],
2651
+ },
2652
+ },
2653
+ },
2654
+ },
2655
+ // Type alias types
2656
+ {
2657
+ input: "coords :: Point",
2658
+ expected: {
2659
+ success: true,
2660
+ result: {
2661
+ type: "typeHint",
2662
+ variableName: "coords",
2663
+ variableType: {
2664
+ type: "typeAliasVariable",
2665
+ aliasName: "Point",
2666
+ },
2667
+ },
2668
+ },
2669
+ },
2670
+ {
2671
+ input: "data :: Point | Line",
2672
+ expected: {
2673
+ success: true,
2674
+ result: {
2675
+ type: "typeHint",
2676
+ variableName: "data",
2677
+ variableType: {
2678
+ type: "unionType",
2679
+ types: [
2680
+ {
2681
+ type: "typeAliasVariable",
2682
+ aliasName: "Point",
2683
+ },
2684
+ {
2685
+ type: "typeAliasVariable",
2686
+ aliasName: "Line",
2687
+ },
2688
+ ],
2689
+ },
2690
+ },
2691
+ },
2692
+ },
2693
+ {
2694
+ input: "nested :: { coord: Point }",
2695
+ expected: {
2696
+ success: true,
2697
+ result: {
2698
+ type: "typeHint",
2699
+ variableName: "nested",
2700
+ variableType: {
2701
+ type: "objectType",
2702
+ properties: [
2703
+ {
2704
+ key: "coord",
2705
+ value: {
2706
+ type: "typeAliasVariable",
2707
+ aliasName: "Point",
2708
+ },
2709
+ },
2710
+ ],
2711
+ },
2712
+ },
2713
+ },
2714
+ },
2715
+ // Failure cases
2716
+ {
2717
+ input: "x::number",
2718
+ expected: { success: false },
2719
+ },
2720
+ {
2721
+ input: "bar number",
2722
+ expected: { success: false },
2723
+ },
2724
+ {
2725
+ input: ":: number",
2726
+ expected: { success: false },
2727
+ },
2728
+ {
2729
+ input: "bar ::",
2730
+ expected: { success: false },
2731
+ },
2732
+ {
2733
+ input: "",
2734
+ expected: { success: false },
2735
+ },
2736
+ ];
2737
+ testCases.forEach(({ input, expected }) => {
2738
+ if (expected.success) {
2739
+ it(`should parse "${input}" successfully`, () => {
2740
+ const result = typeHintParser(input);
2741
+ expect(result.success).toBe(true);
2742
+ if (result.success) {
2743
+ expect(result.result).toEqual(expected.result);
2744
+ }
2745
+ });
2746
+ }
2747
+ else {
2748
+ it(`should fail to parse "${input}"`, () => {
2749
+ const result = typeHintParser(input);
2750
+ expect(result.success).toBe(false);
2751
+ });
2752
+ }
2753
+ });
2754
+ });