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,591 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { functionParser, docStringParser } from "./function.js";
3
+ describe("docStringParser", () => {
4
+ const testCases = [
5
+ // Happy path - basic docstrings
6
+ {
7
+ input: '"""This is a docstring"""',
8
+ expected: {
9
+ success: true,
10
+ result: { type: "docString", value: "This is a docstring" },
11
+ },
12
+ },
13
+ {
14
+ input: '"""Simple description"""',
15
+ expected: {
16
+ success: true,
17
+ result: { type: "docString", value: "Simple description" },
18
+ },
19
+ },
20
+ // Docstrings with whitespace
21
+ {
22
+ input: '""" Leading and trailing spaces """',
23
+ expected: {
24
+ success: true,
25
+ result: { type: "docString", value: "Leading and trailing spaces" },
26
+ },
27
+ },
28
+ {
29
+ input: '"""\nMultiline\ndocstring\n"""',
30
+ expected: {
31
+ success: true,
32
+ result: { type: "docString", value: "Multiline\ndocstring" },
33
+ },
34
+ },
35
+ // Empty docstring (fails because many1Till requires at least one char)
36
+ {
37
+ input: '""""""',
38
+ expected: { success: false },
39
+ },
40
+ // Docstring with only whitespace
41
+ {
42
+ input: '""" """',
43
+ expected: {
44
+ success: true,
45
+ result: { type: "docString", value: "" },
46
+ },
47
+ },
48
+ // Docstrings with special characters
49
+ {
50
+ input: '"""Docstring with numbers: 123, 456"""',
51
+ expected: {
52
+ success: true,
53
+ result: {
54
+ type: "docString",
55
+ value: "Docstring with numbers: 123, 456",
56
+ },
57
+ },
58
+ },
59
+ {
60
+ input: '"""Special chars: !@#$%^&*()"""',
61
+ expected: {
62
+ success: true,
63
+ result: { type: "docString", value: "Special chars: !@#$%^&*()" },
64
+ },
65
+ },
66
+ {
67
+ input: '"""Code example: x = 5"""',
68
+ expected: {
69
+ success: true,
70
+ result: { type: "docString", value: "Code example: x = 5" },
71
+ },
72
+ },
73
+ // Docstrings with punctuation
74
+ {
75
+ input: '"""This function does something. It takes params."""',
76
+ expected: {
77
+ success: true,
78
+ result: {
79
+ type: "docString",
80
+ value: "This function does something. It takes params.",
81
+ },
82
+ },
83
+ },
84
+ {
85
+ input: '"""Returns: the result"""',
86
+ expected: {
87
+ success: true,
88
+ result: { type: "docString", value: "Returns: the result" },
89
+ },
90
+ },
91
+ // Failure cases
92
+ { input: '"This is not a docstring"', expected: { success: false } },
93
+ { input: '""incomplete', expected: { success: false } },
94
+ { input: 'incomplete"""', expected: { success: false } },
95
+ { input: '"""no closing', expected: { success: false } },
96
+ { input: "", expected: { success: false } },
97
+ { input: "text", expected: { success: false } },
98
+ ];
99
+ testCases.forEach(({ input, expected }) => {
100
+ if (expected.success) {
101
+ it(`should parse "${input}" successfully`, () => {
102
+ const result = docStringParser(input);
103
+ expect(result.success).toBe(true);
104
+ if (result.success) {
105
+ expect(result.result).toEqual(expected.result);
106
+ }
107
+ });
108
+ }
109
+ else {
110
+ it(`should fail to parse "${input}"`, () => {
111
+ const result = docStringParser(input);
112
+ expect(result.success).toBe(false);
113
+ });
114
+ }
115
+ });
116
+ });
117
+ describe("functionParser", () => {
118
+ const testCases = [
119
+ {
120
+ input: "def test() { foo = 1 }",
121
+ expected: {
122
+ success: true,
123
+ result: {
124
+ type: "function",
125
+ functionName: "test",
126
+ parameters: [],
127
+ docString: undefined,
128
+ body: [
129
+ {
130
+ type: "assignment",
131
+ variableName: "foo",
132
+ value: { type: "number", value: "1" },
133
+ },
134
+ ],
135
+ },
136
+ },
137
+ },
138
+ {
139
+ input: "def greet() { bar = `say hello` }",
140
+ expected: {
141
+ success: true,
142
+ result: {
143
+ type: "function",
144
+ functionName: "greet",
145
+ parameters: [],
146
+ docString: undefined,
147
+ body: [
148
+ {
149
+ type: "assignment",
150
+ variableName: "bar",
151
+ value: {
152
+ type: "prompt",
153
+ segments: [{ type: "text", value: "say hello" }],
154
+ },
155
+ },
156
+ ],
157
+ },
158
+ },
159
+ },
160
+ {
161
+ input: "def calculate() { x = 5\ny = 10 }",
162
+ expected: {
163
+ success: true,
164
+ result: {
165
+ type: "function",
166
+ functionName: "calculate",
167
+ parameters: [],
168
+ docString: undefined,
169
+ body: [
170
+ {
171
+ type: "assignment",
172
+ variableName: "x",
173
+ value: { type: "number", value: "5" },
174
+ },
175
+ {
176
+ type: "assignment",
177
+ variableName: "y",
178
+ value: { type: "number", value: "10" },
179
+ },
180
+ ],
181
+ },
182
+ },
183
+ },
184
+ {
185
+ input: "def empty() {}",
186
+ expected: {
187
+ success: true,
188
+ result: {
189
+ type: "function",
190
+ functionName: "empty",
191
+ parameters: [],
192
+ docString: undefined,
193
+ body: [],
194
+ },
195
+ },
196
+ },
197
+ {
198
+ input: "def withSpaces() { foo = 1 }",
199
+ expected: {
200
+ success: true,
201
+ result: {
202
+ type: "function",
203
+ functionName: "withSpaces",
204
+ parameters: [],
205
+ docString: undefined,
206
+ body: [
207
+ {
208
+ type: "assignment",
209
+ variableName: "foo",
210
+ value: { type: "number", value: "1" },
211
+ },
212
+ ],
213
+ },
214
+ },
215
+ },
216
+ {
217
+ input: "def noSpaces(){foo=1}",
218
+ expected: {
219
+ success: true,
220
+ result: {
221
+ type: "function",
222
+ functionName: "noSpaces",
223
+ parameters: [],
224
+ docString: undefined,
225
+ body: [
226
+ {
227
+ type: "assignment",
228
+ variableName: "foo",
229
+ value: { type: "number", value: "1" },
230
+ },
231
+ ],
232
+ },
233
+ },
234
+ },
235
+ {
236
+ input: "def multiline() {\n x = 5\n y = 10\n}",
237
+ expected: {
238
+ success: true,
239
+ result: {
240
+ type: "function",
241
+ functionName: "multiline",
242
+ parameters: [],
243
+ docString: undefined,
244
+ body: [
245
+ {
246
+ type: "assignment",
247
+ variableName: "x",
248
+ value: { type: "number", value: "5" },
249
+ },
250
+ {
251
+ type: "assignment",
252
+ variableName: "y",
253
+ value: { type: "number", value: "10" },
254
+ },
255
+ ],
256
+ },
257
+ },
258
+ },
259
+ {
260
+ input: "test() { foo = 1 }",
261
+ expected: { success: false },
262
+ },
263
+ {
264
+ input: "def test { foo = 1 }",
265
+ expected: { success: false },
266
+ },
267
+ {
268
+ input: "def test() foo = 1",
269
+ expected: { success: false },
270
+ },
271
+ {
272
+ input: "def () { foo = 1 }",
273
+ expected: { success: false },
274
+ },
275
+ {
276
+ input: "def test() {",
277
+ expected: { success: false },
278
+ },
279
+ {
280
+ input: "",
281
+ expected: { success: false },
282
+ },
283
+ // Functions with docstrings
284
+ {
285
+ input: 'def test() { """This is a test function"""\nfoo = 1 }',
286
+ expected: {
287
+ success: true,
288
+ result: {
289
+ type: "function",
290
+ functionName: "test",
291
+ parameters: [],
292
+ docString: {
293
+ type: "docString",
294
+ value: "This is a test function",
295
+ },
296
+ body: [
297
+ {
298
+ type: "assignment",
299
+ variableName: "foo",
300
+ value: { type: "number", value: "1" },
301
+ },
302
+ ],
303
+ },
304
+ },
305
+ },
306
+ {
307
+ input: 'def greet() {\n """Greets the user"""\n bar = `say hello`\n}',
308
+ expected: {
309
+ success: true,
310
+ result: {
311
+ type: "function",
312
+ functionName: "greet",
313
+ parameters: [],
314
+ docString: {
315
+ type: "docString",
316
+ value: "Greets the user",
317
+ },
318
+ body: [
319
+ {
320
+ type: "assignment",
321
+ variableName: "bar",
322
+ value: {
323
+ type: "prompt",
324
+ segments: [{ type: "text", value: "say hello" }],
325
+ },
326
+ },
327
+ ],
328
+ },
329
+ },
330
+ },
331
+ {
332
+ input: 'def calculate() { """Calculate something"""\nx = 5\ny = 10 }',
333
+ expected: {
334
+ success: true,
335
+ result: {
336
+ type: "function",
337
+ functionName: "calculate",
338
+ parameters: [],
339
+ docString: {
340
+ type: "docString",
341
+ value: "Calculate something",
342
+ },
343
+ body: [
344
+ {
345
+ type: "assignment",
346
+ variableName: "x",
347
+ value: { type: "number", value: "5" },
348
+ },
349
+ {
350
+ type: "assignment",
351
+ variableName: "y",
352
+ value: { type: "number", value: "10" },
353
+ },
354
+ ],
355
+ },
356
+ },
357
+ },
358
+ {
359
+ input: 'def empty() { """Empty function with docstring""" }',
360
+ expected: {
361
+ success: true,
362
+ result: {
363
+ type: "function",
364
+ functionName: "empty",
365
+ parameters: [],
366
+ docString: {
367
+ type: "docString",
368
+ value: "Empty function with docstring",
369
+ },
370
+ body: [],
371
+ },
372
+ },
373
+ },
374
+ {
375
+ input: 'def multilineDoc() {\n """\n This is a multi-line\n docstring\n """\n x = 5\n}',
376
+ expected: {
377
+ success: true,
378
+ result: {
379
+ type: "function",
380
+ functionName: "multilineDoc",
381
+ parameters: [],
382
+ docString: {
383
+ type: "docString",
384
+ value: "This is a multi-line\n docstring",
385
+ },
386
+ body: [
387
+ {
388
+ type: "assignment",
389
+ variableName: "x",
390
+ value: { type: "number", value: "5" },
391
+ },
392
+ ],
393
+ },
394
+ },
395
+ },
396
+ // Functions with one parameter
397
+ {
398
+ input: "def add(x) { x }",
399
+ expected: {
400
+ success: true,
401
+ result: {
402
+ type: "function",
403
+ functionName: "add",
404
+ parameters: ["x"],
405
+ docString: undefined,
406
+ body: [
407
+ {
408
+ type: "variableName",
409
+ value: "x",
410
+ },
411
+ ],
412
+ },
413
+ },
414
+ },
415
+ {
416
+ input: "def greet(name) { bar = `say hello to ${name}` }",
417
+ expected: {
418
+ success: true,
419
+ result: {
420
+ type: "function",
421
+ functionName: "greet",
422
+ parameters: ["name"],
423
+ docString: undefined,
424
+ body: [
425
+ {
426
+ type: "assignment",
427
+ variableName: "bar",
428
+ value: {
429
+ type: "prompt",
430
+ segments: [
431
+ { type: "text", value: "say hello to " },
432
+ { type: "interpolation", variableName: "name" },
433
+ ],
434
+ },
435
+ },
436
+ ],
437
+ },
438
+ },
439
+ },
440
+ // Functions with multiple parameters
441
+ {
442
+ input: "def add(x, y) { x }",
443
+ expected: {
444
+ success: true,
445
+ result: {
446
+ type: "function",
447
+ functionName: "add",
448
+ parameters: ["x", "y"],
449
+ docString: undefined,
450
+ body: [
451
+ {
452
+ type: "variableName",
453
+ value: "x",
454
+ },
455
+ ],
456
+ },
457
+ },
458
+ },
459
+ {
460
+ input: "def calculate(a, b, c) { result = 42\nresult }",
461
+ expected: {
462
+ success: true,
463
+ result: {
464
+ type: "function",
465
+ functionName: "calculate",
466
+ parameters: ["a", "b", "c"],
467
+ docString: undefined,
468
+ body: [
469
+ {
470
+ type: "assignment",
471
+ variableName: "result",
472
+ value: { type: "number", value: "42" },
473
+ },
474
+ {
475
+ type: "variableName",
476
+ value: "result",
477
+ },
478
+ ],
479
+ },
480
+ },
481
+ },
482
+ {
483
+ input: "def multiply(x,y) { x }",
484
+ expected: {
485
+ success: true,
486
+ result: {
487
+ type: "function",
488
+ functionName: "multiply",
489
+ parameters: ["x", "y"],
490
+ docString: undefined,
491
+ body: [
492
+ {
493
+ type: "variableName",
494
+ value: "x",
495
+ },
496
+ ],
497
+ },
498
+ },
499
+ },
500
+ {
501
+ input: "def process( a , b ) { a }",
502
+ expected: {
503
+ success: true,
504
+ result: {
505
+ type: "function",
506
+ functionName: "process",
507
+ parameters: ["a", "b"],
508
+ docString: undefined,
509
+ body: [
510
+ {
511
+ type: "variableName",
512
+ value: "a",
513
+ },
514
+ ],
515
+ },
516
+ },
517
+ },
518
+ // Functions with parameters and docstring
519
+ {
520
+ input: 'def add(x, y) { """Adds two numbers"""\nx }',
521
+ expected: {
522
+ success: true,
523
+ result: {
524
+ type: "function",
525
+ functionName: "add",
526
+ parameters: ["x", "y"],
527
+ docString: {
528
+ type: "docString",
529
+ value: "Adds two numbers",
530
+ },
531
+ body: [
532
+ {
533
+ type: "variableName",
534
+ value: "x",
535
+ },
536
+ ],
537
+ },
538
+ },
539
+ },
540
+ {
541
+ input: 'def greet(name, greeting) {\n """Greets someone with a custom greeting"""\n result = `${greeting} ${name}`\n result\n}',
542
+ expected: {
543
+ success: true,
544
+ result: {
545
+ type: "function",
546
+ functionName: "greet",
547
+ parameters: ["name", "greeting"],
548
+ docString: {
549
+ type: "docString",
550
+ value: "Greets someone with a custom greeting",
551
+ },
552
+ body: [
553
+ {
554
+ type: "assignment",
555
+ variableName: "result",
556
+ value: {
557
+ type: "prompt",
558
+ segments: [
559
+ { type: "interpolation", variableName: "greeting" },
560
+ { type: "text", value: " " },
561
+ { type: "interpolation", variableName: "name" },
562
+ ],
563
+ },
564
+ },
565
+ {
566
+ type: "variableName",
567
+ value: "result",
568
+ },
569
+ ],
570
+ },
571
+ },
572
+ },
573
+ ];
574
+ testCases.forEach(({ input, expected }) => {
575
+ if (expected.success) {
576
+ it(`should parse "${input.replace(/\n/g, "\\n")}" successfully`, () => {
577
+ const result = functionParser(input);
578
+ expect(result.success).toBe(true);
579
+ if (result.success) {
580
+ expect(result.result).toEqual(expected.result);
581
+ }
582
+ });
583
+ }
584
+ else {
585
+ it(`should fail to parse "${input.replace(/\n/g, "\\n")}"`, () => {
586
+ const result = functionParser(input);
587
+ expect(result.success).toBe(false);
588
+ });
589
+ }
590
+ });
591
+ });
@@ -0,0 +1,10 @@
1
+ import { capture, char, many1WithJoin, or, sepBy, seqC, seqR, set, } from "tarsec";
2
+ import { accessExpressionParser } from "./access.js";
3
+ import { literalParser } from "./literals.js";
4
+ import { optionalSemicolon } from "./parserUtils.js";
5
+ import { optionalSpaces, varNameChar } from "./utils.js";
6
+ const comma = seqR(optionalSpaces, char(","), optionalSpaces);
7
+ export const functionCallParser = (input) => {
8
+ const parser = seqC(set("type", "functionCall"), capture(many1WithJoin(varNameChar), "functionName"), char("("), optionalSpaces, capture(sepBy(comma, or(functionCallParser, accessExpressionParser, literalParser)), "arguments"), optionalSpaces, char(")"), optionalSemicolon);
9
+ return parser(input);
10
+ };