gitnexus 1.4.0 → 1.4.1
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 +194 -214
- package/dist/cli/ai-context.d.ts +1 -2
- package/dist/cli/ai-context.js +90 -117
- package/dist/cli/analyze.d.ts +0 -2
- package/dist/cli/analyze.js +2 -20
- package/dist/cli/index.js +25 -17
- package/dist/cli/setup.js +19 -17
- package/dist/core/augmentation/engine.js +20 -20
- package/dist/core/embeddings/embedding-pipeline.js +26 -26
- package/dist/core/graph/types.d.ts +2 -5
- package/dist/core/ingestion/ast-cache.js +2 -3
- package/dist/core/ingestion/call-processor.d.ts +5 -5
- package/dist/core/ingestion/call-processor.js +258 -173
- package/dist/core/ingestion/cluster-enricher.js +16 -16
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -2
- package/dist/core/ingestion/entry-point-scoring.js +22 -81
- package/dist/core/ingestion/framework-detection.d.ts +1 -5
- package/dist/core/ingestion/framework-detection.js +8 -39
- package/dist/core/ingestion/heritage-processor.d.ts +4 -13
- package/dist/core/ingestion/heritage-processor.js +28 -92
- package/dist/core/ingestion/import-processor.d.ts +19 -17
- package/dist/core/ingestion/import-processor.js +695 -170
- package/dist/core/ingestion/parsing-processor.d.ts +10 -1
- package/dist/core/ingestion/parsing-processor.js +177 -41
- package/dist/core/ingestion/pipeline.js +26 -49
- package/dist/core/ingestion/process-processor.js +1 -2
- package/dist/core/ingestion/symbol-table.d.ts +1 -12
- package/dist/core/ingestion/symbol-table.js +12 -19
- package/dist/core/ingestion/tree-sitter-queries.d.ts +11 -11
- package/dist/core/ingestion/tree-sitter-queries.js +485 -590
- package/dist/core/ingestion/utils.d.ts +0 -67
- package/dist/core/ingestion/utils.js +9 -692
- package/dist/core/ingestion/workers/parse-worker.d.ts +3 -20
- package/dist/core/ingestion/workers/parse-worker.js +345 -84
- package/dist/core/ingestion/workers/worker-pool.js +0 -8
- package/dist/core/kuzu/csv-generator.js +3 -19
- package/dist/core/kuzu/kuzu-adapter.js +19 -14
- package/dist/core/kuzu/schema.d.ts +3 -3
- package/dist/core/kuzu/schema.js +288 -303
- package/dist/core/search/bm25-index.js +6 -7
- package/dist/core/search/hybrid-search.js +3 -3
- package/dist/core/wiki/diagrams.d.ts +27 -0
- package/dist/core/wiki/diagrams.js +163 -0
- package/dist/core/wiki/generator.d.ts +50 -2
- package/dist/core/wiki/generator.js +548 -49
- package/dist/core/wiki/graph-queries.d.ts +42 -0
- package/dist/core/wiki/graph-queries.js +276 -97
- package/dist/core/wiki/html-viewer.js +192 -192
- package/dist/core/wiki/llm-client.js +73 -11
- package/dist/core/wiki/prompts.d.ts +52 -8
- package/dist/core/wiki/prompts.js +200 -86
- package/dist/mcp/core/kuzu-adapter.d.ts +3 -1
- package/dist/mcp/core/kuzu-adapter.js +44 -13
- package/dist/mcp/local/local-backend.js +128 -128
- package/dist/mcp/resources.js +42 -42
- package/dist/mcp/server.js +19 -18
- package/dist/mcp/tools.js +104 -103
- package/hooks/claude/gitnexus-hook.cjs +155 -238
- package/hooks/claude/pre-tool-use.sh +79 -79
- package/hooks/claude/session-start.sh +42 -42
- package/package.json +96 -96
- package/scripts/patch-tree-sitter-swift.cjs +74 -74
- package/skills/gitnexus-cli.md +82 -82
- package/skills/gitnexus-debugging.md +89 -89
- package/skills/gitnexus-exploring.md +78 -78
- package/skills/gitnexus-guide.md +64 -64
- package/skills/gitnexus-impact-analysis.md +97 -97
- package/skills/gitnexus-pr-review.md +163 -163
- package/skills/gitnexus-refactoring.md +121 -121
- package/vendor/leiden/index.cjs +355 -355
- package/vendor/leiden/utils.cjs +392 -392
- package/dist/cli/lazy-action.d.ts +0 -6
- package/dist/cli/lazy-action.js +0 -18
- package/dist/cli/skill-gen.d.ts +0 -26
- package/dist/cli/skill-gen.js +0 -549
- package/dist/core/ingestion/constants.d.ts +0 -16
- package/dist/core/ingestion/constants.js +0 -16
- package/dist/core/ingestion/export-detection.d.ts +0 -18
- package/dist/core/ingestion/export-detection.js +0 -230
- package/dist/core/ingestion/language-config.d.ts +0 -46
- package/dist/core/ingestion/language-config.js +0 -167
- package/dist/core/ingestion/mro-processor.d.ts +0 -45
- package/dist/core/ingestion/mro-processor.js +0 -369
- package/dist/core/ingestion/named-binding-extraction.d.ts +0 -61
- package/dist/core/ingestion/named-binding-extraction.js +0 -363
- package/dist/core/ingestion/resolvers/csharp.d.ts +0 -22
- package/dist/core/ingestion/resolvers/csharp.js +0 -109
- package/dist/core/ingestion/resolvers/go.d.ts +0 -19
- package/dist/core/ingestion/resolvers/go.js +0 -42
- package/dist/core/ingestion/resolvers/index.d.ts +0 -16
- package/dist/core/ingestion/resolvers/index.js +0 -11
- package/dist/core/ingestion/resolvers/jvm.d.ts +0 -23
- package/dist/core/ingestion/resolvers/jvm.js +0 -87
- package/dist/core/ingestion/resolvers/php.d.ts +0 -15
- package/dist/core/ingestion/resolvers/php.js +0 -35
- package/dist/core/ingestion/resolvers/rust.d.ts +0 -15
- package/dist/core/ingestion/resolvers/rust.js +0 -73
- package/dist/core/ingestion/resolvers/standard.d.ts +0 -28
- package/dist/core/ingestion/resolvers/standard.js +0 -145
- package/dist/core/ingestion/resolvers/utils.d.ts +0 -33
- package/dist/core/ingestion/resolvers/utils.js +0 -120
- package/dist/core/ingestion/symbol-resolver.d.ts +0 -32
- package/dist/core/ingestion/symbol-resolver.js +0 -83
- package/dist/core/ingestion/type-env.d.ts +0 -27
- package/dist/core/ingestion/type-env.js +0 -86
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/c-cpp.js +0 -60
- package/dist/core/ingestion/type-extractors/csharp.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/csharp.js +0 -89
- package/dist/core/ingestion/type-extractors/go.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/go.js +0 -105
- package/dist/core/ingestion/type-extractors/index.d.ts +0 -21
- package/dist/core/ingestion/type-extractors/index.js +0 -29
- package/dist/core/ingestion/type-extractors/jvm.d.ts +0 -3
- package/dist/core/ingestion/type-extractors/jvm.js +0 -121
- package/dist/core/ingestion/type-extractors/php.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/php.js +0 -31
- package/dist/core/ingestion/type-extractors/python.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/python.js +0 -41
- package/dist/core/ingestion/type-extractors/rust.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/rust.js +0 -39
- package/dist/core/ingestion/type-extractors/shared.d.ts +0 -17
- package/dist/core/ingestion/type-extractors/shared.js +0 -97
- package/dist/core/ingestion/type-extractors/swift.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/swift.js +0 -43
- package/dist/core/ingestion/type-extractors/types.d.ts +0 -14
- package/dist/core/ingestion/type-extractors/types.js +0 -1
- package/dist/core/ingestion/type-extractors/typescript.d.ts +0 -2
- package/dist/core/ingestion/type-extractors/typescript.js +0 -46
- package/dist/mcp/compatible-stdio-transport.d.ts +0 -25
- package/dist/mcp/compatible-stdio-transport.js +0 -200
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
2
|
-
/**
|
|
3
|
-
* Walk a named-binding re-export chain through NamedImportMap.
|
|
4
|
-
*
|
|
5
|
-
* When file A imports { User } from B, and B re-exports { User } from C,
|
|
6
|
-
* the NamedImportMap for A points to B, but B has no User definition.
|
|
7
|
-
* This function follows the chain: A→B→C until a definition is found.
|
|
8
|
-
*
|
|
9
|
-
* Returns the definitions found at the end of the chain, or null if the
|
|
10
|
-
* chain breaks (missing binding, circular reference, or depth exceeded).
|
|
11
|
-
* Max depth 5 to prevent infinite loops.
|
|
12
|
-
*
|
|
13
|
-
* @param allDefs Pre-computed `symbolTable.lookupFuzzy(name)` result — must be the
|
|
14
|
-
* complete unfiltered result. Passing a file-filtered subset will cause
|
|
15
|
-
* silent misses at depth=0 for non-aliased bindings.
|
|
16
|
-
*/
|
|
17
|
-
export function walkBindingChain(name, currentFilePath, symbolTable, namedImportMap, allDefs) {
|
|
18
|
-
let lookupFile = currentFilePath;
|
|
19
|
-
let lookupName = name;
|
|
20
|
-
const visited = new Set();
|
|
21
|
-
for (let depth = 0; depth < 5; depth++) {
|
|
22
|
-
const bindings = namedImportMap.get(lookupFile);
|
|
23
|
-
if (!bindings)
|
|
24
|
-
return null;
|
|
25
|
-
const binding = bindings.get(lookupName);
|
|
26
|
-
if (!binding)
|
|
27
|
-
return null;
|
|
28
|
-
const key = `${binding.sourcePath}:${binding.exportedName}`;
|
|
29
|
-
if (visited.has(key))
|
|
30
|
-
return null; // circular
|
|
31
|
-
visited.add(key);
|
|
32
|
-
const targetName = binding.exportedName;
|
|
33
|
-
const resolvedDefs = targetName !== lookupName || depth > 0
|
|
34
|
-
? symbolTable.lookupFuzzy(targetName).filter(def => def.filePath === binding.sourcePath)
|
|
35
|
-
: allDefs.filter(def => def.filePath === binding.sourcePath);
|
|
36
|
-
if (resolvedDefs.length > 0)
|
|
37
|
-
return resolvedDefs;
|
|
38
|
-
// No definition in source file → follow re-export chain
|
|
39
|
-
lookupFile = binding.sourcePath;
|
|
40
|
-
lookupName = targetName;
|
|
41
|
-
}
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Extract named bindings from an import AST node.
|
|
46
|
-
* Returns undefined if the import is not a named import (e.g., import * or default).
|
|
47
|
-
*
|
|
48
|
-
* TS: import { User, Repo as R } from './models'
|
|
49
|
-
* → [{local:'User', exported:'User'}, {local:'R', exported:'Repo'}]
|
|
50
|
-
*
|
|
51
|
-
* Python: from models import User, Repo as R
|
|
52
|
-
* → [{local:'User', exported:'User'}, {local:'R', exported:'Repo'}]
|
|
53
|
-
*/
|
|
54
|
-
export function extractNamedBindings(importNode, language) {
|
|
55
|
-
if (language === SupportedLanguages.TypeScript || language === SupportedLanguages.JavaScript) {
|
|
56
|
-
return extractTsNamedBindings(importNode);
|
|
57
|
-
}
|
|
58
|
-
if (language === SupportedLanguages.Python) {
|
|
59
|
-
return extractPythonNamedBindings(importNode);
|
|
60
|
-
}
|
|
61
|
-
if (language === SupportedLanguages.Kotlin) {
|
|
62
|
-
return extractKotlinNamedBindings(importNode);
|
|
63
|
-
}
|
|
64
|
-
if (language === SupportedLanguages.Rust) {
|
|
65
|
-
return extractRustNamedBindings(importNode);
|
|
66
|
-
}
|
|
67
|
-
if (language === SupportedLanguages.PHP) {
|
|
68
|
-
return extractPhpNamedBindings(importNode);
|
|
69
|
-
}
|
|
70
|
-
if (language === SupportedLanguages.CSharp) {
|
|
71
|
-
return extractCsharpNamedBindings(importNode);
|
|
72
|
-
}
|
|
73
|
-
if (language === SupportedLanguages.Java) {
|
|
74
|
-
return extractJavaNamedBindings(importNode);
|
|
75
|
-
}
|
|
76
|
-
return undefined;
|
|
77
|
-
}
|
|
78
|
-
export function extractTsNamedBindings(importNode) {
|
|
79
|
-
// import_statement > import_clause > named_imports > import_specifier*
|
|
80
|
-
const importClause = findChild(importNode, 'import_clause');
|
|
81
|
-
if (importClause) {
|
|
82
|
-
const namedImports = findChild(importClause, 'named_imports');
|
|
83
|
-
if (!namedImports)
|
|
84
|
-
return undefined; // default import, namespace import, or side-effect
|
|
85
|
-
const bindings = [];
|
|
86
|
-
for (let i = 0; i < namedImports.namedChildCount; i++) {
|
|
87
|
-
const specifier = namedImports.namedChild(i);
|
|
88
|
-
if (specifier?.type !== 'import_specifier')
|
|
89
|
-
continue;
|
|
90
|
-
const identifiers = [];
|
|
91
|
-
for (let j = 0; j < specifier.namedChildCount; j++) {
|
|
92
|
-
const child = specifier.namedChild(j);
|
|
93
|
-
if (child?.type === 'identifier')
|
|
94
|
-
identifiers.push(child.text);
|
|
95
|
-
}
|
|
96
|
-
if (identifiers.length === 1) {
|
|
97
|
-
bindings.push({ local: identifiers[0], exported: identifiers[0] });
|
|
98
|
-
}
|
|
99
|
-
else if (identifiers.length === 2) {
|
|
100
|
-
// import { Foo as Bar } → exported='Foo', local='Bar'
|
|
101
|
-
bindings.push({ local: identifiers[1], exported: identifiers[0] });
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return bindings.length > 0 ? bindings : undefined;
|
|
105
|
-
}
|
|
106
|
-
// Re-export: export { X } from './y' → export_statement > export_clause > export_specifier
|
|
107
|
-
const exportClause = findChild(importNode, 'export_clause');
|
|
108
|
-
if (exportClause) {
|
|
109
|
-
const bindings = [];
|
|
110
|
-
for (let i = 0; i < exportClause.namedChildCount; i++) {
|
|
111
|
-
const specifier = exportClause.namedChild(i);
|
|
112
|
-
if (specifier?.type !== 'export_specifier')
|
|
113
|
-
continue;
|
|
114
|
-
const identifiers = [];
|
|
115
|
-
for (let j = 0; j < specifier.namedChildCount; j++) {
|
|
116
|
-
const child = specifier.namedChild(j);
|
|
117
|
-
if (child?.type === 'identifier')
|
|
118
|
-
identifiers.push(child.text);
|
|
119
|
-
}
|
|
120
|
-
if (identifiers.length === 1) {
|
|
121
|
-
// export { User } from './base' → re-exports User as User
|
|
122
|
-
bindings.push({ local: identifiers[0], exported: identifiers[0] });
|
|
123
|
-
}
|
|
124
|
-
else if (identifiers.length === 2) {
|
|
125
|
-
// export { Repo as Repository } from './models' → name=Repo, alias=Repository
|
|
126
|
-
// For re-exports, the first id is the source name, second is what's exported
|
|
127
|
-
// When another file imports { Repository }, they get Repo from the source
|
|
128
|
-
bindings.push({ local: identifiers[1], exported: identifiers[0] });
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return bindings.length > 0 ? bindings : undefined;
|
|
132
|
-
}
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
export function extractPythonNamedBindings(importNode) {
|
|
136
|
-
// Only from import_from_statement, not plain import_statement
|
|
137
|
-
if (importNode.type !== 'import_from_statement')
|
|
138
|
-
return undefined;
|
|
139
|
-
const bindings = [];
|
|
140
|
-
for (let i = 0; i < importNode.namedChildCount; i++) {
|
|
141
|
-
const child = importNode.namedChild(i);
|
|
142
|
-
if (!child)
|
|
143
|
-
continue;
|
|
144
|
-
if (child.type === 'dotted_name') {
|
|
145
|
-
// Skip the module_name (first dotted_name is the source module)
|
|
146
|
-
const fieldName = importNode.childForFieldName?.('module_name');
|
|
147
|
-
if (fieldName && child.startIndex === fieldName.startIndex)
|
|
148
|
-
continue;
|
|
149
|
-
// This is an imported name: from x import User
|
|
150
|
-
const name = child.text;
|
|
151
|
-
if (name)
|
|
152
|
-
bindings.push({ local: name, exported: name });
|
|
153
|
-
}
|
|
154
|
-
if (child.type === 'aliased_import') {
|
|
155
|
-
// from x import Repo as R
|
|
156
|
-
const dottedName = findChild(child, 'dotted_name');
|
|
157
|
-
const aliasIdent = findChild(child, 'identifier');
|
|
158
|
-
if (dottedName && aliasIdent) {
|
|
159
|
-
bindings.push({ local: aliasIdent.text, exported: dottedName.text });
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
return bindings.length > 0 ? bindings : undefined;
|
|
164
|
-
}
|
|
165
|
-
export function extractKotlinNamedBindings(importNode) {
|
|
166
|
-
// import_header > identifier + import_alias > simple_identifier
|
|
167
|
-
if (importNode.type !== 'import_header')
|
|
168
|
-
return undefined;
|
|
169
|
-
const fullIdent = findChild(importNode, 'identifier');
|
|
170
|
-
if (!fullIdent)
|
|
171
|
-
return undefined;
|
|
172
|
-
const fullText = fullIdent.text;
|
|
173
|
-
const exportedName = fullText.includes('.') ? fullText.split('.').pop() : fullText;
|
|
174
|
-
const importAlias = findChild(importNode, 'import_alias');
|
|
175
|
-
if (importAlias) {
|
|
176
|
-
// Aliased: import com.example.User as U
|
|
177
|
-
const aliasIdent = findChild(importAlias, 'simple_identifier');
|
|
178
|
-
if (!aliasIdent)
|
|
179
|
-
return undefined;
|
|
180
|
-
return [{ local: aliasIdent.text, exported: exportedName }];
|
|
181
|
-
}
|
|
182
|
-
// Non-aliased: import com.example.User → local="User", exported="User"
|
|
183
|
-
// Skip wildcard imports (ending in *)
|
|
184
|
-
if (fullText.endsWith('.*') || fullText.endsWith('*'))
|
|
185
|
-
return undefined;
|
|
186
|
-
// Skip lowercase last segments — those are member/function imports (e.g.,
|
|
187
|
-
// import util.OneArg.writeAudit), not class imports. Multiple member imports
|
|
188
|
-
// with the same function name would collide in NamedImportMap, breaking
|
|
189
|
-
// arity-based disambiguation.
|
|
190
|
-
if (exportedName[0] && exportedName[0] === exportedName[0].toLowerCase())
|
|
191
|
-
return undefined;
|
|
192
|
-
return [{ local: exportedName, exported: exportedName }];
|
|
193
|
-
}
|
|
194
|
-
export function extractRustNamedBindings(importNode) {
|
|
195
|
-
// use_declaration may contain use_as_clause at any depth
|
|
196
|
-
if (importNode.type !== 'use_declaration')
|
|
197
|
-
return undefined;
|
|
198
|
-
const bindings = [];
|
|
199
|
-
collectRustBindings(importNode, bindings);
|
|
200
|
-
return bindings.length > 0 ? bindings : undefined;
|
|
201
|
-
}
|
|
202
|
-
function collectRustBindings(node, bindings) {
|
|
203
|
-
if (node.type === 'use_as_clause') {
|
|
204
|
-
// First identifier = exported name, second identifier = local alias
|
|
205
|
-
const idents = [];
|
|
206
|
-
for (let i = 0; i < node.namedChildCount; i++) {
|
|
207
|
-
const child = node.namedChild(i);
|
|
208
|
-
if (child?.type === 'identifier')
|
|
209
|
-
idents.push(child.text);
|
|
210
|
-
// For scoped_identifier, extract the last segment
|
|
211
|
-
if (child?.type === 'scoped_identifier') {
|
|
212
|
-
const nameNode = child.childForFieldName?.('name');
|
|
213
|
-
if (nameNode)
|
|
214
|
-
idents.push(nameNode.text);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
if (idents.length === 2) {
|
|
218
|
-
bindings.push({ local: idents[1], exported: idents[0] });
|
|
219
|
-
}
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
// Terminal identifier in a use_list: use crate::models::{User, Repo}
|
|
223
|
-
if (node.type === 'identifier' && node.parent?.type === 'use_list') {
|
|
224
|
-
bindings.push({ local: node.text, exported: node.text });
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
// Skip scoped_identifier that serves as path prefix in scoped_use_list
|
|
228
|
-
// e.g. use crate::models::{User, Repo} — the path node "crate::models" is not an importable symbol
|
|
229
|
-
if (node.type === 'scoped_identifier' && node.parent?.type === 'scoped_use_list') {
|
|
230
|
-
return; // path prefix — the use_list sibling handles the actual symbols
|
|
231
|
-
}
|
|
232
|
-
// Terminal scoped_identifier: use crate::models::User;
|
|
233
|
-
// Only extract if this is a leaf (no deeper use_list/use_as_clause/scoped_use_list)
|
|
234
|
-
if (node.type === 'scoped_identifier') {
|
|
235
|
-
let hasDeeper = false;
|
|
236
|
-
for (let i = 0; i < node.namedChildCount; i++) {
|
|
237
|
-
const child = node.namedChild(i);
|
|
238
|
-
if (child?.type === 'use_list' || child?.type === 'use_as_clause' || child?.type === 'scoped_use_list') {
|
|
239
|
-
hasDeeper = true;
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
if (!hasDeeper) {
|
|
244
|
-
const nameNode = node.childForFieldName?.('name');
|
|
245
|
-
if (nameNode) {
|
|
246
|
-
bindings.push({ local: nameNode.text, exported: nameNode.text });
|
|
247
|
-
}
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// Recurse into children
|
|
252
|
-
for (let i = 0; i < node.namedChildCount; i++) {
|
|
253
|
-
const child = node.namedChild(i);
|
|
254
|
-
if (child)
|
|
255
|
-
collectRustBindings(child, bindings);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
export function extractPhpNamedBindings(importNode) {
|
|
259
|
-
// namespace_use_declaration > namespace_use_clause* (flat)
|
|
260
|
-
// namespace_use_declaration > namespace_use_group > namespace_use_clause* (grouped)
|
|
261
|
-
if (importNode.type !== 'namespace_use_declaration')
|
|
262
|
-
return undefined;
|
|
263
|
-
const bindings = [];
|
|
264
|
-
// Collect all clauses — from direct children AND from namespace_use_group
|
|
265
|
-
const clauses = [];
|
|
266
|
-
for (let i = 0; i < importNode.namedChildCount; i++) {
|
|
267
|
-
const child = importNode.namedChild(i);
|
|
268
|
-
if (child?.type === 'namespace_use_clause') {
|
|
269
|
-
clauses.push(child);
|
|
270
|
-
}
|
|
271
|
-
else if (child?.type === 'namespace_use_group') {
|
|
272
|
-
for (let j = 0; j < child.namedChildCount; j++) {
|
|
273
|
-
const groupChild = child.namedChild(j);
|
|
274
|
-
if (groupChild?.type === 'namespace_use_clause')
|
|
275
|
-
clauses.push(groupChild);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
for (const clause of clauses) {
|
|
280
|
-
// Flat imports: qualified_name + name (alias)
|
|
281
|
-
let qualifiedName = null;
|
|
282
|
-
const names = [];
|
|
283
|
-
for (let j = 0; j < clause.namedChildCount; j++) {
|
|
284
|
-
const child = clause.namedChild(j);
|
|
285
|
-
if (child?.type === 'qualified_name')
|
|
286
|
-
qualifiedName = child;
|
|
287
|
-
else if (child?.type === 'name')
|
|
288
|
-
names.push(child);
|
|
289
|
-
}
|
|
290
|
-
if (qualifiedName && names.length > 0) {
|
|
291
|
-
// Flat aliased import: use App\Models\Repo as R;
|
|
292
|
-
const fullText = qualifiedName.text;
|
|
293
|
-
const exportedName = fullText.includes('\\') ? fullText.split('\\').pop() : fullText;
|
|
294
|
-
bindings.push({ local: names[0].text, exported: exportedName });
|
|
295
|
-
}
|
|
296
|
-
else if (qualifiedName && names.length === 0) {
|
|
297
|
-
// Flat non-aliased import: use App\Models\User;
|
|
298
|
-
const fullText = qualifiedName.text;
|
|
299
|
-
const lastSegment = fullText.includes('\\') ? fullText.split('\\').pop() : fullText;
|
|
300
|
-
bindings.push({ local: lastSegment, exported: lastSegment });
|
|
301
|
-
}
|
|
302
|
-
else if (!qualifiedName && names.length >= 2) {
|
|
303
|
-
// Grouped aliased import: {Repo as R} — first name = exported, second = alias
|
|
304
|
-
bindings.push({ local: names[1].text, exported: names[0].text });
|
|
305
|
-
}
|
|
306
|
-
else if (!qualifiedName && names.length === 1) {
|
|
307
|
-
// Grouped non-aliased import: {User} in use App\Models\{User, Repo as R}
|
|
308
|
-
bindings.push({ local: names[0].text, exported: names[0].text });
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return bindings.length > 0 ? bindings : undefined;
|
|
312
|
-
}
|
|
313
|
-
export function extractCsharpNamedBindings(importNode) {
|
|
314
|
-
// using_directive with identifier (alias) + qualified_name (target)
|
|
315
|
-
if (importNode.type !== 'using_directive')
|
|
316
|
-
return undefined;
|
|
317
|
-
let aliasIdent = null;
|
|
318
|
-
let qualifiedName = null;
|
|
319
|
-
for (let i = 0; i < importNode.namedChildCount; i++) {
|
|
320
|
-
const child = importNode.namedChild(i);
|
|
321
|
-
if (child?.type === 'identifier' && !aliasIdent)
|
|
322
|
-
aliasIdent = child;
|
|
323
|
-
else if (child?.type === 'qualified_name')
|
|
324
|
-
qualifiedName = child;
|
|
325
|
-
}
|
|
326
|
-
if (!aliasIdent || !qualifiedName)
|
|
327
|
-
return undefined;
|
|
328
|
-
const fullText = qualifiedName.text;
|
|
329
|
-
const exportedName = fullText.includes('.') ? fullText.split('.').pop() : fullText;
|
|
330
|
-
return [{ local: aliasIdent.text, exported: exportedName }];
|
|
331
|
-
}
|
|
332
|
-
export function extractJavaNamedBindings(importNode) {
|
|
333
|
-
// import_declaration > scoped_identifier "com.example.models.User"
|
|
334
|
-
// Wildcard imports (.*) don't produce named bindings
|
|
335
|
-
if (importNode.type !== 'import_declaration')
|
|
336
|
-
return undefined;
|
|
337
|
-
// Check for asterisk (wildcard import) — skip those
|
|
338
|
-
for (let i = 0; i < importNode.childCount; i++) {
|
|
339
|
-
const child = importNode.child(i);
|
|
340
|
-
if (child?.type === 'asterisk')
|
|
341
|
-
return undefined;
|
|
342
|
-
}
|
|
343
|
-
const scopedId = findChild(importNode, 'scoped_identifier');
|
|
344
|
-
if (!scopedId)
|
|
345
|
-
return undefined;
|
|
346
|
-
const fullText = scopedId.text;
|
|
347
|
-
const lastDot = fullText.lastIndexOf('.');
|
|
348
|
-
if (lastDot === -1)
|
|
349
|
-
return undefined;
|
|
350
|
-
const className = fullText.slice(lastDot + 1);
|
|
351
|
-
// Skip lowercase names — those are package imports, not class imports
|
|
352
|
-
if (className[0] && className[0] === className[0].toLowerCase())
|
|
353
|
-
return undefined;
|
|
354
|
-
return [{ local: className, exported: className }];
|
|
355
|
-
}
|
|
356
|
-
function findChild(node, type) {
|
|
357
|
-
for (let i = 0; i < node.namedChildCount; i++) {
|
|
358
|
-
const child = node.namedChild(i);
|
|
359
|
-
if (child?.type === type)
|
|
360
|
-
return child;
|
|
361
|
-
}
|
|
362
|
-
return null;
|
|
363
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* C# namespace import resolution.
|
|
3
|
-
* Handles using-directive resolution via .csproj root namespace stripping.
|
|
4
|
-
*/
|
|
5
|
-
import type { SuffixIndex } from './utils.js';
|
|
6
|
-
/** C# project config parsed from .csproj files */
|
|
7
|
-
export interface CSharpProjectConfig {
|
|
8
|
-
/** Root namespace from <RootNamespace> or assembly name (default: project directory name) */
|
|
9
|
-
rootNamespace: string;
|
|
10
|
-
/** Directory containing the .csproj file */
|
|
11
|
-
projectDir: string;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Resolve a C# using-directive import path to matching .cs files.
|
|
15
|
-
* Tries single-file match first, then directory match for namespace imports.
|
|
16
|
-
*/
|
|
17
|
-
export declare function resolveCSharpImport(importPath: string, csharpConfigs: CSharpProjectConfig[], normalizedFileList: string[], allFileList: string[], index?: SuffixIndex): string[];
|
|
18
|
-
/**
|
|
19
|
-
* Compute the directory suffix for a C# namespace import (for PackageMap).
|
|
20
|
-
* Returns a suffix like "/ProjectDir/Models/" or null if no config matches.
|
|
21
|
-
*/
|
|
22
|
-
export declare function resolveCSharpNamespaceDir(importPath: string, csharpConfigs: CSharpProjectConfig[]): string | null;
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* C# namespace import resolution.
|
|
3
|
-
* Handles using-directive resolution via .csproj root namespace stripping.
|
|
4
|
-
*/
|
|
5
|
-
import { suffixResolve } from './utils.js';
|
|
6
|
-
/**
|
|
7
|
-
* Resolve a C# using-directive import path to matching .cs files.
|
|
8
|
-
* Tries single-file match first, then directory match for namespace imports.
|
|
9
|
-
*/
|
|
10
|
-
export function resolveCSharpImport(importPath, csharpConfigs, normalizedFileList, allFileList, index) {
|
|
11
|
-
const namespacePath = importPath.replace(/\./g, '/');
|
|
12
|
-
const results = [];
|
|
13
|
-
for (const config of csharpConfigs) {
|
|
14
|
-
const nsPath = config.rootNamespace.replace(/\./g, '/');
|
|
15
|
-
let relative;
|
|
16
|
-
if (namespacePath.startsWith(nsPath + '/')) {
|
|
17
|
-
relative = namespacePath.slice(nsPath.length + 1);
|
|
18
|
-
}
|
|
19
|
-
else if (namespacePath === nsPath) {
|
|
20
|
-
// The import IS the root namespace — resolve to all .cs files in project root
|
|
21
|
-
relative = '';
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
const dirPrefix = config.projectDir
|
|
27
|
-
? (relative ? config.projectDir + '/' + relative : config.projectDir)
|
|
28
|
-
: relative;
|
|
29
|
-
// 1. Try as single file: relative.cs (e.g., "Models/DlqMessage.cs")
|
|
30
|
-
if (relative) {
|
|
31
|
-
const candidate = dirPrefix + '.cs';
|
|
32
|
-
if (index) {
|
|
33
|
-
const result = index.get(candidate) || index.getInsensitive(candidate);
|
|
34
|
-
if (result)
|
|
35
|
-
return [result];
|
|
36
|
-
}
|
|
37
|
-
// Also try suffix match
|
|
38
|
-
const suffixResult = index?.get(relative + '.cs') || index?.getInsensitive(relative + '.cs');
|
|
39
|
-
if (suffixResult)
|
|
40
|
-
return [suffixResult];
|
|
41
|
-
}
|
|
42
|
-
// 2. Try as directory: all .cs files directly inside (namespace import)
|
|
43
|
-
if (index) {
|
|
44
|
-
const dirFiles = index.getFilesInDir(dirPrefix, '.cs');
|
|
45
|
-
for (const f of dirFiles) {
|
|
46
|
-
const normalized = f.replace(/\\/g, '/');
|
|
47
|
-
// Check it's a direct child by finding the dirPrefix and ensuring no deeper slashes
|
|
48
|
-
const prefixIdx = normalized.indexOf(dirPrefix + '/');
|
|
49
|
-
if (prefixIdx < 0)
|
|
50
|
-
continue;
|
|
51
|
-
const afterDir = normalized.substring(prefixIdx + dirPrefix.length + 1);
|
|
52
|
-
if (!afterDir.includes('/')) {
|
|
53
|
-
results.push(f);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (results.length > 0)
|
|
57
|
-
return results;
|
|
58
|
-
}
|
|
59
|
-
// 3. Linear scan fallback for directory matching
|
|
60
|
-
if (results.length === 0) {
|
|
61
|
-
const dirTrail = dirPrefix + '/';
|
|
62
|
-
for (let i = 0; i < normalizedFileList.length; i++) {
|
|
63
|
-
const normalized = normalizedFileList[i];
|
|
64
|
-
if (!normalized.endsWith('.cs'))
|
|
65
|
-
continue;
|
|
66
|
-
const prefixIdx = normalized.indexOf(dirTrail);
|
|
67
|
-
if (prefixIdx < 0)
|
|
68
|
-
continue;
|
|
69
|
-
const afterDir = normalized.substring(prefixIdx + dirTrail.length);
|
|
70
|
-
if (!afterDir.includes('/')) {
|
|
71
|
-
results.push(allFileList[i]);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (results.length > 0)
|
|
75
|
-
return results;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// Fallback: suffix matching without namespace stripping (single file)
|
|
79
|
-
const pathParts = namespacePath.split('/').filter(Boolean);
|
|
80
|
-
const fallback = suffixResolve(pathParts, normalizedFileList, allFileList, index);
|
|
81
|
-
return fallback ? [fallback] : [];
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Compute the directory suffix for a C# namespace import (for PackageMap).
|
|
85
|
-
* Returns a suffix like "/ProjectDir/Models/" or null if no config matches.
|
|
86
|
-
*/
|
|
87
|
-
export function resolveCSharpNamespaceDir(importPath, csharpConfigs) {
|
|
88
|
-
const namespacePath = importPath.replace(/\./g, '/');
|
|
89
|
-
for (const config of csharpConfigs) {
|
|
90
|
-
const nsPath = config.rootNamespace.replace(/\./g, '/');
|
|
91
|
-
let relative;
|
|
92
|
-
if (namespacePath.startsWith(nsPath + '/')) {
|
|
93
|
-
relative = namespacePath.slice(nsPath.length + 1);
|
|
94
|
-
}
|
|
95
|
-
else if (namespacePath === nsPath) {
|
|
96
|
-
relative = '';
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
const dirPrefix = config.projectDir
|
|
102
|
-
? (relative ? config.projectDir + '/' + relative : config.projectDir)
|
|
103
|
-
: relative;
|
|
104
|
-
if (!dirPrefix)
|
|
105
|
-
continue;
|
|
106
|
-
return '/' + dirPrefix + '/';
|
|
107
|
-
}
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Go package import resolution.
|
|
3
|
-
* Handles Go module path-based package imports.
|
|
4
|
-
*/
|
|
5
|
-
/** Go module config parsed from go.mod */
|
|
6
|
-
export interface GoModuleConfig {
|
|
7
|
-
/** Module path (e.g., "github.com/user/repo") */
|
|
8
|
-
modulePath: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Extract the package directory suffix from a Go import path.
|
|
12
|
-
* Returns the suffix string (e.g., "/internal/auth/") or null if invalid.
|
|
13
|
-
*/
|
|
14
|
-
export declare function resolveGoPackageDir(importPath: string, goModule: GoModuleConfig): string | null;
|
|
15
|
-
/**
|
|
16
|
-
* Resolve a Go internal package import to all .go files in the package directory.
|
|
17
|
-
* Returns an array of file paths.
|
|
18
|
-
*/
|
|
19
|
-
export declare function resolveGoPackage(importPath: string, goModule: GoModuleConfig, normalizedFileList: string[], allFileList: string[]): string[];
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Go package import resolution.
|
|
3
|
-
* Handles Go module path-based package imports.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Extract the package directory suffix from a Go import path.
|
|
7
|
-
* Returns the suffix string (e.g., "/internal/auth/") or null if invalid.
|
|
8
|
-
*/
|
|
9
|
-
export function resolveGoPackageDir(importPath, goModule) {
|
|
10
|
-
if (!importPath.startsWith(goModule.modulePath))
|
|
11
|
-
return null;
|
|
12
|
-
const relativePkg = importPath.slice(goModule.modulePath.length + 1);
|
|
13
|
-
if (!relativePkg)
|
|
14
|
-
return null;
|
|
15
|
-
return '/' + relativePkg + '/';
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Resolve a Go internal package import to all .go files in the package directory.
|
|
19
|
-
* Returns an array of file paths.
|
|
20
|
-
*/
|
|
21
|
-
export function resolveGoPackage(importPath, goModule, normalizedFileList, allFileList) {
|
|
22
|
-
if (!importPath.startsWith(goModule.modulePath))
|
|
23
|
-
return [];
|
|
24
|
-
// Strip module path to get relative package path
|
|
25
|
-
const relativePkg = importPath.slice(goModule.modulePath.length + 1); // e.g., "internal/auth"
|
|
26
|
-
if (!relativePkg)
|
|
27
|
-
return [];
|
|
28
|
-
const pkgSuffix = '/' + relativePkg + '/';
|
|
29
|
-
const matches = [];
|
|
30
|
-
for (let i = 0; i < normalizedFileList.length; i++) {
|
|
31
|
-
// Prepend '/' so paths like "internal/auth/service.go" match suffix "/internal/auth/"
|
|
32
|
-
const normalized = '/' + normalizedFileList[i];
|
|
33
|
-
// File must be directly in the package directory (not a subdirectory)
|
|
34
|
-
if (normalized.includes(pkgSuffix) && normalized.endsWith('.go') && !normalized.endsWith('_test.go')) {
|
|
35
|
-
const afterPkg = normalized.substring(normalized.indexOf(pkgSuffix) + pkgSuffix.length);
|
|
36
|
-
if (!afterPkg.includes('/')) {
|
|
37
|
-
matches.push(allFileList[i]);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return matches;
|
|
42
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Language-specific import resolvers.
|
|
3
|
-
* Extracted from import-processor.ts for maintainability.
|
|
4
|
-
*/
|
|
5
|
-
export { EXTENSIONS, tryResolveWithExtensions, buildSuffixIndex, suffixResolve } from './utils.js';
|
|
6
|
-
export type { SuffixIndex } from './utils.js';
|
|
7
|
-
export { KOTLIN_EXTENSIONS, appendKotlinWildcard, resolveJvmWildcard, resolveJvmMemberImport } from './jvm.js';
|
|
8
|
-
export { resolveGoPackageDir, resolveGoPackage } from './go.js';
|
|
9
|
-
export type { GoModuleConfig } from './go.js';
|
|
10
|
-
export { resolveCSharpImport, resolveCSharpNamespaceDir } from './csharp.js';
|
|
11
|
-
export type { CSharpProjectConfig } from './csharp.js';
|
|
12
|
-
export { resolvePhpImport } from './php.js';
|
|
13
|
-
export type { ComposerConfig } from './php.js';
|
|
14
|
-
export { resolveRustImport, tryRustModulePath } from './rust.js';
|
|
15
|
-
export { resolveImportPath, RESOLVE_CACHE_CAP } from './standard.js';
|
|
16
|
-
export type { TsconfigPaths } from './standard.js';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Language-specific import resolvers.
|
|
3
|
-
* Extracted from import-processor.ts for maintainability.
|
|
4
|
-
*/
|
|
5
|
-
export { EXTENSIONS, tryResolveWithExtensions, buildSuffixIndex, suffixResolve } from './utils.js';
|
|
6
|
-
export { KOTLIN_EXTENSIONS, appendKotlinWildcard, resolveJvmWildcard, resolveJvmMemberImport } from './jvm.js';
|
|
7
|
-
export { resolveGoPackageDir, resolveGoPackage } from './go.js';
|
|
8
|
-
export { resolveCSharpImport, resolveCSharpNamespaceDir } from './csharp.js';
|
|
9
|
-
export { resolvePhpImport } from './php.js';
|
|
10
|
-
export { resolveRustImport, tryRustModulePath } from './rust.js';
|
|
11
|
-
export { resolveImportPath, RESOLVE_CACHE_CAP } from './standard.js';
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JVM import resolution (Java + Kotlin).
|
|
3
|
-
* Handles wildcard imports, member/static imports, and Kotlin-specific patterns.
|
|
4
|
-
*/
|
|
5
|
-
import type { SuffixIndex } from './utils.js';
|
|
6
|
-
/** Kotlin file extensions for JVM resolver reuse */
|
|
7
|
-
export declare const KOTLIN_EXTENSIONS: readonly string[];
|
|
8
|
-
/**
|
|
9
|
-
* Append .* to a Kotlin import path if the AST has a wildcard_import sibling node.
|
|
10
|
-
* Pure function — returns a new string without mutating the input.
|
|
11
|
-
*/
|
|
12
|
-
export declare const appendKotlinWildcard: (importPath: string, importNode: any) => string;
|
|
13
|
-
/**
|
|
14
|
-
* Resolve a JVM wildcard import (com.example.*) to all matching files.
|
|
15
|
-
* Works for both Java (.java) and Kotlin (.kt, .kts).
|
|
16
|
-
*/
|
|
17
|
-
export declare function resolveJvmWildcard(importPath: string, normalizedFileList: string[], allFileList: string[], extensions: readonly string[], index?: SuffixIndex): string[];
|
|
18
|
-
/**
|
|
19
|
-
* Try to resolve a JVM member/static import by stripping the member name.
|
|
20
|
-
* Java: "com.example.Constants.VALUE" -> resolve "com.example.Constants"
|
|
21
|
-
* Kotlin: "com.example.Constants.VALUE" -> resolve "com.example.Constants"
|
|
22
|
-
*/
|
|
23
|
-
export declare function resolveJvmMemberImport(importPath: string, normalizedFileList: string[], allFileList: string[], extensions: readonly string[], index?: SuffixIndex): string | null;
|