@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,300 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach } from 'bun:test';
|
|
2
|
+
import {
|
|
3
|
+
createAdvancedDebugState,
|
|
4
|
+
setAdvancedBreakpoint,
|
|
5
|
+
removeAdvancedBreakpoint,
|
|
6
|
+
getAdvancedBreakpoint,
|
|
7
|
+
evaluateCondition,
|
|
8
|
+
checkHitCondition,
|
|
9
|
+
shouldBreakpointTrigger,
|
|
10
|
+
interpolateLogMessage,
|
|
11
|
+
addWatchExpression,
|
|
12
|
+
removeWatchExpression,
|
|
13
|
+
evaluateWatchExpressions,
|
|
14
|
+
setExceptionBreakpoints,
|
|
15
|
+
shouldBreakOnException,
|
|
16
|
+
flushLogOutput,
|
|
17
|
+
} from '../advanced-features';
|
|
18
|
+
import { createInitialState } from '../../runtime/state';
|
|
19
|
+
import { parse } from '../../parser/parse';
|
|
20
|
+
import { runUntilPause } from '../../runtime/step';
|
|
21
|
+
|
|
22
|
+
describe('Advanced Debug Features', () => {
|
|
23
|
+
describe('createAdvancedDebugState', () => {
|
|
24
|
+
test('creates initial state', () => {
|
|
25
|
+
const state = createAdvancedDebugState();
|
|
26
|
+
|
|
27
|
+
expect(state.advancedBreakpoints.size).toBe(0);
|
|
28
|
+
expect(state.watchExpressions).toEqual([]);
|
|
29
|
+
expect(state.nextWatchId).toBe(1);
|
|
30
|
+
expect(state.exceptionBreakpoints.all).toBe(false);
|
|
31
|
+
expect(state.exceptionBreakpoints.uncaught).toBe(true);
|
|
32
|
+
expect(state.logOutput).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('Conditional Breakpoints', () => {
|
|
37
|
+
test('setAdvancedBreakpoint with condition', () => {
|
|
38
|
+
let state = createAdvancedDebugState();
|
|
39
|
+
|
|
40
|
+
const { state: newState, breakpoint } = setAdvancedBreakpoint(
|
|
41
|
+
state,
|
|
42
|
+
'/test.vibe',
|
|
43
|
+
10,
|
|
44
|
+
{ condition: 'x > 5' }
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
expect(breakpoint.condition).toBe('x > 5');
|
|
48
|
+
expect(breakpoint.line).toBe(10);
|
|
49
|
+
expect(newState.advancedBreakpoints.size).toBe(1);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('getAdvancedBreakpoint retrieves breakpoint', () => {
|
|
53
|
+
let state = createAdvancedDebugState();
|
|
54
|
+
const { state: newState } = setAdvancedBreakpoint(state, '/test.vibe', 15, {
|
|
55
|
+
condition: 'y == 10',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const bp = getAdvancedBreakpoint(newState, '/test.vibe', 15);
|
|
59
|
+
expect(bp).toBeDefined();
|
|
60
|
+
expect(bp?.condition).toBe('y == 10');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('removeAdvancedBreakpoint removes breakpoint', () => {
|
|
64
|
+
let state = createAdvancedDebugState();
|
|
65
|
+
const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 10, {});
|
|
66
|
+
const newState = removeAdvancedBreakpoint(state2, '/test.vibe', 10);
|
|
67
|
+
|
|
68
|
+
expect(getAdvancedBreakpoint(newState, '/test.vibe', 10)).toBeUndefined();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('evaluateCondition', () => {
|
|
73
|
+
test('returns true for no condition', () => {
|
|
74
|
+
const ast = parse('let x = 5');
|
|
75
|
+
const runtimeState = createInitialState(ast);
|
|
76
|
+
|
|
77
|
+
expect(evaluateCondition(undefined, runtimeState)).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('evaluates simple comparisons', () => {
|
|
81
|
+
const ast = parse('let x = 10');
|
|
82
|
+
let runtimeState = createInitialState(ast);
|
|
83
|
+
runtimeState = runUntilPause(runtimeState);
|
|
84
|
+
|
|
85
|
+
// x should be 10
|
|
86
|
+
expect(evaluateCondition('x > 5', runtimeState)).toBe(true);
|
|
87
|
+
expect(evaluateCondition('x < 5', runtimeState)).toBe(false);
|
|
88
|
+
expect(evaluateCondition('x == 10', runtimeState)).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('Hit Count Conditions', () => {
|
|
93
|
+
test('checkHitCondition with >= operator', () => {
|
|
94
|
+
expect(checkHitCondition('>=5', 5)).toBe(true);
|
|
95
|
+
expect(checkHitCondition('>=5', 4)).toBe(false);
|
|
96
|
+
expect(checkHitCondition('>=5', 10)).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('checkHitCondition with == operator', () => {
|
|
100
|
+
expect(checkHitCondition('==5', 5)).toBe(true);
|
|
101
|
+
expect(checkHitCondition('==5', 4)).toBe(false);
|
|
102
|
+
expect(checkHitCondition('=5', 5)).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('checkHitCondition with modulo operator', () => {
|
|
106
|
+
expect(checkHitCondition('%3', 3)).toBe(true);
|
|
107
|
+
expect(checkHitCondition('%3', 6)).toBe(true);
|
|
108
|
+
expect(checkHitCondition('%3', 4)).toBe(false);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('checkHitCondition with plain number', () => {
|
|
112
|
+
expect(checkHitCondition('5', 5)).toBe(true);
|
|
113
|
+
expect(checkHitCondition('5', 10)).toBe(true);
|
|
114
|
+
expect(checkHitCondition('5', 3)).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('Logpoints', () => {
|
|
119
|
+
test('setAdvancedBreakpoint with logMessage', () => {
|
|
120
|
+
let state = createAdvancedDebugState();
|
|
121
|
+
|
|
122
|
+
const { state: newState, breakpoint } = setAdvancedBreakpoint(
|
|
123
|
+
state,
|
|
124
|
+
'/test.vibe',
|
|
125
|
+
10,
|
|
126
|
+
{ logMessage: 'Value is {x}' }
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
expect(breakpoint.logMessage).toBe('Value is {x}');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('interpolateLogMessage replaces variables', () => {
|
|
133
|
+
const ast = parse('let x = 42\nlet y = "hello"');
|
|
134
|
+
let runtimeState = createInitialState(ast);
|
|
135
|
+
runtimeState = runUntilPause(runtimeState);
|
|
136
|
+
|
|
137
|
+
const message = interpolateLogMessage('x = {x}, y = {y}', runtimeState);
|
|
138
|
+
expect(message).toBe('x = 42, y = hello');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('shouldBreakpointTrigger returns logMessage for logpoint', () => {
|
|
142
|
+
let state = createAdvancedDebugState();
|
|
143
|
+
const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 2, {
|
|
144
|
+
logMessage: 'Debug: {x}',
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const ast = parse('let x = 100');
|
|
148
|
+
let runtimeState = createInitialState(ast);
|
|
149
|
+
runtimeState = runUntilPause(runtimeState);
|
|
150
|
+
|
|
151
|
+
const result = shouldBreakpointTrigger(state2, runtimeState, {
|
|
152
|
+
file: '/test.vibe',
|
|
153
|
+
line: 2,
|
|
154
|
+
column: 1,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
expect(result.shouldBreak).toBe(false); // Logpoints don't break
|
|
158
|
+
expect(result.logMessage).toBe('Debug: 100');
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('Watch Expressions', () => {
|
|
163
|
+
test('addWatchExpression adds watch', () => {
|
|
164
|
+
let state = createAdvancedDebugState();
|
|
165
|
+
|
|
166
|
+
const { state: newState, watch } = addWatchExpression(state, 'x + y');
|
|
167
|
+
|
|
168
|
+
expect(watch.expression).toBe('x + y');
|
|
169
|
+
expect(watch.id).toBe(1);
|
|
170
|
+
expect(newState.watchExpressions.length).toBe(1);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('removeWatchExpression removes watch', () => {
|
|
174
|
+
let state = createAdvancedDebugState();
|
|
175
|
+
const { state: state2, watch } = addWatchExpression(state, 'x');
|
|
176
|
+
const newState = removeWatchExpression(state2, watch.id);
|
|
177
|
+
|
|
178
|
+
expect(newState.watchExpressions.length).toBe(0);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('evaluateWatchExpressions evaluates all watches', () => {
|
|
182
|
+
let state = createAdvancedDebugState();
|
|
183
|
+
const { state: state2 } = addWatchExpression(state, 'x');
|
|
184
|
+
const { state: state3 } = addWatchExpression(state2, 'y');
|
|
185
|
+
|
|
186
|
+
const ast = parse('let x = 10\nlet y = 20');
|
|
187
|
+
let runtimeState = createInitialState(ast);
|
|
188
|
+
runtimeState = runUntilPause(runtimeState);
|
|
189
|
+
|
|
190
|
+
const newState = evaluateWatchExpressions(state3, runtimeState);
|
|
191
|
+
|
|
192
|
+
expect(newState.watchExpressions[0].lastValue).toBe('10');
|
|
193
|
+
expect(newState.watchExpressions[1].lastValue).toBe('20');
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe('Exception Breakpoints', () => {
|
|
198
|
+
test('setExceptionBreakpoints updates config', () => {
|
|
199
|
+
let state = createAdvancedDebugState();
|
|
200
|
+
|
|
201
|
+
state = setExceptionBreakpoints(state, { all: true });
|
|
202
|
+
expect(state.exceptionBreakpoints.all).toBe(true);
|
|
203
|
+
|
|
204
|
+
state = setExceptionBreakpoints(state, { filters: ['TypeError'] });
|
|
205
|
+
expect(state.exceptionBreakpoints.filters).toEqual(['TypeError']);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('shouldBreakOnException respects all flag', () => {
|
|
209
|
+
let state = createAdvancedDebugState();
|
|
210
|
+
state = setExceptionBreakpoints(state, { all: true });
|
|
211
|
+
|
|
212
|
+
expect(shouldBreakOnException(state, new Error('test'), true)).toBe(true);
|
|
213
|
+
expect(shouldBreakOnException(state, new Error('test'), false)).toBe(true);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('shouldBreakOnException respects uncaught flag', () => {
|
|
217
|
+
let state = createAdvancedDebugState();
|
|
218
|
+
state = setExceptionBreakpoints(state, { all: false, uncaught: true });
|
|
219
|
+
|
|
220
|
+
expect(shouldBreakOnException(state, new Error('test'), true)).toBe(false);
|
|
221
|
+
expect(shouldBreakOnException(state, new Error('test'), false)).toBe(true);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test('shouldBreakOnException respects filters', () => {
|
|
225
|
+
let state = createAdvancedDebugState();
|
|
226
|
+
state = setExceptionBreakpoints(state, {
|
|
227
|
+
all: false,
|
|
228
|
+
uncaught: false,
|
|
229
|
+
filters: ['TypeError'],
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
expect(shouldBreakOnException(state, new TypeError('test'), true)).toBe(true);
|
|
233
|
+
expect(shouldBreakOnException(state, new Error('test'), true)).toBe(false);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
describe('Log Output', () => {
|
|
238
|
+
test('flushLogOutput returns and clears logs', () => {
|
|
239
|
+
let state = createAdvancedDebugState();
|
|
240
|
+
const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 1, {
|
|
241
|
+
logMessage: 'Log 1',
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const ast = parse('let x = 1');
|
|
245
|
+
let runtimeState = createInitialState(ast);
|
|
246
|
+
|
|
247
|
+
// Trigger the logpoint
|
|
248
|
+
const { newState: state3 } = shouldBreakpointTrigger(state2, runtimeState, {
|
|
249
|
+
file: '/test.vibe',
|
|
250
|
+
line: 1,
|
|
251
|
+
column: 1,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const { state: state4, logs } = flushLogOutput(state3);
|
|
255
|
+
|
|
256
|
+
expect(logs.length).toBe(1);
|
|
257
|
+
expect(logs[0]).toBe('Log 1');
|
|
258
|
+
expect(state4.logOutput.length).toBe(0);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe('shouldBreakpointTrigger', () => {
|
|
263
|
+
test('increments hit count', () => {
|
|
264
|
+
let state = createAdvancedDebugState();
|
|
265
|
+
const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 1, {});
|
|
266
|
+
|
|
267
|
+
const ast = parse('let x = 1');
|
|
268
|
+
const runtimeState = createInitialState(ast);
|
|
269
|
+
const location = { file: '/test.vibe', line: 1, column: 1 };
|
|
270
|
+
|
|
271
|
+
let { newState: state3 } = shouldBreakpointTrigger(state2, runtimeState, location);
|
|
272
|
+
expect(getAdvancedBreakpoint(state3, '/test.vibe', 1)?.hitCount).toBe(1);
|
|
273
|
+
|
|
274
|
+
let { newState: state4 } = shouldBreakpointTrigger(state3, runtimeState, location);
|
|
275
|
+
expect(getAdvancedBreakpoint(state4, '/test.vibe', 1)?.hitCount).toBe(2);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test('respects hit condition', () => {
|
|
279
|
+
let state = createAdvancedDebugState();
|
|
280
|
+
const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 1, {
|
|
281
|
+
hitCondition: '>=3',
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const ast = parse('let x = 1');
|
|
285
|
+
const runtimeState = createInitialState(ast);
|
|
286
|
+
const location = { file: '/test.vibe', line: 1, column: 1 };
|
|
287
|
+
|
|
288
|
+
// First two hits should not break
|
|
289
|
+
let { shouldBreak: b1, newState: s1 } = shouldBreakpointTrigger(state2, runtimeState, location);
|
|
290
|
+
expect(b1).toBe(false);
|
|
291
|
+
|
|
292
|
+
let { shouldBreak: b2, newState: s2 } = shouldBreakpointTrigger(s1, runtimeState, location);
|
|
293
|
+
expect(b2).toBe(false);
|
|
294
|
+
|
|
295
|
+
// Third hit should break
|
|
296
|
+
let { shouldBreak: b3 } = shouldBreakpointTrigger(s2, runtimeState, location);
|
|
297
|
+
expect(b3).toBe(true);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
});
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { describe, test, expect } from 'bun:test';
|
|
2
|
+
import { parse } from '../../parser/parse';
|
|
3
|
+
import { createInitialState } from '../../runtime/state';
|
|
4
|
+
import { loadImports } from '../../runtime/modules';
|
|
5
|
+
import {
|
|
6
|
+
createDebugState,
|
|
7
|
+
setBreakpoints,
|
|
8
|
+
getStackTrace,
|
|
9
|
+
getScopes,
|
|
10
|
+
getVariables,
|
|
11
|
+
getCurrentLocation,
|
|
12
|
+
} from '../state';
|
|
13
|
+
import { runWithDebug, createOutputEvent } from '../runner';
|
|
14
|
+
import type { RuntimeEvent } from '@vibe-lang/debug-core';
|
|
15
|
+
import type { AIProvider, AIExecutionResult } from '../../runtime';
|
|
16
|
+
|
|
17
|
+
// Mock AI provider for testing
|
|
18
|
+
const mockAIProvider: AIProvider = {
|
|
19
|
+
async execute(prompt: string): Promise<AIExecutionResult> {
|
|
20
|
+
return { value: `Mock response to: ${prompt.slice(0, 50)}...` };
|
|
21
|
+
},
|
|
22
|
+
async generateCode(prompt: string): Promise<AIExecutionResult> {
|
|
23
|
+
return { value: '// mock code' };
|
|
24
|
+
},
|
|
25
|
+
async askUser(prompt: string): Promise<string> {
|
|
26
|
+
return 'mock user input';
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe('End-to-End Debug Session', () => {
|
|
31
|
+
test('full debug session with breakpoints', async () => {
|
|
32
|
+
const code = `
|
|
33
|
+
let x = 10
|
|
34
|
+
let y = 20
|
|
35
|
+
let z = x + y
|
|
36
|
+
`;
|
|
37
|
+
const ast = parse(code, { file: '/test.vibe' });
|
|
38
|
+
let runtimeState = createInitialState(ast);
|
|
39
|
+
let debugState = createDebugState();
|
|
40
|
+
|
|
41
|
+
// Set breakpoint on line 3 (let y = 20)
|
|
42
|
+
const bpResult = setBreakpoints(debugState, '/test.vibe', [3]);
|
|
43
|
+
debugState = bpResult.debugState;
|
|
44
|
+
|
|
45
|
+
// Collect events
|
|
46
|
+
const events: RuntimeEvent[] = [];
|
|
47
|
+
const onEvent = (event: RuntimeEvent) => events.push(event);
|
|
48
|
+
|
|
49
|
+
// Run with debug
|
|
50
|
+
const result = await runWithDebug(runtimeState, debugState, mockAIProvider, onEvent);
|
|
51
|
+
|
|
52
|
+
// Should have stopped at breakpoint or completed
|
|
53
|
+
expect(result.runtimeState).toBeDefined();
|
|
54
|
+
expect(result.debugState).toBeDefined();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('stop on entry', async () => {
|
|
58
|
+
const code = 'let x = 1';
|
|
59
|
+
const ast = parse(code, { file: '/test.vibe' });
|
|
60
|
+
const runtimeState = createInitialState(ast);
|
|
61
|
+
const debugState = createDebugState({ stopOnEntry: true });
|
|
62
|
+
|
|
63
|
+
const events: RuntimeEvent[] = [];
|
|
64
|
+
const result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => events.push(e));
|
|
65
|
+
|
|
66
|
+
// Should be paused at entry
|
|
67
|
+
expect(result.debugState.paused).toBe(true);
|
|
68
|
+
expect(result.debugState.stopReason).toBe('entry');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('inspect variables at breakpoint', async () => {
|
|
72
|
+
const code = `
|
|
73
|
+
let x = 42
|
|
74
|
+
let y = "hello"
|
|
75
|
+
let z = x
|
|
76
|
+
`;
|
|
77
|
+
const ast = parse(code, { file: '/test.vibe' });
|
|
78
|
+
let runtimeState = createInitialState(ast);
|
|
79
|
+
let debugState = createDebugState();
|
|
80
|
+
|
|
81
|
+
// Set breakpoint on line 4 (after x and y are set)
|
|
82
|
+
const bpResult = setBreakpoints(debugState, '/test.vibe', [4]);
|
|
83
|
+
debugState = bpResult.debugState;
|
|
84
|
+
|
|
85
|
+
const events: RuntimeEvent[] = [];
|
|
86
|
+
const result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => events.push(e));
|
|
87
|
+
|
|
88
|
+
runtimeState = result.runtimeState;
|
|
89
|
+
debugState = result.debugState;
|
|
90
|
+
|
|
91
|
+
// Get stack trace
|
|
92
|
+
const { stackFrames } = getStackTrace(runtimeState);
|
|
93
|
+
expect(stackFrames.length).toBeGreaterThan(0);
|
|
94
|
+
|
|
95
|
+
// Get scopes
|
|
96
|
+
const scopeResult = getScopes(debugState, runtimeState, 0);
|
|
97
|
+
debugState = scopeResult.debugState;
|
|
98
|
+
expect(scopeResult.scopes.length).toBeGreaterThan(0);
|
|
99
|
+
|
|
100
|
+
// Get local variables
|
|
101
|
+
const localScope = scopeResult.scopes.find(s => s.type === 'local');
|
|
102
|
+
if (localScope) {
|
|
103
|
+
const varResult = getVariables(debugState, runtimeState, localScope.variablesReference);
|
|
104
|
+
expect(Array.isArray(varResult.variables)).toBe(true);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('step through function calls', async () => {
|
|
109
|
+
const code = `
|
|
110
|
+
function double(n: number): number {
|
|
111
|
+
return n * 2
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let x = 5
|
|
115
|
+
let y = double(x)
|
|
116
|
+
`;
|
|
117
|
+
const ast = parse(code, { file: '/test.vibe' });
|
|
118
|
+
let runtimeState = createInitialState(ast);
|
|
119
|
+
let debugState = createDebugState({ stopOnEntry: true });
|
|
120
|
+
|
|
121
|
+
const events: RuntimeEvent[] = [];
|
|
122
|
+
let result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => events.push(e));
|
|
123
|
+
|
|
124
|
+
// Should stop on entry
|
|
125
|
+
expect(result.debugState.paused).toBe(true);
|
|
126
|
+
|
|
127
|
+
// Continue to completion
|
|
128
|
+
debugState = { ...result.debugState, paused: false, stepMode: 'none' as const, running: true };
|
|
129
|
+
result = await runWithDebug(result.runtimeState, debugState, mockAIProvider, (e) => events.push(e));
|
|
130
|
+
|
|
131
|
+
// Should complete
|
|
132
|
+
expect(result.runtimeState.status).toBe('completed');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('handles AI calls during debug', async () => {
|
|
136
|
+
const code = `
|
|
137
|
+
let question = "What is 2+2?"
|
|
138
|
+
let answer = vibe "{question}"
|
|
139
|
+
`;
|
|
140
|
+
const ast = parse(code, { file: '/test.vibe' });
|
|
141
|
+
let runtimeState = createInitialState(ast);
|
|
142
|
+
const debugState = createDebugState();
|
|
143
|
+
|
|
144
|
+
const events: RuntimeEvent[] = [];
|
|
145
|
+
const result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => events.push(e));
|
|
146
|
+
|
|
147
|
+
// Debug runner should execute without throwing
|
|
148
|
+
// The exact final status depends on runtime behavior with mock AI
|
|
149
|
+
expect(result.runtimeState).toBeDefined();
|
|
150
|
+
expect(result.debugState).toBeDefined();
|
|
151
|
+
// Should reach some terminal state (completed, error, or awaiting)
|
|
152
|
+
expect(['completed', 'awaiting_ai', 'error'].includes(result.runtimeState.status)).toBe(true);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('multiple breakpoints', async () => {
|
|
156
|
+
const code = `
|
|
157
|
+
let a = 1
|
|
158
|
+
let b = 2
|
|
159
|
+
let c = 3
|
|
160
|
+
let d = 4
|
|
161
|
+
`;
|
|
162
|
+
const ast = parse(code, { file: '/test.vibe' });
|
|
163
|
+
let runtimeState = createInitialState(ast);
|
|
164
|
+
let debugState = createDebugState();
|
|
165
|
+
|
|
166
|
+
// Set breakpoints on lines 2 and 4
|
|
167
|
+
const bpResult = setBreakpoints(debugState, '/test.vibe', [2, 4]);
|
|
168
|
+
debugState = bpResult.debugState;
|
|
169
|
+
|
|
170
|
+
const events: RuntimeEvent[] = [];
|
|
171
|
+
const stoppedEvents: RuntimeEvent[] = [];
|
|
172
|
+
|
|
173
|
+
// First run - should stop at first breakpoint
|
|
174
|
+
let result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => {
|
|
175
|
+
events.push(e);
|
|
176
|
+
if (e.event === 'stopped') stoppedEvents.push(e);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Should have some events
|
|
180
|
+
expect(events.length).toBeGreaterThanOrEqual(0);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('Debug Protocol Messages', () => {
|
|
185
|
+
test('createOutputEvent creates proper event', () => {
|
|
186
|
+
const event = createOutputEvent('Hello World', 'stdout');
|
|
187
|
+
|
|
188
|
+
expect(event.type).toBe('event');
|
|
189
|
+
expect(event.event).toBe('output');
|
|
190
|
+
expect(event.body.output).toBe('Hello World');
|
|
191
|
+
expect(event.body.category).toBe('stdout');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('createOutputEvent defaults to stdout', () => {
|
|
195
|
+
const event = createOutputEvent('Test output');
|
|
196
|
+
|
|
197
|
+
expect(event.body.category).toBe('stdout');
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('Location Tracking', () => {
|
|
202
|
+
test('getCurrentLocation returns location from runtime state', () => {
|
|
203
|
+
const code = `
|
|
204
|
+
let x = 1
|
|
205
|
+
let y = 2
|
|
206
|
+
`;
|
|
207
|
+
const ast = parse(code, { file: '/test.vibe' });
|
|
208
|
+
const runtimeState = createInitialState(ast);
|
|
209
|
+
|
|
210
|
+
const location = getCurrentLocation(runtimeState);
|
|
211
|
+
|
|
212
|
+
// May or may not have location depending on state
|
|
213
|
+
if (location) {
|
|
214
|
+
expect(typeof location.line).toBe('number');
|
|
215
|
+
expect(typeof location.column).toBe('number');
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
});
|