edhindex 1.0.2 → 1.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/README.md +43 -9
- package/dist/cli/commands/index_cmd.d.ts.map +1 -1
- package/dist/cli/commands/index_cmd.js +2 -0
- package/dist/cli/commands/index_cmd.js.map +1 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +3 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/graph/builder.d.ts.map +1 -1
- package/dist/graph/builder.js +5 -0
- package/dist/graph/builder.js.map +1 -1
- package/dist/indexer/chunker.d.ts +2 -2
- package/dist/indexer/chunker.d.ts.map +1 -1
- package/dist/indexer/chunker.js +7 -5
- package/dist/indexer/chunker.js.map +1 -1
- package/dist/indexer/file-utils.d.ts +2 -3
- package/dist/indexer/file-utils.d.ts.map +1 -1
- package/dist/indexer/file-utils.js +4 -33
- package/dist/indexer/file-utils.js.map +1 -1
- package/dist/indexer/fixture.test.d.ts +2 -0
- package/dist/indexer/fixture.test.d.ts.map +1 -0
- package/dist/indexer/fixture.test.js +104 -0
- package/dist/indexer/fixture.test.js.map +1 -0
- package/dist/indexer/indexer.d.ts +3 -1
- package/dist/indexer/indexer.d.ts.map +1 -1
- package/dist/indexer/indexer.js +8 -32
- package/dist/indexer/indexer.js.map +1 -1
- package/dist/indexer/parser.d.ts.map +1 -1
- package/dist/indexer/parser.js +196 -14
- package/dist/indexer/parser.js.map +1 -1
- package/dist/indexer/parser.test.d.ts +2 -0
- package/dist/indexer/parser.test.d.ts.map +1 -0
- package/dist/indexer/parser.test.js +120 -0
- package/dist/indexer/parser.test.js.map +1 -0
- package/dist/language/adapters/c.d.ts +7 -0
- package/dist/language/adapters/c.d.ts.map +1 -0
- package/dist/language/adapters/c.js +25 -0
- package/dist/language/adapters/c.js.map +1 -0
- package/dist/language/adapters/cpp.d.ts +7 -0
- package/dist/language/adapters/cpp.d.ts.map +1 -0
- package/dist/language/adapters/cpp.js +29 -0
- package/dist/language/adapters/cpp.js.map +1 -0
- package/dist/language/adapters/csharp.d.ts +7 -0
- package/dist/language/adapters/csharp.d.ts.map +1 -0
- package/dist/language/adapters/csharp.js +32 -0
- package/dist/language/adapters/csharp.js.map +1 -0
- package/dist/language/adapters/css.d.ts +10 -0
- package/dist/language/adapters/css.d.ts.map +1 -0
- package/dist/language/adapters/css.js +54 -0
- package/dist/language/adapters/css.js.map +1 -0
- package/dist/language/adapters/go.d.ts +7 -0
- package/dist/language/adapters/go.d.ts.map +1 -0
- package/dist/language/adapters/go.js +26 -0
- package/dist/language/adapters/go.js.map +1 -0
- package/dist/language/adapters/html.d.ts +11 -0
- package/dist/language/adapters/html.d.ts.map +1 -0
- package/dist/language/adapters/html.js +67 -0
- package/dist/language/adapters/html.js.map +1 -0
- package/dist/language/adapters/java.d.ts +7 -0
- package/dist/language/adapters/java.d.ts.map +1 -0
- package/dist/language/adapters/java.js +30 -0
- package/dist/language/adapters/java.js.map +1 -0
- package/dist/language/adapters/javascript.d.ts +7 -0
- package/dist/language/adapters/javascript.d.ts.map +1 -0
- package/dist/language/adapters/javascript.js +31 -0
- package/dist/language/adapters/javascript.js.map +1 -0
- package/dist/language/adapters/json.d.ts +11 -0
- package/dist/language/adapters/json.d.ts.map +1 -0
- package/dist/language/adapters/json.js +57 -0
- package/dist/language/adapters/json.js.map +1 -0
- package/dist/language/adapters/php.d.ts +7 -0
- package/dist/language/adapters/php.d.ts.map +1 -0
- package/dist/language/adapters/php.js +29 -0
- package/dist/language/adapters/php.js.map +1 -0
- package/dist/language/adapters/python.d.ts +7 -0
- package/dist/language/adapters/python.d.ts.map +1 -0
- package/dist/language/adapters/python.js +27 -0
- package/dist/language/adapters/python.js.map +1 -0
- package/dist/language/adapters/ruby.d.ts +7 -0
- package/dist/language/adapters/ruby.d.ts.map +1 -0
- package/dist/language/adapters/ruby.js +29 -0
- package/dist/language/adapters/ruby.js.map +1 -0
- package/dist/language/adapters/rust.d.ts +7 -0
- package/dist/language/adapters/rust.d.ts.map +1 -0
- package/dist/language/adapters/rust.js +31 -0
- package/dist/language/adapters/rust.js.map +1 -0
- package/dist/language/adapters/typescript.d.ts +7 -0
- package/dist/language/adapters/typescript.d.ts.map +1 -0
- package/dist/language/adapters/typescript.js +35 -0
- package/dist/language/adapters/typescript.js.map +1 -0
- package/dist/language/base.d.ts +34 -0
- package/dist/language/base.d.ts.map +1 -0
- package/dist/language/base.js +144 -0
- package/dist/language/base.js.map +1 -0
- package/dist/language/generic.d.ts +11 -0
- package/dist/language/generic.d.ts.map +1 -0
- package/dist/language/generic.js +51 -0
- package/dist/language/generic.js.map +1 -0
- package/dist/language/registry.d.ts +29 -0
- package/dist/language/registry.d.ts.map +1 -0
- package/dist/language/registry.js +111 -0
- package/dist/language/registry.js.map +1 -0
- package/dist/language/types.d.ts +55 -0
- package/dist/language/types.d.ts.map +1 -0
- package/dist/language/types.js +23 -0
- package/dist/language/types.js.map +1 -0
- package/package.json +19 -3
- package/src/cli/commands/index_cmd.ts +2 -0
- package/src/cli/commands/start.ts +3 -1
- package/src/config/index.ts +1 -1
- package/src/graph/builder.ts +5 -0
- package/src/indexer/chunker.ts +9 -7
- package/src/indexer/file-utils.ts +6 -38
- package/src/indexer/fixture.test.ts +121 -0
- package/src/indexer/indexer.ts +17 -41
- package/src/indexer/parser.test.ts +127 -0
- package/src/indexer/parser.ts +194 -13
- package/src/language/adapters/c.ts +27 -0
- package/src/language/adapters/cpp.ts +31 -0
- package/src/language/adapters/csharp.ts +34 -0
- package/src/language/adapters/css.ts +57 -0
- package/src/language/adapters/go.ts +28 -0
- package/src/language/adapters/html.ts +68 -0
- package/src/language/adapters/java.ts +32 -0
- package/src/language/adapters/javascript.ts +33 -0
- package/src/language/adapters/json.ts +60 -0
- package/src/language/adapters/php.ts +31 -0
- package/src/language/adapters/python.ts +29 -0
- package/src/language/adapters/ruby.ts +31 -0
- package/src/language/adapters/rust.ts +33 -0
- package/src/language/adapters/typescript.ts +37 -0
- package/src/language/base.ts +167 -0
- package/src/language/generic.ts +58 -0
- package/src/language/registry.ts +126 -0
- package/src/language/types.ts +58 -0
package/src/indexer/indexer.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { readFileSync
|
|
2
|
-
import { join } from 'node:path';
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
3
2
|
import { logger } from '../logging.js';
|
|
4
3
|
import { emitProgress } from '../progress.js';
|
|
5
|
-
import { Config
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
4
|
+
import { Config } from '../config/index.js';
|
|
5
|
+
import { LanguageRegistry } from '../language/registry.js';
|
|
6
|
+
import { SymbolType } from '../language/types.js';
|
|
7
|
+
import { scanFiles, computeFileHash, ScannedFile } from './file-utils.js';
|
|
9
8
|
import { Chunk, chunkFile } from './chunker.js';
|
|
10
|
-
import { computeFileDelta
|
|
9
|
+
import { computeFileDelta } from './incremental.js';
|
|
11
10
|
|
|
12
11
|
export interface IndexFileResult {
|
|
13
12
|
chunks: Chunk[];
|
|
@@ -23,6 +22,7 @@ export interface IndexerOptions {
|
|
|
23
22
|
config: Config;
|
|
24
23
|
rootPath: string;
|
|
25
24
|
indexDir: string;
|
|
25
|
+
registry: LanguageRegistry;
|
|
26
26
|
onIndex: IndexCallback;
|
|
27
27
|
onDelete?: DeleteCallback;
|
|
28
28
|
signal?: AbortSignal;
|
|
@@ -32,44 +32,29 @@ export class Indexer {
|
|
|
32
32
|
private config: Config;
|
|
33
33
|
private rootPath: string;
|
|
34
34
|
private indexDir: string;
|
|
35
|
+
private registry: LanguageRegistry;
|
|
35
36
|
private onIndex: IndexCallback;
|
|
36
37
|
private onDelete?: DeleteCallback;
|
|
37
38
|
private signal: AbortSignal;
|
|
38
|
-
private extToLang: Map<string, string>;
|
|
39
39
|
|
|
40
40
|
constructor(opts: IndexerOptions) {
|
|
41
41
|
this.config = opts.config;
|
|
42
42
|
this.rootPath = opts.rootPath;
|
|
43
43
|
this.indexDir = opts.indexDir;
|
|
44
|
+
this.registry = opts.registry;
|
|
44
45
|
this.onIndex = opts.onIndex;
|
|
45
46
|
this.onDelete = opts.onDelete;
|
|
46
47
|
this.signal = opts.signal || new AbortController().signal;
|
|
47
|
-
|
|
48
|
-
this.extToLang = new Map();
|
|
49
|
-
for (const lang of this.config.languages) {
|
|
50
|
-
const exts = LANG_EXTENSIONS[lang] || [];
|
|
51
|
-
for (const ext of exts) {
|
|
52
|
-
this.extToLang.set(ext, lang);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
48
|
}
|
|
56
49
|
|
|
57
50
|
async initialize() {
|
|
58
|
-
await
|
|
59
|
-
for (const lang of this.config.languages) {
|
|
60
|
-
try {
|
|
61
|
-
await loadLanguage(lang);
|
|
62
|
-
logger.verbose(`Loaded tree-sitter grammar for ${lang}`);
|
|
63
|
-
} catch (e) {
|
|
64
|
-
logger.error(`Failed to load tree-sitter grammar for ${lang}:`, e);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
51
|
+
await this.registry.initialize(this.config.languages);
|
|
67
52
|
}
|
|
68
53
|
|
|
69
54
|
async runFullIndex(): Promise<Chunk[]> {
|
|
70
55
|
emitProgress({ phase: 'scanning', current: 0, total: 0 });
|
|
71
56
|
|
|
72
|
-
const files = scanFiles(this.rootPath, this.
|
|
57
|
+
const files = scanFiles(this.rootPath, this.registry);
|
|
73
58
|
const allChunks: Chunk[] = [];
|
|
74
59
|
let processed = 0;
|
|
75
60
|
|
|
@@ -103,7 +88,7 @@ export class Indexer {
|
|
|
103
88
|
): Promise<{ chunks: Chunk[]; removed: string[] }> {
|
|
104
89
|
emitProgress({ phase: 'scanning', current: 0, total: 0 });
|
|
105
90
|
|
|
106
|
-
const scannedFiles = scanFiles(this.rootPath, this.
|
|
91
|
+
const scannedFiles = scanFiles(this.rootPath, this.registry);
|
|
107
92
|
const scannedMap = new Map(scannedFiles.map(f => [f.relativePath, f]));
|
|
108
93
|
const delta = computeFileDelta(scannedMap, existingFileHashes);
|
|
109
94
|
|
|
@@ -155,27 +140,18 @@ export class Indexer {
|
|
|
155
140
|
const content = readFileSync(filePath, 'utf-8');
|
|
156
141
|
const lines = content.split('\n');
|
|
157
142
|
|
|
158
|
-
const {
|
|
159
|
-
const
|
|
160
|
-
const imports = extractImports(tree, language);
|
|
161
|
-
const exports = extractExports(tree, language);
|
|
143
|
+
const { adapter } = this.registry.getAdapter(relativePath);
|
|
144
|
+
const result = await adapter.parse(content, relativePath);
|
|
162
145
|
|
|
163
146
|
return chunkFile(
|
|
164
147
|
filePath,
|
|
165
148
|
relativePath,
|
|
166
149
|
language,
|
|
167
|
-
symbols,
|
|
150
|
+
result.symbols,
|
|
168
151
|
content,
|
|
169
152
|
lines,
|
|
170
|
-
imports,
|
|
171
|
-
exports,
|
|
153
|
+
result.imports,
|
|
154
|
+
result.exports,
|
|
172
155
|
);
|
|
173
156
|
}
|
|
174
157
|
}
|
|
175
|
-
|
|
176
|
-
const LANG_EXTENSIONS: Record<string, string[]> = {
|
|
177
|
-
ts: ['.ts', '.tsx', '.mts', '.cts'],
|
|
178
|
-
js: ['.js', '.jsx', '.mjs', '.cjs'],
|
|
179
|
-
py: ['.py', '.pyw'],
|
|
180
|
-
go: ['.go'],
|
|
181
|
-
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
2
|
+
import { LanguageRegistry } from '../language/registry.js';
|
|
3
|
+
|
|
4
|
+
const registry = new LanguageRegistry();
|
|
5
|
+
const adapters = registry.getInfoList().filter(a => a.key !== 'generic');
|
|
6
|
+
|
|
7
|
+
describe('Language Adapter Registry', () => {
|
|
8
|
+
it('registers all adapters', () => {
|
|
9
|
+
expect(adapters.length).toBeGreaterThan(0);
|
|
10
|
+
expect(adapters.find(a => a.key === 'ts')).toBeTruthy();
|
|
11
|
+
expect(adapters.find(a => a.key === 'py')).toBeTruthy();
|
|
12
|
+
expect(adapters.find(a => a.key === 'go')).toBeTruthy();
|
|
13
|
+
expect(adapters.find(a => a.key === 'rs')).toBeTruthy();
|
|
14
|
+
expect(adapters.find(a => a.key === 'java')).toBeTruthy();
|
|
15
|
+
expect(adapters.find(a => a.key === 'html')).toBeTruthy();
|
|
16
|
+
expect(adapters.find(a => a.key === 'css')).toBeTruthy();
|
|
17
|
+
expect(adapters.find(a => a.key === 'json')).toBeTruthy();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('maps file extensions to correct adapters', () => {
|
|
21
|
+
expect(registry.getAdapter('file.ts').key).toBe('ts');
|
|
22
|
+
expect(registry.getAdapter('file.js').key).toBe('js');
|
|
23
|
+
expect(registry.getAdapter('file.py').key).toBe('py');
|
|
24
|
+
expect(registry.getAdapter('file.go').key).toBe('go');
|
|
25
|
+
expect(registry.getAdapter('file.rs').key).toBe('rs');
|
|
26
|
+
expect(registry.getAdapter('file.java').key).toBe('java');
|
|
27
|
+
expect(registry.getAdapter('file.rb').key).toBe('rb');
|
|
28
|
+
expect(registry.getAdapter('file.c').key).toBe('c');
|
|
29
|
+
expect(registry.getAdapter('file.cpp').key).toBe('cpp');
|
|
30
|
+
expect(registry.getAdapter('file.cs').key).toBe('csharp');
|
|
31
|
+
expect(registry.getAdapter('file.php').key).toBe('php');
|
|
32
|
+
expect(registry.getAdapter('file.html').key).toBe('html');
|
|
33
|
+
expect(registry.getAdapter('file.css').key).toBe('css');
|
|
34
|
+
expect(registry.getAdapter('file.json').key).toBe('json');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('returns generic for unknown extensions', () => {
|
|
38
|
+
const { adapter, key } = registry.getAdapter('file.xyz');
|
|
39
|
+
expect(key).toBe('generic');
|
|
40
|
+
expect(adapter.languageName()).toBe('Generic');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const SAMPLES: Record<string, string> = {
|
|
45
|
+
ts: `import { readFileSync } from 'node:fs';
|
|
46
|
+
export interface Config { name: string }
|
|
47
|
+
export class App { start() {} }
|
|
48
|
+
function helper() {}`,
|
|
49
|
+
js: `const { join } = require('node:path');
|
|
50
|
+
class App { constructor() { this.name = 'app'; } }
|
|
51
|
+
function helper() {}`,
|
|
52
|
+
py: `import os
|
|
53
|
+
def hello(name):
|
|
54
|
+
pass
|
|
55
|
+
class App:
|
|
56
|
+
def start(self):
|
|
57
|
+
pass`,
|
|
58
|
+
go: `package main
|
|
59
|
+
import "fmt"
|
|
60
|
+
func hello() {}
|
|
61
|
+
func (a App) Start() {}`,
|
|
62
|
+
rs: `use std::fs;
|
|
63
|
+
pub struct User { name: String }
|
|
64
|
+
pub trait Runner { fn run(&self); }
|
|
65
|
+
pub fn hello() -> String { "hi".into() }
|
|
66
|
+
enum Color { Red, Green }`,
|
|
67
|
+
java: `import java.util.List;
|
|
68
|
+
public class App {
|
|
69
|
+
public void start() {}
|
|
70
|
+
public interface Handler { void handle(); }
|
|
71
|
+
}`,
|
|
72
|
+
rb: `require 'json'
|
|
73
|
+
module App
|
|
74
|
+
class User
|
|
75
|
+
def login; end
|
|
76
|
+
end
|
|
77
|
+
end`,
|
|
78
|
+
c: `#include <stdio.h>
|
|
79
|
+
struct Point { int x; int y; };
|
|
80
|
+
void hello() { printf("hi"); }`,
|
|
81
|
+
cpp: `#include <vector>
|
|
82
|
+
class App { void start() {} };
|
|
83
|
+
struct Point { int x; };
|
|
84
|
+
void hello() {}`,
|
|
85
|
+
csharp: `using System;
|
|
86
|
+
class App { void Start() {} }
|
|
87
|
+
interface IHandler { void Handle(); }`,
|
|
88
|
+
php: `<?php
|
|
89
|
+
function hello() {}
|
|
90
|
+
class App {
|
|
91
|
+
public function start() {}
|
|
92
|
+
}`,
|
|
93
|
+
json: `{ "name": "test", "version": "1.0.0" }`,
|
|
94
|
+
css: `.btn { color: red; }
|
|
95
|
+
#header { font-size: 16px; }`,
|
|
96
|
+
html: `<!DOCTYPE html><html><body><p>Hello</p></body></html>`,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
for (const info of adapters) {
|
|
100
|
+
const sample = SAMPLES[info.key];
|
|
101
|
+
if (!sample) continue;
|
|
102
|
+
|
|
103
|
+
describe(`${info.name} (${info.key})`, () => {
|
|
104
|
+
const { adapter } = registry.getAdapter(`file.${info.extensions[0]?.replace('.', '') || 'txt'}`);
|
|
105
|
+
|
|
106
|
+
it('parses content', async () => {
|
|
107
|
+
const result = await adapter.parse(sample, `file${info.extensions[0] || ''}`);
|
|
108
|
+
expect(result).toBeTruthy();
|
|
109
|
+
expect(Array.isArray(result.symbols)).toBe(true);
|
|
110
|
+
expect(Array.isArray(result.imports)).toBe(true);
|
|
111
|
+
expect(Array.isArray(result.exports)).toBe(true);
|
|
112
|
+
}, 30000);
|
|
113
|
+
|
|
114
|
+
if (info.supportsSymbols) {
|
|
115
|
+
it('extracts symbols', async () => {
|
|
116
|
+
const result = await adapter.parse(sample, `file${info.extensions[0] || ''}`);
|
|
117
|
+
expect(result.symbols.length).toBeGreaterThan(0);
|
|
118
|
+
for (const sym of result.symbols) {
|
|
119
|
+
expect(sym.name).toBeTruthy();
|
|
120
|
+
expect(sym.type).toBeTruthy();
|
|
121
|
+
expect(sym.startLine).toBeGreaterThan(0);
|
|
122
|
+
expect(sym.endLine).toBeGreaterThanOrEqual(sym.startLine);
|
|
123
|
+
}
|
|
124
|
+
}, 30000);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
package/src/indexer/parser.ts
CHANGED
|
@@ -44,6 +44,45 @@ export async function loadLanguage(language: string): Promise<any> {
|
|
|
44
44
|
case 'go':
|
|
45
45
|
wasmPath = require.resolve('tree-sitter-go/tree-sitter-go.wasm');
|
|
46
46
|
break;
|
|
47
|
+
case 'rs':
|
|
48
|
+
wasmPath = require.resolve('tree-sitter-rust/tree-sitter-rust.wasm');
|
|
49
|
+
break;
|
|
50
|
+
case 'java':
|
|
51
|
+
wasmPath = require.resolve('tree-sitter-java/tree-sitter-java.wasm');
|
|
52
|
+
break;
|
|
53
|
+
case 'rb':
|
|
54
|
+
wasmPath = require.resolve('tree-sitter-ruby/tree-sitter-ruby.wasm');
|
|
55
|
+
break;
|
|
56
|
+
case 'c':
|
|
57
|
+
wasmPath = require.resolve('tree-sitter-c/tree-sitter-c.wasm');
|
|
58
|
+
break;
|
|
59
|
+
case 'cpp':
|
|
60
|
+
wasmPath = require.resolve('tree-sitter-cpp/tree-sitter-cpp.wasm');
|
|
61
|
+
break;
|
|
62
|
+
case 'csharp':
|
|
63
|
+
wasmPath = require.resolve('tree-sitter-c-sharp/tree-sitter-c_sharp.wasm');
|
|
64
|
+
break;
|
|
65
|
+
case 'php':
|
|
66
|
+
wasmPath = require.resolve('tree-sitter-php/tree-sitter-php.wasm');
|
|
67
|
+
break;
|
|
68
|
+
case 'scala':
|
|
69
|
+
wasmPath = require.resolve('tree-sitter-scala/tree-sitter-scala.wasm');
|
|
70
|
+
break;
|
|
71
|
+
case 'hs':
|
|
72
|
+
wasmPath = require.resolve('tree-sitter-haskell/tree-sitter-haskell.wasm');
|
|
73
|
+
break;
|
|
74
|
+
case 'solidity':
|
|
75
|
+
wasmPath = require.resolve('tree-sitter-solidity/tree-sitter-solidity.wasm');
|
|
76
|
+
break;
|
|
77
|
+
case 'css':
|
|
78
|
+
wasmPath = require.resolve('tree-sitter-css/tree-sitter-css.wasm');
|
|
79
|
+
break;
|
|
80
|
+
case 'json':
|
|
81
|
+
wasmPath = require.resolve('tree-sitter-json/tree-sitter-json.wasm');
|
|
82
|
+
break;
|
|
83
|
+
case 'html':
|
|
84
|
+
wasmPath = require.resolve('tree-sitter-html/tree-sitter-html.wasm');
|
|
85
|
+
break;
|
|
47
86
|
default:
|
|
48
87
|
throw new Error(`Unsupported language: ${language}`);
|
|
49
88
|
}
|
|
@@ -55,7 +94,9 @@ export async function loadLanguage(language: string): Promise<any> {
|
|
|
55
94
|
}
|
|
56
95
|
|
|
57
96
|
function langKey(language: string): string {
|
|
58
|
-
|
|
97
|
+
if (language === 'ts' || language === 'js') return 'ts';
|
|
98
|
+
if (language === 'c' || language === 'cpp') return 'c-like';
|
|
99
|
+
return language;
|
|
59
100
|
}
|
|
60
101
|
|
|
61
102
|
export function parseFile(filePath: string, language: string): any {
|
|
@@ -136,6 +177,68 @@ const QUERY_PATTERNS: Record<string, Record<string, string>> = {
|
|
|
136
177
|
function: '(function_declaration name: (identifier) @name)',
|
|
137
178
|
method: '(method_declaration name: (field_identifier) @name)',
|
|
138
179
|
},
|
|
180
|
+
rs: {
|
|
181
|
+
function: '(function_item name: (identifier) @name)',
|
|
182
|
+
struct: '(struct_item name: (type_identifier) @name)',
|
|
183
|
+
trait: '(trait_item name: (type_identifier) @name)',
|
|
184
|
+
impl: '(impl_item trait: (type_identifier) @name)',
|
|
185
|
+
enum: '(enum_item name: (type_identifier) @name)',
|
|
186
|
+
},
|
|
187
|
+
java: {
|
|
188
|
+
method: '(method_declaration name: (identifier) @name)',
|
|
189
|
+
class: '(class_declaration name: (identifier) @name)',
|
|
190
|
+
interface: '(interface_declaration name: (identifier) @name)',
|
|
191
|
+
enum: '(enum_declaration name: (identifier) @name)',
|
|
192
|
+
},
|
|
193
|
+
rb: {
|
|
194
|
+
method: '(method name: (identifier) @name)',
|
|
195
|
+
class: '(class name: (constant) @name)',
|
|
196
|
+
module: '(module name: (constant) @name)',
|
|
197
|
+
},
|
|
198
|
+
c: {
|
|
199
|
+
function: '(function_definition declarator: (function_declarator declarator: (identifier) @name))',
|
|
200
|
+
struct: '(struct_specifier name: (type_identifier) @name)',
|
|
201
|
+
},
|
|
202
|
+
cpp: {
|
|
203
|
+
function: '(function_definition declarator: (function_declarator declarator: (identifier) @name))',
|
|
204
|
+
method: '(function_definition declarator: (function_declarator declarator: (field_identifier) @name))',
|
|
205
|
+
class: '(class_specifier name: (type_identifier) @name)',
|
|
206
|
+
struct: '(struct_specifier name: (type_identifier) @name)',
|
|
207
|
+
enum: '(enum_specifier name: (type_identifier) @name)',
|
|
208
|
+
},
|
|
209
|
+
csharp: {
|
|
210
|
+
method: '(method_declaration name: (identifier) @name)',
|
|
211
|
+
class: '(class_declaration name: (identifier) @name)',
|
|
212
|
+
interface: '(interface_declaration name: (identifier) @name)',
|
|
213
|
+
struct: '(struct_declaration name: (identifier) @name)',
|
|
214
|
+
enum: '(enum_declaration name: (identifier) @name)',
|
|
215
|
+
},
|
|
216
|
+
php: {
|
|
217
|
+
function: '(function_definition name: (name) @name)',
|
|
218
|
+
method: '(method_declaration name: (name) @name)',
|
|
219
|
+
class: '(class_declaration name: (name) @name)',
|
|
220
|
+
interface: '(interface_declaration name: (name) @name)',
|
|
221
|
+
},
|
|
222
|
+
scala: {
|
|
223
|
+
function: '(function_definition name: (identifier) @name)',
|
|
224
|
+
class: '(class_definition name: (identifier) @name)',
|
|
225
|
+
trait: '(trait_definition name: (identifier) @name)',
|
|
226
|
+
object: '(object_definition name: (identifier) @name)',
|
|
227
|
+
enum: '(enum_definition name: (identifier) @name)',
|
|
228
|
+
},
|
|
229
|
+
hs: {
|
|
230
|
+
function: '(function name: (variable) @name)',
|
|
231
|
+
class: '(class name: (type) @name)',
|
|
232
|
+
},
|
|
233
|
+
solidity: {
|
|
234
|
+
function: '(function_definition name: (identifier) @name)',
|
|
235
|
+
event: '(event_definition name: (identifier) @name)',
|
|
236
|
+
error: '(error_definition name: (identifier) @name)',
|
|
237
|
+
modifier: '(modifier_definition name: (identifier) @name)',
|
|
238
|
+
},
|
|
239
|
+
css: {
|
|
240
|
+
rule: '(rule_set selectors: (selectors) @name)',
|
|
241
|
+
},
|
|
139
242
|
};
|
|
140
243
|
|
|
141
244
|
export function extractSymbols(tree: any, language: string): SymbolInfo[] {
|
|
@@ -191,6 +294,87 @@ function nodeTypeToKind(type: string, language: string): SymbolInfo['kind'] | nu
|
|
|
191
294
|
case 'method_declaration': return 'method';
|
|
192
295
|
default: return null;
|
|
193
296
|
}
|
|
297
|
+
case 'rs':
|
|
298
|
+
switch (type) {
|
|
299
|
+
case 'function_item': return 'function';
|
|
300
|
+
case 'struct_item': return 'class';
|
|
301
|
+
case 'trait_item': return 'interface';
|
|
302
|
+
case 'impl_item': return 'module';
|
|
303
|
+
case 'enum_item': return 'enum';
|
|
304
|
+
default: return null;
|
|
305
|
+
}
|
|
306
|
+
case 'java':
|
|
307
|
+
switch (type) {
|
|
308
|
+
case 'method_declaration': return 'method';
|
|
309
|
+
case 'class_declaration': return 'class';
|
|
310
|
+
case 'interface_declaration': return 'interface';
|
|
311
|
+
case 'enum_declaration': return 'enum';
|
|
312
|
+
default: return null;
|
|
313
|
+
}
|
|
314
|
+
case 'rb':
|
|
315
|
+
switch (type) {
|
|
316
|
+
case 'method': return 'method';
|
|
317
|
+
case 'class': return 'class';
|
|
318
|
+
case 'module': return 'module';
|
|
319
|
+
default: return null;
|
|
320
|
+
}
|
|
321
|
+
case 'c':
|
|
322
|
+
switch (type) {
|
|
323
|
+
case 'function_definition': return 'function';
|
|
324
|
+
case 'struct_specifier': return 'class';
|
|
325
|
+
default: return null;
|
|
326
|
+
}
|
|
327
|
+
case 'cpp':
|
|
328
|
+
switch (type) {
|
|
329
|
+
case 'function_definition': return 'function';
|
|
330
|
+
case 'class_specifier': return 'class';
|
|
331
|
+
case 'struct_specifier': return 'class';
|
|
332
|
+
case 'enum_specifier': return 'enum';
|
|
333
|
+
default: return null;
|
|
334
|
+
}
|
|
335
|
+
case 'csharp':
|
|
336
|
+
switch (type) {
|
|
337
|
+
case 'method_declaration': return 'method';
|
|
338
|
+
case 'class_declaration': return 'class';
|
|
339
|
+
case 'interface_declaration': return 'interface';
|
|
340
|
+
case 'struct_declaration': return 'class';
|
|
341
|
+
case 'enum_declaration': return 'enum';
|
|
342
|
+
default: return null;
|
|
343
|
+
}
|
|
344
|
+
case 'php':
|
|
345
|
+
switch (type) {
|
|
346
|
+
case 'function_definition': return 'function';
|
|
347
|
+
case 'method_declaration': return 'method';
|
|
348
|
+
case 'class_declaration': return 'class';
|
|
349
|
+
case 'interface_declaration': return 'interface';
|
|
350
|
+
default: return null;
|
|
351
|
+
}
|
|
352
|
+
case 'scala':
|
|
353
|
+
switch (type) {
|
|
354
|
+
case 'function_definition': return 'function';
|
|
355
|
+
case 'class_definition': return 'class';
|
|
356
|
+
case 'trait_definition': return 'interface';
|
|
357
|
+
case 'object_definition': return 'module';
|
|
358
|
+
case 'enum_definition': return 'enum';
|
|
359
|
+
default: return null;
|
|
360
|
+
}
|
|
361
|
+
case 'hs':
|
|
362
|
+
switch (type) {
|
|
363
|
+
case 'function': return 'function';
|
|
364
|
+
case 'class': return 'interface';
|
|
365
|
+
default: return null;
|
|
366
|
+
}
|
|
367
|
+
case 'solidity':
|
|
368
|
+
switch (type) {
|
|
369
|
+
case 'function_definition': return 'function';
|
|
370
|
+
case 'event_definition': return 'function';
|
|
371
|
+
case 'error_definition': return 'function';
|
|
372
|
+
case 'modifier_definition': return 'method';
|
|
373
|
+
default: return null;
|
|
374
|
+
}
|
|
375
|
+
case 'css':
|
|
376
|
+
if (type === 'rule_set') return 'module';
|
|
377
|
+
return null;
|
|
194
378
|
default:
|
|
195
379
|
return null;
|
|
196
380
|
}
|
|
@@ -200,18 +384,15 @@ function extractName(node: any, language: string): string | null {
|
|
|
200
384
|
try {
|
|
201
385
|
for (let i = 0; i < node.childCount; i++) {
|
|
202
386
|
const child = node.child(i);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (child.type === 'identifier' || child.type === 'field_identifier') {
|
|
213
|
-
return child.text;
|
|
214
|
-
}
|
|
387
|
+
const nameTypes = new Set([
|
|
388
|
+
'identifier', 'property_identifier', 'type_identifier',
|
|
389
|
+
'field_identifier', 'constant', 'variable', 'name', 'type',
|
|
390
|
+
]);
|
|
391
|
+
if (nameTypes.has(child.type)) {
|
|
392
|
+
return child.text;
|
|
393
|
+
}
|
|
394
|
+
if (language === 'css' && child.type === 'selectors') {
|
|
395
|
+
return child.text?.split(',')[0]?.trim() || null;
|
|
215
396
|
}
|
|
216
397
|
}
|
|
217
398
|
} catch {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { BaseTreeSitterAdapter, GrammarConfig } from '../base.js';
|
|
3
|
+
import { SymbolType } from '../types.js';
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
const GRAMMAR: GrammarConfig = {
|
|
8
|
+
language: 'c',
|
|
9
|
+
wasmPath: require.resolve('tree-sitter-c/tree-sitter-c.wasm'),
|
|
10
|
+
queryPatterns: {
|
|
11
|
+
function_definition: '(function_definition declarator: (function_declarator declarator: (identifier) @name))',
|
|
12
|
+
struct_specifier: '(struct_specifier name: (type_identifier) @name)',
|
|
13
|
+
},
|
|
14
|
+
typeMap: {
|
|
15
|
+
function_definition: SymbolType.Function,
|
|
16
|
+
struct_specifier: SymbolType.Struct,
|
|
17
|
+
},
|
|
18
|
+
nameNodeTypes: ['identifier', 'type_identifier', 'field_identifier'],
|
|
19
|
+
importNodeTypes: ['preproc_include'],
|
|
20
|
+
exportNodeTypes: [],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export class CAdapter extends BaseTreeSitterAdapter {
|
|
24
|
+
protected grammar = GRAMMAR;
|
|
25
|
+
languageName(): string { return 'C'; }
|
|
26
|
+
fileExtensions(): string[] { return ['.c', '.h']; }
|
|
27
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { BaseTreeSitterAdapter, GrammarConfig } from '../base.js';
|
|
3
|
+
import { SymbolType } from '../types.js';
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
const GRAMMAR: GrammarConfig = {
|
|
8
|
+
language: 'cpp',
|
|
9
|
+
wasmPath: require.resolve('tree-sitter-cpp/tree-sitter-cpp.wasm'),
|
|
10
|
+
queryPatterns: {
|
|
11
|
+
function_definition: '(function_definition declarator: (function_declarator declarator: (identifier) @name))',
|
|
12
|
+
class_specifier: '(class_specifier name: (type_identifier) @name)',
|
|
13
|
+
struct_specifier: '(struct_specifier name: (type_identifier) @name)',
|
|
14
|
+
enum_specifier: '(enum_specifier name: (type_identifier) @name)',
|
|
15
|
+
},
|
|
16
|
+
typeMap: {
|
|
17
|
+
function_definition: SymbolType.Function,
|
|
18
|
+
class_specifier: SymbolType.Class,
|
|
19
|
+
struct_specifier: SymbolType.Struct,
|
|
20
|
+
enum_specifier: SymbolType.Enum,
|
|
21
|
+
},
|
|
22
|
+
nameNodeTypes: ['identifier', 'type_identifier', 'field_identifier'],
|
|
23
|
+
importNodeTypes: ['preproc_include', 'using_declaration'],
|
|
24
|
+
exportNodeTypes: [],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export class CppAdapter extends BaseTreeSitterAdapter {
|
|
28
|
+
protected grammar = GRAMMAR;
|
|
29
|
+
languageName(): string { return 'C++'; }
|
|
30
|
+
fileExtensions(): string[] { return ['.cpp', '.cxx', '.cc', '.c++', '.hpp', '.hxx', '.hh']; }
|
|
31
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { BaseTreeSitterAdapter, GrammarConfig } from '../base.js';
|
|
3
|
+
import { SymbolType } from '../types.js';
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
const GRAMMAR: GrammarConfig = {
|
|
8
|
+
language: 'csharp',
|
|
9
|
+
wasmPath: require.resolve('tree-sitter-c-sharp/tree-sitter-c_sharp.wasm'),
|
|
10
|
+
queryPatterns: {
|
|
11
|
+
method_declaration: '(method_declaration name: (identifier) @name)',
|
|
12
|
+
class_declaration: '(class_declaration name: (identifier) @name)',
|
|
13
|
+
interface_declaration: '(interface_declaration name: (identifier) @name)',
|
|
14
|
+
struct_declaration: '(struct_declaration name: (identifier) @name)',
|
|
15
|
+
enum_declaration: '(enum_declaration name: (identifier) @name)',
|
|
16
|
+
},
|
|
17
|
+
typeMap: {
|
|
18
|
+
method_declaration: SymbolType.Method,
|
|
19
|
+
class_declaration: SymbolType.Class,
|
|
20
|
+
interface_declaration: SymbolType.Interface,
|
|
21
|
+
struct_declaration: SymbolType.Struct,
|
|
22
|
+
enum_declaration: SymbolType.Enum,
|
|
23
|
+
using_directive: SymbolType.Import,
|
|
24
|
+
},
|
|
25
|
+
nameNodeTypes: ['identifier'],
|
|
26
|
+
importNodeTypes: ['using_directive'],
|
|
27
|
+
exportNodeTypes: [],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export class CSharpAdapter extends BaseTreeSitterAdapter {
|
|
31
|
+
protected grammar = GRAMMAR;
|
|
32
|
+
languageName(): string { return 'C#'; }
|
|
33
|
+
fileExtensions(): string[] { return ['.cs']; }
|
|
34
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { BaseTreeSitterAdapter, GrammarConfig } from '../base.js';
|
|
3
|
+
import { SymbolType, CodeSymbol } from '../types.js';
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
const GRAMMAR: GrammarConfig = {
|
|
8
|
+
language: 'css',
|
|
9
|
+
wasmPath: require.resolve('tree-sitter-css/tree-sitter-css.wasm'),
|
|
10
|
+
queryPatterns: {},
|
|
11
|
+
typeMap: {},
|
|
12
|
+
nameNodeTypes: [],
|
|
13
|
+
importNodeTypes: [],
|
|
14
|
+
exportNodeTypes: [],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class CssAdapter extends BaseTreeSitterAdapter {
|
|
18
|
+
protected grammar = GRAMMAR;
|
|
19
|
+
languageName(): string { return 'CSS'; }
|
|
20
|
+
fileExtensions(): string[] { return ['.css', '.scss', '.less']; }
|
|
21
|
+
|
|
22
|
+
protected async extractSymbolsFromTree(tree: any, filePath: string, content: string): Promise<CodeSymbol[]> {
|
|
23
|
+
const symbols: CodeSymbol[] = [];
|
|
24
|
+
this.collectRules(tree.rootNode, symbols, filePath);
|
|
25
|
+
return symbols;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private collectRules(node: any, symbols: CodeSymbol[], filePath: string) {
|
|
29
|
+
if (node.type === 'rule_set') {
|
|
30
|
+
let selectorText = '';
|
|
31
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
32
|
+
const child = node.child(i);
|
|
33
|
+
if (child && child.type === 'selectors') {
|
|
34
|
+
selectorText = child.text || '';
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (selectorText) {
|
|
39
|
+
const first = selectorText.split(',')[0].trim();
|
|
40
|
+
symbols.push({
|
|
41
|
+
id: `${filePath}:${node.startPosition.row + 1}`,
|
|
42
|
+
name: first,
|
|
43
|
+
type: SymbolType.Module,
|
|
44
|
+
language: 'css',
|
|
45
|
+
file: filePath,
|
|
46
|
+
startLine: node.startPosition.row + 1,
|
|
47
|
+
endLine: node.endPosition.row + 1,
|
|
48
|
+
parent: null, children: [], metadata: { selector: selectorText },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
53
|
+
const child = node.child(i);
|
|
54
|
+
if (child) this.collectRules(child, symbols, filePath);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { BaseTreeSitterAdapter, GrammarConfig } from '../base.js';
|
|
3
|
+
import { SymbolType } from '../types.js';
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
const GRAMMAR: GrammarConfig = {
|
|
8
|
+
language: 'go',
|
|
9
|
+
wasmPath: require.resolve('tree-sitter-go/tree-sitter-go.wasm'),
|
|
10
|
+
queryPatterns: {
|
|
11
|
+
function_declaration: '(function_declaration name: (identifier) @name)',
|
|
12
|
+
method_declaration: '(method_declaration name: (field_identifier) @name)',
|
|
13
|
+
},
|
|
14
|
+
typeMap: {
|
|
15
|
+
function_declaration: SymbolType.Function,
|
|
16
|
+
method_declaration: SymbolType.Method,
|
|
17
|
+
import_declaration: SymbolType.Import,
|
|
18
|
+
},
|
|
19
|
+
nameNodeTypes: ['identifier', 'field_identifier'],
|
|
20
|
+
importNodeTypes: ['import_declaration', 'import_spec'],
|
|
21
|
+
exportNodeTypes: [],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export class GoAdapter extends BaseTreeSitterAdapter {
|
|
25
|
+
protected grammar = GRAMMAR;
|
|
26
|
+
languageName(): string { return 'Go'; }
|
|
27
|
+
fileExtensions(): string[] { return ['.go']; }
|
|
28
|
+
}
|