@vibe-lang/runtime 0.2.5

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 (250) hide show
  1. package/package.json +46 -0
  2. package/src/ast/index.ts +375 -0
  3. package/src/ast.ts +2 -0
  4. package/src/debug/advanced-features.ts +482 -0
  5. package/src/debug/bun-inspector.ts +424 -0
  6. package/src/debug/handoff-manager.ts +283 -0
  7. package/src/debug/index.ts +150 -0
  8. package/src/debug/runner.ts +365 -0
  9. package/src/debug/server.ts +565 -0
  10. package/src/debug/stack-merger.ts +267 -0
  11. package/src/debug/state.ts +581 -0
  12. package/src/debug/test/advanced-features.test.ts +300 -0
  13. package/src/debug/test/e2e.test.ts +218 -0
  14. package/src/debug/test/handoff-manager.test.ts +256 -0
  15. package/src/debug/test/runner.test.ts +256 -0
  16. package/src/debug/test/stack-merger.test.ts +163 -0
  17. package/src/debug/test/state.test.ts +400 -0
  18. package/src/debug/test/ts-debug-integration.test.ts +374 -0
  19. package/src/debug/test/ts-import-tracker.test.ts +125 -0
  20. package/src/debug/test/ts-source-map.test.ts +169 -0
  21. package/src/debug/ts-import-tracker.ts +151 -0
  22. package/src/debug/ts-source-map.ts +171 -0
  23. package/src/errors/index.ts +124 -0
  24. package/src/index.ts +358 -0
  25. package/src/lexer/index.ts +348 -0
  26. package/src/lexer.ts +2 -0
  27. package/src/parser/index.ts +792 -0
  28. package/src/parser/parse.ts +45 -0
  29. package/src/parser/test/async.test.ts +248 -0
  30. package/src/parser/test/destructuring.test.ts +167 -0
  31. package/src/parser/test/do-expression.test.ts +486 -0
  32. package/src/parser/test/errors/do-expression.test.ts +95 -0
  33. package/src/parser/test/errors/error-locations.test.ts +230 -0
  34. package/src/parser/test/errors/invalid-expressions.test.ts +144 -0
  35. package/src/parser/test/errors/missing-tokens.test.ts +126 -0
  36. package/src/parser/test/errors/model-declaration.test.ts +185 -0
  37. package/src/parser/test/errors/nested-blocks.test.ts +226 -0
  38. package/src/parser/test/errors/unclosed-delimiters.test.ts +122 -0
  39. package/src/parser/test/errors/unexpected-tokens.test.ts +120 -0
  40. package/src/parser/test/import-export.test.ts +143 -0
  41. package/src/parser/test/literals.test.ts +404 -0
  42. package/src/parser/test/model-declaration.test.ts +161 -0
  43. package/src/parser/test/nested-blocks.test.ts +402 -0
  44. package/src/parser/test/parser.test.ts +743 -0
  45. package/src/parser/test/private.test.ts +136 -0
  46. package/src/parser/test/template-literal.test.ts +127 -0
  47. package/src/parser/test/tool-declaration.test.ts +302 -0
  48. package/src/parser/test/ts-block.test.ts +252 -0
  49. package/src/parser/test/type-annotations.test.ts +254 -0
  50. package/src/parser/visitor/helpers.ts +330 -0
  51. package/src/parser/visitor.ts +794 -0
  52. package/src/parser.ts +2 -0
  53. package/src/runtime/ai/cache-chunking.test.ts +69 -0
  54. package/src/runtime/ai/cache-chunking.ts +73 -0
  55. package/src/runtime/ai/client.ts +109 -0
  56. package/src/runtime/ai/context.ts +168 -0
  57. package/src/runtime/ai/formatters.ts +316 -0
  58. package/src/runtime/ai/index.ts +38 -0
  59. package/src/runtime/ai/language-ref.ts +38 -0
  60. package/src/runtime/ai/providers/anthropic.ts +253 -0
  61. package/src/runtime/ai/providers/google.ts +201 -0
  62. package/src/runtime/ai/providers/openai.ts +156 -0
  63. package/src/runtime/ai/retry.ts +100 -0
  64. package/src/runtime/ai/return-tools.ts +301 -0
  65. package/src/runtime/ai/test/client.test.ts +83 -0
  66. package/src/runtime/ai/test/formatters.test.ts +485 -0
  67. package/src/runtime/ai/test/retry.test.ts +137 -0
  68. package/src/runtime/ai/test/return-tools.test.ts +450 -0
  69. package/src/runtime/ai/test/tool-loop.test.ts +319 -0
  70. package/src/runtime/ai/test/tool-schema.test.ts +241 -0
  71. package/src/runtime/ai/tool-loop.ts +203 -0
  72. package/src/runtime/ai/tool-schema.ts +151 -0
  73. package/src/runtime/ai/types.ts +113 -0
  74. package/src/runtime/ai-logger.ts +255 -0
  75. package/src/runtime/ai-provider.ts +347 -0
  76. package/src/runtime/async/dependencies.ts +276 -0
  77. package/src/runtime/async/executor.ts +293 -0
  78. package/src/runtime/async/index.ts +43 -0
  79. package/src/runtime/async/scheduling.ts +163 -0
  80. package/src/runtime/async/test/dependencies.test.ts +284 -0
  81. package/src/runtime/async/test/executor.test.ts +388 -0
  82. package/src/runtime/context.ts +357 -0
  83. package/src/runtime/exec/ai.ts +139 -0
  84. package/src/runtime/exec/expressions.ts +475 -0
  85. package/src/runtime/exec/frames.ts +26 -0
  86. package/src/runtime/exec/functions.ts +305 -0
  87. package/src/runtime/exec/interpolation.ts +312 -0
  88. package/src/runtime/exec/statements.ts +604 -0
  89. package/src/runtime/exec/tools.ts +129 -0
  90. package/src/runtime/exec/typescript.ts +215 -0
  91. package/src/runtime/exec/variables.ts +279 -0
  92. package/src/runtime/index.ts +975 -0
  93. package/src/runtime/modules.ts +452 -0
  94. package/src/runtime/serialize.ts +103 -0
  95. package/src/runtime/state.ts +489 -0
  96. package/src/runtime/stdlib/core.ts +45 -0
  97. package/src/runtime/stdlib/directory.test.ts +156 -0
  98. package/src/runtime/stdlib/edit.test.ts +154 -0
  99. package/src/runtime/stdlib/fastEdit.test.ts +201 -0
  100. package/src/runtime/stdlib/glob.test.ts +106 -0
  101. package/src/runtime/stdlib/grep.test.ts +144 -0
  102. package/src/runtime/stdlib/index.ts +16 -0
  103. package/src/runtime/stdlib/readFile.test.ts +123 -0
  104. package/src/runtime/stdlib/tools/index.ts +707 -0
  105. package/src/runtime/stdlib/writeFile.test.ts +157 -0
  106. package/src/runtime/step.ts +969 -0
  107. package/src/runtime/test/ai-context.test.ts +1086 -0
  108. package/src/runtime/test/ai-result-object.test.ts +419 -0
  109. package/src/runtime/test/ai-tool-flow.test.ts +859 -0
  110. package/src/runtime/test/async-execution-order.test.ts +618 -0
  111. package/src/runtime/test/async-execution.test.ts +344 -0
  112. package/src/runtime/test/async-nested.test.ts +660 -0
  113. package/src/runtime/test/async-parallel-timing.test.ts +546 -0
  114. package/src/runtime/test/basic1.test.ts +154 -0
  115. package/src/runtime/test/binary-operators.test.ts +431 -0
  116. package/src/runtime/test/break-statement.test.ts +257 -0
  117. package/src/runtime/test/context-modes.test.ts +650 -0
  118. package/src/runtime/test/context.test.ts +466 -0
  119. package/src/runtime/test/core-functions.test.ts +228 -0
  120. package/src/runtime/test/e2e.test.ts +88 -0
  121. package/src/runtime/test/error-locations/error-locations.test.ts +80 -0
  122. package/src/runtime/test/error-locations/main-error.vibe +4 -0
  123. package/src/runtime/test/error-locations/main-import-error.vibe +3 -0
  124. package/src/runtime/test/error-locations/utils/helper.vibe +5 -0
  125. package/src/runtime/test/for-in.test.ts +312 -0
  126. package/src/runtime/test/helpers.ts +69 -0
  127. package/src/runtime/test/imports.test.ts +334 -0
  128. package/src/runtime/test/json-expressions.test.ts +232 -0
  129. package/src/runtime/test/literals.test.ts +372 -0
  130. package/src/runtime/test/logical-indexing.test.ts +478 -0
  131. package/src/runtime/test/member-methods.test.ts +324 -0
  132. package/src/runtime/test/model-config.test.ts +338 -0
  133. package/src/runtime/test/null-handling.test.ts +342 -0
  134. package/src/runtime/test/private-visibility.test.ts +332 -0
  135. package/src/runtime/test/runtime-state.test.ts +514 -0
  136. package/src/runtime/test/scoping.test.ts +370 -0
  137. package/src/runtime/test/string-interpolation.test.ts +354 -0
  138. package/src/runtime/test/template-literal.test.ts +181 -0
  139. package/src/runtime/test/tool-execution.test.ts +467 -0
  140. package/src/runtime/test/tool-schema-generation.test.ts +477 -0
  141. package/src/runtime/test/tostring.test.ts +210 -0
  142. package/src/runtime/test/ts-block.test.ts +594 -0
  143. package/src/runtime/test/ts-error-location.test.ts +231 -0
  144. package/src/runtime/test/types.test.ts +732 -0
  145. package/src/runtime/test/verbose-logger.test.ts +710 -0
  146. package/src/runtime/test/vibe-expression.test.ts +54 -0
  147. package/src/runtime/test/vibe-value-errors.test.ts +541 -0
  148. package/src/runtime/test/while.test.ts +232 -0
  149. package/src/runtime/tools/builtin.ts +30 -0
  150. package/src/runtime/tools/directory-tools.ts +70 -0
  151. package/src/runtime/tools/file-tools.ts +228 -0
  152. package/src/runtime/tools/index.ts +5 -0
  153. package/src/runtime/tools/registry.ts +48 -0
  154. package/src/runtime/tools/search-tools.ts +134 -0
  155. package/src/runtime/tools/security.ts +36 -0
  156. package/src/runtime/tools/system-tools.ts +312 -0
  157. package/src/runtime/tools/test/fixtures/base-types.ts +40 -0
  158. package/src/runtime/tools/test/fixtures/test-types.ts +132 -0
  159. package/src/runtime/tools/test/registry.test.ts +713 -0
  160. package/src/runtime/tools/test/security.test.ts +86 -0
  161. package/src/runtime/tools/test/system-tools.test.ts +679 -0
  162. package/src/runtime/tools/test/ts-schema.test.ts +357 -0
  163. package/src/runtime/tools/ts-schema.ts +341 -0
  164. package/src/runtime/tools/types.ts +89 -0
  165. package/src/runtime/tools/utility-tools.ts +198 -0
  166. package/src/runtime/ts-eval.ts +126 -0
  167. package/src/runtime/types.ts +797 -0
  168. package/src/runtime/validation.ts +160 -0
  169. package/src/runtime/verbose-logger.ts +459 -0
  170. package/src/runtime.ts +2 -0
  171. package/src/semantic/analyzer-context.ts +62 -0
  172. package/src/semantic/analyzer-validators.ts +575 -0
  173. package/src/semantic/analyzer-visitors.ts +534 -0
  174. package/src/semantic/analyzer.ts +83 -0
  175. package/src/semantic/index.ts +11 -0
  176. package/src/semantic/symbol-table.ts +58 -0
  177. package/src/semantic/test/async-validation.test.ts +301 -0
  178. package/src/semantic/test/compress-validation.test.ts +179 -0
  179. package/src/semantic/test/const-reassignment.test.ts +111 -0
  180. package/src/semantic/test/control-flow.test.ts +346 -0
  181. package/src/semantic/test/destructuring.test.ts +185 -0
  182. package/src/semantic/test/duplicate-declarations.test.ts +168 -0
  183. package/src/semantic/test/export-validation.test.ts +111 -0
  184. package/src/semantic/test/fixtures/math.ts +31 -0
  185. package/src/semantic/test/imports.test.ts +148 -0
  186. package/src/semantic/test/json-type.test.ts +68 -0
  187. package/src/semantic/test/literals.test.ts +127 -0
  188. package/src/semantic/test/model-validation.test.ts +179 -0
  189. package/src/semantic/test/prompt-validation.test.ts +343 -0
  190. package/src/semantic/test/scoping.test.ts +312 -0
  191. package/src/semantic/test/tool-validation.test.ts +306 -0
  192. package/src/semantic/test/ts-type-checking.test.ts +563 -0
  193. package/src/semantic/test/type-constraints.test.ts +111 -0
  194. package/src/semantic/test/type-inference.test.ts +87 -0
  195. package/src/semantic/test/type-validation.test.ts +552 -0
  196. package/src/semantic/test/undefined-variables.test.ts +163 -0
  197. package/src/semantic/ts-block-checker.ts +204 -0
  198. package/src/semantic/ts-signatures.ts +194 -0
  199. package/src/semantic/ts-types.ts +170 -0
  200. package/src/semantic/types.ts +58 -0
  201. package/tests/fixtures/conditional-logic.vibe +14 -0
  202. package/tests/fixtures/function-call.vibe +16 -0
  203. package/tests/fixtures/imports/cycle-detection/a.vibe +6 -0
  204. package/tests/fixtures/imports/cycle-detection/b.vibe +5 -0
  205. package/tests/fixtures/imports/cycle-detection/main.vibe +3 -0
  206. package/tests/fixtures/imports/module-isolation/main-b.vibe +8 -0
  207. package/tests/fixtures/imports/module-isolation/main.vibe +9 -0
  208. package/tests/fixtures/imports/module-isolation/moduleA.vibe +6 -0
  209. package/tests/fixtures/imports/module-isolation/moduleB.vibe +6 -0
  210. package/tests/fixtures/imports/nested-import/helper.vibe +6 -0
  211. package/tests/fixtures/imports/nested-import/main.vibe +3 -0
  212. package/tests/fixtures/imports/nested-import/utils.ts +3 -0
  213. package/tests/fixtures/imports/nested-isolation/file2.vibe +15 -0
  214. package/tests/fixtures/imports/nested-isolation/file3.vibe +10 -0
  215. package/tests/fixtures/imports/nested-isolation/main.vibe +21 -0
  216. package/tests/fixtures/imports/pure-cycle/a.vibe +5 -0
  217. package/tests/fixtures/imports/pure-cycle/b.vibe +5 -0
  218. package/tests/fixtures/imports/pure-cycle/main.vibe +3 -0
  219. package/tests/fixtures/imports/ts-boolean/checks.ts +14 -0
  220. package/tests/fixtures/imports/ts-boolean/main.vibe +10 -0
  221. package/tests/fixtures/imports/ts-boolean/type-mismatch.vibe +5 -0
  222. package/tests/fixtures/imports/ts-boolean/use-constant.vibe +18 -0
  223. package/tests/fixtures/imports/ts-error-handling/helpers.ts +42 -0
  224. package/tests/fixtures/imports/ts-error-handling/main.vibe +5 -0
  225. package/tests/fixtures/imports/ts-import/main.vibe +4 -0
  226. package/tests/fixtures/imports/ts-import/math.ts +9 -0
  227. package/tests/fixtures/imports/ts-variables/call-non-function.vibe +5 -0
  228. package/tests/fixtures/imports/ts-variables/data.ts +10 -0
  229. package/tests/fixtures/imports/ts-variables/import-json.vibe +5 -0
  230. package/tests/fixtures/imports/ts-variables/import-type-mismatch.vibe +5 -0
  231. package/tests/fixtures/imports/ts-variables/import-variable.vibe +5 -0
  232. package/tests/fixtures/imports/vibe-import/greet.vibe +5 -0
  233. package/tests/fixtures/imports/vibe-import/main.vibe +3 -0
  234. package/tests/fixtures/multiple-ai-calls.vibe +10 -0
  235. package/tests/fixtures/simple-greeting.vibe +6 -0
  236. package/tests/fixtures/template-literals.vibe +11 -0
  237. package/tests/integration/basic-ai/basic-ai.integration.test.ts +166 -0
  238. package/tests/integration/basic-ai/basic-ai.vibe +12 -0
  239. package/tests/integration/bug-fix/bug-fix.integration.test.ts +201 -0
  240. package/tests/integration/bug-fix/buggy-code.ts +22 -0
  241. package/tests/integration/bug-fix/fix-bug.vibe +21 -0
  242. package/tests/integration/compress/compress.integration.test.ts +206 -0
  243. package/tests/integration/destructuring/destructuring.integration.test.ts +92 -0
  244. package/tests/integration/hello-world-translator/hello-world-translator.integration.test.ts +61 -0
  245. package/tests/integration/line-annotator/context-modes.integration.test.ts +261 -0
  246. package/tests/integration/line-annotator/line-annotator.integration.test.ts +148 -0
  247. package/tests/integration/multi-feature/cumulative-sum.integration.test.ts +75 -0
  248. package/tests/integration/multi-feature/number-analyzer.integration.test.ts +191 -0
  249. package/tests/integration/multi-feature/number-analyzer.vibe +59 -0
  250. package/tests/integration/tool-calls/tool-calls.integration.test.ts +93 -0
