agency-lang 0.0.15 → 0.0.17

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 (41) hide show
  1. package/dist/lib/backends/agencyGenerator.js +24 -6
  2. package/dist/lib/backends/agencyGenerator.test.d.ts +1 -0
  3. package/dist/lib/backends/agencyGenerator.test.js +205 -0
  4. package/dist/lib/backends/baseGenerator.d.ts +1 -0
  5. package/dist/lib/backends/baseGenerator.js +12 -2
  6. package/dist/lib/backends/graphGenerator.js +7 -5
  7. package/dist/lib/backends/typescriptGenerator.d.ts +3 -3
  8. package/dist/lib/backends/typescriptGenerator.js +17 -11
  9. package/dist/lib/parsers/access.d.ts +3 -5
  10. package/dist/lib/parsers/access.js +54 -13
  11. package/dist/lib/parsers/access.test.js +40 -500
  12. package/dist/lib/parsers/assignment.js +2 -2
  13. package/dist/lib/parsers/assignment.test.d.ts +1 -0
  14. package/dist/lib/parsers/assignment.test.js +279 -0
  15. package/dist/lib/parsers/dataStructures.js +3 -3
  16. package/dist/lib/parsers/function.d.ts +3 -1
  17. package/dist/lib/parsers/function.js +6 -4
  18. package/dist/lib/parsers/function.test.js +653 -8
  19. package/dist/lib/parsers/functionCall.js +3 -2
  20. package/dist/lib/parsers/functionCall.test.js +310 -0
  21. package/dist/lib/parsers/literals.d.ts +2 -1
  22. package/dist/lib/parsers/literals.js +15 -5
  23. package/dist/lib/parsers/literals.test.js +189 -16
  24. package/dist/lib/parsers/matchBlock.js +2 -2
  25. package/dist/lib/parsers/parserUtils.test.d.ts +1 -0
  26. package/dist/lib/parsers/parserUtils.test.js +46 -0
  27. package/dist/lib/parsers/returnStatement.js +2 -2
  28. package/dist/lib/parsers/returnStatement.test.d.ts +1 -0
  29. package/dist/lib/parsers/returnStatement.test.js +268 -0
  30. package/dist/lib/parsers/specialVar.test.d.ts +1 -0
  31. package/dist/lib/parsers/specialVar.test.js +219 -0
  32. package/dist/lib/types/access.d.ts +5 -5
  33. package/dist/lib/types/access.js +6 -1
  34. package/dist/lib/types/dataStructures.d.ts +3 -3
  35. package/dist/lib/types/function.d.ts +10 -4
  36. package/dist/lib/types/literals.d.ts +5 -1
  37. package/dist/lib/types/matchBlock.d.ts +2 -2
  38. package/dist/lib/types/returnStatement.d.ts +2 -2
  39. package/dist/lib/types/whileLoop.d.ts +2 -2
  40. package/dist/lib/types.d.ts +3 -3
  41. package/package.json +2 -2
