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
@@ -0,0 +1,111 @@
1
+ import { TypeScriptAdapter } from './adapters/typescript.js';
2
+ import { JavaScriptAdapter } from './adapters/javascript.js';
3
+ import { PythonAdapter } from './adapters/python.js';
4
+ import { GoAdapter } from './adapters/go.js';
5
+ import { RustAdapter } from './adapters/rust.js';
6
+ import { JavaAdapter } from './adapters/java.js';
7
+ import { RubyAdapter } from './adapters/ruby.js';
8
+ import { CAdapter } from './adapters/c.js';
9
+ import { CppAdapter } from './adapters/cpp.js';
10
+ import { CSharpAdapter } from './adapters/csharp.js';
11
+ import { PhpAdapter } from './adapters/php.js';
12
+ import { HtmlAdapter } from './adapters/html.js';
13
+ import { CssAdapter } from './adapters/css.js';
14
+ import { JsonAdapter } from './adapters/json.js';
15
+ import { GenericAdapter } from './generic.js';
16
+ export class LanguageRegistry {
17
+ adapters = [];
18
+ extMap = new Map();
19
+ nameMap = new Map();
20
+ generic;
21
+ constructor() {
22
+ this.generic = new GenericAdapter();
23
+ this.registerDefaults();
24
+ }
25
+ registerDefaults() {
26
+ this.register('ts', new TypeScriptAdapter(), 1);
27
+ this.register('js', new JavaScriptAdapter(), 1);
28
+ this.register('py', new PythonAdapter(), 1);
29
+ this.register('go', new GoAdapter(), 1);
30
+ this.register('rs', new RustAdapter(), 1);
31
+ this.register('java', new JavaAdapter(), 1);
32
+ this.register('rb', new RubyAdapter(), 1);
33
+ this.register('c', new CAdapter(), 1);
34
+ this.register('cpp', new CppAdapter(), 1);
35
+ this.register('csharp', new CSharpAdapter(), 1);
36
+ this.register('php', new PhpAdapter(), 1);
37
+ this.register('html', new HtmlAdapter(), 2);
38
+ this.register('css', new CssAdapter(), 2);
39
+ this.register('json', new JsonAdapter(), 2);
40
+ }
41
+ register(key, adapter, tier) {
42
+ const entry = { key, adapter, tier };
43
+ this.adapters.push(entry);
44
+ for (const ext of adapter.fileExtensions()) {
45
+ const lower = ext.toLowerCase();
46
+ if (!this.extMap.has(lower)) {
47
+ this.extMap.set(lower, entry);
48
+ }
49
+ }
50
+ for (const name of adapter.fileNames()) {
51
+ const lower = name.toLowerCase();
52
+ if (!this.nameMap.has(lower)) {
53
+ this.nameMap.set(lower, entry);
54
+ }
55
+ }
56
+ }
57
+ getAdapter(filePath) {
58
+ const lower = filePath.toLowerCase();
59
+ const fileName = lower.split('/').pop() || lower;
60
+ const nameEntry = this.nameMap.get(fileName);
61
+ if (nameEntry)
62
+ return { adapter: nameEntry.adapter, key: nameEntry.key };
63
+ for (const [ext, entry] of this.extMap) {
64
+ if (lower.endsWith(ext))
65
+ return { adapter: entry.adapter, key: entry.key };
66
+ }
67
+ return { adapter: this.generic, key: 'generic' };
68
+ }
69
+ getAdapterByKey(key) {
70
+ const entry = this.adapters.find(a => a.key === key);
71
+ if (!entry)
72
+ return null;
73
+ return { adapter: entry.adapter, key: entry.key };
74
+ }
75
+ getAllAdapters() {
76
+ return [...this.adapters];
77
+ }
78
+ getInfoList() {
79
+ return this.adapters.map(a => ({
80
+ key: a.key,
81
+ name: a.adapter.languageName(),
82
+ extensions: a.adapter.fileExtensions(),
83
+ tier: a.tier,
84
+ supportsSymbols: a.adapter.supportsSymbols(),
85
+ }));
86
+ }
87
+ getExtensionsForKeys(keys) {
88
+ const exts = [];
89
+ for (const key of keys) {
90
+ const entry = this.adapters.find(a => a.key === key);
91
+ if (entry)
92
+ exts.push(...entry.adapter.fileExtensions());
93
+ }
94
+ return exts;
95
+ }
96
+ async initialize(keys) {
97
+ for (const key of keys) {
98
+ const entry = this.adapters.find(a => a.key === key);
99
+ if (entry && entry.adapter instanceof (await import('./base.js')).BaseTreeSitterAdapter) {
100
+ try {
101
+ await entry.adapter.loadGrammar();
102
+ }
103
+ catch (e) {
104
+ // grammar load failure is non-fatal
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ export const defaultRegistry = new LanguageRegistry();
111
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/language/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ export declare enum SymbolType {
2
+ Workspace = "workspace",
3
+ Folder = "folder",
4
+ File = "file",
5
+ Module = "module",
6
+ Namespace = "namespace",
7
+ Class = "class",
8
+ Interface = "interface",
9
+ Enum = "enum",
10
+ Struct = "struct",
11
+ Trait = "trait",
12
+ Function = "function",
13
+ Method = "method",
14
+ Variable = "variable",
15
+ Constant = "constant",
16
+ Property = "property",
17
+ Import = "import",
18
+ Export = "export",
19
+ Comment = "comment",
20
+ Unknown = "unknown"
21
+ }
22
+ export interface CodeSymbol {
23
+ id: string;
24
+ name: string;
25
+ type: SymbolType;
26
+ language: string;
27
+ file: string;
28
+ startLine: number;
29
+ endLine: number;
30
+ parent: string | null;
31
+ children: CodeSymbol[];
32
+ metadata: Record<string, unknown>;
33
+ }
34
+ export interface ParseResult {
35
+ symbols: CodeSymbol[];
36
+ imports: string[];
37
+ exports: string[];
38
+ comments: string[];
39
+ }
40
+ export interface LanguageAdapter {
41
+ languageName(): string;
42
+ fileExtensions(): string[];
43
+ fileNames(): string[];
44
+ canParse(filePath: string): boolean;
45
+ parse(content: string, filePath: string): Promise<ParseResult>;
46
+ supportsSymbols(): boolean;
47
+ }
48
+ export interface AdapterInfo {
49
+ key: string;
50
+ name: string;
51
+ extensions: string[];
52
+ tier: 1 | 2 | 3;
53
+ supportsSymbols: boolean;
54
+ }
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/language/types.ts"],"names":[],"mappings":"AAAA,oBAAY,UAAU;IACpB,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,IAAI,MAAM,CAAC;IACvB,cAAc,IAAI,MAAM,EAAE,CAAC;IAC3B,SAAS,IAAI,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/D,eAAe,IAAI,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;CAC1B"}
@@ -0,0 +1,23 @@
1
+ export var SymbolType;
2
+ (function (SymbolType) {
3
+ SymbolType["Workspace"] = "workspace";
4
+ SymbolType["Folder"] = "folder";
5
+ SymbolType["File"] = "file";
6
+ SymbolType["Module"] = "module";
7
+ SymbolType["Namespace"] = "namespace";
8
+ SymbolType["Class"] = "class";
9
+ SymbolType["Interface"] = "interface";
10
+ SymbolType["Enum"] = "enum";
11
+ SymbolType["Struct"] = "struct";
12
+ SymbolType["Trait"] = "trait";
13
+ SymbolType["Function"] = "function";
14
+ SymbolType["Method"] = "method";
15
+ SymbolType["Variable"] = "variable";
16
+ SymbolType["Constant"] = "constant";
17
+ SymbolType["Property"] = "property";
18
+ SymbolType["Import"] = "import";
19
+ SymbolType["Export"] = "export";
20
+ SymbolType["Comment"] = "comment";
21
+ SymbolType["Unknown"] = "unknown";
22
+ })(SymbolType || (SymbolType = {}));
23
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/language/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,UAoBX;AApBD,WAAY,UAAU;IACpB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;IACjB,2BAAa,CAAA;IACb,+BAAiB,CAAA;IACjB,qCAAuB,CAAA;IACvB,6BAAe,CAAA;IACf,qCAAuB,CAAA;IACvB,2BAAa,CAAA;IACb,+BAAiB,CAAA;IACjB,6BAAe,CAAA;IACf,mCAAqB,CAAA;IACrB,+BAAiB,CAAA;IACjB,mCAAqB,CAAA;IACrB,mCAAqB,CAAA;IACrB,mCAAqB,CAAA;IACrB,+BAAiB,CAAA;IACjB,+BAAiB,CAAA;IACjB,iCAAmB,CAAA;IACnB,iCAAmB,CAAA;AACrB,CAAC,EApBW,UAAU,KAAV,UAAU,QAoBrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edhindex",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Local-first hybrid code search engine with knowledge graph — BM25 + vector + rerank, tree-sitter parsing, MCP server",
5
5
  "keywords": [
6
6
  "code-search",
@@ -43,7 +43,8 @@
43
43
  "build": "tsc",
44
44
  "prepublishOnly": "npm run build",
45
45
  "start": "node dist/cli/index.js",
46
- "dev": "npx tsx src/cli/index.ts"
46
+ "dev": "npx tsx src/cli/index.ts",
47
+ "test": "vitest run"
47
48
  },
48
49
  "dependencies": {
49
50
  "@huggingface/transformers": "^4.2.0",
@@ -55,8 +56,22 @@
55
56
  "cli-progress": "^3.12.0",
56
57
  "commander": "^15.0.0",
57
58
  "simple-git": "^3.36.0",
59
+ "tree-sitter-c": "^0.24.1",
60
+ "tree-sitter-c-sharp": "^0.23.5",
61
+ "tree-sitter-cpp": "^0.23.4",
62
+ "tree-sitter-css": "^0.25.0",
63
+ "tree-sitter-dart": "^1.0.0",
58
64
  "tree-sitter-go": "^0.25.0",
65
+ "tree-sitter-haskell": "^0.23.1",
66
+ "tree-sitter-html": "^0.23.2",
67
+ "tree-sitter-java": "^0.23.5",
68
+ "tree-sitter-json": "^0.24.8",
69
+ "tree-sitter-php": "^0.24.2",
59
70
  "tree-sitter-python": "^0.25.0",
71
+ "tree-sitter-ruby": "^0.23.1",
72
+ "tree-sitter-rust": "^0.24.0",
73
+ "tree-sitter-scala": "^0.24.0",
74
+ "tree-sitter-solidity": "^1.2.13",
60
75
  "tree-sitter-typescript": "^0.23.2",
61
76
  "web-tree-sitter": "^0.26.11"
62
77
  },
@@ -64,6 +79,7 @@
64
79
  "@types/better-sqlite3": "^7.6.13",
65
80
  "@types/cli-progress": "^3.11.6",
66
81
  "@types/node": "^22.13.0",
67
- "typescript": "^5.7.0"
82
+ "typescript": "^5.7.0",
83
+ "vitest": "^4.1.10"
68
84
  }
69
85
  }
@@ -9,6 +9,7 @@ import { FTSStore } from '../../storage/fts.js';
9
9
  import { TransformersEmbeddingProvider } from '../../embeddings/transformers.js';
10
10
  import { LanceDBStore } from '../../vector/lancedb.js';
11
11
  import { Indexer } from '../../indexer/indexer.js';
12
+ import { defaultRegistry } from '../../language/registry.js';
12
13
  import cliProgress from 'cli-progress';
13
14
  import chalk from 'chalk';
14
15
 
@@ -44,6 +45,7 @@ export async function indexCommand(rootPath: string) {
44
45
  config,
45
46
  rootPath,
46
47
  indexDir,
48
+ registry: defaultRegistry,
47
49
  onIndex: async (result) => {
48
50
  for (const chunk of result.chunks) {
49
51
  metadataStore.upsertChunk({
@@ -9,6 +9,7 @@ import { FTSStore } from '../../storage/fts.js';
9
9
  import { TransformersEmbeddingProvider, TransformersReranker } from '../../embeddings/transformers.js';
10
10
  import { LanceDBStore } from '../../vector/lancedb.js';
11
11
  import { Indexer } from '../../indexer/indexer.js';
12
+ import { defaultRegistry } from '../../language/registry.js';
12
13
  import { SearchEngine } from '../../retrieval/search.js';
13
14
  import { createMCPServer } from '../../mcp/server.js';
14
15
  import { FileWatcher } from '../../watcher/index.js';
@@ -96,6 +97,7 @@ export async function startCommand(rootPath: string) {
96
97
  config,
97
98
  rootPath,
98
99
  indexDir,
100
+ registry: defaultRegistry,
99
101
  onIndex: async (result) => {
100
102
  for (const chunk of result.chunks) {
101
103
  metadataStore.upsertChunk({
@@ -196,7 +198,7 @@ export async function startCommand(rootPath: string) {
196
198
  watcher = new FileWatcher(rootPath, async (filePath) => {
197
199
  logger.info(`File changed: ${filePath}`);
198
200
  const { scanFiles } = await import('../../indexer/file-utils.js');
199
- const files = scanFiles(rootPath, config.languages);
201
+ const files = scanFiles(rootPath, defaultRegistry);
200
202
  const file = files.find(f => f.relativePath === filePath);
201
203
  if (file) {
202
204
  const oldChunks = metadataStore.getChunksForFile(filePath);
@@ -23,7 +23,7 @@ export interface Config {
23
23
 
24
24
  const DEFAULT_CONFIG: Config = {
25
25
  model: 'balanced',
26
- languages: ['ts', 'js', 'go', 'py'],
26
+ languages: ['ts', 'js', 'py', 'go', 'rs', 'java', 'rb', 'c', 'cpp', 'csharp', 'php', 'html', 'css', 'json'],
27
27
  watch: true,
28
28
  rerank: true,
29
29
  maxResults: 10,
@@ -217,10 +217,15 @@ export class GraphBuilder {
217
217
  case 'class': return 'class';
218
218
  case 'interface': return 'interface';
219
219
  case 'enum': return 'enum';
220
+ case 'struct': return 'class';
221
+ case 'trait': return 'interface';
220
222
  case 'function': return 'function';
221
223
  case 'method': return 'method';
222
224
  case 'variable': return 'variable';
225
+ case 'constant': return 'variable';
226
+ case 'property': return 'variable';
223
227
  case 'module': return 'module';
228
+ case 'namespace': return 'module';
224
229
  default: return 'module';
225
230
  }
226
231
  }
@@ -1,5 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { SymbolInfo } from './parser.js';
2
+ import { CodeSymbol } from '../language/types.js';
3
3
  import { logger } from '../logging.js';
4
4
 
5
5
  export interface Chunk {
@@ -31,7 +31,7 @@ export async function chunkFile(
31
31
  filePath: string,
32
32
  relativePath: string,
33
33
  language: string,
34
- symbols: SymbolInfo[],
34
+ symbols: CodeSymbol[],
35
35
  content: string,
36
36
  lines: string[],
37
37
  imports: string[],
@@ -43,13 +43,15 @@ export async function chunkFile(
43
43
  method: 1,
44
44
  class: 2,
45
45
  interface: 3,
46
+ struct: 3,
47
+ trait: 3,
46
48
  enum: 4,
47
49
  module: 5,
48
50
  };
49
51
 
50
52
  const sorted = [...symbols].sort((a, b) => {
51
- const aP = priorityOrder[a.kind] ?? 99;
52
- const bP = priorityOrder[b.kind] ?? 99;
53
+ const aP = priorityOrder[a.type] ?? 99;
54
+ const bP = priorityOrder[b.type] ?? 99;
53
55
  if (aP !== bP) return aP - bP;
54
56
  return a.startLine - b.startLine;
55
57
  });
@@ -60,7 +62,7 @@ export async function chunkFile(
60
62
  if (isCovered(covered, sym.startLine, sym.endLine)) continue;
61
63
  markCovered(covered, sym.startLine, sym.endLine);
62
64
 
63
- const chunkContent = sym.text || content.slice(
65
+ const chunkContent = content.slice(
64
66
  content.split('\n').slice(0, sym.startLine - 1).join('\n').length + (sym.startLine > 1 ? 1 : 0),
65
67
  content.split('\n').slice(0, sym.endLine).join('\n').length
66
68
  );
@@ -72,7 +74,7 @@ export async function chunkFile(
72
74
  file: relativePath,
73
75
  language,
74
76
  symbol: sym.name,
75
- kind: sym.kind,
77
+ kind: sym.type,
76
78
  parent: null,
77
79
  hash,
78
80
  startLine: sym.startLine,
@@ -83,7 +85,7 @@ export async function chunkFile(
83
85
  });
84
86
  } else {
85
87
  const childChunks = splitRecursive(
86
- chunkContent, lines, sym.startLine, sym.name, sym.kind,
88
+ chunkContent, lines, sym.startLine, sym.name, sym.type,
87
89
  relativePath, language, imports, exports
88
90
  );
89
91
  chunks.push(...childChunks);
@@ -2,7 +2,8 @@ import { readdirSync, statSync, readFileSync } from 'node:fs';
2
2
  import { join, relative } from 'node:path';
3
3
  import { createHash } from 'node:crypto';
4
4
  import { checkSymlinkSafety } from '../security.js';
5
- import { createIgnoreRules, IgnoreRules } from './ignore.js';
5
+ import { createIgnoreRules } from './ignore.js';
6
+ import { LanguageRegistry } from '../language/registry.js';
6
7
  import { logger } from '../logging.js';
7
8
 
8
9
  const MAX_FILE_SIZE = 10 * 1024 * 1024;
@@ -18,29 +19,6 @@ const BINARY_EXTENSIONS = new Set([
18
19
  '.mp3', '.wav', '.flac', '.ogg',
19
20
  ]);
20
21
 
21
- const LANGUAGE_EXTENSIONS: Record<string, string[]> = {
22
- ts: ['.ts', '.tsx', '.mts', '.cts'],
23
- js: ['.js', '.jsx', '.mjs', '.cjs'],
24
- py: ['.py', '.pyw'],
25
- go: ['.go'],
26
- };
27
-
28
- const EXTENSION_TO_LANG: Record<string, string> = {};
29
- for (const [lang, exts] of Object.entries(LANGUAGE_EXTENSIONS)) {
30
- for (const ext of exts) {
31
- EXTENSION_TO_LANG[ext] = lang;
32
- }
33
- }
34
-
35
- export function getLanguageForFile(filePath: string): string | null {
36
- const ext = filePath.toLowerCase().split('.').pop();
37
- return EXTENSION_TO_LANG[`.${ext}`] || null;
38
- }
39
-
40
- export function languageFromExtension(ext: string): string | null {
41
- return EXTENSION_TO_LANG[ext.toLowerCase()] || null;
42
- }
43
-
44
22
  export function isIndexableFile(filePath: string, stat: { size: number }): boolean {
45
23
  if (stat.size > MAX_FILE_SIZE) return false;
46
24
  if (stat.size === 0) return false;
@@ -73,16 +51,10 @@ export interface ScannedFile {
73
51
  size: number;
74
52
  }
75
53
 
76
- export function scanFiles(rootPath: string, languages: string[]): ScannedFile[] {
54
+ export function scanFiles(rootPath: string, registry: LanguageRegistry): ScannedFile[] {
77
55
  const ignore = createIgnoreRules(rootPath);
78
56
  const results: ScannedFile[] = [];
79
57
 
80
- const allowedExts = new Set<string>();
81
- for (const lang of languages) {
82
- const exts = LANGUAGE_EXTENSIONS[lang];
83
- if (exts) for (const ext of exts) allowedExts.add(ext);
84
- }
85
-
86
58
  function walk(dir: string) {
87
59
  let entries: string[];
88
60
  try {
@@ -106,19 +78,17 @@ export function scanFiles(rootPath: string, languages: string[]): ScannedFile[]
106
78
  if (!checkSymlinkSafety(rootPath, fullPath)) continue;
107
79
  }
108
80
 
109
- const ext = '.' + (entry.split('.').pop() || '').toLowerCase();
110
- if (!allowedExts.has(ext)) continue;
111
81
  if (!isIndexableFile(fullPath, stat)) continue;
112
82
 
113
- const lang = EXTENSION_TO_LANG[ext];
114
- if (!lang) continue;
83
+ const { adapter, key } = registry.getAdapter(relPath);
84
+ if (!adapter.canParse(relPath)) continue;
115
85
 
116
86
  try {
117
87
  const hash = computeFileHash(fullPath);
118
88
  results.push({
119
89
  path: fullPath,
120
90
  relativePath: relPath,
121
- language: lang,
91
+ language: key,
122
92
  hash,
123
93
  size: stat.size,
124
94
  });
@@ -135,5 +105,3 @@ export function scanFiles(rootPath: string, languages: string[]): ScannedFile[]
135
105
  walk(rootPath);
136
106
  return results;
137
107
  }
138
-
139
-
@@ -0,0 +1,121 @@
1
+ import { describe, it, expect, beforeAll } from 'vitest';
2
+ import { readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { LanguageRegistry } from '../language/registry.js';
5
+
6
+ const FIXTURES_DIR = join(import.meta.dirname, '../../test-fixtures');
7
+
8
+ const registry = new LanguageRegistry();
9
+
10
+ const FIXTURES: Array<{ key: string; file: string; minSymbols: number }> = [
11
+ { key: 'ts', file: 'sample.ts', minSymbols: 3 },
12
+ { key: 'js', file: 'sample.js', minSymbols: 2 },
13
+ { key: 'py', file: 'sample.py', minSymbols: 2 },
14
+ { key: 'go', file: 'sample.go', minSymbols: 2 },
15
+ { key: 'rs', file: 'sample.rs', minSymbols: 3 },
16
+ { key: 'java', file: 'sample.java', minSymbols: 2 },
17
+ { key: 'rb', file: 'sample.rb', minSymbols: 2 },
18
+ { key: 'c', file: 'sample.c', minSymbols: 2 },
19
+ { key: 'cpp', file: 'sample.cpp', minSymbols: 2 },
20
+ { key: 'csharp', file: 'sample.cs', minSymbols: 2 },
21
+ { key: 'php', file: 'sample.php', minSymbols: 2 },
22
+ { key: 'html', file: 'sample.html', minSymbols: 1 },
23
+ { key: 'css', file: 'sample.css', minSymbols: 1 },
24
+ { key: 'json', file: 'sample.json', minSymbols: 1 },
25
+ ];
26
+
27
+ function countLines(content: string): number {
28
+ return content.split('\n').length;
29
+ }
30
+
31
+ for (const { key, file, minSymbols } of FIXTURES) {
32
+ describe(`${key} adapter — ${file}`, () => {
33
+ let content: string;
34
+ let lineCount: number;
35
+
36
+ beforeAll(() => {
37
+ const filePath = join(FIXTURES_DIR, file);
38
+ content = readFileSync(filePath, 'utf-8');
39
+ lineCount = countLines(content);
40
+ });
41
+
42
+ it('fixture file exists and has 100+ lines', () => {
43
+ expect(lineCount).toBeGreaterThanOrEqual(100);
44
+ });
45
+
46
+ it('adapter can parse the file', async () => {
47
+ const { adapter } = registry.getAdapter(file);
48
+ expect(adapter).toBeTruthy();
49
+ expect(adapter.canParse(file)).toBe(true);
50
+
51
+ const result = await adapter.parse(content, file);
52
+ expect(result).toBeTruthy();
53
+ expect(Array.isArray(result.symbols)).toBe(true);
54
+ expect(Array.isArray(result.imports)).toBe(true);
55
+ expect(Array.isArray(result.exports)).toBe(true);
56
+ expect(Array.isArray(result.comments)).toBe(true);
57
+ }, 30000);
58
+
59
+ it('extracts the expected number of symbols', async () => {
60
+ const { adapter } = registry.getAdapter(file);
61
+ const result = await adapter.parse(content, file);
62
+ expect(result.symbols.length).toBeGreaterThanOrEqual(minSymbols);
63
+ }, 30000);
64
+
65
+ it('every symbol has required fields', async () => {
66
+ const { adapter } = registry.getAdapter(file);
67
+ const result = await adapter.parse(content, file);
68
+
69
+ for (const sym of result.symbols) {
70
+ expect(sym.id).toBeTruthy();
71
+ expect(sym.name).toBeTruthy();
72
+ expect(sym.type).toBeTruthy();
73
+ expect(sym.language).toBeTruthy();
74
+ expect(sym.file).toBe(file);
75
+ expect(typeof sym.startLine).toBe('number');
76
+ expect(typeof sym.endLine).toBe('number');
77
+ expect(sym.startLine).toBeGreaterThan(0);
78
+ expect(sym.endLine).toBeGreaterThanOrEqual(sym.startLine);
79
+ expect(sym.endLine).toBeLessThanOrEqual(lineCount);
80
+ expect(Array.isArray(sym.children)).toBe(true);
81
+ }
82
+ }, 30000);
83
+
84
+ it('symbol start lines are within file bounds', async () => {
85
+ const { adapter } = registry.getAdapter(file);
86
+ const result = await adapter.parse(content, file);
87
+
88
+ for (const sym of result.symbols) {
89
+ expect(sym.startLine).toBeLessThanOrEqual(lineCount);
90
+ expect(sym.endLine).toBeLessThanOrEqual(lineCount);
91
+ }
92
+ }, 30000);
93
+
94
+ it('produces different symbols for different fixtures', async () => {
95
+ const { adapter } = registry.getAdapter(file);
96
+ const result = await adapter.parse(content, file);
97
+
98
+ const names = result.symbols.map(s => s.name);
99
+ const unique = new Set(names);
100
+ expect(unique.size).toBeGreaterThanOrEqual(Math.min(minSymbols, names.length));
101
+ }, 30000);
102
+ });
103
+ }
104
+
105
+ describe('All fixtures', () => {
106
+ it('every fixture file exists', () => {
107
+ for (const { file } of FIXTURES) {
108
+ const filePath = join(FIXTURES_DIR, file);
109
+ const content = readFileSync(filePath, 'utf-8');
110
+ expect(content.length).toBeGreaterThan(0);
111
+ }
112
+ });
113
+
114
+ it('registry maps every fixture extension correctly', () => {
115
+ for (const { key, file } of FIXTURES) {
116
+ const { adapter, key: resolvedKey } = registry.getAdapter(file);
117
+ expect(adapter).toBeTruthy();
118
+ expect(resolvedKey).toBe(key);
119
+ }
120
+ });
121
+ });