@@ -0,0 +1,324 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { Runtime, AIProvider } from '../index';
4
+
5
+ // Mock AI provider
6
+ function createMockProvider(): AIProvider {
7
+ return {
8
+ async execute() {
9
+ return { value: '' };
10
+ },
11
+ async generateCode() {
12
+ return { value: '' };
13
+ },
14
+ async askUser(): Promise<string> {
15
+ return '';
16
+ },
17
+ };
18
+ }
19
+
20
+ describe('Array Methods - len()', () => {
21
+ test('len of empty array', async () => {
22
+ const ast = parse(`
23
+ let arr = []
24
+ let result = arr.len()
25
+ `);
26
+ const runtime = new Runtime(ast, createMockProvider());
27
+ await runtime.run();
28
+ expect(runtime.getValue('result')).toBe(0);
29
+ });
30
+
31
+ test('len of non-empty array', async () => {
32
+ const ast = parse(`
33
+ let arr = [1, 2, 3, 4, 5]
34
+ let result = arr.len()
35
+ `);
36
+ const runtime = new Runtime(ast, createMockProvider());
37
+ await runtime.run();
38
+ expect(runtime.getValue('result')).toBe(5);
39
+ });
40
+
41
+ test('len of array literal', async () => {
42
+ const ast = parse(`
43
+ let result = [10, 20, 30].len()
44
+ `);
45
+ const runtime = new Runtime(ast, createMockProvider());
46
+ await runtime.run();
47
+ expect(runtime.getValue('result')).toBe(3);
48
+ });
49
+
50
+ test('len in expression', async () => {
51
+ const ast = parse(`
52
+ let arr = [1, 2, 3]
53
+ let result = arr.len() + 10
54
+ `);
55
+ const runtime = new Runtime(ast, createMockProvider());
56
+ await runtime.run();
57
+ expect(runtime.getValue('result')).toBe(13);
58
+ });
59
+
60
+ test('len in condition', async () => {
61
+ const ast = parse(`
62
+ let arr = [1, 2, 3]
63
+ let result = "empty"
64
+ if arr.len() > 0 {
65
+ result = "not empty"
66
+ }
67
+ `);
68
+ const runtime = new Runtime(ast, createMockProvider());
69
+ await runtime.run();
70
+ expect(runtime.getValue('result')).toBe('not empty');
71
+ });
72
+ });
73
+
74
+ describe('Array Methods - push()', () => {
75
+ test('push to empty array', async () => {
76
+ const ast = parse(`
77
+ let arr = []
78
+ arr.push(42)
79
+ `);
80
+ const runtime = new Runtime(ast, createMockProvider());
81
+ await runtime.run();
82
+ expect(runtime.getValue('arr')).toEqual([42]);
83
+ });
84
+
85
+ test('push to non-empty array', async () => {
86
+ const ast = parse(`
87
+ let arr = [1, 2, 3]
88
+ arr.push(4)
89
+ `);
90
+ const runtime = new Runtime(ast, createMockProvider());
91
+ await runtime.run();
92
+ expect(runtime.getValue('arr')).toEqual([1, 2, 3, 4]);
93
+ });
94
+
95
+ test('push multiple times', async () => {
96
+ const ast = parse(`
97
+ let arr = []
98
+ arr.push(1)
99
+ arr.push(2)
100
+ arr.push(3)
101
+ `);
102
+ const runtime = new Runtime(ast, createMockProvider());
103
+ await runtime.run();
104
+ expect(runtime.getValue('arr')).toEqual([1, 2, 3]);
105
+ });
106
+
107
+ test('push returns the array for chaining', async () => {
108
+ const ast = parse(`
109
+ let arr = []
110
+ let result = arr.push(1).push(2).push(3)
111
+ `);
112
+ const runtime = new Runtime(ast, createMockProvider());
113
+ await runtime.run();
114
+ expect(runtime.getValue('arr')).toEqual([1, 2, 3]);
115
+ expect(runtime.getValue('result')).toEqual([1, 2, 3]);
116
+ });
117
+
118
+ test('push in loop', async () => {
119
+ const ast = parse(`
120
+ let arr = []
121
+ for i in 5 {
122
+ arr.push(i)
123
+ }
124
+ `);
125
+ const runtime = new Runtime(ast, createMockProvider());
126
+ await runtime.run();
127
+ expect(runtime.getValue('arr')).toEqual([1, 2, 3, 4, 5]);
128
+ });
129
+ });
130
+
131
+ describe('Array Methods - pop()', () => {
132
+ test('pop from array', async () => {
133
+ const ast = parse(`
134
+ let arr = [1, 2, 3]
135
+ let result = arr.pop()
136
+ `);
137
+ const runtime = new Runtime(ast, createMockProvider());
138
+ await runtime.run();
139
+ expect(runtime.getValue('result')).toBe(3);
140
+ expect(runtime.getValue('arr')).toEqual([1, 2]);
141
+ });
142
+
143
+ test('pop multiple times', async () => {
144
+ const ast = parse(`
145
+ let arr = [10, 20, 30]
146
+ let a = arr.pop()
147
+ let b = arr.pop()
148
+ let c = arr.pop()
149
+ `);
150
+ const runtime = new Runtime(ast, createMockProvider());
151
+ await runtime.run();
152
+ expect(runtime.getValue('a')).toBe(30);
153
+ expect(runtime.getValue('b')).toBe(20);
154
+ expect(runtime.getValue('c')).toBe(10);
155
+ expect(runtime.getValue('arr')).toEqual([]);
156
+ });
157
+
158
+ test('pop returns the removed element', async () => {
159
+ const ast = parse(`
160
+ let arr = ["first", "second", "third"]
161
+ let last = arr.pop()
162
+ `);
163
+ const runtime = new Runtime(ast, createMockProvider());
164
+ await runtime.run();
165
+ expect(runtime.getValue('last')).toBe('third');
166
+ });
167
+ });
168
+
169
+ describe('String Methods - len()', () => {
170
+ test('len of empty string', async () => {
171
+ const ast = parse(`
172
+ let s = ""
173
+ let result = s.len()
174
+ `);
175
+ const runtime = new Runtime(ast, createMockProvider());
176
+ await runtime.run();
177
+ expect(runtime.getValue('result')).toBe(0);
178
+ });
179
+
180
+ test('len of non-empty string', async () => {
181
+ const ast = parse(`
182
+ let s = "hello"
183
+ let result = s.len()
184
+ `);
185
+ const runtime = new Runtime(ast, createMockProvider());
186
+ await runtime.run();
187
+ expect(runtime.getValue('result')).toBe(5);
188
+ });
189
+
190
+ test('len of string literal', async () => {
191
+ const ast = parse(`
192
+ let result = "world".len()
193
+ `);
194
+ const runtime = new Runtime(ast, createMockProvider());
195
+ await runtime.run();
196
+ expect(runtime.getValue('result')).toBe(5);
197
+ });
198
+
199
+ test('len in comparison', async () => {
200
+ const ast = parse(`
201
+ let name = "Alice"
202
+ let result = name.len() == 5
203
+ `);
204
+ const runtime = new Runtime(ast, createMockProvider());
205
+ await runtime.run();
206
+ expect(runtime.getValue('result')).toBe(true);
207
+ });
208
+ });
209
+
210
+ describe('Method Chaining', () => {
211
+ test('push chain then len', async () => {
212
+ const ast = parse(`
213
+ let arr = []
214
+ let result = arr.push(1).push(2).push(3).len()
215
+ `);
216
+ const runtime = new Runtime(ast, createMockProvider());
217
+ await runtime.run();
218
+ expect(runtime.getValue('result')).toBe(3);
219
+ });
220
+
221
+ test('method after index access', async () => {
222
+ const ast = parse(`
223
+ let nested = [["a", "b", "c"], ["d", "e"]]
224
+ let result = nested[0].len()
225
+ `);
226
+ const runtime = new Runtime(ast, createMockProvider());
227
+ await runtime.run();
228
+ expect(runtime.getValue('result')).toBe(3);
229
+ });
230
+
231
+ test('index after method', async () => {
232
+ const ast = parse(`
233
+ let arr = []
234
+ let result = arr.push(10).push(20).push(30)[1]
235
+ `);
236
+ const runtime = new Runtime(ast, createMockProvider());
237
+ await runtime.run();
238
+ expect(runtime.getValue('result')).toBe(20);
239
+ });
240
+ });
241
+
242
+ describe('Methods with Other Features', () => {
243
+ test('method in while loop condition', async () => {
244
+ const ast = parse(`
245
+ let arr = [1, 2, 3, 4, 5]
246
+ let sum = 0
247
+ while arr.len() > 0 {
248
+ sum = sum + arr.pop()
249
+ }
250
+ `);
251
+ const runtime = new Runtime(ast, createMockProvider());
252
+ await runtime.run();
253
+ expect(runtime.getValue('sum')).toBe(15);
254
+ expect(runtime.getValue('arr')).toEqual([]);
255
+ });
256
+
257
+ test('method call passed to function', async () => {
258
+ const ast = parse(`
259
+ function double(n: number): number {
260
+ return n * 2
261
+ }
262
+ let arr = [1, 2, 3]
263
+ let result = double(arr.len())
264
+ `);
265
+ const runtime = new Runtime(ast, createMockProvider());
266
+ await runtime.run();
267
+ expect(runtime.getValue('result')).toBe(6);
268
+ });
269
+
270
+ test('building arrays with push in function', async () => {
271
+ const ast = parse(`
272
+ function buildArray(n: number): number[] {
273
+ let arr = []
274
+ for i in n {
275
+ arr.push(i * 10)
276
+ }
277
+ return arr
278
+ }
279
+ let result = buildArray(4)
280
+ `);
281
+ const runtime = new Runtime(ast, createMockProvider());
282
+ await runtime.run();
283
+ expect(runtime.getValue('result')).toEqual([10, 20, 30, 40]);
284
+ });
285
+ });
286
+
287
+ describe('Method Edge Cases', () => {
288
+ test('len of single element array', async () => {
289
+ const ast = parse(`
290
+ let arr = [42]
291
+ let result = arr.len()
292
+ `);
293
+ const runtime = new Runtime(ast, createMockProvider());
294
+ await runtime.run();
295
+ expect(runtime.getValue('result')).toBe(1);
296
+ });
297
+
298
+ test('push and pop sequence', async () => {
299
+ const ast = parse(`
300
+ let arr = [1]
301
+ arr.push(2)
302
+ let x = arr.pop()
303
+ arr.push(3)
304
+ let y = arr.pop()
305
+ `);
306
+ const runtime = new Runtime(ast, createMockProvider());
307
+ await runtime.run();
308
+ expect(runtime.getValue('x')).toBe(2);
309
+ expect(runtime.getValue('y')).toBe(3);
310
+ expect(runtime.getValue('arr')).toEqual([1]);
311
+ });
312
+
313
+ test('array method after slice', async () => {
314
+ const ast = parse(`
315
+ let arr = [1, 2, 3, 4, 5]
316
+ let sliced = arr[1:4]
317
+ let result = sliced.len()
318
+ `);
319
+ const runtime = new Runtime(ast, createMockProvider());
320
+ await runtime.run();
321
+ // Python-style: [1:4] = indices 1, 2, 3 = 3 elements
322
+ expect(runtime.getValue('result')).toBe(3);
323
+ });
324
+ });
@@ -0,0 +1,338 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { Runtime, type AIProvider } from '../index';
4
+
5
+ describe('Runtime - Model Config Value Resolution', () => {
6
+ const mockProvider: AIProvider = {
7
+ execute: async (prompt: string) => ({ value: prompt }),
8
+ generateCode: async () => ({ value: '' }),
9
+ askUser: async () => '',
10
+ };
11
+
12
+ function createRuntime(code: string): Runtime {
13
+ const ast = parse(code);
14
+ return new Runtime(ast, mockProvider);
15
+ }
16
+
17
+ // ============================================================================
18
+ // Literal Values
19
+ // ============================================================================
20
+
21
+ test('model config with string literals', async () => {
22
+ const runtime = createRuntime(`
23
+ model testModel = {
24
+ name: "gpt-4",
25
+ apiKey: "sk-test-key",
26
+ provider: "openai"
27
+ }
28
+
29
+ let modelInfo = ts(testModel) {
30
+ return { name: testModel.name, apiKey: testModel.apiKey, provider: testModel.provider };
31
+ }
32
+ `);
33
+ await runtime.run();
34
+ expect(runtime.getValue('modelInfo')).toEqual({
35
+ name: 'gpt-4',
36
+ apiKey: 'sk-test-key',
37
+ provider: 'openai',
38
+ });
39
+ });
40
+
41
+ test('model config with url literal', async () => {
42
+ const runtime = createRuntime(`
43
+ model testModel = {
44
+ name: "custom-model",
45
+ apiKey: "key",
46
+ url: "https://api.example.com/v1"
47
+ }
48
+
49
+ let url = ts(testModel) {
50
+ return testModel.url;
51
+ }
52
+ `);
53
+ await runtime.run();
54
+ expect(runtime.getValue('url')).toBe('https://api.example.com/v1');
55
+ });
56
+
57
+ // ============================================================================
58
+ // Variable References
59
+ // ============================================================================
60
+
61
+ test('model config with variable reference for apiKey', async () => {
62
+ const runtime = createRuntime(`
63
+ const myKey = ts() {
64
+ return "resolved-api-key";
65
+ }
66
+
67
+ model testModel = {
68
+ name: "gpt-4",
69
+ apiKey: myKey,
70
+ provider: "openai"
71
+ }
72
+
73
+ let resolvedKey = ts(testModel) {
74
+ return testModel.apiKey;
75
+ }
76
+ `);
77
+ await runtime.run();
78
+ expect(runtime.getValue('resolvedKey')).toBe('resolved-api-key');
79
+ });
80
+
81
+ test('model config with variable reference for name', async () => {
82
+ const runtime = createRuntime(`
83
+ let modelName = "claude-3-opus"
84
+
85
+ model testModel = {
86
+ name: modelName,
87
+ apiKey: "key",
88
+ provider: "anthropic"
89
+ }
90
+
91
+ let resolvedName = ts(testModel) {
92
+ return testModel.name;
93
+ }
94
+ `);
95
+ await runtime.run();
96
+ expect(runtime.getValue('resolvedName')).toBe('claude-3-opus');
97
+ });
98
+
99
+ test('model config with variable reference for provider', async () => {
100
+ const runtime = createRuntime(`
101
+ let myProvider = "anthropic"
102
+
103
+ model testModel = {
104
+ name: "claude",
105
+ apiKey: "key",
106
+ provider: myProvider
107
+ }
108
+
109
+ let resolvedProvider = ts(testModel) {
110
+ return testModel.provider;
111
+ }
112
+ `);
113
+ await runtime.run();
114
+ expect(runtime.getValue('resolvedProvider')).toBe('anthropic');
115
+ });
116
+
117
+ test('model config with multiple variable references', async () => {
118
+ const runtime = createRuntime(`
119
+ let myName = "gpt-4"
120
+ let myKey = "sk-secret"
121
+ let myProvider = "openai"
122
+ let myUrl = "https://custom.api.com"
123
+
124
+ model testModel = {
125
+ name: myName,
126
+ apiKey: myKey,
127
+ provider: myProvider,
128
+ url: myUrl
129
+ }
130
+
131
+ let config = ts(testModel) {
132
+ return {
133
+ name: testModel.name,
134
+ apiKey: testModel.apiKey,
135
+ provider: testModel.provider,
136
+ url: testModel.url
137
+ };
138
+ }
139
+ `);
140
+ await runtime.run();
141
+ expect(runtime.getValue('config')).toEqual({
142
+ name: 'gpt-4',
143
+ apiKey: 'sk-secret',
144
+ provider: 'openai',
145
+ url: 'https://custom.api.com',
146
+ });
147
+ });
148
+
149
+ // ============================================================================
150
+ // Const vs Let Variables
151
+ // ============================================================================
152
+
153
+ test('model config with const variable reference', async () => {
154
+ const runtime = createRuntime(`
155
+ const API_KEY = "const-api-key"
156
+
157
+ model testModel = {
158
+ name: "test",
159
+ apiKey: API_KEY,
160
+ provider: "test"
161
+ }
162
+
163
+ let key = ts(testModel) {
164
+ return testModel.apiKey;
165
+ }
166
+ `);
167
+ await runtime.run();
168
+ expect(runtime.getValue('key')).toBe('const-api-key');
169
+ });
170
+
171
+ test('model config with let variable reference', async () => {
172
+ const runtime = createRuntime(`
173
+ let dynamicKey = "dynamic-key"
174
+
175
+ model testModel = {
176
+ name: "test",
177
+ apiKey: dynamicKey,
178
+ provider: "test"
179
+ }
180
+
181
+ let key = ts(testModel) {
182
+ return testModel.apiKey;
183
+ }
184
+ `);
185
+ await runtime.run();
186
+ expect(runtime.getValue('key')).toBe('dynamic-key');
187
+ });
188
+
189
+ // ============================================================================
190
+ // TS Block Results as Config Values
191
+ // ============================================================================
192
+
193
+ test('model config with ts block result', async () => {
194
+ const runtime = createRuntime(`
195
+ const computedKey = ts() {
196
+ return "computed-" + "key";
197
+ }
198
+
199
+ model testModel = {
200
+ name: "test",
201
+ apiKey: computedKey,
202
+ provider: "test"
203
+ }
204
+
205
+ let key = ts(testModel) {
206
+ return testModel.apiKey;
207
+ }
208
+ `);
209
+ await runtime.run();
210
+ expect(runtime.getValue('key')).toBe('computed-key');
211
+ });
212
+
213
+ // ============================================================================
214
+ // Edge Cases
215
+ // ============================================================================
216
+
217
+ test('model config with empty string', async () => {
218
+ const runtime = createRuntime(`
219
+ model testModel = {
220
+ name: "",
221
+ apiKey: "key",
222
+ provider: "test"
223
+ }
224
+
225
+ let name = ts(testModel) {
226
+ return testModel.name;
227
+ }
228
+ `);
229
+ await runtime.run();
230
+ expect(runtime.getValue('name')).toBe('');
231
+ });
232
+
233
+ test('model config with special characters in strings', async () => {
234
+ const runtime = createRuntime(`
235
+ model testModel = {
236
+ name: "model-with-dashes",
237
+ apiKey: "sk_test_key_123",
238
+ url: "https://api.example.com/v1/chat?param=value"
239
+ }
240
+
241
+ let info = ts(testModel) {
242
+ return { name: testModel.name, apiKey: testModel.apiKey, url: testModel.url };
243
+ }
244
+ `);
245
+ await runtime.run();
246
+ expect(runtime.getValue('info')).toEqual({
247
+ name: 'model-with-dashes',
248
+ apiKey: 'sk_test_key_123',
249
+ url: 'https://api.example.com/v1/chat?param=value',
250
+ });
251
+ });
252
+
253
+ // ============================================================================
254
+ // CallExpression in Model Config - Currently Broken
255
+ // These tests FAIL with current implementation - they define expected behavior.
256
+ // ============================================================================
257
+
258
+ test('model config with env() function call', async () => {
259
+ process.env.TEST_MODEL_API_KEY = 'env-api-key-value';
260
+
261
+ // env() is auto-imported, no import needed
262
+ const runtime = createRuntime(`
263
+ model testModel = {
264
+ name: "test",
265
+ apiKey: env("TEST_MODEL_API_KEY"),
266
+ provider: "test"
267
+ }
268
+
269
+ let key = ts(testModel) {
270
+ return testModel.apiKey;
271
+ }
272
+ `);
273
+ await runtime.run();
274
+ expect(runtime.getValue('key')).toBe('env-api-key-value');
275
+
276
+ delete process.env.TEST_MODEL_API_KEY;
277
+ });
278
+
279
+ test('model config with inline ts block', async () => {
280
+ const runtime = createRuntime(`
281
+ model testModel = {
282
+ name: "test",
283
+ apiKey: ts() { return "inline-key"; },
284
+ provider: "test"
285
+ }
286
+
287
+ let key = ts(testModel) {
288
+ return testModel.apiKey;
289
+ }
290
+ `);
291
+ await runtime.run();
292
+ expect(runtime.getValue('key')).toBe('inline-key');
293
+ });
294
+
295
+ test('model config with vibe function call', async () => {
296
+ const runtime = createRuntime(`
297
+ function getKey(): text {
298
+ return "function-key"
299
+ }
300
+
301
+ model testModel = {
302
+ name: "test",
303
+ apiKey: getKey(),
304
+ provider: "test"
305
+ }
306
+
307
+ let key = ts(testModel) {
308
+ return testModel.apiKey;
309
+ }
310
+ `);
311
+ await runtime.run();
312
+ expect(runtime.getValue('key')).toBe('function-key');
313
+ });
314
+
315
+ // ============================================================================
316
+ // Workaround Tests - Assign to variable first, then use in model
317
+ // ============================================================================
318
+
319
+ test('workaround: ts block result assigned to variable then used in model', async () => {
320
+ const runtime = createRuntime(`
321
+ const apiKey = ts() {
322
+ return process.env.TEST_KEY || "fallback-key";
323
+ }
324
+
325
+ model testModel = {
326
+ name: "test",
327
+ apiKey: apiKey,
328
+ provider: "test"
329
+ }
330
+
331
+ let key = ts(testModel) {
332
+ return testModel.apiKey;
333
+ }
334
+ `);
335
+ await runtime.run();
336
+ expect(runtime.getValue('key')).toBe('fallback-key');
337
+ });
338
+ });