viberag 0.1.0
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/LICENSE +661 -0
- package/README.md +219 -0
- package/dist/cli/__tests__/mcp-setup.test.d.ts +6 -0
- package/dist/cli/__tests__/mcp-setup.test.js +597 -0
- package/dist/cli/app.d.ts +2 -0
- package/dist/cli/app.js +238 -0
- package/dist/cli/commands/handlers.d.ts +57 -0
- package/dist/cli/commands/handlers.js +231 -0
- package/dist/cli/commands/index.d.ts +2 -0
- package/dist/cli/commands/index.js +2 -0
- package/dist/cli/commands/mcp-setup.d.ts +107 -0
- package/dist/cli/commands/mcp-setup.js +509 -0
- package/dist/cli/commands/useRagCommands.d.ts +23 -0
- package/dist/cli/commands/useRagCommands.js +180 -0
- package/dist/cli/components/CleanWizard.d.ts +17 -0
- package/dist/cli/components/CleanWizard.js +169 -0
- package/dist/cli/components/InitWizard.d.ts +20 -0
- package/dist/cli/components/InitWizard.js +370 -0
- package/dist/cli/components/McpSetupWizard.d.ts +37 -0
- package/dist/cli/components/McpSetupWizard.js +387 -0
- package/dist/cli/components/SearchResultsDisplay.d.ts +13 -0
- package/dist/cli/components/SearchResultsDisplay.js +130 -0
- package/dist/cli/components/WelcomeBanner.d.ts +10 -0
- package/dist/cli/components/WelcomeBanner.js +26 -0
- package/dist/cli/components/index.d.ts +1 -0
- package/dist/cli/components/index.js +1 -0
- package/dist/cli/data/mcp-editors.d.ts +80 -0
- package/dist/cli/data/mcp-editors.js +270 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +26 -0
- package/dist/cli-bundle.cjs +5269 -0
- package/dist/common/commands/terminalSetup.d.ts +2 -0
- package/dist/common/commands/terminalSetup.js +144 -0
- package/dist/common/components/CommandSuggestions.d.ts +9 -0
- package/dist/common/components/CommandSuggestions.js +20 -0
- package/dist/common/components/StaticWithResize.d.ts +23 -0
- package/dist/common/components/StaticWithResize.js +62 -0
- package/dist/common/components/StatusBar.d.ts +8 -0
- package/dist/common/components/StatusBar.js +64 -0
- package/dist/common/components/TextInput.d.ts +12 -0
- package/dist/common/components/TextInput.js +239 -0
- package/dist/common/components/index.d.ts +3 -0
- package/dist/common/components/index.js +3 -0
- package/dist/common/hooks/index.d.ts +4 -0
- package/dist/common/hooks/index.js +4 -0
- package/dist/common/hooks/useCommandHistory.d.ts +7 -0
- package/dist/common/hooks/useCommandHistory.js +51 -0
- package/dist/common/hooks/useCtrlC.d.ts +9 -0
- package/dist/common/hooks/useCtrlC.js +40 -0
- package/dist/common/hooks/useKittyKeyboard.d.ts +10 -0
- package/dist/common/hooks/useKittyKeyboard.js +26 -0
- package/dist/common/hooks/useStaticOutputBuffer.d.ts +31 -0
- package/dist/common/hooks/useStaticOutputBuffer.js +58 -0
- package/dist/common/hooks/useTerminalResize.d.ts +28 -0
- package/dist/common/hooks/useTerminalResize.js +51 -0
- package/dist/common/hooks/useTextBuffer.d.ts +13 -0
- package/dist/common/hooks/useTextBuffer.js +165 -0
- package/dist/common/index.d.ts +13 -0
- package/dist/common/index.js +17 -0
- package/dist/common/types.d.ts +162 -0
- package/dist/common/types.js +1 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.js +66 -0
- package/dist/mcp/server.d.ts +25 -0
- package/dist/mcp/server.js +837 -0
- package/dist/mcp/watcher.d.ts +86 -0
- package/dist/mcp/watcher.js +334 -0
- package/dist/rag/__tests__/grammar-smoke.test.d.ts +9 -0
- package/dist/rag/__tests__/grammar-smoke.test.js +161 -0
- package/dist/rag/__tests__/helpers.d.ts +30 -0
- package/dist/rag/__tests__/helpers.js +67 -0
- package/dist/rag/__tests__/merkle.test.d.ts +5 -0
- package/dist/rag/__tests__/merkle.test.js +161 -0
- package/dist/rag/__tests__/metadata-extraction.test.d.ts +10 -0
- package/dist/rag/__tests__/metadata-extraction.test.js +202 -0
- package/dist/rag/__tests__/multi-language.test.d.ts +13 -0
- package/dist/rag/__tests__/multi-language.test.js +535 -0
- package/dist/rag/__tests__/rag.test.d.ts +10 -0
- package/dist/rag/__tests__/rag.test.js +311 -0
- package/dist/rag/__tests__/search-exhaustive.test.d.ts +9 -0
- package/dist/rag/__tests__/search-exhaustive.test.js +87 -0
- package/dist/rag/__tests__/search-filters.test.d.ts +10 -0
- package/dist/rag/__tests__/search-filters.test.js +250 -0
- package/dist/rag/__tests__/search-modes.test.d.ts +8 -0
- package/dist/rag/__tests__/search-modes.test.js +133 -0
- package/dist/rag/config/index.d.ts +61 -0
- package/dist/rag/config/index.js +111 -0
- package/dist/rag/constants.d.ts +41 -0
- package/dist/rag/constants.js +57 -0
- package/dist/rag/embeddings/fastembed.d.ts +62 -0
- package/dist/rag/embeddings/fastembed.js +124 -0
- package/dist/rag/embeddings/gemini.d.ts +26 -0
- package/dist/rag/embeddings/gemini.js +116 -0
- package/dist/rag/embeddings/index.d.ts +10 -0
- package/dist/rag/embeddings/index.js +9 -0
- package/dist/rag/embeddings/local-4b.d.ts +28 -0
- package/dist/rag/embeddings/local-4b.js +51 -0
- package/dist/rag/embeddings/local.d.ts +29 -0
- package/dist/rag/embeddings/local.js +119 -0
- package/dist/rag/embeddings/mistral.d.ts +22 -0
- package/dist/rag/embeddings/mistral.js +85 -0
- package/dist/rag/embeddings/openai.d.ts +22 -0
- package/dist/rag/embeddings/openai.js +85 -0
- package/dist/rag/embeddings/types.d.ts +37 -0
- package/dist/rag/embeddings/types.js +1 -0
- package/dist/rag/gitignore/index.d.ts +57 -0
- package/dist/rag/gitignore/index.js +178 -0
- package/dist/rag/index.d.ts +15 -0
- package/dist/rag/index.js +25 -0
- package/dist/rag/indexer/chunker.d.ts +129 -0
- package/dist/rag/indexer/chunker.js +1352 -0
- package/dist/rag/indexer/index.d.ts +6 -0
- package/dist/rag/indexer/index.js +6 -0
- package/dist/rag/indexer/indexer.d.ts +73 -0
- package/dist/rag/indexer/indexer.js +356 -0
- package/dist/rag/indexer/types.d.ts +68 -0
- package/dist/rag/indexer/types.js +47 -0
- package/dist/rag/logger/index.d.ts +20 -0
- package/dist/rag/logger/index.js +75 -0
- package/dist/rag/manifest/index.d.ts +50 -0
- package/dist/rag/manifest/index.js +97 -0
- package/dist/rag/merkle/diff.d.ts +26 -0
- package/dist/rag/merkle/diff.js +95 -0
- package/dist/rag/merkle/hash.d.ts +34 -0
- package/dist/rag/merkle/hash.js +165 -0
- package/dist/rag/merkle/index.d.ts +68 -0
- package/dist/rag/merkle/index.js +298 -0
- package/dist/rag/merkle/node.d.ts +51 -0
- package/dist/rag/merkle/node.js +69 -0
- package/dist/rag/search/filters.d.ts +21 -0
- package/dist/rag/search/filters.js +100 -0
- package/dist/rag/search/fts.d.ts +32 -0
- package/dist/rag/search/fts.js +61 -0
- package/dist/rag/search/hybrid.d.ts +17 -0
- package/dist/rag/search/hybrid.js +58 -0
- package/dist/rag/search/index.d.ts +89 -0
- package/dist/rag/search/index.js +367 -0
- package/dist/rag/search/types.d.ts +130 -0
- package/dist/rag/search/types.js +4 -0
- package/dist/rag/search/vector.d.ts +25 -0
- package/dist/rag/search/vector.js +44 -0
- package/dist/rag/storage/index.d.ts +92 -0
- package/dist/rag/storage/index.js +287 -0
- package/dist/rag/storage/lancedb-native.d.ts +7 -0
- package/dist/rag/storage/lancedb-native.js +10 -0
- package/dist/rag/storage/schema.d.ts +23 -0
- package/dist/rag/storage/schema.js +50 -0
- package/dist/rag/storage/types.d.ts +100 -0
- package/dist/rag/storage/types.js +68 -0
- package/package.json +67 -0
- package/scripts/check-node-version.js +37 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merkle tree unit tests.
|
|
3
|
+
* Tests tree structure building and change detection (diffing).
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
+
import { MerkleTree } from '../merkle/index.js';
|
|
7
|
+
import { copyFixtureToTemp, addFile, modifyFile, deleteFile, waitForFs, } from './helpers.js';
|
|
8
|
+
/**
|
|
9
|
+
* Helper to collect all file paths from tree.
|
|
10
|
+
*/
|
|
11
|
+
function collectFiles(node) {
|
|
12
|
+
if (!node)
|
|
13
|
+
return [];
|
|
14
|
+
if (node.type === 'file')
|
|
15
|
+
return [node.path];
|
|
16
|
+
const files = [];
|
|
17
|
+
if (node.children) {
|
|
18
|
+
for (const child of node.children.values()) {
|
|
19
|
+
files.push(...collectFiles(child));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return files;
|
|
23
|
+
}
|
|
24
|
+
describe('MerkleTree', () => {
|
|
25
|
+
let ctx;
|
|
26
|
+
beforeEach(async () => {
|
|
27
|
+
ctx = await copyFixtureToTemp('codebase');
|
|
28
|
+
});
|
|
29
|
+
afterEach(async () => {
|
|
30
|
+
await ctx.cleanup();
|
|
31
|
+
});
|
|
32
|
+
describe('Tree structure', () => {
|
|
33
|
+
it('includes all files from nested directories', async () => {
|
|
34
|
+
const tree = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx', '.js', '.py'], []);
|
|
35
|
+
// Count all files in tree
|
|
36
|
+
const allFiles = collectFiles(tree.root);
|
|
37
|
+
// Should have all ~15 files (5 original + 10 nested)
|
|
38
|
+
expect(allFiles.length).toBeGreaterThanOrEqual(10);
|
|
39
|
+
// Should include deeply nested file
|
|
40
|
+
expect(allFiles.some(f => f.includes('deep/nested/file.ts'))).toBe(true);
|
|
41
|
+
// Should include files at different levels
|
|
42
|
+
expect(allFiles.some(f => f.includes('src/components/Button.tsx'))).toBe(true);
|
|
43
|
+
expect(allFiles.some(f => f.includes('src/components/forms/LoginForm.tsx'))).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
it('populates directory children correctly', async () => {
|
|
46
|
+
const tree = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx', '.js', '.py'], []);
|
|
47
|
+
// Navigate to src/components
|
|
48
|
+
const src = tree.root?.children?.get('src');
|
|
49
|
+
expect(src).toBeDefined();
|
|
50
|
+
expect(src?.type).toBe('directory');
|
|
51
|
+
const components = src?.children?.get('components');
|
|
52
|
+
expect(components).toBeDefined();
|
|
53
|
+
expect(components?.type).toBe('directory');
|
|
54
|
+
// Should have Button.tsx, Input.tsx, and forms/ as children
|
|
55
|
+
expect(components?.children?.size).toBeGreaterThanOrEqual(2);
|
|
56
|
+
// Check Button.tsx is a child
|
|
57
|
+
const button = components?.children?.get('Button.tsx');
|
|
58
|
+
expect(button).toBeDefined();
|
|
59
|
+
expect(button?.type).toBe('file');
|
|
60
|
+
});
|
|
61
|
+
it('handles 4+ levels of nesting', async () => {
|
|
62
|
+
const tree = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx', '.js', '.py'], []);
|
|
63
|
+
// Navigate: src → utils → deep → nested → file.ts
|
|
64
|
+
const src = tree.root?.children?.get('src');
|
|
65
|
+
expect(src).toBeDefined();
|
|
66
|
+
const utils = src?.children?.get('utils');
|
|
67
|
+
expect(utils).toBeDefined();
|
|
68
|
+
const deep = utils?.children?.get('deep');
|
|
69
|
+
expect(deep).toBeDefined();
|
|
70
|
+
const nested = deep?.children?.get('nested');
|
|
71
|
+
expect(nested).toBeDefined();
|
|
72
|
+
const file = nested?.children?.get('file.ts');
|
|
73
|
+
expect(file).toBeDefined();
|
|
74
|
+
expect(file?.type).toBe('file');
|
|
75
|
+
expect(file?.path).toBe('src/utils/deep/nested/file.ts');
|
|
76
|
+
});
|
|
77
|
+
it('handles multiple siblings at each level', async () => {
|
|
78
|
+
const tree = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx', '.js', '.py'], []);
|
|
79
|
+
// src/services should have api.ts AND auth.ts
|
|
80
|
+
const services = tree.root?.children
|
|
81
|
+
?.get('src')
|
|
82
|
+
?.children?.get('services');
|
|
83
|
+
expect(services?.children?.has('api.ts')).toBe(true);
|
|
84
|
+
expect(services?.children?.has('auth.ts')).toBe(true);
|
|
85
|
+
// Root should have src/ AND lib/
|
|
86
|
+
expect(tree.root?.children?.has('src')).toBe(true);
|
|
87
|
+
expect(tree.root?.children?.has('lib')).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe('Tree diffing', () => {
|
|
91
|
+
it('detects new file in subdirectory', async () => {
|
|
92
|
+
const tree1 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], []);
|
|
93
|
+
await addFile(ctx.projectRoot, 'src/utils/newHelper.ts', 'export const x = 1;');
|
|
94
|
+
await waitForFs();
|
|
95
|
+
const tree2 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], [], tree1);
|
|
96
|
+
const diff = tree1.compare(tree2);
|
|
97
|
+
expect(diff.new).toContain('src/utils/newHelper.ts');
|
|
98
|
+
expect(diff.modified.length).toBe(0);
|
|
99
|
+
expect(diff.deleted.length).toBe(0);
|
|
100
|
+
});
|
|
101
|
+
it('detects modified file in deeply nested directory', async () => {
|
|
102
|
+
const tree1 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], []);
|
|
103
|
+
await modifyFile(ctx.projectRoot, 'src/utils/deep/nested/file.ts', '// changed\nexport const y = 2;');
|
|
104
|
+
await waitForFs();
|
|
105
|
+
const tree2 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], [], tree1);
|
|
106
|
+
const diff = tree1.compare(tree2);
|
|
107
|
+
expect(diff.modified).toContain('src/utils/deep/nested/file.ts');
|
|
108
|
+
});
|
|
109
|
+
it('detects deleted file from subdirectory', async () => {
|
|
110
|
+
const tree1 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], []);
|
|
111
|
+
await deleteFile(ctx.projectRoot, 'src/components/Input.tsx');
|
|
112
|
+
await waitForFs();
|
|
113
|
+
const tree2 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], [], tree1);
|
|
114
|
+
const diff = tree1.compare(tree2);
|
|
115
|
+
expect(diff.deleted).toContain('src/components/Input.tsx');
|
|
116
|
+
});
|
|
117
|
+
it('detects new directory with files', async () => {
|
|
118
|
+
const tree1 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], []);
|
|
119
|
+
// Add new directory with multiple files
|
|
120
|
+
await addFile(ctx.projectRoot, 'src/newDir/a.ts', 'export const a = 1;');
|
|
121
|
+
await addFile(ctx.projectRoot, 'src/newDir/b.ts', 'export const b = 2;');
|
|
122
|
+
await waitForFs();
|
|
123
|
+
const tree2 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], [], tree1);
|
|
124
|
+
const diff = tree1.compare(tree2);
|
|
125
|
+
expect(diff.new).toContain('src/newDir/a.ts');
|
|
126
|
+
expect(diff.new).toContain('src/newDir/b.ts');
|
|
127
|
+
});
|
|
128
|
+
it('directory hash changes when child file changes', async () => {
|
|
129
|
+
const tree1 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], []);
|
|
130
|
+
const srcHash1 = tree1.root?.children?.get('src')?.hash;
|
|
131
|
+
const utilsHash1 = tree1.root?.children
|
|
132
|
+
?.get('src')
|
|
133
|
+
?.children?.get('utils')?.hash;
|
|
134
|
+
await modifyFile(ctx.projectRoot, 'src/utils/helpers.ts', '// changed');
|
|
135
|
+
await waitForFs();
|
|
136
|
+
const tree2 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], []);
|
|
137
|
+
const srcHash2 = tree2.root?.children?.get('src')?.hash;
|
|
138
|
+
const utilsHash2 = tree2.root?.children
|
|
139
|
+
?.get('src')
|
|
140
|
+
?.children?.get('utils')?.hash;
|
|
141
|
+
// Both parent directories should have different hashes
|
|
142
|
+
expect(utilsHash2).not.toBe(utilsHash1);
|
|
143
|
+
expect(srcHash2).not.toBe(srcHash1);
|
|
144
|
+
});
|
|
145
|
+
it('sibling directory hash unchanged when other sibling changes', async () => {
|
|
146
|
+
const tree1 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], []);
|
|
147
|
+
const servicesHash1 = tree1.root?.children
|
|
148
|
+
?.get('src')
|
|
149
|
+
?.children?.get('services')?.hash;
|
|
150
|
+
// Modify file in utils (sibling of services)
|
|
151
|
+
await modifyFile(ctx.projectRoot, 'src/utils/helpers.ts', '// changed');
|
|
152
|
+
await waitForFs();
|
|
153
|
+
const tree2 = await MerkleTree.build(ctx.projectRoot, ['.ts', '.tsx'], []);
|
|
154
|
+
const servicesHash2 = tree2.root?.children
|
|
155
|
+
?.get('src')
|
|
156
|
+
?.children?.get('services')?.hash;
|
|
157
|
+
// Services hash should be unchanged
|
|
158
|
+
expect(servicesHash2).toBe(servicesHash1);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for metadata extraction.
|
|
3
|
+
*
|
|
4
|
+
* Tests that the Chunker correctly extracts:
|
|
5
|
+
* - signature: Function/method signature lines
|
|
6
|
+
* - docstring: JSDoc/Python docstrings
|
|
7
|
+
* - is_exported: Export keyword detection
|
|
8
|
+
* - decorator_names: Decorator/annotation extraction
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for metadata extraction.
|
|
3
|
+
*
|
|
4
|
+
* Tests that the Chunker correctly extracts:
|
|
5
|
+
* - signature: Function/method signature lines
|
|
6
|
+
* - docstring: JSDoc/Python docstrings
|
|
7
|
+
* - is_exported: Export keyword detection
|
|
8
|
+
* - decorator_names: Decorator/annotation extraction
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
11
|
+
import { Indexer } from '../indexer/indexer.js';
|
|
12
|
+
import { SearchEngine } from '../search/index.js';
|
|
13
|
+
import { copyFixtureToTemp } from './helpers.js';
|
|
14
|
+
describe('Metadata Extraction', () => {
|
|
15
|
+
let ctx;
|
|
16
|
+
let search;
|
|
17
|
+
beforeAll(async () => {
|
|
18
|
+
// Setup once - index the codebase
|
|
19
|
+
ctx = await copyFixtureToTemp('codebase');
|
|
20
|
+
const indexer = new Indexer(ctx.projectRoot);
|
|
21
|
+
await indexer.index();
|
|
22
|
+
indexer.close();
|
|
23
|
+
search = new SearchEngine(ctx.projectRoot);
|
|
24
|
+
}, 120000);
|
|
25
|
+
afterAll(async () => {
|
|
26
|
+
search.close();
|
|
27
|
+
await ctx.cleanup();
|
|
28
|
+
});
|
|
29
|
+
describe('signature extraction', () => {
|
|
30
|
+
it('extracts TypeScript function signature', async () => {
|
|
31
|
+
const results = await search.search('getUser', {
|
|
32
|
+
mode: 'definition',
|
|
33
|
+
symbolName: 'getUser',
|
|
34
|
+
});
|
|
35
|
+
expect(results.results.length).toBeGreaterThan(0);
|
|
36
|
+
const result = results.results[0];
|
|
37
|
+
// Signature should contain the function declaration
|
|
38
|
+
if (result?.signature) {
|
|
39
|
+
expect(result.signature).toContain('getUser');
|
|
40
|
+
}
|
|
41
|
+
}, 60000);
|
|
42
|
+
it('extracts Python function signature', async () => {
|
|
43
|
+
const results = await search.search('add_two_numbers', {
|
|
44
|
+
mode: 'definition',
|
|
45
|
+
symbolName: 'add_two_numbers',
|
|
46
|
+
});
|
|
47
|
+
if (results.results.length > 0) {
|
|
48
|
+
const result = results.results[0];
|
|
49
|
+
if (result?.signature) {
|
|
50
|
+
expect(result.signature).toContain('add_two_numbers');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}, 60000);
|
|
54
|
+
it('extracts class signature', async () => {
|
|
55
|
+
// Use semantic search with class filter
|
|
56
|
+
const results = await search.search('UserService class service', {
|
|
57
|
+
mode: 'semantic',
|
|
58
|
+
filters: { type: ['class'] },
|
|
59
|
+
});
|
|
60
|
+
// Should find some classes with signatures
|
|
61
|
+
if (results.results.length > 0) {
|
|
62
|
+
const classResult = results.results.find(r => r.type === 'class');
|
|
63
|
+
if (classResult?.signature) {
|
|
64
|
+
expect(classResult.signature).toContain('class');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}, 60000);
|
|
68
|
+
});
|
|
69
|
+
describe('export detection', () => {
|
|
70
|
+
it('detects exported functions', async () => {
|
|
71
|
+
// Search for exported function in exported.ts
|
|
72
|
+
const results = await search.search('publicUtil', {
|
|
73
|
+
mode: 'definition',
|
|
74
|
+
symbolName: 'publicUtil',
|
|
75
|
+
});
|
|
76
|
+
expect(results.results.length).toBeGreaterThan(0);
|
|
77
|
+
const result = results.results.find(r => r.filepath.includes('exported.ts'));
|
|
78
|
+
expect(result?.isExported).toBe(true);
|
|
79
|
+
}, 60000);
|
|
80
|
+
it('detects non-exported functions', async () => {
|
|
81
|
+
// Search for internal helper in exported.ts
|
|
82
|
+
const results = await search.search('internalHelper', {
|
|
83
|
+
mode: 'definition',
|
|
84
|
+
symbolName: 'internalHelper',
|
|
85
|
+
});
|
|
86
|
+
if (results.results.length > 0) {
|
|
87
|
+
const result = results.results.find(r => r.filepath.includes('exported.ts'));
|
|
88
|
+
if (result) {
|
|
89
|
+
expect(result.isExported).toBe(false);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}, 60000);
|
|
93
|
+
it('detects exported classes', async () => {
|
|
94
|
+
// Use semantic search with export filter
|
|
95
|
+
const results = await search.search('class service user', {
|
|
96
|
+
mode: 'semantic',
|
|
97
|
+
filters: {
|
|
98
|
+
type: ['class'],
|
|
99
|
+
isExported: true,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
// Should find exported classes
|
|
103
|
+
if (results.results.length > 0) {
|
|
104
|
+
results.results.forEach(r => {
|
|
105
|
+
expect(r.isExported).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}, 60000);
|
|
109
|
+
it('filters work with isExported', async () => {
|
|
110
|
+
// Get only exported symbols
|
|
111
|
+
const exportedResults = await search.search('user', {
|
|
112
|
+
filters: { isExported: true },
|
|
113
|
+
});
|
|
114
|
+
// All should be exported
|
|
115
|
+
exportedResults.results.forEach(r => {
|
|
116
|
+
expect(r.isExported).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
// Get non-exported
|
|
119
|
+
const internalResults = await search.search('helper', {
|
|
120
|
+
filters: { isExported: false },
|
|
121
|
+
});
|
|
122
|
+
// All should NOT be exported
|
|
123
|
+
internalResults.results.forEach(r => {
|
|
124
|
+
expect(r.isExported).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
}, 60000);
|
|
127
|
+
});
|
|
128
|
+
describe('docstring extraction', () => {
|
|
129
|
+
it('finds documented functions via hasDocstring filter', async () => {
|
|
130
|
+
const results = await search.search('process', {
|
|
131
|
+
filters: { hasDocstring: true },
|
|
132
|
+
});
|
|
133
|
+
// Should find documented functions
|
|
134
|
+
expect(results.results.length).toBeGreaterThan(0);
|
|
135
|
+
}, 60000);
|
|
136
|
+
it('documented Python functions are findable', async () => {
|
|
137
|
+
// process_data in decorators.py has a docstring
|
|
138
|
+
const results = await search.search('process_data', {
|
|
139
|
+
mode: 'definition',
|
|
140
|
+
symbolName: 'process_data',
|
|
141
|
+
});
|
|
142
|
+
if (results.results.length > 0) {
|
|
143
|
+
const result = results.results.find(r => r.filepath.includes('decorators.py'));
|
|
144
|
+
// The function should be found
|
|
145
|
+
expect(result).toBeDefined();
|
|
146
|
+
}
|
|
147
|
+
}, 60000);
|
|
148
|
+
});
|
|
149
|
+
describe('decorator extraction', () => {
|
|
150
|
+
it('finds decorated Python functions', async () => {
|
|
151
|
+
// Search semantically for Python functions in decorators file
|
|
152
|
+
const results = await search.search('process data logging decorator python', {
|
|
153
|
+
mode: 'semantic',
|
|
154
|
+
filters: { extension: ['.py'] },
|
|
155
|
+
});
|
|
156
|
+
// Should find functions from decorators.py
|
|
157
|
+
if (results.results.length > 0) {
|
|
158
|
+
expect(results.results.some(r => r.filepath.includes('decorators.py'))).toBe(true);
|
|
159
|
+
}
|
|
160
|
+
}, 60000);
|
|
161
|
+
it('decoratorContains filter works', async () => {
|
|
162
|
+
const results = await search.search('function', {
|
|
163
|
+
filters: { decoratorContains: 'log' },
|
|
164
|
+
});
|
|
165
|
+
// Should find functions with 'log' in decorator names
|
|
166
|
+
// Results may be empty if extraction isn't working, but filter should not error
|
|
167
|
+
expect(results).toBeDefined();
|
|
168
|
+
}, 60000);
|
|
169
|
+
it('finds functions with multiple decorators', async () => {
|
|
170
|
+
// Search for transform function in Python files
|
|
171
|
+
const results = await search.search('transform value validate input', {
|
|
172
|
+
mode: 'semantic',
|
|
173
|
+
filters: { extension: ['.py'] },
|
|
174
|
+
});
|
|
175
|
+
// Should find functions from decorators.py
|
|
176
|
+
if (results.results.length > 0) {
|
|
177
|
+
expect(results.results.some(r => r.filepath.includes('.py'))).toBe(true);
|
|
178
|
+
}
|
|
179
|
+
}, 60000);
|
|
180
|
+
});
|
|
181
|
+
describe('metadata in search results', () => {
|
|
182
|
+
it('includes signature in results when available', async () => {
|
|
183
|
+
const results = await search.search('async function fetch', {
|
|
184
|
+
mode: 'semantic',
|
|
185
|
+
limit: 5,
|
|
186
|
+
});
|
|
187
|
+
// At least some results should have signatures
|
|
188
|
+
const withSignature = results.results.filter(r => r.signature);
|
|
189
|
+
expect(withSignature.length).toBeGreaterThan(0);
|
|
190
|
+
}, 60000);
|
|
191
|
+
it('includes isExported in results', async () => {
|
|
192
|
+
const results = await search.search('export function', {
|
|
193
|
+
mode: 'semantic',
|
|
194
|
+
limit: 10,
|
|
195
|
+
});
|
|
196
|
+
// Results should have isExported defined
|
|
197
|
+
results.results.forEach(r => {
|
|
198
|
+
expect(typeof r.isExported).toBe('boolean');
|
|
199
|
+
});
|
|
200
|
+
}, 60000);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Language Support Tests.
|
|
3
|
+
*
|
|
4
|
+
* Tests that the indexer correctly handles 8 additional languages:
|
|
5
|
+
* - Go, Rust, Java, C#, Dart, Swift, Kotlin, PHP
|
|
6
|
+
*
|
|
7
|
+
* Validates:
|
|
8
|
+
* - Export detection (capitalization, pub, public, underscore prefix)
|
|
9
|
+
* - Decorator/attribute extraction (#[], @, [])
|
|
10
|
+
* - Docstring extraction (various comment styles)
|
|
11
|
+
* - Cross-language search capabilities
|
|
12
|
+
*/
|
|
13
|
+
export {};
|