@@ -1,135 +1,6 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { dotPropertyParser, indexAccessParser, dotFunctionCallParser, accessExpressionParser, } from "./access.js";
2
+ import { indexAccessParser, accessExpressionParser } from "./access.js";
3
3
  describe("access expression parsers", () => {
4
- describe("dotPropertyParser", () => {
5
- const testCases = [
6
- // Happy path - variable name with property
7
- {
8
- input: "obj.foo",
9
- expected: {
10
- success: true,
11
- result: {
12
- type: "dotProperty",
13
- object: { type: "variableName", value: "obj" },
14
- propertyName: "foo",
15
- },
16
- },
17
- },
18
- {
19
- input: "response.status",
20
- expected: {
21
- success: true,
22
- result: {
23
- type: "dotProperty",
24
- object: { type: "variableName", value: "response" },
25
- propertyName: "status",
26
- },
27
- },
28
- },
29
- {
30
- input: "user.name",
31
- expected: {
32
- success: true,
33
- result: {
34
- type: "dotProperty",
35
- object: { type: "variableName", value: "user" },
36
- propertyName: "name",
37
- },
38
- },
39
- },
40
- // Edge cases - single character names
41
- {
42
- input: "x.y",
43
- expected: {
44
- success: true,
45
- result: {
46
- type: "dotProperty",
47
- object: { type: "variableName", value: "x" },
48
- propertyName: "y",
49
- },
50
- },
51
- },
52
- {
53
- input: "a.b",
54
- expected: {
55
- success: true,
56
- result: {
57
- type: "dotProperty",
58
- object: { type: "variableName", value: "a" },
59
- propertyName: "b",
60
- },
61
- },
62
- },
63
- // Property names with numbers
64
- {
65
- input: "obj.prop123",
66
- expected: {
67
- success: true,
68
- result: {
69
- type: "dotProperty",
70
- object: { type: "variableName", value: "obj" },
71
- propertyName: "prop123",
72
- },
73
- },
74
- },
75
- {
76
- input: "data.field2",
77
- expected: {
78
- success: true,
79
- result: {
80
- type: "dotProperty",
81
- object: { type: "variableName", value: "data" },
82
- propertyName: "field2",
83
- },
84
- },
85
- },
86
- // Note: Function calls as objects like "fetch().body" are not currently supported
87
- // by this parser due to the order of parsers in the or() combinator on line 24.
88
- // The literalParser matches the function name as a variableName before
89
- // functionCallParser gets a chance to parse the full function call.
90
- // This parser still uses or(literalParser, functionCallParser) instead of
91
- // or(functionCallParser, literalParser).
92
- // Note: Number literals with property access like "42.toString" are not supported
93
- // because the dot is consumed as part of the number (decimal point).
94
- // String literal as object
95
- {
96
- input: '"hello".length',
97
- expected: {
98
- success: true,
99
- result: {
100
- type: "dotProperty",
101
- object: { type: "string", value: "hello" },
102
- propertyName: "length",
103
- },
104
- },
105
- },
106
- // Failure cases
107
- { input: "obj.", expected: { success: false } },
108
- { input: ".property", expected: { success: false } },
109
- { input: "obj", expected: { success: false } },
110
- { input: "", expected: { success: false } },
111
- { input: ".", expected: { success: false } },
112
- // Note: "obj.123" actually parses successfully because alphanum includes digits
113
- { input: "obj..prop", expected: { success: false } },
114
- ];
115
- testCases.forEach(({ input, expected }) => {
116
- if (expected.success) {
117
- it(`should parse "${input}" successfully`, () => {
118
- const result = dotPropertyParser(input);
119
- expect(result.success).toBe(true);
120
- if (result.success) {
121
- expect(result.result).toEqual(expected.result);
122
- }
123
- });
124
- }
125
- else {
126
- it(`should fail to parse "${input}"`, () => {
127
- const result = dotPropertyParser(input);
128
- expect(result.success).toBe(false);
129
- });
130
- }
131
- });
132
- });
133
4
  describe("indexAccessParser", () => {
134
5
  const testCases = [
135
6
  // Happy path - variable with number index
@@ -354,310 +225,6 @@ describe("access expression parsers", () => {
354
225
  }
355
226
  });
356
227
  });
357
- describe("dotFunctionCallParser", () => {
358
- const testCases = [
359
- // Happy path - variable with method call
360
- {
361
- input: "story.json()",
362
- expected: {
363
- success: true,
364
- result: {
365
- type: "dotFunctionCall",
366
- object: { type: "variableName", value: "story" },
367
- functionCall: {
368
- type: "functionCall",
369
- functionName: "json",
370
- arguments: [],
371
- },
372
- },
373
- },
374
- },
375
- {
376
- input: "response.text()",
377
- expected: {
378
- success: true,
379
- result: {
380
- type: "dotFunctionCall",
381
- object: { type: "variableName", value: "response" },
382
- functionCall: {
383
- type: "functionCall",
384
- functionName: "text",
385
- arguments: [],
386
- },
387
- },
388
- },
389
- },
390
- {
391
- input: "obj.getData()",
392
- expected: {
393
- success: true,
394
- result: {
395
- type: "dotFunctionCall",
396
- object: { type: "variableName", value: "obj" },
397
- functionCall: {
398
- type: "functionCall",
399
- functionName: "getData",
400
- arguments: [],
401
- },
402
- },
403
- },
404
- },
405
- // Method call with arguments
406
- {
407
- input: "obj.method(42)",
408
- expected: {
409
- success: true,
410
- result: {
411
- type: "dotFunctionCall",
412
- object: { type: "variableName", value: "obj" },
413
- functionCall: {
414
- type: "functionCall",
415
- functionName: "method",
416
- arguments: [{ type: "number", value: "42" }],
417
- },
418
- },
419
- },
420
- },
421
- {
422
- input: 'str.split(",")',
423
- expected: {
424
- success: true,
425
- result: {
426
- type: "dotFunctionCall",
427
- object: { type: "variableName", value: "str" },
428
- functionCall: {
429
- type: "functionCall",
430
- functionName: "split",
431
- arguments: [{ type: "string", value: "," }],
432
- },
433
- },
434
- },
435
- },
436
- {
437
- input: "arr.slice(0)",
438
- expected: {
439
- success: true,
440
- result: {
441
- type: "dotFunctionCall",
442
- object: { type: "variableName", value: "arr" },
443
- functionCall: {
444
- type: "functionCall",
445
- functionName: "slice",
446
- arguments: [{ type: "number", value: "0" }],
447
- },
448
- },
449
- },
450
- },
451
- // Multiple arguments
452
- {
453
- input: "obj.calculate(1, 2)",
454
- expected: {
455
- success: true,
456
- result: {
457
- type: "dotFunctionCall",
458
- object: { type: "variableName", value: "obj" },
459
- functionCall: {
460
- type: "functionCall",
461
- functionName: "calculate",
462
- arguments: [
463
- { type: "number", value: "1" },
464
- { type: "number", value: "2" },
465
- ],
466
- },
467
- },
468
- },
469
- },
470
- {
471
- input: 'str.replace("old", "new")',
472
- expected: {
473
- success: true,
474
- result: {
475
- type: "dotFunctionCall",
476
- object: { type: "variableName", value: "str" },
477
- functionCall: {
478
- type: "functionCall",
479
- functionName: "replace",
480
- arguments: [
481
- { type: "string", value: "old" },
482
- { type: "string", value: "new" },
483
- ],
484
- },
485
- },
486
- },
487
- },
488
- // Variable as argument
489
- {
490
- input: "obj.process(data)",
491
- expected: {
492
- success: true,
493
- result: {
494
- type: "dotFunctionCall",
495
- object: { type: "variableName", value: "obj" },
496
- functionCall: {
497
- type: "functionCall",
498
- functionName: "process",
499
- arguments: [{ type: "variableName", value: "data" }],
500
- },
501
- },
502
- },
503
- },
504
- // Chained function calls
505
- {
506
- input: "fetch().json()",
507
- expected: {
508
- success: true,
509
- result: {
510
- type: "dotFunctionCall",
511
- object: {
512
- type: "functionCall",
513
- functionName: "fetch",
514
- arguments: [],
515
- },
516
- functionCall: {
517
- type: "functionCall",
518
- functionName: "json",
519
- arguments: [],
520
- },
521
- },
522
- },
523
- },
524
- {
525
- input: "getData().process()",
526
- expected: {
527
- success: true,
528
- result: {
529
- type: "dotFunctionCall",
530
- object: {
531
- type: "functionCall",
532
- functionName: "getData",
533
- arguments: [],
534
- },
535
- functionCall: {
536
- type: "functionCall",
537
- functionName: "process",
538
- arguments: [],
539
- },
540
- },
541
- },
542
- },
543
- {
544
- input: "getResponse().text()",
545
- expected: {
546
- success: true,
547
- result: {
548
- type: "dotFunctionCall",
549
- object: {
550
- type: "functionCall",
551
- functionName: "getResponse",
552
- arguments: [],
553
- },
554
- functionCall: {
555
- type: "functionCall",
556
- functionName: "text",
557
- arguments: [],
558
- },
559
- },
560
- },
561
- },
562
- // Chained function calls with arguments
563
- {
564
- input: 'fetch("url").json()',
565
- expected: {
566
- success: true,
567
- result: {
568
- type: "dotFunctionCall",
569
- object: {
570
- type: "functionCall",
571
- functionName: "fetch",
572
- arguments: [{ type: "string", value: "url" }],
573
- },
574
- functionCall: {
575
- type: "functionCall",
576
- functionName: "json",
577
- arguments: [],
578
- },
579
- },
580
- },
581
- },
582
- {
583
- input: "getUser(42).getName()",
584
- expected: {
585
- success: true,
586
- result: {
587
- type: "dotFunctionCall",
588
- object: {
589
- type: "functionCall",
590
- functionName: "getUser",
591
- arguments: [{ type: "number", value: "42" }],
592
- },
593
- functionCall: {
594
- type: "functionCall",
595
- functionName: "getName",
596
- arguments: [],
597
- },
598
- },
599
- },
600
- },
601
- // Edge cases - single character names
602
- {
603
- input: "x.f()",
604
- expected: {
605
- success: true,
606
- result: {
607
- type: "dotFunctionCall",
608
- object: { type: "variableName", value: "x" },
609
- functionCall: {
610
- type: "functionCall",
611
- functionName: "f",
612
- arguments: [],
613
- },
614
- },
615
- },
616
- },
617
- // String literal as object
618
- {
619
- input: '"hello".toUpperCase()',
620
- expected: {
621
- success: true,
622
- result: {
623
- type: "dotFunctionCall",
624
- object: { type: "string", value: "hello" },
625
- functionCall: {
626
- type: "functionCall",
627
- functionName: "toUpperCase",
628
- arguments: [],
629
- },
630
- },
631
- },
632
- },
633
- // Failure cases
634
- { input: "obj.method", expected: { success: false } }, // missing ()
635
- { input: "obj.()", expected: { success: false } }, // missing method name
636
- { input: ".method()", expected: { success: false } }, // missing object
637
- { input: "obj.", expected: { success: false } },
638
- { input: "method()", expected: { success: false } }, // no dot
639
- { input: "", expected: { success: false } },
640
- { input: "obj.method(", expected: { success: false } }, // unclosed paren
641
- { input: "obj.method)", expected: { success: false } }, // no opening paren
642
- ];
643
- testCases.forEach(({ input, expected }) => {
644
- if (expected.success) {
645
- it(`should parse "${input}" successfully`, () => {
646
- const result = dotFunctionCallParser(input);
647
- expect(result.success).toBe(true);
648
- if (result.success) {
649
- expect(result.result).toEqual(expected.result);
650
- }
651
- });
652
- }
653
- else {
654
- it(`should fail to parse "${input}"`, () => {
655
- const result = dotFunctionCallParser(input);
656
- expect(result.success).toBe(false);
657
- });
658
- }
659
- });
660
- });
661
228
  describe("accessExpressionParser", () => {
662
229
  const testCases = [
663
230
  // Dot property access
@@ -689,49 +256,6 @@ describe("access expression parsers", () => {
689
256
  },
690
257
  },
691
258
  },
692
- // Index access
693
- {
694
- input: "arr[0]",
695
- expected: {
696
- success: true,
697
- result: {
698
- type: "accessExpression",
699
- expression: {
700
- type: "indexAccess",
701
- array: { type: "variableName", value: "arr" },
702
- index: { type: "number", value: "0" },
703
- },
704
- },
705
- },
706
- },
707
- {
708
- input: "items[i]",
709
- expected: {
710
- success: true,
711
- result: {
712
- type: "accessExpression",
713
- expression: {
714
- type: "indexAccess",
715
- array: { type: "variableName", value: "items" },
716
- index: { type: "variableName", value: "i" },
717
- },
718
- },
719
- },
720
- },
721
- {
722
- input: 'data["key"]',
723
- expected: {
724
- success: true,
725
- result: {
726
- type: "accessExpression",
727
- expression: {
728
- type: "indexAccess",
729
- array: { type: "variableName", value: "data" },
730
- index: { type: "string", value: "key" },
731
- },
732
- },
733
- },
734
- },
735
259
  // Dot function call
736
260
  {
737
261
  input: "story.json()",
@@ -832,22 +356,52 @@ describe("access expression parsers", () => {
832
356
  },
833
357
  },
834
358
  },
835
- // Function call with index access
836
359
  {
837
- input: "getData()[0]",
360
+ input: "foo.bar().baz()[3].a1",
838
361
  expected: {
839
362
  success: true,
840
363
  result: {
841
- type: "accessExpression",
842
364
  expression: {
843
- type: "indexAccess",
844
- array: {
845
- type: "functionCall",
846
- functionName: "getData",
847
- arguments: [],
365
+ object: {
366
+ expression: {
367
+ array: {
368
+ expression: {
369
+ functionCall: {
370
+ arguments: [],
371
+ functionName: "baz",
372
+ type: "functionCall",
373
+ },
374
+ object: {
375
+ expression: {
376
+ functionCall: {
377
+ arguments: [],
378
+ functionName: "bar",
379
+ type: "functionCall",
380
+ },
381
+ object: {
382
+ type: "variableName",
383
+ value: "foo",
384
+ },
385
+ type: "dotFunctionCall",
386
+ },
387
+ type: "accessExpression",
388
+ },
389
+ type: "dotFunctionCall",
390
+ },
391
+ type: "accessExpression",
392
+ },
393
+ index: {
394
+ type: "number",
395
+ value: "3",
396
+ },
397
+ type: "indexAccess",
398
+ },
399
+ type: "accessExpression",
848
400
  },
849
- index: { type: "number", value: "0" },
401
+ propertyName: "a1",
402
+ type: "dotProperty",
850
403
  },
404
+ type: "accessExpression",
851
405
  },
852
406
  },
853
407
  },
@@ -866,20 +420,6 @@ describe("access expression parsers", () => {
866
420
  },
867
421
  },
868
422
  },
869
- {
870
- input: "a[0]",
871
- expected: {
872
- success: true,
873
- result: {
874
- type: "accessExpression",
875
- expression: {
876
- type: "indexAccess",
877
- array: { type: "variableName", value: "a" },
878
- index: { type: "number", value: "0" },
879
- },
880
- },
881
- },
882
- },
883
423
  {
884
424
  input: "x.f()",
885
425
  expected: {
@@ -1,8 +1,8 @@
1
1
  import { capture, char, many1WithJoin, or, seqC, set, trace, } from "tarsec";
2
- import { accessExpressionParser } from "./access.js";
2
+ import { accessExpressionParser, indexAccessParser } from "./access.js";
3
3
  import { agencyArrayParser, agencyObjectParser } from "./dataStructures.js";
4
4
  import { functionCallParser } from "./functionCall.js";
5
5
  import { literalParser } from "./literals.js";
6
6
  import { optionalSemicolon } from "./parserUtils.js";
7
7
  import { optionalSpaces, varNameChar } from "./utils.js";
8
- export const assignmentParser = trace("assignmentParser", seqC(set("type", "assignment"), optionalSpaces, capture(many1WithJoin(varNameChar), "variableName"), optionalSpaces, char("="), optionalSpaces, capture(or(functionCallParser, accessExpressionParser, agencyArrayParser, agencyObjectParser, literalParser), "value"), optionalSemicolon));
8
+ export const assignmentParser = trace("assignmentParser", seqC(set("type", "assignment"), optionalSpaces, capture(many1WithJoin(varNameChar), "variableName"), optionalSpaces, char("="), optionalSpaces, capture(or(functionCallParser, indexAccessParser, accessExpressionParser, agencyArrayParser, agencyObjectParser, literalParser), "value"), optionalSemicolon));
@@ -0,0 +1 @@
1
+ export {};