@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.
- package/package.json +46 -0
- package/src/ast/index.ts +375 -0
- package/src/ast.ts +2 -0
- package/src/debug/advanced-features.ts +482 -0
- package/src/debug/bun-inspector.ts +424 -0
- package/src/debug/handoff-manager.ts +283 -0
- package/src/debug/index.ts +150 -0
- package/src/debug/runner.ts +365 -0
- package/src/debug/server.ts +565 -0
- package/src/debug/stack-merger.ts +267 -0
- package/src/debug/state.ts +581 -0
- package/src/debug/test/advanced-features.test.ts +300 -0
- package/src/debug/test/e2e.test.ts +218 -0
- package/src/debug/test/handoff-manager.test.ts +256 -0
- package/src/debug/test/runner.test.ts +256 -0
- package/src/debug/test/stack-merger.test.ts +163 -0
- package/src/debug/test/state.test.ts +400 -0
- package/src/debug/test/ts-debug-integration.test.ts +374 -0
- package/src/debug/test/ts-import-tracker.test.ts +125 -0
- package/src/debug/test/ts-source-map.test.ts +169 -0
- package/src/debug/ts-import-tracker.ts +151 -0
- package/src/debug/ts-source-map.ts +171 -0
- package/src/errors/index.ts +124 -0
- package/src/index.ts +358 -0
- package/src/lexer/index.ts +348 -0
- package/src/lexer.ts +2 -0
- package/src/parser/index.ts +792 -0
- package/src/parser/parse.ts +45 -0
- package/src/parser/test/async.test.ts +248 -0
- package/src/parser/test/destructuring.test.ts +167 -0
- package/src/parser/test/do-expression.test.ts +486 -0
- package/src/parser/test/errors/do-expression.test.ts +95 -0
- package/src/parser/test/errors/error-locations.test.ts +230 -0
- package/src/parser/test/errors/invalid-expressions.test.ts +144 -0
- package/src/parser/test/errors/missing-tokens.test.ts +126 -0
- package/src/parser/test/errors/model-declaration.test.ts +185 -0
- package/src/parser/test/errors/nested-blocks.test.ts +226 -0
- package/src/parser/test/errors/unclosed-delimiters.test.ts +122 -0
- package/src/parser/test/errors/unexpected-tokens.test.ts +120 -0
- package/src/parser/test/import-export.test.ts +143 -0
- package/src/parser/test/literals.test.ts +404 -0
- package/src/parser/test/model-declaration.test.ts +161 -0
- package/src/parser/test/nested-blocks.test.ts +402 -0
- package/src/parser/test/parser.test.ts +743 -0
- package/src/parser/test/private.test.ts +136 -0
- package/src/parser/test/template-literal.test.ts +127 -0
- package/src/parser/test/tool-declaration.test.ts +302 -0
- package/src/parser/test/ts-block.test.ts +252 -0
- package/src/parser/test/type-annotations.test.ts +254 -0
- package/src/parser/visitor/helpers.ts +330 -0
- package/src/parser/visitor.ts +794 -0
- package/src/parser.ts +2 -0
- package/src/runtime/ai/cache-chunking.test.ts +69 -0
- package/src/runtime/ai/cache-chunking.ts +73 -0
- package/src/runtime/ai/client.ts +109 -0
- package/src/runtime/ai/context.ts +168 -0
- package/src/runtime/ai/formatters.ts +316 -0
- package/src/runtime/ai/index.ts +38 -0
- package/src/runtime/ai/language-ref.ts +38 -0
- package/src/runtime/ai/providers/anthropic.ts +253 -0
- package/src/runtime/ai/providers/google.ts +201 -0
- package/src/runtime/ai/providers/openai.ts +156 -0
- package/src/runtime/ai/retry.ts +100 -0
- package/src/runtime/ai/return-tools.ts +301 -0
- package/src/runtime/ai/test/client.test.ts +83 -0
- package/src/runtime/ai/test/formatters.test.ts +485 -0
- package/src/runtime/ai/test/retry.test.ts +137 -0
- package/src/runtime/ai/test/return-tools.test.ts +450 -0
- package/src/runtime/ai/test/tool-loop.test.ts +319 -0
- package/src/runtime/ai/test/tool-schema.test.ts +241 -0
- package/src/runtime/ai/tool-loop.ts +203 -0
- package/src/runtime/ai/tool-schema.ts +151 -0
- package/src/runtime/ai/types.ts +113 -0
- package/src/runtime/ai-logger.ts +255 -0
- package/src/runtime/ai-provider.ts +347 -0
- package/src/runtime/async/dependencies.ts +276 -0
- package/src/runtime/async/executor.ts +293 -0
- package/src/runtime/async/index.ts +43 -0
- package/src/runtime/async/scheduling.ts +163 -0
- package/src/runtime/async/test/dependencies.test.ts +284 -0
- package/src/runtime/async/test/executor.test.ts +388 -0
- package/src/runtime/context.ts +357 -0
- package/src/runtime/exec/ai.ts +139 -0
- package/src/runtime/exec/expressions.ts +475 -0
- package/src/runtime/exec/frames.ts +26 -0
- package/src/runtime/exec/functions.ts +305 -0
- package/src/runtime/exec/interpolation.ts +312 -0
- package/src/runtime/exec/statements.ts +604 -0
- package/src/runtime/exec/tools.ts +129 -0
- package/src/runtime/exec/typescript.ts +215 -0
- package/src/runtime/exec/variables.ts +279 -0
- package/src/runtime/index.ts +975 -0
- package/src/runtime/modules.ts +452 -0
- package/src/runtime/serialize.ts +103 -0
- package/src/runtime/state.ts +489 -0
- package/src/runtime/stdlib/core.ts +45 -0
- package/src/runtime/stdlib/directory.test.ts +156 -0
- package/src/runtime/stdlib/edit.test.ts +154 -0
- package/src/runtime/stdlib/fastEdit.test.ts +201 -0
- package/src/runtime/stdlib/glob.test.ts +106 -0
- package/src/runtime/stdlib/grep.test.ts +144 -0
- package/src/runtime/stdlib/index.ts +16 -0
- package/src/runtime/stdlib/readFile.test.ts +123 -0
- package/src/runtime/stdlib/tools/index.ts +707 -0
- package/src/runtime/stdlib/writeFile.test.ts +157 -0
- package/src/runtime/step.ts +969 -0
- package/src/runtime/test/ai-context.test.ts +1086 -0
- package/src/runtime/test/ai-result-object.test.ts +419 -0
- package/src/runtime/test/ai-tool-flow.test.ts +859 -0
- package/src/runtime/test/async-execution-order.test.ts +618 -0
- package/src/runtime/test/async-execution.test.ts +344 -0
- package/src/runtime/test/async-nested.test.ts +660 -0
- package/src/runtime/test/async-parallel-timing.test.ts +546 -0
- package/src/runtime/test/basic1.test.ts +154 -0
- package/src/runtime/test/binary-operators.test.ts +431 -0
- package/src/runtime/test/break-statement.test.ts +257 -0
- package/src/runtime/test/context-modes.test.ts +650 -0
- package/src/runtime/test/context.test.ts +466 -0
- package/src/runtime/test/core-functions.test.ts +228 -0
- package/src/runtime/test/e2e.test.ts +88 -0
- package/src/runtime/test/error-locations/error-locations.test.ts +80 -0
- package/src/runtime/test/error-locations/main-error.vibe +4 -0
- package/src/runtime/test/error-locations/main-import-error.vibe +3 -0
- package/src/runtime/test/error-locations/utils/helper.vibe +5 -0
- package/src/runtime/test/for-in.test.ts +312 -0
- package/src/runtime/test/helpers.ts +69 -0
- package/src/runtime/test/imports.test.ts +334 -0
- package/src/runtime/test/json-expressions.test.ts +232 -0
- package/src/runtime/test/literals.test.ts +372 -0
- package/src/runtime/test/logical-indexing.test.ts +478 -0
- package/src/runtime/test/member-methods.test.ts +324 -0
- package/src/runtime/test/model-config.test.ts +338 -0
- package/src/runtime/test/null-handling.test.ts +342 -0
- package/src/runtime/test/private-visibility.test.ts +332 -0
- package/src/runtime/test/runtime-state.test.ts +514 -0
- package/src/runtime/test/scoping.test.ts +370 -0
- package/src/runtime/test/string-interpolation.test.ts +354 -0
- package/src/runtime/test/template-literal.test.ts +181 -0
- package/src/runtime/test/tool-execution.test.ts +467 -0
- package/src/runtime/test/tool-schema-generation.test.ts +477 -0
- package/src/runtime/test/tostring.test.ts +210 -0
- package/src/runtime/test/ts-block.test.ts +594 -0
- package/src/runtime/test/ts-error-location.test.ts +231 -0
- package/src/runtime/test/types.test.ts +732 -0
- package/src/runtime/test/verbose-logger.test.ts +710 -0
- package/src/runtime/test/vibe-expression.test.ts +54 -0
- package/src/runtime/test/vibe-value-errors.test.ts +541 -0
- package/src/runtime/test/while.test.ts +232 -0
- package/src/runtime/tools/builtin.ts +30 -0
- package/src/runtime/tools/directory-tools.ts +70 -0
- package/src/runtime/tools/file-tools.ts +228 -0
- package/src/runtime/tools/index.ts +5 -0
- package/src/runtime/tools/registry.ts +48 -0
- package/src/runtime/tools/search-tools.ts +134 -0
- package/src/runtime/tools/security.ts +36 -0
- package/src/runtime/tools/system-tools.ts +312 -0
- package/src/runtime/tools/test/fixtures/base-types.ts +40 -0
- package/src/runtime/tools/test/fixtures/test-types.ts +132 -0
- package/src/runtime/tools/test/registry.test.ts +713 -0
- package/src/runtime/tools/test/security.test.ts +86 -0
- package/src/runtime/tools/test/system-tools.test.ts +679 -0
- package/src/runtime/tools/test/ts-schema.test.ts +357 -0
- package/src/runtime/tools/ts-schema.ts +341 -0
- package/src/runtime/tools/types.ts +89 -0
- package/src/runtime/tools/utility-tools.ts +198 -0
- package/src/runtime/ts-eval.ts +126 -0
- package/src/runtime/types.ts +797 -0
- package/src/runtime/validation.ts +160 -0
- package/src/runtime/verbose-logger.ts +459 -0
- package/src/runtime.ts +2 -0
- package/src/semantic/analyzer-context.ts +62 -0
- package/src/semantic/analyzer-validators.ts +575 -0
- package/src/semantic/analyzer-visitors.ts +534 -0
- package/src/semantic/analyzer.ts +83 -0
- package/src/semantic/index.ts +11 -0
- package/src/semantic/symbol-table.ts +58 -0
- package/src/semantic/test/async-validation.test.ts +301 -0
- package/src/semantic/test/compress-validation.test.ts +179 -0
- package/src/semantic/test/const-reassignment.test.ts +111 -0
- package/src/semantic/test/control-flow.test.ts +346 -0
- package/src/semantic/test/destructuring.test.ts +185 -0
- package/src/semantic/test/duplicate-declarations.test.ts +168 -0
- package/src/semantic/test/export-validation.test.ts +111 -0
- package/src/semantic/test/fixtures/math.ts +31 -0
- package/src/semantic/test/imports.test.ts +148 -0
- package/src/semantic/test/json-type.test.ts +68 -0
- package/src/semantic/test/literals.test.ts +127 -0
- package/src/semantic/test/model-validation.test.ts +179 -0
- package/src/semantic/test/prompt-validation.test.ts +343 -0
- package/src/semantic/test/scoping.test.ts +312 -0
- package/src/semantic/test/tool-validation.test.ts +306 -0
- package/src/semantic/test/ts-type-checking.test.ts +563 -0
- package/src/semantic/test/type-constraints.test.ts +111 -0
- package/src/semantic/test/type-inference.test.ts +87 -0
- package/src/semantic/test/type-validation.test.ts +552 -0
- package/src/semantic/test/undefined-variables.test.ts +163 -0
- package/src/semantic/ts-block-checker.ts +204 -0
- package/src/semantic/ts-signatures.ts +194 -0
- package/src/semantic/ts-types.ts +170 -0
- package/src/semantic/types.ts +58 -0
- package/tests/fixtures/conditional-logic.vibe +14 -0
- package/tests/fixtures/function-call.vibe +16 -0
- package/tests/fixtures/imports/cycle-detection/a.vibe +6 -0
- package/tests/fixtures/imports/cycle-detection/b.vibe +5 -0
- package/tests/fixtures/imports/cycle-detection/main.vibe +3 -0
- package/tests/fixtures/imports/module-isolation/main-b.vibe +8 -0
- package/tests/fixtures/imports/module-isolation/main.vibe +9 -0
- package/tests/fixtures/imports/module-isolation/moduleA.vibe +6 -0
- package/tests/fixtures/imports/module-isolation/moduleB.vibe +6 -0
- package/tests/fixtures/imports/nested-import/helper.vibe +6 -0
- package/tests/fixtures/imports/nested-import/main.vibe +3 -0
- package/tests/fixtures/imports/nested-import/utils.ts +3 -0
- package/tests/fixtures/imports/nested-isolation/file2.vibe +15 -0
- package/tests/fixtures/imports/nested-isolation/file3.vibe +10 -0
- package/tests/fixtures/imports/nested-isolation/main.vibe +21 -0
- package/tests/fixtures/imports/pure-cycle/a.vibe +5 -0
- package/tests/fixtures/imports/pure-cycle/b.vibe +5 -0
- package/tests/fixtures/imports/pure-cycle/main.vibe +3 -0
- package/tests/fixtures/imports/ts-boolean/checks.ts +14 -0
- package/tests/fixtures/imports/ts-boolean/main.vibe +10 -0
- package/tests/fixtures/imports/ts-boolean/type-mismatch.vibe +5 -0
- package/tests/fixtures/imports/ts-boolean/use-constant.vibe +18 -0
- package/tests/fixtures/imports/ts-error-handling/helpers.ts +42 -0
- package/tests/fixtures/imports/ts-error-handling/main.vibe +5 -0
- package/tests/fixtures/imports/ts-import/main.vibe +4 -0
- package/tests/fixtures/imports/ts-import/math.ts +9 -0
- package/tests/fixtures/imports/ts-variables/call-non-function.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/data.ts +10 -0
- package/tests/fixtures/imports/ts-variables/import-json.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/import-type-mismatch.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/import-variable.vibe +5 -0
- package/tests/fixtures/imports/vibe-import/greet.vibe +5 -0
- package/tests/fixtures/imports/vibe-import/main.vibe +3 -0
- package/tests/fixtures/multiple-ai-calls.vibe +10 -0
- package/tests/fixtures/simple-greeting.vibe +6 -0
- package/tests/fixtures/template-literals.vibe +11 -0
- package/tests/integration/basic-ai/basic-ai.integration.test.ts +166 -0
- package/tests/integration/basic-ai/basic-ai.vibe +12 -0
- package/tests/integration/bug-fix/bug-fix.integration.test.ts +201 -0
- package/tests/integration/bug-fix/buggy-code.ts +22 -0
- package/tests/integration/bug-fix/fix-bug.vibe +21 -0
- package/tests/integration/compress/compress.integration.test.ts +206 -0
- package/tests/integration/destructuring/destructuring.integration.test.ts +92 -0
- package/tests/integration/hello-world-translator/hello-world-translator.integration.test.ts +61 -0
- package/tests/integration/line-annotator/context-modes.integration.test.ts +261 -0
- package/tests/integration/line-annotator/line-annotator.integration.test.ts +148 -0
- package/tests/integration/multi-feature/cumulative-sum.integration.test.ts +75 -0
- package/tests/integration/multi-feature/number-analyzer.integration.test.ts +191 -0
- package/tests/integration/multi-feature/number-analyzer.vibe +59 -0
- package/tests/integration/tool-calls/tool-calls.integration.test.ts +93 -0
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
+
import { parse } from '../../parser/parse';
|
|
3
|
+
import { SemanticAnalyzer } from '../analyzer';
|
|
4
|
+
import { extractFunctionSignature, clearSignatureCache } from '../ts-signatures';
|
|
5
|
+
import { checkTsBlockTypes, inferTsBlockReturnType } from '../ts-block-checker';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
|
|
8
|
+
// Test fixtures directory
|
|
9
|
+
const fixturesDir = join(__dirname, 'fixtures');
|
|
10
|
+
|
|
11
|
+
describe('TS Signature Extraction', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
clearSignatureCache();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('extracts function declaration signature', () => {
|
|
17
|
+
const sig = extractFunctionSignature(
|
|
18
|
+
join(fixturesDir, 'math.ts'),
|
|
19
|
+
'add'
|
|
20
|
+
);
|
|
21
|
+
expect(sig).toBeDefined();
|
|
22
|
+
expect(sig!.name).toBe('add');
|
|
23
|
+
expect(sig!.params).toHaveLength(2);
|
|
24
|
+
expect(sig!.params[0]).toEqual({ name: 'a', tsType: 'number', optional: false });
|
|
25
|
+
expect(sig!.params[1]).toEqual({ name: 'b', tsType: 'number', optional: false });
|
|
26
|
+
expect(sig!.returnType).toBe('number');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('extracts arrow function signature', () => {
|
|
30
|
+
const sig = extractFunctionSignature(
|
|
31
|
+
join(fixturesDir, 'math.ts'),
|
|
32
|
+
'multiply'
|
|
33
|
+
);
|
|
34
|
+
expect(sig).toBeDefined();
|
|
35
|
+
expect(sig!.name).toBe('multiply');
|
|
36
|
+
expect(sig!.params).toHaveLength(2);
|
|
37
|
+
expect(sig!.params[0].tsType).toBe('number');
|
|
38
|
+
expect(sig!.params[1].tsType).toBe('number');
|
|
39
|
+
expect(sig!.returnType).toBe('number');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('extracts function with optional parameter', () => {
|
|
43
|
+
const sig = extractFunctionSignature(
|
|
44
|
+
join(fixturesDir, 'math.ts'),
|
|
45
|
+
'greet'
|
|
46
|
+
);
|
|
47
|
+
expect(sig).toBeDefined();
|
|
48
|
+
expect(sig!.params).toHaveLength(2);
|
|
49
|
+
expect(sig!.params[0]).toEqual({ name: 'name', tsType: 'string', optional: false });
|
|
50
|
+
expect(sig!.params[1].optional).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('extracts function with object parameter', () => {
|
|
54
|
+
const sig = extractFunctionSignature(
|
|
55
|
+
join(fixturesDir, 'math.ts'),
|
|
56
|
+
'processData'
|
|
57
|
+
);
|
|
58
|
+
expect(sig).toBeDefined();
|
|
59
|
+
expect(sig!.params).toHaveLength(1);
|
|
60
|
+
// The type should be object-like
|
|
61
|
+
expect(sig!.params[0].name).toBe('data');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('returns undefined for non-existent function', () => {
|
|
65
|
+
const sig = extractFunctionSignature(
|
|
66
|
+
join(fixturesDir, 'math.ts'),
|
|
67
|
+
'nonExistent'
|
|
68
|
+
);
|
|
69
|
+
expect(sig).toBeUndefined();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('caches extracted signatures', () => {
|
|
73
|
+
const sig1 = extractFunctionSignature(join(fixturesDir, 'math.ts'), 'add');
|
|
74
|
+
const sig2 = extractFunctionSignature(join(fixturesDir, 'math.ts'), 'add');
|
|
75
|
+
expect(sig1).toBe(sig2); // Same object reference (cached)
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('TS Block Return Type Inference', () => {
|
|
80
|
+
test('infers text from string return', () => {
|
|
81
|
+
const type = inferTsBlockReturnType([], 'return "hello"');
|
|
82
|
+
expect(type).toBe('text');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('infers number from number return', () => {
|
|
86
|
+
const type = inferTsBlockReturnType([], 'return 42');
|
|
87
|
+
expect(type).toBe('number');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('infers boolean from boolean return', () => {
|
|
91
|
+
const type = inferTsBlockReturnType([], 'return true');
|
|
92
|
+
expect(type).toBe('boolean');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('infers json from object return', () => {
|
|
96
|
+
const type = inferTsBlockReturnType([], 'return { key: "value" }');
|
|
97
|
+
expect(type).toBe('json');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('infers json[] from array return', () => {
|
|
101
|
+
const type = inferTsBlockReturnType([], 'return [1, 2, 3]');
|
|
102
|
+
// Arrays of numbers become number[]
|
|
103
|
+
expect(type).toBe('number[]');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('infers type from parameter operation', () => {
|
|
107
|
+
const type = inferTsBlockReturnType(
|
|
108
|
+
[{ name: 'x', vibeType: 'number' }],
|
|
109
|
+
'return x * 2'
|
|
110
|
+
);
|
|
111
|
+
expect(type).toBe('number');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('infers text from string concatenation', () => {
|
|
115
|
+
const type = inferTsBlockReturnType(
|
|
116
|
+
[{ name: 's', vibeType: 'text' }],
|
|
117
|
+
'return s + "!"'
|
|
118
|
+
);
|
|
119
|
+
expect(type).toBe('text');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('infers null from void return', () => {
|
|
123
|
+
// Note: 'return undefined' and 'return null' are expressions that TS types as 'any'
|
|
124
|
+
// Only bare 'return' (void) maps to null
|
|
125
|
+
const type = inferTsBlockReturnType([], 'return');
|
|
126
|
+
expect(type).toBe('null');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('TS Block Type Checking', () => {
|
|
131
|
+
test('no errors for valid type usage', () => {
|
|
132
|
+
const errors = checkTsBlockTypes(
|
|
133
|
+
[{ name: 'x', vibeType: 'number' }],
|
|
134
|
+
'return x * 2',
|
|
135
|
+
{ line: 1, column: 1 }
|
|
136
|
+
);
|
|
137
|
+
expect(errors).toHaveLength(0);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test('error for invalid operation on string', () => {
|
|
141
|
+
const errors = checkTsBlockTypes(
|
|
142
|
+
[{ name: 'x', vibeType: 'text' }],
|
|
143
|
+
'return x * 2',
|
|
144
|
+
{ line: 1, column: 1 }
|
|
145
|
+
);
|
|
146
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
147
|
+
expect(errors[0].message).toContain('TypeScript error');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('no errors when no typed parameters', () => {
|
|
151
|
+
// If no parameters have types, we skip checking
|
|
152
|
+
const errors = checkTsBlockTypes(
|
|
153
|
+
[],
|
|
154
|
+
'return undefinedVar * 2',
|
|
155
|
+
{ line: 1, column: 1 }
|
|
156
|
+
);
|
|
157
|
+
expect(errors).toHaveLength(0);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('no errors for external function calls', () => {
|
|
161
|
+
// External functions like fetchData() should not error
|
|
162
|
+
const errors = checkTsBlockTypes(
|
|
163
|
+
[{ name: 'x', vibeType: 'number' }],
|
|
164
|
+
'return externalFunction(x)',
|
|
165
|
+
{ line: 1, column: 1 }
|
|
166
|
+
);
|
|
167
|
+
expect(errors).toHaveLength(0);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('error includes location info', () => {
|
|
171
|
+
const errors = checkTsBlockTypes(
|
|
172
|
+
[{ name: 's', vibeType: 'text' }],
|
|
173
|
+
'return s * 2',
|
|
174
|
+
{ line: 10, column: 5 }
|
|
175
|
+
);
|
|
176
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
177
|
+
expect(errors[0].location.line).toBeGreaterThanOrEqual(10);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('handles multiple parameters', () => {
|
|
181
|
+
const errors = checkTsBlockTypes(
|
|
182
|
+
[
|
|
183
|
+
{ name: 'a', vibeType: 'number' },
|
|
184
|
+
{ name: 'b', vibeType: 'text' },
|
|
185
|
+
],
|
|
186
|
+
'return a + b.length',
|
|
187
|
+
{ line: 1, column: 1 }
|
|
188
|
+
);
|
|
189
|
+
expect(errors).toHaveLength(0);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('handles json type as Record', () => {
|
|
193
|
+
const errors = checkTsBlockTypes(
|
|
194
|
+
[{ name: 'data', vibeType: 'json' }],
|
|
195
|
+
'return data.key',
|
|
196
|
+
{ line: 1, column: 1 }
|
|
197
|
+
);
|
|
198
|
+
expect(errors).toHaveLength(0);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test('prompt type maps to string in ts blocks', () => {
|
|
202
|
+
// prompt should be treated as string, allowing string operations
|
|
203
|
+
const errors = checkTsBlockTypes(
|
|
204
|
+
[{ name: 'p', vibeType: 'prompt' }],
|
|
205
|
+
'return p.toUpperCase()',
|
|
206
|
+
{ line: 1, column: 1 }
|
|
207
|
+
);
|
|
208
|
+
expect(errors).toHaveLength(0);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('prompt type allows string concatenation', () => {
|
|
212
|
+
const errors = checkTsBlockTypes(
|
|
213
|
+
[{ name: 'p', vibeType: 'prompt' }],
|
|
214
|
+
'return "Hello: " + p',
|
|
215
|
+
{ line: 1, column: 1 }
|
|
216
|
+
);
|
|
217
|
+
expect(errors).toHaveLength(0);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test('prompt type disallows number operations', () => {
|
|
221
|
+
// prompt maps to string, so number operations should fail
|
|
222
|
+
const errors = checkTsBlockTypes(
|
|
223
|
+
[{ name: 'p', vibeType: 'prompt' }],
|
|
224
|
+
'return p * 2',
|
|
225
|
+
{ line: 1, column: 1 }
|
|
226
|
+
);
|
|
227
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
describe('Semantic Analyzer - TS Import Type Checking', () => {
|
|
232
|
+
const analyzer = new SemanticAnalyzer();
|
|
233
|
+
|
|
234
|
+
function getErrors(code: string, basePath?: string): string[] {
|
|
235
|
+
const ast = parse(code);
|
|
236
|
+
const errors = analyzer.analyze(ast, code, basePath ?? fixturesDir + '/main.vibe');
|
|
237
|
+
return errors.map((e) => e.message);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
test('TS function call with correct types passes', () => {
|
|
241
|
+
const errors = getErrors(`
|
|
242
|
+
import { add } from "./math.ts"
|
|
243
|
+
let x: number = 5
|
|
244
|
+
let result = add(x, 10)
|
|
245
|
+
`);
|
|
246
|
+
expect(errors).toEqual([]);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('TS function call with wrong arg type errors', () => {
|
|
250
|
+
const errors = getErrors(`
|
|
251
|
+
import { add } from "./math.ts"
|
|
252
|
+
let x: text = "hi"
|
|
253
|
+
let result = add(x, 5)
|
|
254
|
+
`);
|
|
255
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
256
|
+
expect(errors.some(e => e.includes('expected number') && e.includes('got text'))).toBe(true);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('TS function call with too few arguments errors', () => {
|
|
260
|
+
const errors = getErrors(`
|
|
261
|
+
import { add } from "./math.ts"
|
|
262
|
+
let result = add(5)
|
|
263
|
+
`);
|
|
264
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
265
|
+
expect(errors.some(e => e.includes('requires 2 arguments'))).toBe(true);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
test('TS function call with too many arguments errors', () => {
|
|
269
|
+
const errors = getErrors(`
|
|
270
|
+
import { add } from "./math.ts"
|
|
271
|
+
let result = add(1, 2, 3)
|
|
272
|
+
`);
|
|
273
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
274
|
+
expect(errors.some(e => e.includes('accepts at most'))).toBe(true);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('TS function with optional param - missing optional is ok', () => {
|
|
278
|
+
const errors = getErrors(`
|
|
279
|
+
import { greet } from "./math.ts"
|
|
280
|
+
let result = greet("Alice")
|
|
281
|
+
`);
|
|
282
|
+
expect(errors).toEqual([]);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test('json type is compatible with object params', () => {
|
|
286
|
+
const errors = getErrors(`
|
|
287
|
+
import { processData } from "./math.ts"
|
|
288
|
+
let data: json = "{}"
|
|
289
|
+
processData(data)
|
|
290
|
+
`);
|
|
291
|
+
expect(errors).toEqual([]);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test('text type incompatible with number param', () => {
|
|
295
|
+
const errors = getErrors(`
|
|
296
|
+
import { add } from "./math.ts"
|
|
297
|
+
let s: text = "hello"
|
|
298
|
+
add(s, s)
|
|
299
|
+
`);
|
|
300
|
+
expect(errors.length).toBe(2); // Both args wrong
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test('number literal is compatible with number param', () => {
|
|
304
|
+
const errors = getErrors(`
|
|
305
|
+
import { add } from "./math.ts"
|
|
306
|
+
add(1, 2)
|
|
307
|
+
`);
|
|
308
|
+
expect(errors).toEqual([]);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
test('boolean type incompatible with string param', () => {
|
|
312
|
+
const errors = getErrors(`
|
|
313
|
+
import { greet } from "./math.ts"
|
|
314
|
+
let b: boolean = true
|
|
315
|
+
greet(b)
|
|
316
|
+
`);
|
|
317
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
318
|
+
expect(errors.some(e => e.includes('expected string') && e.includes('got boolean'))).toBe(true);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test('prompt type is compatible with string param in TS function', () => {
|
|
322
|
+
const errors = getErrors(`
|
|
323
|
+
import { greet } from "./math.ts"
|
|
324
|
+
let p: prompt = "Alice"
|
|
325
|
+
greet(p)
|
|
326
|
+
`);
|
|
327
|
+
expect(errors).toEqual([]);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test('prompt type works with TS function expecting string', () => {
|
|
331
|
+
const errors = getErrors(`
|
|
332
|
+
import { repeat } from "./math.ts"
|
|
333
|
+
let p: prompt = "hello"
|
|
334
|
+
let result = repeat(p, 3)
|
|
335
|
+
`);
|
|
336
|
+
expect(errors).toEqual([]);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
describe('Semantic Analyzer - ts() Block Type Checking', () => {
|
|
341
|
+
const analyzer = new SemanticAnalyzer();
|
|
342
|
+
|
|
343
|
+
function getErrors(code: string): string[] {
|
|
344
|
+
const ast = parse(code);
|
|
345
|
+
const errors = analyzer.analyze(ast, code);
|
|
346
|
+
return errors.map((e) => e.message);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
test('ts block with valid type usage passes', () => {
|
|
350
|
+
const errors = getErrors(`
|
|
351
|
+
let x: number = 5
|
|
352
|
+
let result = ts(x) { return x * 2 }
|
|
353
|
+
`);
|
|
354
|
+
expect(errors).toEqual([]);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test('ts block with invalid type usage errors', () => {
|
|
358
|
+
const errors = getErrors(`
|
|
359
|
+
let x: text = "hello"
|
|
360
|
+
let result = ts(x) { return x * 2 }
|
|
361
|
+
`);
|
|
362
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
363
|
+
expect(errors.some(e => e.includes('TypeScript error'))).toBe(true);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
test('ts block with untyped parameter skips checking', () => {
|
|
367
|
+
// If parameter has no type, we can't check it
|
|
368
|
+
const errors = getErrors(`
|
|
369
|
+
let x = someFn()
|
|
370
|
+
let result = ts(x) { return x * 2 }
|
|
371
|
+
`);
|
|
372
|
+
// Should only error about someFn not being defined, not TS type errors
|
|
373
|
+
expect(errors.some(e => e.includes("'someFn' is not defined"))).toBe(true);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
test('ts block with undefined parameter errors', () => {
|
|
377
|
+
const errors = getErrors(`
|
|
378
|
+
let result = ts(undefinedVar) { return undefinedVar }
|
|
379
|
+
`);
|
|
380
|
+
expect(errors.some(e => e.includes("'undefinedVar' is not defined"))).toBe(true);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test('ts block with no parameters skips type checking', () => {
|
|
384
|
+
const errors = getErrors(`
|
|
385
|
+
let result = ts() { return fetchData() }
|
|
386
|
+
`);
|
|
387
|
+
// Should not error - external calls are allowed
|
|
388
|
+
expect(errors).toEqual([]);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test('ts block with json parameter works', () => {
|
|
392
|
+
const errors = getErrors(`
|
|
393
|
+
let data: json = "{}"
|
|
394
|
+
let result = ts(data) { return data.key }
|
|
395
|
+
`);
|
|
396
|
+
expect(errors).toEqual([]);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test('ts block with multiple typed parameters', () => {
|
|
400
|
+
const errors = getErrors(`
|
|
401
|
+
let a: number = 1
|
|
402
|
+
let b: text = "hi"
|
|
403
|
+
let result = ts(a, b) { return a + b.length }
|
|
404
|
+
`);
|
|
405
|
+
expect(errors).toEqual([]);
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
describe('Return Type Inference - ts() Blocks', () => {
|
|
410
|
+
const analyzer = new SemanticAnalyzer();
|
|
411
|
+
|
|
412
|
+
function getErrors(code: string): string[] {
|
|
413
|
+
const ast = parse(code);
|
|
414
|
+
const errors = analyzer.analyze(ast, code);
|
|
415
|
+
return errors.map((e) => e.message);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
test('infers text type from ts block returning string', () => {
|
|
419
|
+
const errors = getErrors(`
|
|
420
|
+
let x = ts() { return "hello" }
|
|
421
|
+
let y: number = x
|
|
422
|
+
`);
|
|
423
|
+
expect(errors.length).toBe(1);
|
|
424
|
+
expect(errors[0]).toContain('cannot assign text to number');
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
test('infers number type from ts block returning number', () => {
|
|
428
|
+
const errors = getErrors(`
|
|
429
|
+
let x = ts() { return 42 }
|
|
430
|
+
let y: text = x
|
|
431
|
+
`);
|
|
432
|
+
expect(errors.length).toBe(1);
|
|
433
|
+
expect(errors[0]).toContain('cannot assign number to text');
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test('infers boolean type from ts block returning boolean', () => {
|
|
437
|
+
const errors = getErrors(`
|
|
438
|
+
let x = ts() { return true }
|
|
439
|
+
let y: text = x
|
|
440
|
+
`);
|
|
441
|
+
expect(errors.length).toBe(1);
|
|
442
|
+
expect(errors[0]).toContain('cannot assign boolean to text');
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test('infers array type from ts block returning array', () => {
|
|
446
|
+
const errors = getErrors(`
|
|
447
|
+
let x: text = ts() { return [] }
|
|
448
|
+
`);
|
|
449
|
+
expect(errors.length).toBe(1);
|
|
450
|
+
// Arrays map to json[] or similar
|
|
451
|
+
expect(errors[0]).toContain('cannot assign');
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
test('infers json type from ts block returning object', () => {
|
|
455
|
+
const errors = getErrors(`
|
|
456
|
+
let x = ts() { return { key: "value" } }
|
|
457
|
+
let y: number = x
|
|
458
|
+
`);
|
|
459
|
+
expect(errors.length).toBe(1);
|
|
460
|
+
expect(errors[0]).toContain('cannot assign json to number');
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
test('correct inference allows compatible assignment', () => {
|
|
464
|
+
const errors = getErrors(`
|
|
465
|
+
let x = ts() { return "hello" }
|
|
466
|
+
let y: text = x
|
|
467
|
+
`);
|
|
468
|
+
expect(errors).toEqual([]);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
test('infers type through parameter usage', () => {
|
|
472
|
+
const errors = getErrors(`
|
|
473
|
+
let a: number = 5
|
|
474
|
+
let x = ts(a) { return a * 2 }
|
|
475
|
+
let y: text = x
|
|
476
|
+
`);
|
|
477
|
+
expect(errors.length).toBe(1);
|
|
478
|
+
expect(errors[0]).toContain('cannot assign number to text');
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
test('type mismatch with explicit annotation on ts block variable', () => {
|
|
482
|
+
const errors = getErrors(`
|
|
483
|
+
let x: text = ts() { return 42 }
|
|
484
|
+
`);
|
|
485
|
+
expect(errors.length).toBe(1);
|
|
486
|
+
expect(errors[0]).toContain('cannot assign number to text');
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
test('type mismatch with array return to text', () => {
|
|
490
|
+
const errors = getErrors(`
|
|
491
|
+
let x: text = ts() { return [1, 2, 3] }
|
|
492
|
+
`);
|
|
493
|
+
expect(errors.length).toBe(1);
|
|
494
|
+
expect(errors[0]).toContain('cannot assign');
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
describe('Return Type Inference - Imported TS Functions', () => {
|
|
499
|
+
const analyzer = new SemanticAnalyzer();
|
|
500
|
+
|
|
501
|
+
function getErrors(code: string): string[] {
|
|
502
|
+
const ast = parse(code);
|
|
503
|
+
const errors = analyzer.analyze(ast, code, fixturesDir + '/main.vibe');
|
|
504
|
+
return errors.map((e) => e.message);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
test('infers number type from TS function returning number', () => {
|
|
508
|
+
const errors = getErrors(`
|
|
509
|
+
import { add } from "./math.ts"
|
|
510
|
+
let x = add(1, 2)
|
|
511
|
+
let y: text = x
|
|
512
|
+
`);
|
|
513
|
+
expect(errors.length).toBe(1);
|
|
514
|
+
expect(errors[0]).toContain('cannot assign number to text');
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
test('type mismatch when assigning TS function result to wrong type', () => {
|
|
518
|
+
const errors = getErrors(`
|
|
519
|
+
import { add } from "./math.ts"
|
|
520
|
+
let x: text = add(1, 2)
|
|
521
|
+
`);
|
|
522
|
+
expect(errors.length).toBe(1);
|
|
523
|
+
expect(errors[0]).toContain('cannot assign number to text');
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
test('correct type assignment from TS function', () => {
|
|
527
|
+
const errors = getErrors(`
|
|
528
|
+
import { add } from "./math.ts"
|
|
529
|
+
let x: number = add(1, 2)
|
|
530
|
+
`);
|
|
531
|
+
expect(errors).toEqual([]);
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
test('inferred type allows correct usage', () => {
|
|
535
|
+
const errors = getErrors(`
|
|
536
|
+
import { add } from "./math.ts"
|
|
537
|
+
let x = add(1, 2)
|
|
538
|
+
let y: number = x
|
|
539
|
+
`);
|
|
540
|
+
expect(errors).toEqual([]);
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
test('infers string type from TS function returning string', () => {
|
|
544
|
+
const errors = getErrors(`
|
|
545
|
+
import { greet } from "./math.ts"
|
|
546
|
+
let x = greet("Alice")
|
|
547
|
+
let y: number = x
|
|
548
|
+
`);
|
|
549
|
+
expect(errors.length).toBe(1);
|
|
550
|
+
expect(errors[0]).toContain('cannot assign text to number');
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
test('chained inference through TS function and variable', () => {
|
|
554
|
+
const errors = getErrors(`
|
|
555
|
+
import { add } from "./math.ts"
|
|
556
|
+
let a = add(1, 2)
|
|
557
|
+
let b = a
|
|
558
|
+
let c: text = b
|
|
559
|
+
`);
|
|
560
|
+
expect(errors.length).toBe(1);
|
|
561
|
+
expect(errors[0]).toContain('cannot assign number to text');
|
|
562
|
+
});
|
|
563
|
+
});
|
|
@@ -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 - Type Constraints', () => {
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Do expression model argument must be a model type
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
test('vibe expression with variable as model argument', () => {
|
|
11
|
+
const ast = parse(`
|
|
12
|
+
let notAModel = "test"
|
|
13
|
+
let x: text = vibe "prompt" notAModel default
|
|
14
|
+
`);
|
|
15
|
+
const errors = analyze(ast);
|
|
16
|
+
expect(errors.length).toBe(1);
|
|
17
|
+
expect(errors[0].message).toBe("Expected model, got variable 'notAModel'");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('vibe expression with constant as model argument', () => {
|
|
21
|
+
const ast = parse(`
|
|
22
|
+
const notAModel = "test"
|
|
23
|
+
let x: text = vibe "prompt" notAModel default
|
|
24
|
+
`);
|
|
25
|
+
const errors = analyze(ast);
|
|
26
|
+
expect(errors.length).toBe(1);
|
|
27
|
+
expect(errors[0].message).toBe("Expected model, got constant 'notAModel'");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('vibe expression with function as model argument', () => {
|
|
31
|
+
const ast = parse(`
|
|
32
|
+
function notAModel() {
|
|
33
|
+
return "test"
|
|
34
|
+
}
|
|
35
|
+
let x: text = vibe "prompt" notAModel default
|
|
36
|
+
`);
|
|
37
|
+
const errors = analyze(ast);
|
|
38
|
+
expect(errors.length).toBe(1);
|
|
39
|
+
expect(errors[0].message).toBe("Expected model, got function 'notAModel'");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('vibe expression with parameter as model argument', () => {
|
|
43
|
+
const ast = parse(`
|
|
44
|
+
model realModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
45
|
+
function test(notAModel: text): text {
|
|
46
|
+
let x: text = vibe "prompt" notAModel default
|
|
47
|
+
return x
|
|
48
|
+
}
|
|
49
|
+
`);
|
|
50
|
+
const errors = analyze(ast);
|
|
51
|
+
expect(errors.length).toBe(1);
|
|
52
|
+
expect(errors[0].message).toBe("Expected model, got parameter 'notAModel'");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// Valid model usage
|
|
57
|
+
// ============================================================================
|
|
58
|
+
|
|
59
|
+
test('vibe expression with valid model', () => {
|
|
60
|
+
const ast = parse(`
|
|
61
|
+
model myModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
62
|
+
let x: text = vibe "prompt" myModel default
|
|
63
|
+
`);
|
|
64
|
+
const errors = analyze(ast);
|
|
65
|
+
expect(errors.length).toBe(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('vibe expression with model from outer scope', () => {
|
|
69
|
+
const ast = parse(`
|
|
70
|
+
model myModel = { name: "test", apiKey: "key", url: "http://test" }
|
|
71
|
+
function test() {
|
|
72
|
+
let x: text = vibe "prompt" myModel default
|
|
73
|
+
return x
|
|
74
|
+
}
|
|
75
|
+
`);
|
|
76
|
+
const errors = analyze(ast);
|
|
77
|
+
expect(errors.length).toBe(0);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// ============================================================================
|
|
81
|
+
// Multiple type errors
|
|
82
|
+
// ============================================================================
|
|
83
|
+
|
|
84
|
+
test('multiple vibe expressions with wrong model types', () => {
|
|
85
|
+
const ast = parse(`
|
|
86
|
+
let notAModel = "test"
|
|
87
|
+
let x: text = vibe "prompt1" notAModel default
|
|
88
|
+
let y: text = vibe "prompt2" notAModel default
|
|
89
|
+
`);
|
|
90
|
+
const errors = analyze(ast);
|
|
91
|
+
expect(errors.length).toBe(2);
|
|
92
|
+
expect(errors[0].message).toBe("Expected model, got variable 'notAModel'");
|
|
93
|
+
expect(errors[1].message).toBe("Expected model, got variable 'notAModel'");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// Combined errors
|
|
98
|
+
// ============================================================================
|
|
99
|
+
|
|
100
|
+
test('undefined model and wrong type model', () => {
|
|
101
|
+
const ast = parse(`
|
|
102
|
+
let notAModel = "test"
|
|
103
|
+
let x: text = vibe "prompt1" undefinedModel default
|
|
104
|
+
let y: text = vibe "prompt2" notAModel default
|
|
105
|
+
`);
|
|
106
|
+
const errors = analyze(ast);
|
|
107
|
+
expect(errors.length).toBe(2);
|
|
108
|
+
expect(errors[0].message).toBe("'undefinedModel' is not defined");
|
|
109
|
+
expect(errors[1].message).toBe("Expected model, got variable 'notAModel'");
|
|
110
|
+
});
|
|
111
|
+
});
|