@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,486 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../parse';
3
+
4
+ describe('Parser - Vibe Expression', () => {
5
+ // ============================================================================
6
+ // Basic vibe expressions with all 3 arguments
7
+ // ============================================================================
8
+
9
+ test('vibe with string prompt and default context', () => {
10
+ const ast = parse(`
11
+ vibe "what is 2+2" myModel default
12
+ `);
13
+ expect(ast.body).toHaveLength(1);
14
+ expect(ast.body[0]).toMatchObject({
15
+ type: 'ExpressionStatement',
16
+ expression: {
17
+ type: 'VibeExpression',
18
+ operationType: 'vibe',
19
+ prompt: {
20
+ type: 'StringLiteral',
21
+ value: 'what is 2+2',
22
+ },
23
+ model: {
24
+ type: 'Identifier',
25
+ name: 'myModel',
26
+ },
27
+ context: {
28
+ type: 'ContextSpecifier',
29
+ kind: 'default',
30
+ },
31
+ },
32
+ });
33
+ });
34
+
35
+ test('vibe with string prompt and local context', () => {
36
+ const ast = parse(`
37
+ vibe "explain this" myModel local
38
+ `);
39
+ expect(ast.body).toHaveLength(1);
40
+ expect(ast.body[0]).toMatchObject({
41
+ type: 'ExpressionStatement',
42
+ expression: {
43
+ type: 'VibeExpression',
44
+ prompt: {
45
+ type: 'StringLiteral',
46
+ value: 'explain this',
47
+ },
48
+ model: {
49
+ type: 'Identifier',
50
+ name: 'myModel',
51
+ },
52
+ context: {
53
+ type: 'ContextSpecifier',
54
+ kind: 'local',
55
+ },
56
+ },
57
+ });
58
+ });
59
+
60
+ test('vibe with variable context', () => {
61
+ const ast = parse(`
62
+ vibe "prompt" myModel myContext
63
+ `);
64
+ expect(ast.body).toHaveLength(1);
65
+ expect(ast.body[0]).toMatchObject({
66
+ type: 'ExpressionStatement',
67
+ expression: {
68
+ type: 'VibeExpression',
69
+ context: {
70
+ type: 'ContextSpecifier',
71
+ kind: 'variable',
72
+ variable: 'myContext',
73
+ },
74
+ },
75
+ });
76
+ });
77
+
78
+ test('vibe with variable prompt', () => {
79
+ const ast = parse(`
80
+ vibe promptVar myModel default
81
+ `);
82
+ expect(ast.body).toHaveLength(1);
83
+ expect(ast.body[0]).toMatchObject({
84
+ type: 'ExpressionStatement',
85
+ expression: {
86
+ type: 'VibeExpression',
87
+ prompt: {
88
+ type: 'Identifier',
89
+ name: 'promptVar',
90
+ },
91
+ model: {
92
+ type: 'Identifier',
93
+ name: 'myModel',
94
+ },
95
+ },
96
+ });
97
+ });
98
+
99
+ // ============================================================================
100
+ // Do in variable assignment
101
+ // ============================================================================
102
+
103
+ test('vibe result assigned to let', () => {
104
+ const ast = parse(`
105
+ let result = vibe "what is AI" gptModel default
106
+ `);
107
+ expect(ast.body).toHaveLength(1);
108
+ expect(ast.body[0]).toMatchObject({
109
+ type: 'LetDeclaration',
110
+ name: 'result',
111
+ initializer: {
112
+ type: 'VibeExpression',
113
+ prompt: {
114
+ type: 'StringLiteral',
115
+ value: 'what is AI',
116
+ },
117
+ },
118
+ });
119
+ });
120
+
121
+ test('vibe result assigned to const', () => {
122
+ const ast = parse(`
123
+ const answer = vibe "calculate sum" mathModel local
124
+ `);
125
+ expect(ast.body).toHaveLength(1);
126
+ expect(ast.body[0]).toMatchObject({
127
+ type: 'ConstDeclaration',
128
+ name: 'answer',
129
+ initializer: {
130
+ type: 'VibeExpression',
131
+ },
132
+ });
133
+ });
134
+
135
+ // ============================================================================
136
+ // Do with model declaration
137
+ // ============================================================================
138
+
139
+ test('model declaration followed by do', () => {
140
+ const ast = parse(`
141
+ model gpt4 = {
142
+ name: "gpt-4",
143
+ apiUrl: "https://api.openai.com"
144
+ }
145
+
146
+ let response = vibe "hello world" gpt4 default
147
+ `);
148
+ expect(ast.body).toHaveLength(2);
149
+ expect(ast.body[0]).toMatchObject({
150
+ type: 'ModelDeclaration',
151
+ name: 'gpt4',
152
+ });
153
+ expect(ast.body[1]).toMatchObject({
154
+ type: 'LetDeclaration',
155
+ initializer: {
156
+ type: 'VibeExpression',
157
+ model: {
158
+ type: 'Identifier',
159
+ name: 'gpt4',
160
+ },
161
+ },
162
+ });
163
+ });
164
+
165
+ // ============================================================================
166
+ // Do in function body
167
+ // ============================================================================
168
+
169
+ test('vibe inside function', () => {
170
+ const ast = parse(`
171
+ function askAI(question: text): text {
172
+ return vibe question aiModel default
173
+ }
174
+ `);
175
+ expect(ast.body).toHaveLength(1);
176
+ expect(ast.body[0]).toMatchObject({
177
+ type: 'FunctionDeclaration',
178
+ name: 'askAI',
179
+ body: {
180
+ type: 'BlockStatement',
181
+ body: [
182
+ {
183
+ type: 'ReturnStatement',
184
+ value: {
185
+ type: 'VibeExpression',
186
+ prompt: {
187
+ type: 'Identifier',
188
+ name: 'question',
189
+ },
190
+ },
191
+ },
192
+ ],
193
+ },
194
+ });
195
+ });
196
+ });
197
+
198
+ // ============================================================================
199
+ // Optional Model and Context Tests
200
+ // ============================================================================
201
+
202
+ describe('Parser - Vibe Expression with Optional Modifiers', () => {
203
+ test('vibe with prompt only (no model, no context)', () => {
204
+ const ast = parse(`
205
+ let x = vibe "just a prompt"
206
+ `);
207
+ expect(ast.body).toHaveLength(1);
208
+ expect(ast.body[0]).toMatchObject({
209
+ type: 'LetDeclaration',
210
+ name: 'x',
211
+ initializer: {
212
+ type: 'VibeExpression',
213
+ operationType: 'vibe',
214
+ prompt: {
215
+ type: 'StringLiteral',
216
+ value: 'just a prompt',
217
+ },
218
+ model: null,
219
+ context: null,
220
+ },
221
+ });
222
+ });
223
+
224
+ test('vibe with prompt and context keyword only (no model)', () => {
225
+ const ast = parse(`
226
+ let x = vibe "prompt" default
227
+ `);
228
+ expect(ast.body).toHaveLength(1);
229
+ expect(ast.body[0]).toMatchObject({
230
+ type: 'LetDeclaration',
231
+ initializer: {
232
+ type: 'VibeExpression',
233
+ prompt: { type: 'StringLiteral', value: 'prompt' },
234
+ model: null,
235
+ context: { type: 'ContextSpecifier', kind: 'default' },
236
+ },
237
+ });
238
+ });
239
+
240
+ test('vibe with prompt and local context (no model)', () => {
241
+ const ast = parse(`
242
+ let x = vibe "prompt" local
243
+ `);
244
+ expect(ast.body).toHaveLength(1);
245
+ expect(ast.body[0]).toMatchObject({
246
+ type: 'LetDeclaration',
247
+ initializer: {
248
+ type: 'VibeExpression',
249
+ model: null,
250
+ context: { type: 'ContextSpecifier', kind: 'local' },
251
+ },
252
+ });
253
+ });
254
+
255
+ test('vibe with prompt and model only (no context)', () => {
256
+ const ast = parse(`
257
+ let x = vibe "prompt" myModel
258
+ `);
259
+ expect(ast.body).toHaveLength(1);
260
+ expect(ast.body[0]).toMatchObject({
261
+ type: 'LetDeclaration',
262
+ initializer: {
263
+ type: 'VibeExpression',
264
+ prompt: { type: 'StringLiteral', value: 'prompt' },
265
+ model: { type: 'Identifier', name: 'myModel' },
266
+ context: null,
267
+ },
268
+ });
269
+ });
270
+
271
+ test('vibe with all three: prompt, model, and context', () => {
272
+ const ast = parse(`
273
+ let x = vibe "prompt" myModel default
274
+ `);
275
+ expect(ast.body).toHaveLength(1);
276
+ expect(ast.body[0]).toMatchObject({
277
+ type: 'LetDeclaration',
278
+ initializer: {
279
+ type: 'VibeExpression',
280
+ prompt: { type: 'StringLiteral', value: 'prompt' },
281
+ model: { type: 'Identifier', name: 'myModel' },
282
+ context: { type: 'ContextSpecifier', kind: 'default' },
283
+ },
284
+ });
285
+ });
286
+ });
287
+
288
+ describe('Syntax Errors - Vibe Expression', () => {
289
+ test('vibe with no arguments at all', () => {
290
+ expect(() => parse(`
291
+ vibe
292
+ `)).toThrow();
293
+ });
294
+ });
295
+
296
+ // ============================================================================
297
+ // Do Expression (single-round, no tool loop)
298
+ // ============================================================================
299
+
300
+ describe('Parser - Do Expression', () => {
301
+ test('do with string prompt and default context', () => {
302
+ const ast = parse(`
303
+ do "summarize this" myModel default
304
+ `);
305
+ expect(ast.body).toHaveLength(1);
306
+ expect(ast.body[0]).toMatchObject({
307
+ type: 'ExpressionStatement',
308
+ expression: {
309
+ type: 'VibeExpression',
310
+ operationType: 'do',
311
+ prompt: {
312
+ type: 'StringLiteral',
313
+ value: 'summarize this',
314
+ },
315
+ model: {
316
+ type: 'Identifier',
317
+ name: 'myModel',
318
+ },
319
+ context: {
320
+ type: 'ContextSpecifier',
321
+ kind: 'default',
322
+ },
323
+ },
324
+ });
325
+ });
326
+
327
+ test('do with local context', () => {
328
+ const ast = parse(`
329
+ do "analyze" myModel local
330
+ `);
331
+ expect(ast.body).toHaveLength(1);
332
+ expect(ast.body[0]).toMatchObject({
333
+ type: 'ExpressionStatement',
334
+ expression: {
335
+ type: 'VibeExpression',
336
+ operationType: 'do',
337
+ context: {
338
+ type: 'ContextSpecifier',
339
+ kind: 'local',
340
+ },
341
+ },
342
+ });
343
+ });
344
+
345
+ test('do with variable context', () => {
346
+ const ast = parse(`
347
+ do "prompt" myModel myContext
348
+ `);
349
+ expect(ast.body).toHaveLength(1);
350
+ expect(ast.body[0]).toMatchObject({
351
+ type: 'ExpressionStatement',
352
+ expression: {
353
+ type: 'VibeExpression',
354
+ operationType: 'do',
355
+ context: {
356
+ type: 'ContextSpecifier',
357
+ kind: 'variable',
358
+ variable: 'myContext',
359
+ },
360
+ },
361
+ });
362
+ });
363
+
364
+ test('do result assigned to let', () => {
365
+ const ast = parse(`
366
+ let summary = do "summarize the code" gpt4 default
367
+ `);
368
+ expect(ast.body).toHaveLength(1);
369
+ expect(ast.body[0]).toMatchObject({
370
+ type: 'LetDeclaration',
371
+ name: 'summary',
372
+ initializer: {
373
+ type: 'VibeExpression',
374
+ operationType: 'do',
375
+ prompt: {
376
+ type: 'StringLiteral',
377
+ value: 'summarize the code',
378
+ },
379
+ },
380
+ });
381
+ });
382
+
383
+ test('do result assigned to typed const', () => {
384
+ const ast = parse(`
385
+ const count: number = do "how many items?" myModel default
386
+ `);
387
+ expect(ast.body).toHaveLength(1);
388
+ expect(ast.body[0]).toMatchObject({
389
+ type: 'ConstDeclaration',
390
+ name: 'count',
391
+ typeAnnotation: 'number',
392
+ initializer: {
393
+ type: 'VibeExpression',
394
+ operationType: 'do',
395
+ },
396
+ });
397
+ });
398
+
399
+ test('do inside function', () => {
400
+ const ast = parse(`
401
+ function summarize(input: text): text {
402
+ return do input summaryModel default
403
+ }
404
+ `);
405
+ expect(ast.body).toHaveLength(1);
406
+ expect(ast.body[0]).toMatchObject({
407
+ type: 'FunctionDeclaration',
408
+ name: 'summarize',
409
+ body: {
410
+ type: 'BlockStatement',
411
+ body: [
412
+ {
413
+ type: 'ReturnStatement',
414
+ value: {
415
+ type: 'VibeExpression',
416
+ operationType: 'do',
417
+ prompt: {
418
+ type: 'Identifier',
419
+ name: 'input',
420
+ },
421
+ },
422
+ },
423
+ ],
424
+ },
425
+ });
426
+ });
427
+ });
428
+
429
+ describe('Parser - Do Expression with Optional Modifiers', () => {
430
+ test('do with prompt only (no model, no context)', () => {
431
+ const ast = parse(`
432
+ let x = do "just a prompt"
433
+ `);
434
+ expect(ast.body).toHaveLength(1);
435
+ expect(ast.body[0]).toMatchObject({
436
+ type: 'LetDeclaration',
437
+ initializer: {
438
+ type: 'VibeExpression',
439
+ operationType: 'do',
440
+ prompt: { type: 'StringLiteral', value: 'just a prompt' },
441
+ model: null,
442
+ context: null,
443
+ },
444
+ });
445
+ });
446
+
447
+ test('do with prompt and context only (no model)', () => {
448
+ const ast = parse(`
449
+ let x = do "prompt" default
450
+ `);
451
+ expect(ast.body).toHaveLength(1);
452
+ expect(ast.body[0]).toMatchObject({
453
+ type: 'LetDeclaration',
454
+ initializer: {
455
+ type: 'VibeExpression',
456
+ operationType: 'do',
457
+ model: null,
458
+ context: { type: 'ContextSpecifier', kind: 'default' },
459
+ },
460
+ });
461
+ });
462
+
463
+ test('do with prompt and model only (no context)', () => {
464
+ const ast = parse(`
465
+ let x = do "prompt" myModel
466
+ `);
467
+ expect(ast.body).toHaveLength(1);
468
+ expect(ast.body[0]).toMatchObject({
469
+ type: 'LetDeclaration',
470
+ initializer: {
471
+ type: 'VibeExpression',
472
+ operationType: 'do',
473
+ model: { type: 'Identifier', name: 'myModel' },
474
+ context: null,
475
+ },
476
+ });
477
+ });
478
+ });
479
+
480
+ describe('Syntax Errors - Do Expression', () => {
481
+ test('do with no arguments', () => {
482
+ expect(() => parse(`
483
+ do
484
+ `)).toThrow();
485
+ });
486
+ });
@@ -0,0 +1,95 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parse';
3
+
4
+ describe('Syntax Errors - Vibe Expression', () => {
5
+ // ============================================================================
6
+ // Vibe/Do with no arguments at all (prompt is required)
7
+ // ============================================================================
8
+
9
+ test('vibe with no arguments', () => {
10
+ expect(() => parse(`
11
+ let x = vibe
12
+ `)).toThrow();
13
+ });
14
+
15
+ test('do with no arguments', () => {
16
+ expect(() => parse(`
17
+ let x = do
18
+ `)).toThrow();
19
+ });
20
+
21
+ // ============================================================================
22
+ // Invalid prompt argument (special characters that can't start an expression)
23
+ // ============================================================================
24
+
25
+ test('vibe with equals as prompt', () => {
26
+ expect(() => parse(`
27
+ let x = vibe = myModel default
28
+ `)).toThrow();
29
+ });
30
+
31
+ test('vibe with comma as prompt', () => {
32
+ expect(() => parse(`
33
+ let x = vibe , myModel default
34
+ `)).toThrow();
35
+ });
36
+
37
+ test('vibe with closing brace as prompt', () => {
38
+ expect(() => parse(`
39
+ let x = vibe } myModel default
40
+ `)).toThrow();
41
+ });
42
+
43
+ // ============================================================================
44
+ // Invalid model argument
45
+ // ============================================================================
46
+
47
+ test('vibe with equals as model', () => {
48
+ expect(() => parse(`
49
+ let x = vibe "prompt" = default
50
+ `)).toThrow();
51
+ });
52
+
53
+ test('vibe with comma as model', () => {
54
+ expect(() => parse(`
55
+ let x = vibe "prompt" , default
56
+ `)).toThrow();
57
+ });
58
+
59
+ // ============================================================================
60
+ // Invalid context argument
61
+ // ============================================================================
62
+
63
+ test('vibe with equals as context', () => {
64
+ expect(() => parse(`
65
+ let x = vibe "prompt" myModel =
66
+ `)).toThrow();
67
+ });
68
+
69
+ test('vibe with comma as context', () => {
70
+ expect(() => parse(`
71
+ let x = vibe "prompt" myModel ,
72
+ `)).toThrow();
73
+ });
74
+
75
+ // Note: `vibe "prompt" myModel "invalid"` parses successfully because
76
+ // the grammar treats "invalid" as a separate expression statement.
77
+ // The semantic analyzer catches this as an error.
78
+
79
+ // ============================================================================
80
+ // Do in invalid positions
81
+ // ============================================================================
82
+
83
+ test('vibe as model declaration value', () => {
84
+ expect(() => parse(`
85
+ model myModel = vibe "prompt" otherModel default
86
+ `)).toThrow();
87
+ });
88
+
89
+ test('vibe with unclosed surrounding block', () => {
90
+ expect(() => parse(`
91
+ function test() {
92
+ let x = vibe "prompt" myModel default
93
+ `)).toThrow();
94
+ });
95
+ });