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.
Files changed (136) hide show
  1. package/README.md +43 -9
  2. package/dist/cli/commands/index_cmd.d.ts.map +1 -1
  3. package/dist/cli/commands/index_cmd.js +2 -0
  4. package/dist/cli/commands/index_cmd.js.map +1 -1
  5. package/dist/cli/commands/start.d.ts.map +1 -1
  6. package/dist/cli/commands/start.js +3 -1
  7. package/dist/cli/commands/start.js.map +1 -1
  8. package/dist/config/index.js +1 -1
  9. package/dist/config/index.js.map +1 -1
  10. package/dist/graph/builder.d.ts.map +1 -1
  11. package/dist/graph/builder.js +5 -0
  12. package/dist/graph/builder.js.map +1 -1
  13. package/dist/indexer/chunker.d.ts +2 -2
  14. package/dist/indexer/chunker.d.ts.map +1 -1
  15. package/dist/indexer/chunker.js +7 -5
  16. package/dist/indexer/chunker.js.map +1 -1
  17. package/dist/indexer/file-utils.d.ts +2 -3
  18. package/dist/indexer/file-utils.d.ts.map +1 -1
  19. package/dist/indexer/file-utils.js +4 -33
  20. package/dist/indexer/file-utils.js.map +1 -1
  21. package/dist/indexer/fixture.test.d.ts +2 -0
  22. package/dist/indexer/fixture.test.d.ts.map +1 -0
  23. package/dist/indexer/fixture.test.js +104 -0
  24. package/dist/indexer/fixture.test.js.map +1 -0
  25. package/dist/indexer/indexer.d.ts +3 -1
  26. package/dist/indexer/indexer.d.ts.map +1 -1
  27. package/dist/indexer/indexer.js +8 -32
  28. package/dist/indexer/indexer.js.map +1 -1
  29. package/dist/indexer/parser.d.ts.map +1 -1
  30. package/dist/indexer/parser.js +196 -14
  31. package/dist/indexer/parser.js.map +1 -1
  32. package/dist/indexer/parser.test.d.ts +2 -0
  33. package/dist/indexer/parser.test.d.ts.map +1 -0
  34. package/dist/indexer/parser.test.js +120 -0
  35. package/dist/indexer/parser.test.js.map +1 -0
  36. package/dist/language/adapters/c.d.ts +7 -0
  37. package/dist/language/adapters/c.d.ts.map +1 -0
  38. package/dist/language/adapters/c.js +25 -0
  39. package/dist/language/adapters/c.js.map +1 -0
  40. package/dist/language/adapters/cpp.d.ts +7 -0
  41. package/dist/language/adapters/cpp.d.ts.map +1 -0
  42. package/dist/language/adapters/cpp.js +29 -0
  43. package/dist/language/adapters/cpp.js.map +1 -0
  44. package/dist/language/adapters/csharp.d.ts +7 -0
  45. package/dist/language/adapters/csharp.d.ts.map +1 -0
  46. package/dist/language/adapters/csharp.js +32 -0
  47. package/dist/language/adapters/csharp.js.map +1 -0
  48. package/dist/language/adapters/css.d.ts +10 -0
  49. package/dist/language/adapters/css.d.ts.map +1 -0
  50. package/dist/language/adapters/css.js +54 -0
  51. package/dist/language/adapters/css.js.map +1 -0
  52. package/dist/language/adapters/go.d.ts +7 -0
  53. package/dist/language/adapters/go.d.ts.map +1 -0
  54. package/dist/language/adapters/go.js +26 -0
  55. package/dist/language/adapters/go.js.map +1 -0
  56. package/dist/language/adapters/html.d.ts +11 -0
  57. package/dist/language/adapters/html.d.ts.map +1 -0
  58. package/dist/language/adapters/html.js +67 -0
  59. package/dist/language/adapters/html.js.map +1 -0
  60. package/dist/language/adapters/java.d.ts +7 -0
  61. package/dist/language/adapters/java.d.ts.map +1 -0
  62. package/dist/language/adapters/java.js +30 -0
  63. package/dist/language/adapters/java.js.map +1 -0
  64. package/dist/language/adapters/javascript.d.ts +7 -0
  65. package/dist/language/adapters/javascript.d.ts.map +1 -0
  66. package/dist/language/adapters/javascript.js +31 -0
  67. package/dist/language/adapters/javascript.js.map +1 -0
  68. package/dist/language/adapters/json.d.ts +11 -0
  69. package/dist/language/adapters/json.d.ts.map +1 -0
  70. package/dist/language/adapters/json.js +57 -0
  71. package/dist/language/adapters/json.js.map +1 -0
  72. package/dist/language/adapters/php.d.ts +7 -0
  73. package/dist/language/adapters/php.d.ts.map +1 -0
  74. package/dist/language/adapters/php.js +29 -0
  75. package/dist/language/adapters/php.js.map +1 -0
  76. package/dist/language/adapters/python.d.ts +7 -0
  77. package/dist/language/adapters/python.d.ts.map +1 -0
  78. package/dist/language/adapters/python.js +27 -0
  79. package/dist/language/adapters/python.js.map +1 -0
  80. package/dist/language/adapters/ruby.d.ts +7 -0
  81. package/dist/language/adapters/ruby.d.ts.map +1 -0
  82. package/dist/language/adapters/ruby.js +29 -0
  83. package/dist/language/adapters/ruby.js.map +1 -0
  84. package/dist/language/adapters/rust.d.ts +7 -0
  85. package/dist/language/adapters/rust.d.ts.map +1 -0
  86. package/dist/language/adapters/rust.js +31 -0
  87. package/dist/language/adapters/rust.js.map +1 -0
  88. package/dist/language/adapters/typescript.d.ts +7 -0
  89. package/dist/language/adapters/typescript.d.ts.map +1 -0
  90. package/dist/language/adapters/typescript.js +35 -0
  91. package/dist/language/adapters/typescript.js.map +1 -0
  92. package/dist/language/base.d.ts +34 -0
  93. package/dist/language/base.d.ts.map +1 -0
  94. package/dist/language/base.js +144 -0
  95. package/dist/language/base.js.map +1 -0
  96. package/dist/language/generic.d.ts +11 -0
  97. package/dist/language/generic.d.ts.map +1 -0
  98. package/dist/language/generic.js +51 -0
  99. package/dist/language/generic.js.map +1 -0
  100. package/dist/language/registry.d.ts +29 -0
  101. package/dist/language/registry.d.ts.map +1 -0
  102. package/dist/language/registry.js +111 -0
  103. package/dist/language/registry.js.map +1 -0
  104. package/dist/language/types.d.ts +55 -0
  105. package/dist/language/types.d.ts.map +1 -0
  106. package/dist/language/types.js +23 -0
  107. package/dist/language/types.js.map +1 -0
  108. package/package.json +19 -3
  109. package/src/cli/commands/index_cmd.ts +2 -0
  110. package/src/cli/commands/start.ts +3 -1
  111. package/src/config/index.ts +1 -1
  112. package/src/graph/builder.ts +5 -0
  113. package/src/indexer/chunker.ts +9 -7
  114. package/src/indexer/file-utils.ts +6 -38
  115. package/src/indexer/fixture.test.ts +121 -0
  116. package/src/indexer/indexer.ts +17 -41
  117. package/src/indexer/parser.test.ts +127 -0
  118. package/src/indexer/parser.ts +194 -13
  119. package/src/language/adapters/c.ts +27 -0
  120. package/src/language/adapters/cpp.ts +31 -0
  121. package/src/language/adapters/csharp.ts +34 -0
  122. package/src/language/adapters/css.ts +57 -0
  123. package/src/language/adapters/go.ts +28 -0
  124. package/src/language/adapters/html.ts +68 -0
  125. package/src/language/adapters/java.ts +32 -0
  126. package/src/language/adapters/javascript.ts +33 -0
  127. package/src/language/adapters/json.ts +60 -0
  128. package/src/language/adapters/php.ts +31 -0
  129. package/src/language/adapters/python.ts +29 -0
  130. package/src/language/adapters/ruby.ts +31 -0
  131. package/src/language/adapters/rust.ts +33 -0
  132. package/src/language/adapters/typescript.ts +37 -0
  133. package/src/language/base.ts +167 -0
  134. package/src/language/generic.ts +58 -0
  135. package/src/language/registry.ts +126 -0
  136. package/src/language/types.ts +58 -0
@@ -1,13 +1,12 @@
1
- import { readFileSync, existsSync, mkdirSync } from 'node:fs';
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, MODEL_CONFIGS } from '../config/index.js';
6
- import { scanFiles, computeFileHash } from './file-utils.js';
7
- import { createIgnoreRules } from './ignore.js';
8
- import { initParser, loadLanguage, parseContentAsync, extractSymbols, extractImports, extractExports } from './parser.js';
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, computeChunkDelta } from './incremental.js';
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 initParser();
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.config.languages);
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.config.languages);
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 { tree } = await parseContentAsync(content, language);
159
- const symbols = extractSymbols(tree, language);
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
+ }
@@ -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
- return language === 'ts' || language === 'js' ? 'ts' : language;
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
- if (language === 'ts' || language === 'js') {
204
- if (child.type === 'identifier' || child.type === 'property_identifier' || child.type === 'type_identifier') {
205
- return child.text;
206
- }
207
- } else if (language === 'py') {
208
- if (child.type === 'identifier') {
209
- return child.text;
210
- }
211
- } else if (language === 'go') {
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
+ }