@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,111 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { analyze } from '../index';
4
+
5
+ describe('Semantic Errors - Export Validation', () => {
6
+ // ============================================================================
7
+ // Export let is not allowed
8
+ // ============================================================================
9
+
10
+ test('cannot export let variable', () => {
11
+ const ast = parse(`
12
+ export let x = "hello"
13
+ `);
14
+ const errors = analyze(ast);
15
+ expect(errors.length).toBe(1);
16
+ expect(errors[0].message).toBe("Cannot export mutable variable 'x'. Only constants can be exported.");
17
+ });
18
+
19
+ test('cannot export let with type annotation', () => {
20
+ const ast = parse(`
21
+ export let count: number = 42
22
+ `);
23
+ const errors = analyze(ast);
24
+ expect(errors.length).toBe(1);
25
+ expect(errors[0].message).toBe("Cannot export mutable variable 'count'. Only constants can be exported.");
26
+ });
27
+
28
+ // ============================================================================
29
+ // Valid exports
30
+ // ============================================================================
31
+
32
+ test('can export const variable', () => {
33
+ const ast = parse(`
34
+ export const X = "hello"
35
+ `);
36
+ const errors = analyze(ast);
37
+ expect(errors.length).toBe(0);
38
+ });
39
+
40
+ test('can export const with type annotation', () => {
41
+ const ast = parse(`
42
+ export const COUNT: number = 42
43
+ `);
44
+ const errors = analyze(ast);
45
+ expect(errors.length).toBe(0);
46
+ });
47
+
48
+ test('can export function', () => {
49
+ const ast = parse(`
50
+ export function greet(name: text): text {
51
+ return "Hello " + name
52
+ }
53
+ `);
54
+ const errors = analyze(ast);
55
+ expect(errors.length).toBe(0);
56
+ });
57
+
58
+ test('can export model', () => {
59
+ const ast = parse(`
60
+ export model myModel = {
61
+ name: "gpt-4",
62
+ provider: "openai",
63
+ apiKey: "test",
64
+ url: "https://api.openai.com"
65
+ }
66
+ `);
67
+ const errors = analyze(ast);
68
+ expect(errors.length).toBe(0);
69
+ });
70
+
71
+ // ============================================================================
72
+ // Multiple exports
73
+ // ============================================================================
74
+
75
+ test('multiple export let errors reported separately', () => {
76
+ const ast = parse(`
77
+ export let a = 1
78
+ export let b = 2
79
+ `);
80
+ const errors = analyze(ast);
81
+ expect(errors.length).toBe(2);
82
+ expect(errors[0].message).toBe("Cannot export mutable variable 'a'. Only constants can be exported.");
83
+ expect(errors[1].message).toBe("Cannot export mutable variable 'b'. Only constants can be exported.");
84
+ });
85
+
86
+ test('mixed valid and invalid exports', () => {
87
+ const ast = parse(`
88
+ export const VALID = "ok"
89
+ export let invalid = "not ok"
90
+ export function alsoValid(): text {
91
+ return "ok"
92
+ }
93
+ `);
94
+ const errors = analyze(ast);
95
+ expect(errors.length).toBe(1);
96
+ expect(errors[0].message).toBe("Cannot export mutable variable 'invalid'. Only constants can be exported.");
97
+ });
98
+
99
+ // ============================================================================
100
+ // Non-exported let is still allowed
101
+ // ============================================================================
102
+
103
+ test('non-exported let is allowed', () => {
104
+ const ast = parse(`
105
+ let x = "hello"
106
+ export const Y = x
107
+ `);
108
+ const errors = analyze(ast);
109
+ expect(errors.length).toBe(0);
110
+ });
111
+ });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Test fixture for TS type checking tests
3
+ */
4
+
5
+ // Function declaration
6
+ export function add(a: number, b: number): number {
7
+ return a + b;
8
+ }
9
+
10
+ // Arrow function
11
+ export const multiply = (a: number, b: number): number => a * b;
12
+
13
+ // Function with optional parameter
14
+ export function greet(name: string, greeting?: string): string {
15
+ return `${greeting ?? 'Hello'}, ${name}!`;
16
+ }
17
+
18
+ // Function with object parameter
19
+ export function processData(data: Record<string, unknown>): string {
20
+ return JSON.stringify(data);
21
+ }
22
+
23
+ // Function with array parameter
24
+ export function sumArray(nums: number[]): number {
25
+ return nums.reduce((a, b) => a + b, 0);
26
+ }
27
+
28
+ // Function with default parameter
29
+ export function repeat(str: string, times: number = 1): string {
30
+ return str.repeat(times);
31
+ }
@@ -0,0 +1,148 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { SemanticAnalyzer } from '../analyzer';
4
+
5
+ function analyze(source: string) {
6
+ const ast = parse(source);
7
+ const analyzer = new SemanticAnalyzer();
8
+ return analyzer.analyze(ast, source);
9
+ }
10
+
11
+ describe('Semantic Analysis - Import Declarations', () => {
12
+ test('valid import declaration', () => {
13
+ const errors = analyze(`
14
+ import { add } from "./math.ts"
15
+ let result = add("1", "2")
16
+ `);
17
+ expect(errors).toHaveLength(0);
18
+ });
19
+
20
+ test('multiple imports from same file', () => {
21
+ const errors = analyze(`
22
+ import { add, subtract } from "./math.ts"
23
+ let sum = add("1", "2")
24
+ let diff = subtract("5", "3")
25
+ `);
26
+ expect(errors).toHaveLength(0);
27
+ });
28
+
29
+ test('imports from different files', () => {
30
+ const errors = analyze(`
31
+ import { add } from "./math.ts"
32
+ import { greet } from "./greet.vibe"
33
+ let sum = add("1", "2")
34
+ let greeting = greet("Alice")
35
+ `);
36
+ expect(errors).toHaveLength(0);
37
+ });
38
+
39
+ test('error: duplicate import name from different sources', () => {
40
+ const errors = analyze(`
41
+ import { helper } from "./a.ts"
42
+ import { helper } from "./b.ts"
43
+ `);
44
+ expect(errors).toHaveLength(1);
45
+ expect(errors[0].message).toMatch(/already imported/);
46
+ });
47
+
48
+ test('error: import conflicts with local function', () => {
49
+ const errors = analyze(`
50
+ function add(a: text, b: text): text {
51
+ return a
52
+ }
53
+ import { add } from "./math.ts"
54
+ `);
55
+ expect(errors).toHaveLength(1);
56
+ expect(errors[0].message).toMatch(/conflicts with existing function/);
57
+ });
58
+
59
+ test('error: import conflicts with local variable', () => {
60
+ const errors = analyze(`
61
+ let counter = "0"
62
+ import { counter } from "./state.ts"
63
+ `);
64
+ expect(errors).toHaveLength(1);
65
+ expect(errors[0].message).toMatch(/conflicts with existing variable/);
66
+ });
67
+
68
+ test('error: import conflicts with model', () => {
69
+ const errors = analyze(`
70
+ model gpt = { name: "gpt-4", apiKey: "key", url: "url" }
71
+ import { gpt } from "./models.ts"
72
+ `);
73
+ expect(errors).toHaveLength(1);
74
+ expect(errors[0].message).toMatch(/conflicts with existing model/);
75
+ });
76
+
77
+ test('error: cannot reassign import', () => {
78
+ const errors = analyze(`
79
+ import { counter } from "./state.ts"
80
+ counter = "new value"
81
+ `);
82
+ expect(errors).toHaveLength(1);
83
+ expect(errors[0].message).toMatch(/Cannot reassign imported/);
84
+ });
85
+ });
86
+
87
+ describe('Semantic Analysis - Export Declarations', () => {
88
+ test('valid export function', () => {
89
+ const errors = analyze(`
90
+ model gpt = { name: "gpt-4", apiKey: "key", url: "url" }
91
+ export function greet(name: text): text {
92
+ return vibe "Hello {name}" gpt default
93
+ }
94
+ `);
95
+ expect(errors).toHaveLength(0);
96
+ });
97
+
98
+ test('valid export const', () => {
99
+ const errors = analyze(`
100
+ export const API_KEY = "secret"
101
+ export const COUNT = 42
102
+ `);
103
+ expect(errors).toHaveLength(0);
104
+ });
105
+
106
+ test('valid export model', () => {
107
+ const errors = analyze(`
108
+ export model gpt = { name: "gpt-4", apiKey: "key", url: "url" }
109
+ `);
110
+ expect(errors).toHaveLength(0);
111
+ });
112
+
113
+ test('error: duplicate export names', () => {
114
+ const errors = analyze(`
115
+ export function foo() { return "a" }
116
+ export function foo() { return "b" }
117
+ `);
118
+ expect(errors).toHaveLength(1);
119
+ expect(errors[0].message).toMatch(/already declared/);
120
+ });
121
+ });
122
+
123
+ describe('Semantic Analysis - TsBlock', () => {
124
+ test('valid ts block with defined parameters', () => {
125
+ const errors = analyze(`
126
+ let a = "5"
127
+ let b = "3"
128
+ let sum = ts(a, b) { return a + b }
129
+ `);
130
+ expect(errors).toHaveLength(0);
131
+ });
132
+
133
+ test('error: ts block with undefined parameter', () => {
134
+ const errors = analyze(`
135
+ let a = "5"
136
+ let sum = ts(a, b) { return a + b }
137
+ `);
138
+ expect(errors).toHaveLength(1);
139
+ expect(errors[0].message).toMatch(/'b' is not defined/);
140
+ });
141
+
142
+ test('error: ts block with multiple undefined parameters', () => {
143
+ const errors = analyze(`
144
+ let sum = ts(x, y, z) { return x + y + z }
145
+ `);
146
+ expect(errors).toHaveLength(3);
147
+ });
148
+ });
@@ -0,0 +1,68 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { analyze } from '../index';
4
+
5
+ describe('Semantic Errors - JSON Type Strictness', () => {
6
+ // ============================================================================
7
+ // json type cannot be array
8
+ // ============================================================================
9
+
10
+ test('json type rejects array literal', () => {
11
+ const ast = parse(`let x: json = [1, 2, 3]`);
12
+ const errors = analyze(ast);
13
+ expect(errors.length).toBe(1);
14
+ expect(errors[0].message).toBe('json type expects an object, not an array. Use json[] for arrays.');
15
+ });
16
+
17
+ test('json type rejects array of objects literal', () => {
18
+ const ast = parse(`let x: json = [{ a: 1 }, { b: 2 }]`);
19
+ const errors = analyze(ast);
20
+ expect(errors.length).toBe(1);
21
+ expect(errors[0].message).toBe('json type expects an object, not an array. Use json[] for arrays.');
22
+ });
23
+
24
+ test('json type rejects empty array literal', () => {
25
+ const ast = parse(`let x: json = []`);
26
+ const errors = analyze(ast);
27
+ expect(errors.length).toBe(1);
28
+ expect(errors[0].message).toBe('json type expects an object, not an array. Use json[] for arrays.');
29
+ });
30
+
31
+ // ============================================================================
32
+ // json type accepts objects
33
+ // ============================================================================
34
+
35
+ test('json type accepts object literal', () => {
36
+ const ast = parse(`let x: json = { name: "Alice", age: 30 }`);
37
+ const errors = analyze(ast);
38
+ expect(errors.length).toBe(0);
39
+ });
40
+
41
+ test('json type accepts empty object literal', () => {
42
+ const ast = parse(`let x: json = {}`);
43
+ const errors = analyze(ast);
44
+ expect(errors.length).toBe(0);
45
+ });
46
+
47
+ test('json type accepts nested object literal', () => {
48
+ const ast = parse(`let x: json = { user: { name: "Bob", items: [1, 2, 3] } }`);
49
+ const errors = analyze(ast);
50
+ expect(errors.length).toBe(0);
51
+ });
52
+
53
+ // ============================================================================
54
+ // json[] type for arrays
55
+ // ============================================================================
56
+
57
+ test('json[] accepts array of objects', () => {
58
+ const ast = parse(`let x: json[] = [{ a: 1 }, { b: 2 }]`);
59
+ const errors = analyze(ast);
60
+ expect(errors.length).toBe(0);
61
+ });
62
+
63
+ test('json[] accepts empty array', () => {
64
+ const ast = parse(`let x: json[] = []`);
65
+ const errors = analyze(ast);
66
+ expect(errors.length).toBe(0);
67
+ });
68
+ });
@@ -0,0 +1,127 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { SemanticAnalyzer } from '../analyzer';
4
+
5
+ describe('Semantic Analyzer - Object and Array Literals', () => {
6
+ const analyzer = new SemanticAnalyzer();
7
+
8
+ function getErrors(code: string): string[] {
9
+ const ast = parse(code);
10
+ const errors = analyzer.analyze(ast, code);
11
+ return errors.map((e) => e.message);
12
+ }
13
+
14
+ // ============================================================================
15
+ // Valid cases
16
+ // ============================================================================
17
+
18
+ test('object literal with string values is valid', () => {
19
+ const errors = getErrors('let x = {name: "test"}');
20
+ expect(errors).toEqual([]);
21
+ });
22
+
23
+ test('array literal with string values is valid', () => {
24
+ const errors = getErrors('let x = ["a", "b", "c"]');
25
+ expect(errors).toEqual([]);
26
+ });
27
+
28
+ test('object literal with defined variable reference is valid', () => {
29
+ const errors = getErrors(`
30
+ let name = "alice"
31
+ let x = {user: name}
32
+ `);
33
+ expect(errors).toEqual([]);
34
+ });
35
+
36
+ test('array literal with defined variable reference is valid', () => {
37
+ const errors = getErrors(`
38
+ let item = "first"
39
+ let x = [item, "second"]
40
+ `);
41
+ expect(errors).toEqual([]);
42
+ });
43
+
44
+ test('nested object literal is valid', () => {
45
+ const errors = getErrors('let x = {outer: {inner: "value"}}');
46
+ expect(errors).toEqual([]);
47
+ });
48
+
49
+ test('nested array literal is valid', () => {
50
+ const errors = getErrors('let x = [["a"], ["b"]]');
51
+ expect(errors).toEqual([]);
52
+ });
53
+
54
+ test('array of objects is valid', () => {
55
+ const errors = getErrors('let x = [{name: "a"}, {name: "b"}]');
56
+ expect(errors).toEqual([]);
57
+ });
58
+
59
+ test('object with array property is valid', () => {
60
+ const errors = getErrors('let x = {items: ["a", "b"]}');
61
+ expect(errors).toEqual([]);
62
+ });
63
+
64
+ // ============================================================================
65
+ // Undefined variable errors
66
+ // ============================================================================
67
+
68
+ test('undefined variable in object literal value', () => {
69
+ const errors = getErrors('let x = {name: undefined_var}');
70
+ expect(errors).toContain("'undefined_var' is not defined");
71
+ });
72
+
73
+ test('undefined variable in array literal element', () => {
74
+ const errors = getErrors('let x = ["valid", undefined_var]');
75
+ expect(errors).toContain("'undefined_var' is not defined");
76
+ });
77
+
78
+ test('undefined variable in nested object', () => {
79
+ const errors = getErrors('let x = {outer: {inner: undefined_var}}');
80
+ expect(errors).toContain("'undefined_var' is not defined");
81
+ });
82
+
83
+ test('undefined variable in nested array', () => {
84
+ const errors = getErrors('let x = [["valid"], [undefined_var]]');
85
+ expect(errors).toContain("'undefined_var' is not defined");
86
+ });
87
+
88
+ test('undefined variable in object inside array', () => {
89
+ const errors = getErrors('let x = [{name: undefined_var}]');
90
+ expect(errors).toContain("'undefined_var' is not defined");
91
+ });
92
+
93
+ test('undefined variable in array inside object', () => {
94
+ const errors = getErrors('let x = {items: [undefined_var]}');
95
+ expect(errors).toContain("'undefined_var' is not defined");
96
+ });
97
+
98
+ test('multiple undefined variables reported', () => {
99
+ const errors = getErrors('let x = {a: undefined1, b: undefined2}');
100
+ expect(errors).toContain("'undefined1' is not defined");
101
+ expect(errors).toContain("'undefined2' is not defined");
102
+ });
103
+
104
+ // ============================================================================
105
+ // With type annotations
106
+ // ============================================================================
107
+
108
+ test('json type with object literal is valid', () => {
109
+ const errors = getErrors('let x: json = {name: "test"}');
110
+ expect(errors).toEqual([]);
111
+ });
112
+
113
+ test('json type with array literal is error (use json[] for arrays)', () => {
114
+ const errors = getErrors('let x: json = ["a", "b"]');
115
+ expect(errors).toContain('json type expects an object, not an array. Use json[] for arrays.');
116
+ });
117
+
118
+ test('json[] type with array literal is valid', () => {
119
+ const errors = getErrors('let x: json[] = [{ a: 1 }, { b: 2 }]');
120
+ expect(errors).toEqual([]);
121
+ });
122
+
123
+ test('json type with undefined variable in literal still errors', () => {
124
+ const errors = getErrors('let x: json = {name: undefined_var}');
125
+ expect(errors).toContain("'undefined_var' is not defined");
126
+ });
127
+ });
@@ -0,0 +1,179 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { analyze } from '../index';
4
+
5
+ describe('Semantic Errors - Model Validation', () => {
6
+ // ============================================================================
7
+ // Model reassignment (should be blocked)
8
+ // ============================================================================
9
+
10
+ test('cannot reassign model variable', () => {
11
+ const ast = parse(`
12
+ model myModel = {
13
+ name: "gpt-4",
14
+ apiKey: "sk-test",
15
+ url: "https://api.openai.com"
16
+ }
17
+ myModel = "something"
18
+ `);
19
+ const errors = analyze(ast);
20
+ expect(errors.length).toBe(1);
21
+ expect(errors[0].message).toBe("Cannot reassign model 'myModel'");
22
+ });
23
+
24
+ // ============================================================================
25
+ // Required fields validation
26
+ // ============================================================================
27
+
28
+ test('model with all required fields is valid', () => {
29
+ const ast = parse(`
30
+ model myModel = {
31
+ name: "gpt-4",
32
+ apiKey: "sk-test",
33
+ url: "https://api.openai.com"
34
+ }
35
+ `);
36
+ const errors = analyze(ast);
37
+ expect(errors.length).toBe(0);
38
+ });
39
+
40
+ test('model missing name field', () => {
41
+ const ast = parse(`
42
+ model myModel = {
43
+ apiKey: "sk-test",
44
+ url: "https://api.openai.com"
45
+ }
46
+ `);
47
+ const errors = analyze(ast);
48
+ expect(errors.length).toBe(1);
49
+ expect(errors[0].message).toBe("Model 'myModel' is missing required field 'name'");
50
+ });
51
+
52
+ test('model missing apiKey field', () => {
53
+ const ast = parse(`
54
+ model myModel = {
55
+ name: "gpt-4",
56
+ url: "https://api.openai.com"
57
+ }
58
+ `);
59
+ const errors = analyze(ast);
60
+ expect(errors.length).toBe(1);
61
+ expect(errors[0].message).toBe("Model 'myModel' is missing required field 'apiKey'");
62
+ });
63
+
64
+ test('model missing url field', () => {
65
+ const ast = parse(`
66
+ model myModel = {
67
+ name: "gpt-4",
68
+ apiKey: "sk-test"
69
+ }
70
+ `);
71
+ const errors = analyze(ast);
72
+ expect(errors.length).toBe(1);
73
+ expect(errors[0].message).toBe("Model 'myModel' is missing required field 'url'");
74
+ });
75
+
76
+ test('model missing all fields', () => {
77
+ const ast = parse(`
78
+ model myModel = {}
79
+ `);
80
+ const errors = analyze(ast);
81
+ expect(errors.length).toBe(3);
82
+ expect(errors.map(e => e.message)).toContain("Model 'myModel' is missing required field 'name'");
83
+ expect(errors.map(e => e.message)).toContain("Model 'myModel' is missing required field 'apiKey'");
84
+ expect(errors.map(e => e.message)).toContain("Model 'myModel' is missing required field 'url'");
85
+ });
86
+
87
+ // ============================================================================
88
+ // Unknown fields validation
89
+ // ============================================================================
90
+
91
+ test('model with unknown field', () => {
92
+ const ast = parse(`
93
+ model myModel = {
94
+ name: "gpt-4",
95
+ apiKey: "sk-test",
96
+ url: "https://api.openai.com",
97
+ streaming: true
98
+ }
99
+ `);
100
+ const errors = analyze(ast);
101
+ expect(errors.length).toBe(1);
102
+ expect(errors[0].message).toBe("Model 'myModel' has unknown field 'streaming'");
103
+ });
104
+
105
+ test('model with multiple unknown fields', () => {
106
+ const ast = parse(`
107
+ model myModel = {
108
+ name: "gpt-4",
109
+ apiKey: "sk-test",
110
+ url: "https://api.openai.com",
111
+ streaming: true,
112
+ temperature: "0.7"
113
+ }
114
+ `);
115
+ const errors = analyze(ast);
116
+ expect(errors.length).toBe(2);
117
+ expect(errors.map(e => e.message)).toContain("Model 'myModel' has unknown field 'streaming'");
118
+ expect(errors.map(e => e.message)).toContain("Model 'myModel' has unknown field 'temperature'");
119
+ });
120
+
121
+ // ============================================================================
122
+ // Field expression validation
123
+ // ============================================================================
124
+
125
+ test('model field can reference defined variable', () => {
126
+ const ast = parse(`
127
+ let myKey = "sk-test"
128
+ model myModel = {
129
+ name: "gpt-4",
130
+ apiKey: myKey,
131
+ url: "https://api.openai.com"
132
+ }
133
+ `);
134
+ const errors = analyze(ast);
135
+ expect(errors.length).toBe(0);
136
+ });
137
+
138
+ test('model field referencing undefined variable', () => {
139
+ const ast = parse(`
140
+ model myModel = {
141
+ name: "gpt-4",
142
+ apiKey: undefinedKey,
143
+ url: "https://api.openai.com"
144
+ }
145
+ `);
146
+ const errors = analyze(ast);
147
+ expect(errors.length).toBe(1);
148
+ expect(errors[0].message).toBe("'undefinedKey' is not defined");
149
+ });
150
+
151
+ // ============================================================================
152
+ // Model type annotation must be const
153
+ // ============================================================================
154
+
155
+ test('let with model type is rejected', () => {
156
+ const ast = parse(`
157
+ model myModel = { name: "test", apiKey: "key", url: "http://test" }
158
+ let m: model = myModel
159
+ `);
160
+ const errors = analyze(ast);
161
+ expect(errors.length).toBe(1);
162
+ expect(errors[0].message).toBe("Variables with type 'model' must be declared with 'const', not 'let'");
163
+ });
164
+
165
+ test('const with model type is allowed', () => {
166
+ const ast = parse(`
167
+ model myModel = { name: "test", apiKey: "key", url: "http://test" }
168
+ const m: model = myModel
169
+ `);
170
+ const errors = analyze(ast);
171
+ expect(errors.length).toBe(0);
172
+ });
173
+
174
+ test('function parameter with model type is allowed', () => {
175
+ const ast = parse(`function process(m: model): text { return "done" }`);
176
+ const errors = analyze(ast);
177
+ expect(errors.length).toBe(0);
178
+ });
179
+ });