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,68 @@
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: 'html',
9
+ wasmPath: require.resolve('tree-sitter-html/tree-sitter-html.wasm'),
10
+ queryPatterns: {},
11
+ typeMap: {},
12
+ nameNodeTypes: ['tag_name', 'attribute_name'],
13
+ importNodeTypes: [],
14
+ exportNodeTypes: [],
15
+ };
16
+
17
+ export class HtmlAdapter extends BaseTreeSitterAdapter {
18
+ protected grammar = GRAMMAR;
19
+ languageName(): string { return 'HTML'; }
20
+ fileExtensions(): string[] { return ['.html', '.htm']; }
21
+
22
+ protected async extractSymbolsFromTree(tree: any, filePath: string, content: string): Promise<CodeSymbol[]> {
23
+ const symbols: CodeSymbol[] = [];
24
+ this.collectElements(tree.rootNode, symbols, filePath);
25
+ return symbols;
26
+ }
27
+
28
+ private collectElements(node: any, symbols: CodeSymbol[], filePath: string) {
29
+ if (node.type === 'element') {
30
+ const tagName = this.extractTagName(node);
31
+ const significant = ['script', 'style', 'template', 'main', 'nav', 'header', 'footer',
32
+ 'section', 'article', 'form', 'aside', 'dialog', 'details'];
33
+ if (significant.includes(tagName) || tagName.includes('-')) {
34
+ symbols.push({
35
+ id: `${filePath}:${node.startPosition.row + 1}`,
36
+ name: tagName,
37
+ type: SymbolType.Module,
38
+ language: 'html',
39
+ file: filePath,
40
+ startLine: node.startPosition.row + 1,
41
+ endLine: node.endPosition.row + 1,
42
+ parent: null,
43
+ children: [],
44
+ metadata: { tag: tagName },
45
+ });
46
+ }
47
+ }
48
+ for (let i = 0; i < node.childCount; i++) {
49
+ const child = node.child(i);
50
+ if (child) this.collectElements(child, symbols, filePath);
51
+ }
52
+ }
53
+
54
+ private extractTagName(node: any): string {
55
+ for (let i = 0; i < node.childCount; i++) {
56
+ const child = node.child(i);
57
+ if (!child) continue;
58
+ if (child.type === 'tag_name') return child.text;
59
+ if (child.type === 'start_tag' || child.type === 'end_tag') {
60
+ for (let j = 0; j < child.childCount; j++) {
61
+ const grandchild = child.child(j);
62
+ if (grandchild && grandchild.type === 'tag_name') return grandchild.text;
63
+ }
64
+ }
65
+ }
66
+ return 'unknown';
67
+ }
68
+ }
@@ -0,0 +1,32 @@
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: 'java',
9
+ wasmPath: require.resolve('tree-sitter-java/tree-sitter-java.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
+ enum_declaration: '(enum_declaration name: (identifier) @name)',
15
+ },
16
+ typeMap: {
17
+ method_declaration: SymbolType.Method,
18
+ class_declaration: SymbolType.Class,
19
+ interface_declaration: SymbolType.Interface,
20
+ enum_declaration: SymbolType.Enum,
21
+ import_declaration: SymbolType.Import,
22
+ },
23
+ nameNodeTypes: ['identifier'],
24
+ importNodeTypes: ['import_declaration'],
25
+ exportNodeTypes: [],
26
+ };
27
+
28
+ export class JavaAdapter extends BaseTreeSitterAdapter {
29
+ protected grammar = GRAMMAR;
30
+ languageName(): string { return 'Java'; }
31
+ fileExtensions(): string[] { return ['.java']; }
32
+ }
@@ -0,0 +1,33 @@
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: 'js',
9
+ wasmPath: require.resolve('tree-sitter-typescript/tree-sitter-typescript.wasm'),
10
+ queryPatterns: {
11
+ function_declaration: '(function_declaration name: (identifier) @name)',
12
+ method_definition: '(method_definition name: (property_identifier) @name)',
13
+ class_declaration: '(class_declaration name: (identifier) @name)',
14
+ },
15
+ typeMap: {
16
+ function_declaration: SymbolType.Function,
17
+ arrow_function: SymbolType.Function,
18
+ method_definition: SymbolType.Method,
19
+ class_declaration: SymbolType.Class,
20
+ import_statement: SymbolType.Import,
21
+ import_declaration: SymbolType.Import,
22
+ export_statement: SymbolType.Export,
23
+ },
24
+ nameNodeTypes: ['identifier', 'property_identifier'],
25
+ importNodeTypes: ['import_statement', 'import_declaration'],
26
+ exportNodeTypes: ['export_statement'],
27
+ };
28
+
29
+ export class JavaScriptAdapter extends BaseTreeSitterAdapter {
30
+ protected grammar = GRAMMAR;
31
+ languageName(): string { return 'JavaScript'; }
32
+ fileExtensions(): string[] { return ['.js', '.jsx', '.mjs', '.cjs']; }
33
+ }
@@ -0,0 +1,60 @@
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: 'json',
9
+ wasmPath: require.resolve('tree-sitter-json/tree-sitter-json.wasm'),
10
+ queryPatterns: {},
11
+ typeMap: {},
12
+ nameNodeTypes: [],
13
+ importNodeTypes: [],
14
+ exportNodeTypes: [],
15
+ };
16
+
17
+ export class JsonAdapter extends BaseTreeSitterAdapter {
18
+ protected grammar = GRAMMAR;
19
+ languageName(): string { return 'JSON'; }
20
+ fileExtensions(): string[] { return ['.json']; }
21
+ fileNames(): string[] { return []; }
22
+
23
+ protected async extractSymbolsFromTree(tree: any, filePath: string, content: string): Promise<CodeSymbol[]> {
24
+ const symbols: CodeSymbol[] = [];
25
+ this.walkPairs(tree.rootNode, symbols, filePath, '');
26
+ return symbols;
27
+ }
28
+
29
+ private walkPairs(node: any, symbols: CodeSymbol[], filePath: string, parentId: string) {
30
+ if (node.type === 'pair') {
31
+ let key = '';
32
+ for (let i = 0; i < node.childCount; i++) {
33
+ const child = node.child(i);
34
+ if (child && child.type === 'string' && !key) {
35
+ key = child.text?.replace(/"/g, '') || '';
36
+ break;
37
+ }
38
+ }
39
+ if (key) {
40
+ const id = `${filePath}:${node.startPosition.row + 1}`;
41
+ symbols.push({
42
+ id, name: key, type: SymbolType.Property, language: 'json',
43
+ file: filePath, startLine: node.startPosition.row + 1,
44
+ endLine: node.endPosition.row + 1, parent: parentId || null, children: [], metadata: {},
45
+ });
46
+ for (let i = 0; i < node.childCount; i++) {
47
+ const child = node.child(i);
48
+ if (child && (child.type === 'object' || child.type === 'array')) {
49
+ this.walkPairs(child, symbols, filePath, id);
50
+ }
51
+ }
52
+ }
53
+ return;
54
+ }
55
+ for (let i = 0; i < node.childCount; i++) {
56
+ const child = node.child(i);
57
+ if (child) this.walkPairs(child, symbols, filePath, parentId);
58
+ }
59
+ }
60
+ }
@@ -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: 'php',
9
+ wasmPath: require.resolve('tree-sitter-php/tree-sitter-php.wasm'),
10
+ queryPatterns: {
11
+ function_definition: '(function_definition name: (name) @name)',
12
+ method_declaration: '(method_declaration name: (name) @name)',
13
+ class_declaration: '(class_declaration name: (name) @name)',
14
+ interface_declaration: '(interface_declaration name: (name) @name)',
15
+ },
16
+ typeMap: {
17
+ function_definition: SymbolType.Function,
18
+ method_declaration: SymbolType.Method,
19
+ class_declaration: SymbolType.Class,
20
+ interface_declaration: SymbolType.Interface,
21
+ },
22
+ nameNodeTypes: ['name'],
23
+ importNodeTypes: [],
24
+ exportNodeTypes: [],
25
+ };
26
+
27
+ export class PhpAdapter extends BaseTreeSitterAdapter {
28
+ protected grammar = GRAMMAR;
29
+ languageName(): string { return 'PHP'; }
30
+ fileExtensions(): string[] { return ['.php']; }
31
+ }
@@ -0,0 +1,29 @@
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: 'py',
9
+ wasmPath: require.resolve('tree-sitter-python/tree-sitter-python.wasm'),
10
+ queryPatterns: {
11
+ function_definition: '(function_definition name: (identifier) @name)',
12
+ class_definition: '(class_definition name: (identifier) @name)',
13
+ },
14
+ typeMap: {
15
+ function_definition: SymbolType.Function,
16
+ class_definition: SymbolType.Class,
17
+ import_statement: SymbolType.Import,
18
+ import_from_statement: SymbolType.Import,
19
+ },
20
+ nameNodeTypes: ['identifier'],
21
+ importNodeTypes: ['import_statement', 'import_from_statement'],
22
+ exportNodeTypes: [],
23
+ };
24
+
25
+ export class PythonAdapter extends BaseTreeSitterAdapter {
26
+ protected grammar = GRAMMAR;
27
+ languageName(): string { return 'Python'; }
28
+ fileExtensions(): string[] { return ['.py', '.pyw']; }
29
+ }
@@ -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: 'rb',
9
+ wasmPath: require.resolve('tree-sitter-ruby/tree-sitter-ruby.wasm'),
10
+ queryPatterns: {
11
+ method: '(method name: (identifier) @name)',
12
+ class: '(class name: (constant) @name)',
13
+ module: '(module name: (constant) @name)',
14
+ },
15
+ typeMap: {
16
+ method: SymbolType.Method,
17
+ class: SymbolType.Class,
18
+ module: SymbolType.Module,
19
+ call: SymbolType.Unknown,
20
+ require: SymbolType.Import,
21
+ },
22
+ nameNodeTypes: ['identifier', 'constant'],
23
+ importNodeTypes: ['require'],
24
+ exportNodeTypes: [],
25
+ };
26
+
27
+ export class RubyAdapter extends BaseTreeSitterAdapter {
28
+ protected grammar = GRAMMAR;
29
+ languageName(): string { return 'Ruby'; }
30
+ fileExtensions(): string[] { return ['.rb']; }
31
+ }
@@ -0,0 +1,33 @@
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: 'rs',
9
+ wasmPath: require.resolve('tree-sitter-rust/tree-sitter-rust.wasm'),
10
+ queryPatterns: {
11
+ function_item: '(function_item name: (identifier) @name)',
12
+ struct_item: '(struct_item name: (type_identifier) @name)',
13
+ trait_item: '(trait_item name: (type_identifier) @name)',
14
+ enum_item: '(enum_item name: (type_identifier) @name)',
15
+ },
16
+ typeMap: {
17
+ function_item: SymbolType.Function,
18
+ struct_item: SymbolType.Struct,
19
+ trait_item: SymbolType.Trait,
20
+ impl_item: SymbolType.Module,
21
+ enum_item: SymbolType.Enum,
22
+ use_declaration: SymbolType.Import,
23
+ },
24
+ nameNodeTypes: ['identifier', 'type_identifier'],
25
+ importNodeTypes: ['use_declaration'],
26
+ exportNodeTypes: [],
27
+ };
28
+
29
+ export class RustAdapter extends BaseTreeSitterAdapter {
30
+ protected grammar = GRAMMAR;
31
+ languageName(): string { return 'Rust'; }
32
+ fileExtensions(): string[] { return ['.rs']; }
33
+ }
@@ -0,0 +1,37 @@
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: 'ts',
9
+ wasmPath: require.resolve('tree-sitter-typescript/tree-sitter-typescript.wasm'),
10
+ queryPatterns: {
11
+ function_declaration: '(function_declaration name: (identifier) @name)',
12
+ method_definition: '(method_definition name: (property_identifier) @name)',
13
+ class_declaration: '(class_declaration name: (type_identifier) @name)',
14
+ interface_declaration: '(interface_declaration name: (type_identifier) @name)',
15
+ enum_declaration: '(enum_declaration name: (type_identifier) @name)',
16
+ },
17
+ typeMap: {
18
+ function_declaration: SymbolType.Function,
19
+ arrow_function: SymbolType.Function,
20
+ method_definition: SymbolType.Method,
21
+ class_declaration: SymbolType.Class,
22
+ interface_declaration: SymbolType.Interface,
23
+ enum_declaration: SymbolType.Enum,
24
+ import_statement: SymbolType.Import,
25
+ import_declaration: SymbolType.Import,
26
+ export_statement: SymbolType.Export,
27
+ },
28
+ nameNodeTypes: ['identifier', 'property_identifier', 'type_identifier'],
29
+ importNodeTypes: ['import_statement', 'import_declaration'],
30
+ exportNodeTypes: ['export_statement'],
31
+ };
32
+
33
+ export class TypeScriptAdapter extends BaseTreeSitterAdapter {
34
+ protected grammar = GRAMMAR;
35
+ languageName(): string { return 'TypeScript'; }
36
+ fileExtensions(): string[] { return ['.ts', '.tsx', '.mts', '.cts']; }
37
+ }
@@ -0,0 +1,167 @@
1
+ import { createRequire } from 'node:module';
2
+ import { Parser, Language } from 'web-tree-sitter';
3
+ import { SymbolType, CodeSymbol, ParseResult, LanguageAdapter } from './types.js';
4
+
5
+ const require = createRequire(import.meta.url);
6
+
7
+ export interface GrammarConfig {
8
+ language: string;
9
+ wasmPath: string;
10
+ queryPatterns: Record<string, string>;
11
+ typeMap: Record<string, SymbolType>;
12
+ nameNodeTypes: string[];
13
+ importNodeTypes: string[];
14
+ exportNodeTypes: string[];
15
+ }
16
+
17
+ export abstract class BaseTreeSitterAdapter implements LanguageAdapter {
18
+ protected abstract grammar: GrammarConfig;
19
+ protected parser: Parser | null = null;
20
+ protected loadedLang: any = null;
21
+ private static initialized = false;
22
+ private static loadedGrammars = new Map<string, any>();
23
+
24
+ abstract languageName(): string;
25
+ abstract fileExtensions(): string[];
26
+ fileNames(): string[] { return []; }
27
+
28
+ canParse(filePath: string): boolean {
29
+ const lower = filePath.toLowerCase();
30
+ for (const ext of this.fileExtensions()) {
31
+ if (lower.endsWith(ext)) return true;
32
+ }
33
+ for (const name of this.fileNames()) {
34
+ if (lower === name || lower.endsWith('/' + name)) return true;
35
+ }
36
+ return false;
37
+ }
38
+
39
+ supportsSymbols(): boolean {
40
+ return Object.keys(this.grammar.queryPatterns).length > 0;
41
+ }
42
+
43
+ async loadGrammar(): Promise<void> {
44
+ const key = this.grammar.language;
45
+ if (BaseTreeSitterAdapter.loadedGrammars.has(key)) {
46
+ this.loadedLang = BaseTreeSitterAdapter.loadedGrammars.get(key);
47
+ return;
48
+ }
49
+ if (!BaseTreeSitterAdapter.initialized) {
50
+ await Parser.init();
51
+ BaseTreeSitterAdapter.initialized = true;
52
+ }
53
+ const lang = await Language.load(this.grammar.wasmPath);
54
+ BaseTreeSitterAdapter.loadedGrammars.set(key, lang);
55
+ this.loadedLang = lang;
56
+ this.parser = new Parser();
57
+ this.parser.setLanguage(lang);
58
+ }
59
+
60
+ async parse(content: string, filePath: string): Promise<ParseResult> {
61
+ if (!this.parser) await this.loadGrammar();
62
+
63
+ const tree = this.parser!.parse(content);
64
+ const symbols = await this.extractSymbolsFromTree(tree, filePath, content);
65
+ const imports = this.extractImportsFromTree(tree);
66
+ const exports = this.extractExportsFromTree(tree);
67
+ const comments = this.extractCommentsFromTree(tree);
68
+
69
+ return { symbols, imports, exports, comments };
70
+ }
71
+
72
+ protected async extractSymbolsFromTree(tree: any, filePath: string, content: string): Promise<CodeSymbol[]> {
73
+ const symbols: CodeSymbol[] = [];
74
+ if (Object.keys(this.grammar.queryPatterns).length === 0) return symbols;
75
+ this.walkForSymbols(tree.rootNode, symbols, filePath, '');
76
+ return symbols;
77
+ }
78
+
79
+ protected walkForSymbols(node: any, symbols: CodeSymbol[], filePath: string, parentId: string): void {
80
+ const type = node.type;
81
+ const symbolType = this.grammar.typeMap[type];
82
+
83
+ if (symbolType) {
84
+ const name = this.extractName(node);
85
+ if (name) {
86
+ symbols.push({
87
+ id: `${filePath}:${node.startPosition.row + 1}`,
88
+ name,
89
+ type: symbolType,
90
+ language: this.grammar.language,
91
+ file: filePath,
92
+ startLine: node.startPosition.row + 1,
93
+ endLine: node.endPosition.row + 1,
94
+ parent: parentId || null,
95
+ children: [],
96
+ metadata: {},
97
+ });
98
+ }
99
+ }
100
+
101
+ for (let i = 0; i < node.childCount; i++) {
102
+ const childNode = node.child(i);
103
+ if (childNode) {
104
+ this.walkForSymbols(childNode, symbols, filePath, '');
105
+ }
106
+ }
107
+ }
108
+
109
+ protected extractName(node: any): string | null {
110
+ try {
111
+ const nameTypes = new Set([
112
+ 'identifier', 'property_identifier', 'type_identifier',
113
+ 'field_identifier', 'constant', 'variable', 'name', 'type',
114
+ 'selector', 'class_name', 'function_name', 'method_name',
115
+ ]);
116
+ return this.findName(node, nameTypes);
117
+ } catch {
118
+ return null;
119
+ }
120
+ }
121
+
122
+ private findName(node: any, nameTypes: Set<string>): string | null {
123
+ if (nameTypes.has(node.type)) {
124
+ return node.text;
125
+ }
126
+ for (let i = 0; i < node.childCount; i++) {
127
+ const child = node.child(i);
128
+ if (child) {
129
+ const result = this.findName(child, nameTypes);
130
+ if (result) return result;
131
+ }
132
+ }
133
+ return null;
134
+ }
135
+
136
+ protected extractImportsFromTree(tree: any): string[] {
137
+ const imports: string[] = [];
138
+ const importTypes = this.grammar.importNodeTypes;
139
+ if (importTypes.length === 0) return imports;
140
+ this.collectNodesOfType(tree.rootNode, importTypes, imports);
141
+ return imports;
142
+ }
143
+
144
+ protected extractExportsFromTree(tree: any): string[] {
145
+ const exports: string[] = [];
146
+ const exportTypes = this.grammar.exportNodeTypes;
147
+ if (exportTypes.length === 0) return exports;
148
+ this.collectNodesOfType(tree.rootNode, exportTypes, exports);
149
+ return exports;
150
+ }
151
+
152
+ protected extractCommentsFromTree(tree: any): string[] {
153
+ const comments: string[] = [];
154
+ this.collectNodesOfType(tree.rootNode, ['comment', 'block_comment', 'line_comment'], comments);
155
+ return comments;
156
+ }
157
+
158
+ private collectNodesOfType(node: any, types: string[], results: string[]) {
159
+ if (types.includes(node.type)) {
160
+ results.push(node.text || '');
161
+ }
162
+ for (let i = 0; i < node.childCount; i++) {
163
+ const child = node.child(i);
164
+ if (child) this.collectNodesOfType(child, types, results);
165
+ }
166
+ }
167
+ }
@@ -0,0 +1,58 @@
1
+ import { LanguageAdapter, ParseResult, CodeSymbol, SymbolType } from './types.js';
2
+
3
+ const BINARY_EXTS = new Set([
4
+ '.exe', '.dll', '.so', '.dylib', '.bin', '.wasm',
5
+ '.o', '.a', '.lib', '.pyc', '.class', '.jar', '.war',
6
+ '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.webp', '.bmp', '.tiff',
7
+ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
8
+ '.zip', '.tar', '.gz', '.bz2', '.7z', '.rar',
9
+ '.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv',
10
+ '.mp3', '.wav', '.flac', '.ogg',
11
+ ]);
12
+
13
+ export class GenericAdapter implements LanguageAdapter {
14
+ languageName(): string { return 'Generic'; }
15
+ fileExtensions(): string[] { return []; }
16
+ fileNames(): string[] { return []; }
17
+
18
+ canParse(filePath: string): boolean {
19
+ const ext = '.' + filePath.split('.').pop()?.toLowerCase();
20
+ return !BINARY_EXTS.has(ext);
21
+ }
22
+
23
+ supportsSymbols(): boolean { return false; }
24
+
25
+ async parse(content: string, filePath: string): Promise<ParseResult> {
26
+ const lines = content.split('\n');
27
+ const paragraphs = content.split(/\n\s*\n/).filter(p => p.trim().length > 0);
28
+ const symbols: CodeSymbol[] = [];
29
+
30
+ for (let i = 0; i < Math.min(paragraphs.length, 100); i++) {
31
+ const plines = paragraphs[i].split('\n');
32
+ const firstLine = plines[0].trim().substring(0, 80);
33
+ const startLine = this.lineOf(content, paragraphs[i]);
34
+ const endLine = startLine + plines.length - 1;
35
+
36
+ symbols.push({
37
+ id: `${filePath}:${startLine}`,
38
+ name: firstLine || `paragraph_${i}`,
39
+ type: SymbolType.Module,
40
+ language: 'generic',
41
+ file: filePath,
42
+ startLine,
43
+ endLine,
44
+ parent: null,
45
+ children: [],
46
+ metadata: { size: paragraphs[i].length },
47
+ });
48
+ }
49
+
50
+ return { symbols, imports: [], exports: [], comments: [] };
51
+ }
52
+
53
+ private lineOf(content: string, substring: string): number {
54
+ const idx = content.indexOf(substring);
55
+ if (idx < 0) return 1;
56
+ return content.substring(0, idx).split('\n').length;
57
+ }
58
+ }