gitnexus 1.4.7 → 1.4.9

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 (242) hide show
  1. package/README.md +29 -1
  2. package/dist/cli/ai-context.d.ts +1 -1
  3. package/dist/cli/ai-context.js +1 -1
  4. package/dist/cli/analyze.d.ts +2 -0
  5. package/dist/cli/analyze.js +54 -21
  6. package/dist/cli/index-repo.d.ts +15 -0
  7. package/dist/cli/index-repo.js +115 -0
  8. package/dist/cli/index.js +13 -3
  9. package/dist/cli/setup.js +90 -10
  10. package/dist/cli/wiki.d.ts +4 -0
  11. package/dist/cli/wiki.js +174 -53
  12. package/dist/config/supported-languages.d.ts +33 -1
  13. package/dist/config/supported-languages.js +32 -0
  14. package/dist/core/embeddings/embedder.d.ts +6 -1
  15. package/dist/core/embeddings/embedder.js +65 -5
  16. package/dist/core/embeddings/embedding-pipeline.js +11 -9
  17. package/dist/core/embeddings/http-client.d.ts +31 -0
  18. package/dist/core/embeddings/http-client.js +179 -0
  19. package/dist/core/embeddings/index.d.ts +1 -0
  20. package/dist/core/embeddings/index.js +1 -0
  21. package/dist/core/embeddings/types.d.ts +1 -1
  22. package/dist/core/graph/graph.js +9 -1
  23. package/dist/core/graph/types.d.ts +11 -2
  24. package/dist/core/ingestion/call-processor.d.ts +66 -2
  25. package/dist/core/ingestion/call-processor.js +650 -30
  26. package/dist/core/ingestion/call-routing.d.ts +9 -18
  27. package/dist/core/ingestion/call-routing.js +0 -19
  28. package/dist/core/ingestion/cobol/cobol-copy-expander.d.ts +57 -0
  29. package/dist/core/ingestion/cobol/cobol-copy-expander.js +385 -0
  30. package/dist/core/ingestion/cobol/cobol-preprocessor.d.ts +210 -0
  31. package/dist/core/ingestion/cobol/cobol-preprocessor.js +1509 -0
  32. package/dist/core/ingestion/cobol/jcl-parser.d.ts +68 -0
  33. package/dist/core/ingestion/cobol/jcl-parser.js +217 -0
  34. package/dist/core/ingestion/cobol/jcl-processor.d.ts +33 -0
  35. package/dist/core/ingestion/cobol/jcl-processor.js +229 -0
  36. package/dist/core/ingestion/cobol-processor.d.ts +54 -0
  37. package/dist/core/ingestion/cobol-processor.js +1186 -0
  38. package/dist/core/ingestion/entry-point-scoring.d.ts +17 -0
  39. package/dist/core/ingestion/entry-point-scoring.js +52 -28
  40. package/dist/core/ingestion/export-detection.d.ts +47 -8
  41. package/dist/core/ingestion/export-detection.js +29 -50
  42. package/dist/core/ingestion/field-extractor.d.ts +29 -0
  43. package/dist/core/ingestion/field-extractor.js +25 -0
  44. package/dist/core/ingestion/field-extractors/configs/c-cpp.d.ts +3 -0
  45. package/dist/core/ingestion/field-extractors/configs/c-cpp.js +108 -0
  46. package/dist/core/ingestion/field-extractors/configs/csharp.d.ts +8 -0
  47. package/dist/core/ingestion/field-extractors/configs/csharp.js +73 -0
  48. package/dist/core/ingestion/field-extractors/configs/dart.d.ts +8 -0
  49. package/dist/core/ingestion/field-extractors/configs/dart.js +76 -0
  50. package/dist/core/ingestion/field-extractors/configs/go.d.ts +11 -0
  51. package/dist/core/ingestion/field-extractors/configs/go.js +64 -0
  52. package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +44 -0
  53. package/dist/core/ingestion/field-extractors/configs/helpers.js +134 -0
  54. package/dist/core/ingestion/field-extractors/configs/jvm.d.ts +3 -0
  55. package/dist/core/ingestion/field-extractors/configs/jvm.js +118 -0
  56. package/dist/core/ingestion/field-extractors/configs/php.d.ts +8 -0
  57. package/dist/core/ingestion/field-extractors/configs/php.js +67 -0
  58. package/dist/core/ingestion/field-extractors/configs/python.d.ts +12 -0
  59. package/dist/core/ingestion/field-extractors/configs/python.js +91 -0
  60. package/dist/core/ingestion/field-extractors/configs/ruby.d.ts +16 -0
  61. package/dist/core/ingestion/field-extractors/configs/ruby.js +75 -0
  62. package/dist/core/ingestion/field-extractors/configs/rust.d.ts +9 -0
  63. package/dist/core/ingestion/field-extractors/configs/rust.js +55 -0
  64. package/dist/core/ingestion/field-extractors/configs/swift.d.ts +8 -0
  65. package/dist/core/ingestion/field-extractors/configs/swift.js +63 -0
  66. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.d.ts +3 -0
  67. package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +60 -0
  68. package/dist/core/ingestion/field-extractors/generic.d.ts +46 -0
  69. package/dist/core/ingestion/field-extractors/generic.js +111 -0
  70. package/dist/core/ingestion/field-extractors/typescript.d.ts +77 -0
  71. package/dist/core/ingestion/field-extractors/typescript.js +291 -0
  72. package/dist/core/ingestion/field-types.d.ts +59 -0
  73. package/dist/core/ingestion/field-types.js +2 -0
  74. package/dist/core/ingestion/framework-detection.d.ts +97 -2
  75. package/dist/core/ingestion/framework-detection.js +114 -14
  76. package/dist/core/ingestion/heritage-processor.js +62 -66
  77. package/dist/core/ingestion/import-processor.d.ts +9 -10
  78. package/dist/core/ingestion/import-processor.js +150 -196
  79. package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.d.ts +6 -9
  80. package/dist/core/ingestion/{resolvers → import-resolvers}/csharp.js +20 -2
  81. package/dist/core/ingestion/import-resolvers/dart.d.ts +7 -0
  82. package/dist/core/ingestion/import-resolvers/dart.js +44 -0
  83. package/dist/core/ingestion/{resolvers → import-resolvers}/go.d.ts +4 -5
  84. package/dist/core/ingestion/{resolvers → import-resolvers}/go.js +17 -0
  85. package/dist/core/ingestion/{resolvers → import-resolvers}/jvm.d.ts +10 -1
  86. package/dist/core/ingestion/import-resolvers/jvm.js +159 -0
  87. package/dist/core/ingestion/import-resolvers/php.d.ts +25 -0
  88. package/dist/core/ingestion/import-resolvers/php.js +80 -0
  89. package/dist/core/ingestion/{resolvers → import-resolvers}/python.d.ts +9 -3
  90. package/dist/core/ingestion/{resolvers → import-resolvers}/python.js +35 -3
  91. package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.d.ts +5 -2
  92. package/dist/core/ingestion/{resolvers → import-resolvers}/ruby.js +7 -2
  93. package/dist/core/ingestion/{resolvers → import-resolvers}/rust.d.ts +5 -2
  94. package/dist/core/ingestion/{resolvers → import-resolvers}/rust.js +41 -2
  95. package/dist/core/ingestion/{resolvers → import-resolvers}/standard.d.ts +15 -7
  96. package/dist/core/ingestion/{resolvers → import-resolvers}/standard.js +22 -3
  97. package/dist/core/ingestion/import-resolvers/swift.d.ts +7 -0
  98. package/dist/core/ingestion/import-resolvers/swift.js +23 -0
  99. package/dist/core/ingestion/import-resolvers/types.d.ts +44 -0
  100. package/dist/core/ingestion/import-resolvers/types.js +6 -0
  101. package/dist/core/ingestion/{resolvers → import-resolvers}/utils.d.ts +2 -0
  102. package/dist/core/ingestion/{resolvers → import-resolvers}/utils.js +7 -0
  103. package/dist/core/ingestion/language-config.d.ts +6 -0
  104. package/dist/core/ingestion/language-config.js +13 -0
  105. package/dist/core/ingestion/language-provider.d.ts +121 -0
  106. package/dist/core/ingestion/language-provider.js +24 -0
  107. package/dist/core/ingestion/languages/c-cpp.d.ts +12 -0
  108. package/dist/core/ingestion/languages/c-cpp.js +71 -0
  109. package/dist/core/ingestion/languages/cobol.d.ts +1 -0
  110. package/dist/core/ingestion/languages/cobol.js +26 -0
  111. package/dist/core/ingestion/languages/csharp.d.ts +8 -0
  112. package/dist/core/ingestion/languages/csharp.js +49 -0
  113. package/dist/core/ingestion/languages/dart.d.ts +12 -0
  114. package/dist/core/ingestion/languages/dart.js +58 -0
  115. package/dist/core/ingestion/languages/go.d.ts +11 -0
  116. package/dist/core/ingestion/languages/go.js +28 -0
  117. package/dist/core/ingestion/languages/index.d.ts +38 -0
  118. package/dist/core/ingestion/languages/index.js +63 -0
  119. package/dist/core/ingestion/languages/java.d.ts +9 -0
  120. package/dist/core/ingestion/languages/java.js +29 -0
  121. package/dist/core/ingestion/languages/kotlin.d.ts +9 -0
  122. package/dist/core/ingestion/languages/kotlin.js +53 -0
  123. package/dist/core/ingestion/languages/php.d.ts +8 -0
  124. package/dist/core/ingestion/languages/php.js +145 -0
  125. package/dist/core/ingestion/languages/python.d.ts +12 -0
  126. package/dist/core/ingestion/languages/python.js +39 -0
  127. package/dist/core/ingestion/languages/ruby.d.ts +9 -0
  128. package/dist/core/ingestion/languages/ruby.js +44 -0
  129. package/dist/core/ingestion/languages/rust.d.ts +12 -0
  130. package/dist/core/ingestion/languages/rust.js +44 -0
  131. package/dist/core/ingestion/languages/swift.d.ts +12 -0
  132. package/dist/core/ingestion/languages/swift.js +133 -0
  133. package/dist/core/ingestion/languages/typescript.d.ts +10 -0
  134. package/dist/core/ingestion/languages/typescript.js +60 -0
  135. package/dist/core/ingestion/markdown-processor.d.ts +17 -0
  136. package/dist/core/ingestion/markdown-processor.js +124 -0
  137. package/dist/core/ingestion/mro-processor.js +22 -18
  138. package/dist/core/ingestion/named-binding-processor.d.ts +18 -0
  139. package/dist/core/ingestion/named-binding-processor.js +42 -0
  140. package/dist/core/ingestion/named-bindings/csharp.d.ts +3 -0
  141. package/dist/core/ingestion/named-bindings/csharp.js +37 -0
  142. package/dist/core/ingestion/named-bindings/java.d.ts +3 -0
  143. package/dist/core/ingestion/named-bindings/java.js +29 -0
  144. package/dist/core/ingestion/named-bindings/kotlin.d.ts +3 -0
  145. package/dist/core/ingestion/named-bindings/kotlin.js +36 -0
  146. package/dist/core/ingestion/named-bindings/php.d.ts +3 -0
  147. package/dist/core/ingestion/named-bindings/php.js +61 -0
  148. package/dist/core/ingestion/named-bindings/python.d.ts +3 -0
  149. package/dist/core/ingestion/named-bindings/python.js +49 -0
  150. package/dist/core/ingestion/named-bindings/rust.d.ts +3 -0
  151. package/dist/core/ingestion/named-bindings/rust.js +64 -0
  152. package/dist/core/ingestion/named-bindings/types.d.ts +16 -0
  153. package/dist/core/ingestion/named-bindings/types.js +6 -0
  154. package/dist/core/ingestion/named-bindings/typescript.d.ts +3 -0
  155. package/dist/core/ingestion/named-bindings/typescript.js +58 -0
  156. package/dist/core/ingestion/parsing-processor.d.ts +6 -2
  157. package/dist/core/ingestion/parsing-processor.js +125 -85
  158. package/dist/core/ingestion/pipeline.d.ts +10 -0
  159. package/dist/core/ingestion/pipeline.js +1235 -317
  160. package/dist/core/ingestion/resolution-context.d.ts +5 -0
  161. package/dist/core/ingestion/resolution-context.js +8 -5
  162. package/dist/core/ingestion/route-extractors/expo.d.ts +1 -0
  163. package/dist/core/ingestion/route-extractors/expo.js +36 -0
  164. package/dist/core/ingestion/route-extractors/middleware.d.ts +47 -0
  165. package/dist/core/ingestion/route-extractors/middleware.js +143 -0
  166. package/dist/core/ingestion/route-extractors/nextjs.d.ts +3 -0
  167. package/dist/core/ingestion/route-extractors/nextjs.js +76 -0
  168. package/dist/core/ingestion/route-extractors/php.d.ts +7 -0
  169. package/dist/core/ingestion/route-extractors/php.js +21 -0
  170. package/dist/core/ingestion/route-extractors/response-shapes.d.ts +20 -0
  171. package/dist/core/ingestion/route-extractors/response-shapes.js +290 -0
  172. package/dist/core/ingestion/symbol-table.d.ts +16 -0
  173. package/dist/core/ingestion/symbol-table.js +20 -6
  174. package/dist/core/ingestion/tree-sitter-queries.d.ts +10 -9
  175. package/dist/core/ingestion/tree-sitter-queries.js +274 -11
  176. package/dist/core/ingestion/type-env.d.ts +42 -18
  177. package/dist/core/ingestion/type-env.js +481 -106
  178. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +5 -0
  179. package/dist/core/ingestion/type-extractors/c-cpp.js +119 -0
  180. package/dist/core/ingestion/type-extractors/csharp.js +149 -16
  181. package/dist/core/ingestion/type-extractors/dart.d.ts +15 -0
  182. package/dist/core/ingestion/type-extractors/dart.js +371 -0
  183. package/dist/core/ingestion/type-extractors/jvm.js +169 -66
  184. package/dist/core/ingestion/type-extractors/rust.js +35 -1
  185. package/dist/core/ingestion/type-extractors/shared.d.ts +1 -15
  186. package/dist/core/ingestion/type-extractors/shared.js +14 -112
  187. package/dist/core/ingestion/type-extractors/swift.js +338 -7
  188. package/dist/core/ingestion/type-extractors/types.d.ts +40 -8
  189. package/dist/core/ingestion/type-extractors/typescript.js +141 -9
  190. package/dist/core/ingestion/utils/ast-helpers.d.ts +83 -0
  191. package/dist/core/ingestion/utils/ast-helpers.js +817 -0
  192. package/dist/core/ingestion/utils/call-analysis.d.ts +73 -0
  193. package/dist/core/ingestion/utils/call-analysis.js +527 -0
  194. package/dist/core/ingestion/utils/event-loop.d.ts +5 -0
  195. package/dist/core/ingestion/utils/event-loop.js +5 -0
  196. package/dist/core/ingestion/utils/language-detection.d.ts +9 -0
  197. package/dist/core/ingestion/utils/language-detection.js +70 -0
  198. package/dist/core/ingestion/utils/verbose.d.ts +1 -0
  199. package/dist/core/ingestion/utils/verbose.js +7 -0
  200. package/dist/core/ingestion/workers/parse-worker.d.ts +55 -5
  201. package/dist/core/ingestion/workers/parse-worker.js +415 -225
  202. package/dist/core/lbug/csv-generator.js +51 -1
  203. package/dist/core/lbug/lbug-adapter.d.ts +10 -0
  204. package/dist/core/lbug/lbug-adapter.js +75 -4
  205. package/dist/core/lbug/schema.d.ts +8 -4
  206. package/dist/core/lbug/schema.js +65 -4
  207. package/dist/core/tree-sitter/parser-loader.js +7 -1
  208. package/dist/core/wiki/cursor-client.d.ts +31 -0
  209. package/dist/core/wiki/cursor-client.js +127 -0
  210. package/dist/core/wiki/generator.d.ts +28 -9
  211. package/dist/core/wiki/generator.js +115 -18
  212. package/dist/core/wiki/graph-queries.d.ts +4 -0
  213. package/dist/core/wiki/graph-queries.js +7 -1
  214. package/dist/core/wiki/llm-client.d.ts +2 -0
  215. package/dist/core/wiki/llm-client.js +8 -4
  216. package/dist/core/wiki/prompts.d.ts +3 -3
  217. package/dist/core/wiki/prompts.js +6 -0
  218. package/dist/mcp/core/embedder.js +11 -3
  219. package/dist/mcp/core/lbug-adapter.d.ts +5 -0
  220. package/dist/mcp/core/lbug-adapter.js +23 -2
  221. package/dist/mcp/local/local-backend.d.ts +38 -5
  222. package/dist/mcp/local/local-backend.js +804 -63
  223. package/dist/mcp/resources.js +2 -0
  224. package/dist/mcp/tools.js +73 -4
  225. package/dist/server/api.d.ts +19 -1
  226. package/dist/server/api.js +66 -6
  227. package/dist/storage/git.d.ts +12 -0
  228. package/dist/storage/git.js +21 -0
  229. package/dist/storage/repo-manager.d.ts +3 -0
  230. package/package.json +25 -16
  231. package/dist/core/ingestion/named-binding-extraction.d.ts +0 -61
  232. package/dist/core/ingestion/named-binding-extraction.js +0 -363
  233. package/dist/core/ingestion/resolvers/index.d.ts +0 -18
  234. package/dist/core/ingestion/resolvers/index.js +0 -13
  235. package/dist/core/ingestion/resolvers/jvm.js +0 -87
  236. package/dist/core/ingestion/resolvers/php.d.ts +0 -15
  237. package/dist/core/ingestion/resolvers/php.js +0 -35
  238. package/dist/core/ingestion/type-extractors/index.d.ts +0 -22
  239. package/dist/core/ingestion/type-extractors/index.js +0 -31
  240. package/dist/core/ingestion/utils.d.ts +0 -138
  241. package/dist/core/ingestion/utils.js +0 -1290
  242. package/scripts/patch-tree-sitter-swift.cjs +0 -74
@@ -1,15 +1,37 @@
1
1
  import Parser from 'tree-sitter';
2
2
  import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
3
- import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
3
+ import { getProvider, getProviderForFile, providersWithImplicitWiring } from './languages/index.js';
4
4
  import { generateId } from '../../lib/utils.js';
5
- import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
6
- import { SupportedLanguages } from '../../config/supported-languages.js';
7
- import { extractNamedBindings } from './named-binding-extraction.js';
5
+ import { getLanguageFromFilename } from './utils/language-detection.js';
6
+ import { isVerboseIngestionEnabled } from './utils/verbose.js';
7
+ import { yieldToEventLoop } from './utils/event-loop.js';
8
8
  import { getTreeSitterBufferSize } from './constants.js';
9
- import { loadTsconfigPaths, loadGoModulePath, loadComposerConfig, loadCSharpProjectConfig, loadSwiftPackageConfig, } from './language-config.js';
10
- import { buildSuffixIndex, resolveImportPath, appendKotlinWildcard, KOTLIN_EXTENSIONS, resolveJvmWildcard, resolveJvmMemberImport, resolveGoPackageDir, resolveGoPackage, resolveCSharpImport, resolveCSharpNamespaceDir, resolvePhpImport, resolveRustImport, resolveRubyImport, resolvePythonImport, } from './resolvers/index.js';
11
- import { callRouters } from './call-routing.js';
9
+ import { loadImportConfigs } from './language-config.js';
10
+ import { buildSuffixIndex } from './import-resolvers/utils.js';
12
11
  const isDev = process.env.NODE_ENV === 'development';
12
+ /** Group files by provider (only those with implicit import wiring), then call each wirer
13
+ * with its own language's files. O(n) over files, O(1) per provider lookup. */
14
+ function wireImplicitImports(files, importMap, addImportEdge, projectConfig) {
15
+ if (providersWithImplicitWiring.length === 0)
16
+ return;
17
+ const grouped = new Map();
18
+ for (const file of files) {
19
+ const provider = getProviderForFile(file);
20
+ if (!provider?.implicitImportWirer)
21
+ continue;
22
+ let list = grouped.get(provider);
23
+ if (!list) {
24
+ list = [];
25
+ grouped.set(provider, list);
26
+ }
27
+ list.push(file);
28
+ }
29
+ for (const [provider, langFiles] of grouped) {
30
+ if (langFiles.length > 1) {
31
+ provider.implicitImportWirer(langFiles, importMap, addImportEdge, projectConfig);
32
+ }
33
+ }
34
+ }
13
35
  /**
14
36
  * Check if a file path is directly inside a package directory identified by its suffix.
15
37
  * Used by the symbol resolver for Go and C# directory-level import matching.
@@ -22,125 +44,59 @@ export function isFileInPackageDir(filePath, dirSuffix) {
22
44
  const afterDir = normalized.substring(normalized.indexOf(dirSuffix) + dirSuffix.length);
23
45
  return !afterDir.includes('/');
24
46
  }
47
+ // ImportResolutionContext is defined in ./import-resolvers/types.ts — re-exported here for consumers.
25
48
  export function buildImportResolutionContext(allPaths) {
26
49
  const allFileList = allPaths;
27
50
  const normalizedFileList = allFileList.map(p => p.replace(/\\/g, '/'));
28
51
  const allFilePaths = new Set(allFileList);
29
- const suffixIndex = buildSuffixIndex(normalizedFileList, allFileList);
30
- return { allFilePaths, allFileList, normalizedFileList, suffixIndex, resolveCache: new Map() };
52
+ const index = buildSuffixIndex(normalizedFileList, allFileList);
53
+ return { allFilePaths, allFileList, normalizedFileList, index, resolveCache: new Map() };
31
54
  }
55
+ // Config loaders extracted to ./language-config.ts (Phase 2 refactor)
56
+ // Resolver types are in ./import-resolvers/types.ts; named binding types in ./named-bindings/types.ts
57
+ // ============================================================================
58
+ // Import path preprocessing
59
+ // ============================================================================
32
60
  /**
33
- * Shared language dispatch for import resolution.
34
- * Used by both processImports and processImportsFromExtracted.
61
+ * Clean and preprocess a raw import source text into a resolved import path.
62
+ * Strips quotes/angle brackets (universal) and applies provider-specific
63
+ * transformations (currently only Kotlin wildcard import detection).
35
64
  */
36
- function resolveLanguageImport(filePath, rawImportPath, language, configs, ctx) {
37
- const { allFilePaths, allFileList, normalizedFileList, index, resolveCache } = ctx;
38
- const { tsconfigPaths, goModule, composerConfig, swiftPackageConfig, csharpConfigs } = configs;
39
- // JVM languages (Java + Kotlin): handle wildcards and member imports
40
- if (language === SupportedLanguages.Java || language === SupportedLanguages.Kotlin) {
41
- const exts = language === SupportedLanguages.Java ? ['.java'] : KOTLIN_EXTENSIONS;
42
- if (rawImportPath.endsWith('.*')) {
43
- const matchedFiles = resolveJvmWildcard(rawImportPath, normalizedFileList, allFileList, exts, index);
44
- if (matchedFiles.length === 0 && language === SupportedLanguages.Kotlin) {
45
- const javaMatches = resolveJvmWildcard(rawImportPath, normalizedFileList, allFileList, ['.java'], index);
46
- if (javaMatches.length > 0)
47
- return { kind: 'files', files: javaMatches };
48
- }
49
- if (matchedFiles.length > 0)
50
- return { kind: 'files', files: matchedFiles };
51
- // Fall through to standard resolution
52
- }
53
- else {
54
- let memberResolved = resolveJvmMemberImport(rawImportPath, normalizedFileList, allFileList, exts, index);
55
- if (!memberResolved && language === SupportedLanguages.Kotlin) {
56
- memberResolved = resolveJvmMemberImport(rawImportPath, normalizedFileList, allFileList, ['.java'], index);
57
- }
58
- if (memberResolved)
59
- return { kind: 'files', files: [memberResolved] };
60
- // Fall through to standard resolution
61
- }
62
- }
63
- // Go: handle package-level imports
64
- if (language === SupportedLanguages.Go && goModule && rawImportPath.startsWith(goModule.modulePath)) {
65
- const pkgSuffix = resolveGoPackageDir(rawImportPath, goModule);
66
- if (pkgSuffix) {
67
- const pkgFiles = resolveGoPackage(rawImportPath, goModule, normalizedFileList, allFileList);
68
- if (pkgFiles.length > 0) {
69
- return { kind: 'package', files: pkgFiles, dirSuffix: pkgSuffix };
70
- }
71
- }
72
- // Fall through if no files found (package might be external)
73
- }
74
- // C#: handle namespace-based imports (using directives)
75
- if (language === SupportedLanguages.CSharp && csharpConfigs.length > 0) {
76
- const resolvedFiles = resolveCSharpImport(rawImportPath, csharpConfigs, normalizedFileList, allFileList, index);
77
- if (resolvedFiles.length > 1) {
78
- const dirSuffix = resolveCSharpNamespaceDir(rawImportPath, csharpConfigs);
79
- if (dirSuffix) {
80
- return { kind: 'package', files: resolvedFiles, dirSuffix };
81
- }
82
- }
83
- if (resolvedFiles.length > 0)
84
- return { kind: 'files', files: resolvedFiles };
65
+ export function preprocessImportPath(sourceText, importNode, provider) {
66
+ const cleaned = sourceText.replace(/['"<>]/g, '');
67
+ // Defense-in-depth: reject null bytes and control characters (matches Ruby call-routing pattern)
68
+ if (!cleaned || cleaned.length > 2048 || /[\x00-\x1f]/.test(cleaned))
85
69
  return null;
70
+ if (provider.importPathPreprocessor) {
71
+ return provider.importPathPreprocessor(cleaned, importNode);
86
72
  }
87
- // PHP: handle namespace-based imports (use statements)
88
- if (language === SupportedLanguages.PHP) {
89
- const resolved = resolvePhpImport(rawImportPath, composerConfig, allFilePaths, normalizedFileList, allFileList, index);
90
- return resolved ? { kind: 'files', files: [resolved] } : null;
91
- }
92
- // Swift: handle module imports
93
- if (language === SupportedLanguages.Swift && swiftPackageConfig) {
94
- const targetDir = swiftPackageConfig.targets.get(rawImportPath);
95
- if (targetDir) {
96
- const dirPrefix = targetDir + '/';
97
- const files = [];
98
- for (let i = 0; i < normalizedFileList.length; i++) {
99
- if (normalizedFileList[i].startsWith(dirPrefix) && normalizedFileList[i].endsWith('.swift')) {
100
- files.push(allFileList[i]);
101
- }
102
- }
103
- if (files.length > 0)
104
- return { kind: 'files', files };
105
- }
106
- return null; // External framework (Foundation, UIKit, etc.)
107
- }
108
- // Python: relative imports (PEP 328) + proximity-based bare imports
109
- // Falls through to standard suffix resolution when proximity finds no match.
110
- if (language === SupportedLanguages.Python) {
111
- const resolved = resolvePythonImport(filePath, rawImportPath, allFilePaths);
112
- if (resolved)
113
- return { kind: 'files', files: [resolved] };
114
- if (rawImportPath.startsWith('.'))
115
- return null; // relative but unresolved — don't suffix-match
116
- }
117
- // Ruby: require / require_relative
118
- if (language === SupportedLanguages.Ruby) {
119
- const resolved = resolveRubyImport(rawImportPath, normalizedFileList, allFileList, index);
120
- return resolved ? { kind: 'files', files: [resolved] } : null;
121
- }
122
- // Rust: expand top-level grouped imports: use {crate::a, crate::b}
123
- if (language === SupportedLanguages.Rust && rawImportPath.startsWith('{') && rawImportPath.endsWith('}')) {
124
- const inner = rawImportPath.slice(1, -1);
125
- const parts = inner.split(',').map(p => p.trim()).filter(Boolean);
126
- const resolved = [];
127
- for (const part of parts) {
128
- const r = resolveRustImport(filePath, part, allFilePaths);
129
- if (r)
130
- resolved.push(r);
131
- }
132
- return resolved.length > 0 ? { kind: 'files', files: resolved } : null;
133
- }
134
- // Standard single-file resolution
135
- const resolvedPath = resolveImportPath(filePath, rawImportPath, allFilePaths, allFileList, normalizedFileList, resolveCache, language, tsconfigPaths, index);
136
- return resolvedPath ? { kind: 'files', files: [resolvedPath] } : null;
73
+ return cleaned;
74
+ }
75
+ /** Create IMPORTS edge helpers that share a resolved-count tracker. */
76
+ function createImportEdgeHelpers(graph, importMap) {
77
+ let totalImportsResolved = 0;
78
+ const addImportGraphEdge = (filePath, resolvedPath) => {
79
+ const sourceId = generateId('File', filePath);
80
+ const targetId = generateId('File', resolvedPath);
81
+ const relId = generateId('IMPORTS', `${filePath}->${resolvedPath}`);
82
+ totalImportsResolved++;
83
+ graph.addRelationship({ id: relId, sourceId, targetId, type: 'IMPORTS', confidence: 1.0, reason: '' });
84
+ };
85
+ const addImportEdge = (filePath, resolvedPath) => {
86
+ addImportGraphEdge(filePath, resolvedPath);
87
+ if (!importMap.has(filePath))
88
+ importMap.set(filePath, new Set());
89
+ importMap.get(filePath).add(resolvedPath);
90
+ };
91
+ return { addImportEdge, addImportGraphEdge, getResolvedCount: () => totalImportsResolved };
137
92
  }
138
93
  /**
139
94
  * Apply an ImportResult: emit graph edges and update ImportMap/PackageMap.
140
95
  * If namedBindings are provided and the import resolves to a single file,
141
96
  * also populate the NamedImportMap for precise Tier 2a resolution.
97
+ * Bindings tagged with `isModuleAlias` are routed to moduleAliasMap instead.
142
98
  */
143
- function applyImportResult(result, filePath, importMap, packageMap, addImportEdge, addImportGraphEdge, namedBindings, namedImportMap) {
99
+ function applyImportResult(result, filePath, importMap, packageMap, addImportEdge, addImportGraphEdge, namedBindings, namedImportMap, moduleAliasMap) {
144
100
  if (!result)
145
101
  return;
146
102
  if (result.kind === 'package' && packageMap) {
@@ -158,14 +114,66 @@ function applyImportResult(result, filePath, importMap, packageMap, addImportEdg
158
114
  for (const resolvedFile of files) {
159
115
  addImportEdge(filePath, resolvedFile);
160
116
  }
161
- // Record named bindings for precise Tier 2a resolution
162
- if (namedBindings && namedImportMap && files.length === 1) {
117
+ // Route module aliases (import X as Y) directly to moduleAliasMap.
118
+ // These are module-level aliases, not symbol bindings — they don't belong in namedImportMap.
119
+ if (namedBindings && moduleAliasMap && files.length === 1) {
163
120
  const resolvedFile = files[0];
121
+ for (const binding of namedBindings) {
122
+ if (!binding.isModuleAlias)
123
+ continue;
124
+ let aliasMap = moduleAliasMap.get(filePath);
125
+ if (!aliasMap) {
126
+ aliasMap = new Map();
127
+ moduleAliasMap.set(filePath, aliasMap);
128
+ }
129
+ aliasMap.set(binding.local, resolvedFile);
130
+ }
131
+ }
132
+ // Record named bindings for precise Tier 2a resolution.
133
+ // If the same local name is imported from multiple files (e.g., Java static imports
134
+ // of overloaded methods), remove the entry so resolution falls through to Tier 2a
135
+ // import-scoped which sees all candidates and can apply arity narrowing.
136
+ if (namedBindings && namedImportMap) {
164
137
  if (!namedImportMap.has(filePath))
165
138
  namedImportMap.set(filePath, new Map());
166
139
  const fileBindings = namedImportMap.get(filePath);
167
- for (const binding of namedBindings) {
168
- fileBindings.set(binding.local, { sourcePath: resolvedFile, exportedName: binding.exported });
140
+ if (files.length === 1) {
141
+ const resolvedFile = files[0];
142
+ for (const binding of namedBindings) {
143
+ if (binding.isModuleAlias)
144
+ continue; // already routed to moduleAliasMap
145
+ const existing = fileBindings.get(binding.local);
146
+ if (existing && existing.sourcePath !== resolvedFile) {
147
+ fileBindings.delete(binding.local);
148
+ }
149
+ else {
150
+ fileBindings.set(binding.local, { sourcePath: resolvedFile, exportedName: binding.exported });
151
+ }
152
+ }
153
+ }
154
+ else {
155
+ // Multi-file resolution (e.g., Rust `use crate::models::{User, Repo}`).
156
+ // Match each binding to a resolved file by comparing the lowercase binding name
157
+ // to the file's basename (without extension). If no match, skip the binding.
158
+ for (const binding of namedBindings) {
159
+ if (binding.isModuleAlias)
160
+ continue;
161
+ const lowerName = binding.exported.toLowerCase();
162
+ const matchedFile = files.find(f => {
163
+ const base = f.replace(/\\/g, '/').split('/').pop() ?? '';
164
+ const nameWithoutExt = base.substring(0, base.lastIndexOf('.')).toLowerCase();
165
+ return nameWithoutExt === lowerName;
166
+ });
167
+ if (matchedFile) {
168
+ const existing = fileBindings.get(binding.local);
169
+ if (existing && existing.sourcePath !== matchedFile) {
170
+ fileBindings.delete(binding.local);
171
+ }
172
+ else {
173
+ fileBindings.set(binding.local, { sourcePath: matchedFile, exportedName: binding.exported });
174
+ }
175
+ }
176
+ }
169
177
  }
170
178
  }
171
179
  }
@@ -177,6 +185,7 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
177
185
  const importMap = ctx.importMap;
178
186
  const packageMap = ctx.packageMap;
179
187
  const namedImportMap = ctx.namedImportMap;
188
+ const moduleAliasMap = ctx.moduleAliasMap;
180
189
  // Use allPaths (full repo) when available for cross-chunk resolution, else fall back to chunk files
181
190
  const allFileList = allPaths ?? files.map(f => f.path);
182
191
  const allFilePaths = new Set(allFileList);
@@ -190,40 +199,10 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
190
199
  const index = buildSuffixIndex(normalizedFileList, allFileList);
191
200
  // Track import statistics
192
201
  let totalImportsFound = 0;
193
- let totalImportsResolved = 0;
194
202
  // Load language-specific configs once before the file loop
195
- const effectiveRoot = repoRoot || '';
196
- const configs = {
197
- tsconfigPaths: await loadTsconfigPaths(effectiveRoot),
198
- goModule: await loadGoModulePath(effectiveRoot),
199
- composerConfig: await loadComposerConfig(effectiveRoot),
200
- swiftPackageConfig: await loadSwiftPackageConfig(effectiveRoot),
201
- csharpConfigs: await loadCSharpProjectConfig(effectiveRoot),
202
- };
203
- const resolveCtx = { allFilePaths, allFileList, normalizedFileList, index, resolveCache };
204
- // Helper: add an IMPORTS edge to the graph only (no ImportMap update)
205
- const addImportGraphEdge = (filePath, resolvedPath) => {
206
- const sourceId = generateId('File', filePath);
207
- const targetId = generateId('File', resolvedPath);
208
- const relId = generateId('IMPORTS', `${filePath}->${resolvedPath}`);
209
- totalImportsResolved++;
210
- graph.addRelationship({
211
- id: relId,
212
- sourceId,
213
- targetId,
214
- type: 'IMPORTS',
215
- confidence: 1.0,
216
- reason: '',
217
- });
218
- };
219
- // Helper: add an IMPORTS edge + update import map
220
- const addImportEdge = (filePath, resolvedPath) => {
221
- addImportGraphEdge(filePath, resolvedPath);
222
- if (!importMap.has(filePath)) {
223
- importMap.set(filePath, new Set());
224
- }
225
- importMap.get(filePath).add(resolvedPath);
226
- };
203
+ const configs = await loadImportConfigs(repoRoot || '');
204
+ const resolveCtx = { allFilePaths, allFileList, normalizedFileList, index, resolveCache, configs };
205
+ const { addImportEdge, addImportGraphEdge, getResolvedCount } = createImportEdgeHelpers(graph, importMap);
227
206
  for (let i = 0; i < files.length; i++) {
228
207
  const file = files[i];
229
208
  onProgress?.(i + 1, files.length);
@@ -239,7 +218,8 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
239
218
  }
240
219
  continue;
241
220
  }
242
- const queryStr = LANGUAGE_QUERIES[language];
221
+ const provider = getProvider(language);
222
+ const queryStr = provider.treeSitterQueries;
243
223
  if (!queryStr)
244
224
  continue;
245
225
  // 2. ALWAYS load the language before querying (parser is stateful)
@@ -291,24 +271,23 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
291
271
  }
292
272
  return;
293
273
  }
294
- // Clean path (remove quotes and angle brackets for C/C++ includes)
295
- const rawImportPath = language === SupportedLanguages.Kotlin
296
- ? appendKotlinWildcard(sourceNode.text.replace(/['"<>]/g, ''), captureMap['import'])
297
- : sourceNode.text.replace(/['"<>]/g, '');
274
+ const rawImportPath = preprocessImportPath(sourceNode.text, captureMap['import'], provider);
275
+ if (!rawImportPath)
276
+ return;
298
277
  totalImportsFound++;
299
- const result = resolveLanguageImport(file.path, rawImportPath, language, configs, resolveCtx);
300
- const bindings = namedImportMap ? extractNamedBindings(captureMap['import'], language) : undefined;
301
- applyImportResult(result, file.path, importMap, packageMap, addImportEdge, addImportGraphEdge, bindings, namedImportMap);
278
+ const result = provider.importResolver(rawImportPath, file.path, resolveCtx);
279
+ const extractor = provider.namedBindingExtractor;
280
+ const bindings = namedImportMap && extractor ? extractor(captureMap['import']) : undefined;
281
+ applyImportResult(result, file.path, importMap, packageMap, addImportEdge, addImportGraphEdge, bindings, namedImportMap, moduleAliasMap);
302
282
  }
303
283
  // ---- Language-specific call-as-import routing (Ruby require, etc.) ----
304
284
  if (captureMap['call']) {
305
285
  const callNameNode = captureMap['call.name'];
306
286
  if (callNameNode) {
307
- const callRouter = callRouters[language];
308
- const routed = callRouter(callNameNode.text, captureMap['call']);
287
+ const routed = provider.callRouter?.(callNameNode.text, captureMap['call']);
309
288
  if (routed && routed.kind === 'import') {
310
289
  totalImportsFound++;
311
- const result = resolveLanguageImport(file.path, routed.importPath, language, configs, resolveCtx);
290
+ const result = provider.importResolver(routed.importPath, file.path, resolveCtx);
312
291
  applyImportResult(result, file.path, importMap, packageMap, addImportEdge, addImportGraphEdge);
313
292
  }
314
293
  }
@@ -316,13 +295,14 @@ export const processImports = async (graph, files, astCache, ctx, onProgress, re
316
295
  });
317
296
  // Tree is now owned by the LRU cache — no manual delete needed
318
297
  }
298
+ wireImplicitImports(allFileList, importMap, addImportEdge, configs);
319
299
  if (skippedByLang && skippedByLang.size > 0) {
320
300
  for (const [lang, count] of skippedByLang.entries()) {
321
301
  console.warn(`[ingestion] Skipped ${count} ${lang} file(s) in import processing — ${lang} parser not available.`);
322
302
  }
323
303
  }
324
304
  if (isDev) {
325
- console.log(`📊 Import processing complete: ${totalImportsResolved}/${totalImportsFound} imports resolved to graph edges`);
305
+ console.log(`📊 Import processing complete: ${getResolvedCount()}/${totalImportsFound} imports resolved to graph edges`);
326
306
  }
327
307
  };
328
308
  // ============================================================================
@@ -332,41 +312,13 @@ export const processImportsFromExtracted = async (graph, files, extractedImports
332
312
  const importMap = ctx.importMap;
333
313
  const packageMap = ctx.packageMap;
334
314
  const namedImportMap = ctx.namedImportMap;
315
+ const moduleAliasMap = ctx.moduleAliasMap;
335
316
  const importCtx = prebuiltCtx ?? buildImportResolutionContext(files.map(f => f.path));
336
- const { allFilePaths, allFileList, normalizedFileList, suffixIndex: index, resolveCache } = importCtx;
317
+ const { allFilePaths, allFileList, normalizedFileList, index, resolveCache } = importCtx;
337
318
  let totalImportsFound = 0;
338
- let totalImportsResolved = 0;
339
- const effectiveRoot = repoRoot || '';
340
- const configs = {
341
- tsconfigPaths: await loadTsconfigPaths(effectiveRoot),
342
- goModule: await loadGoModulePath(effectiveRoot),
343
- composerConfig: await loadComposerConfig(effectiveRoot),
344
- swiftPackageConfig: await loadSwiftPackageConfig(effectiveRoot),
345
- csharpConfigs: await loadCSharpProjectConfig(effectiveRoot),
346
- };
347
- const resolveCtx = { allFilePaths, allFileList, normalizedFileList, index, resolveCache };
348
- // Helper: add an IMPORTS edge to the graph only (no ImportMap update)
349
- const addImportGraphEdge = (filePath, resolvedPath) => {
350
- const sourceId = generateId('File', filePath);
351
- const targetId = generateId('File', resolvedPath);
352
- const relId = generateId('IMPORTS', `${filePath}->${resolvedPath}`);
353
- totalImportsResolved++;
354
- graph.addRelationship({
355
- id: relId,
356
- sourceId,
357
- targetId,
358
- type: 'IMPORTS',
359
- confidence: 1.0,
360
- reason: '',
361
- });
362
- };
363
- const addImportEdge = (filePath, resolvedPath) => {
364
- addImportGraphEdge(filePath, resolvedPath);
365
- if (!importMap.has(filePath)) {
366
- importMap.set(filePath, new Set());
367
- }
368
- importMap.get(filePath).add(resolvedPath);
369
- };
319
+ const configs = await loadImportConfigs(repoRoot || '');
320
+ const resolveCtx = { allFilePaths, allFileList, normalizedFileList, index, resolveCache, configs };
321
+ const { addImportEdge, addImportGraphEdge, getResolvedCount } = createImportEdgeHelpers(graph, importMap);
370
322
  // Group by file for progress reporting (users see file count, not import count)
371
323
  const importsByFile = new Map();
372
324
  for (const imp of extractedImports) {
@@ -387,12 +339,14 @@ export const processImportsFromExtracted = async (graph, files, extractedImports
387
339
  }
388
340
  for (const imp of fileImports) {
389
341
  totalImportsFound++;
390
- const result = resolveLanguageImport(filePath, imp.rawImportPath, imp.language, configs, resolveCtx);
391
- applyImportResult(result, filePath, importMap, packageMap, addImportEdge, addImportGraphEdge, imp.namedBindings, namedImportMap);
342
+ const provider = getProvider(imp.language);
343
+ const result = provider.importResolver(imp.rawImportPath, filePath, resolveCtx);
344
+ applyImportResult(result, filePath, importMap, packageMap, addImportEdge, addImportGraphEdge, imp.namedBindings, namedImportMap, moduleAliasMap);
392
345
  }
393
346
  }
394
347
  onProgress?.(totalFiles, totalFiles);
348
+ wireImplicitImports(files.map(f => f.path), importMap, addImportEdge, configs);
395
349
  if (isDev) {
396
- console.log(`📊 Import processing (fast path): ${totalImportsResolved}/${totalImportsFound} imports resolved to graph edges`);
350
+ console.log(`📊 Import processing (fast path): ${getResolvedCount()}/${totalImportsFound} imports resolved to graph edges`);
397
351
  }
398
352
  };
@@ -3,20 +3,17 @@
3
3
  * Handles using-directive resolution via .csproj root namespace stripping.
4
4
  */
5
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
- }
6
+ import type { ImportResult, ResolveCtx } from './types.js';
7
+ import type { CSharpProjectConfig } from '../language-config.js';
13
8
  /**
14
- * Resolve a C# using-directive import path to matching .cs files.
9
+ * Resolve a C# using-directive import path to matching .cs files (low-level helper).
15
10
  * Tries single-file match first, then directory match for namespace imports.
16
11
  */
17
- export declare function resolveCSharpImport(importPath: string, csharpConfigs: CSharpProjectConfig[], normalizedFileList: string[], allFileList: string[], index?: SuffixIndex): string[];
12
+ export declare function resolveCSharpImportInternal(importPath: string, csharpConfigs: CSharpProjectConfig[], normalizedFileList: string[], allFileList: string[], index?: SuffixIndex): string[];
18
13
  /**
19
14
  * Compute the directory suffix for a C# namespace import (for PackageMap).
20
15
  * Returns a suffix like "/ProjectDir/Models/" or null if no config matches.
21
16
  */
22
17
  export declare function resolveCSharpNamespaceDir(importPath: string, csharpConfigs: CSharpProjectConfig[]): string | null;
18
+ /** C#: namespace-based resolution via .csproj configs, with suffix-match fallback. */
19
+ export declare function resolveCSharpImport(rawImportPath: string, filePath: string, ctx: ResolveCtx): ImportResult;
@@ -3,11 +3,13 @@
3
3
  * Handles using-directive resolution via .csproj root namespace stripping.
4
4
  */
5
5
  import { suffixResolve } from './utils.js';
6
+ import { SupportedLanguages } from '../../../config/supported-languages.js';
7
+ import { resolveStandard } from './standard.js';
6
8
  /**
7
- * Resolve a C# using-directive import path to matching .cs files.
9
+ * Resolve a C# using-directive import path to matching .cs files (low-level helper).
8
10
  * Tries single-file match first, then directory match for namespace imports.
9
11
  */
10
- export function resolveCSharpImport(importPath, csharpConfigs, normalizedFileList, allFileList, index) {
12
+ export function resolveCSharpImportInternal(importPath, csharpConfigs, normalizedFileList, allFileList, index) {
11
13
  const namespacePath = importPath.replace(/\./g, '/');
12
14
  const results = [];
13
15
  for (const config of csharpConfigs) {
@@ -107,3 +109,19 @@ export function resolveCSharpNamespaceDir(importPath, csharpConfigs) {
107
109
  }
108
110
  return null;
109
111
  }
112
+ /** C#: namespace-based resolution via .csproj configs, with suffix-match fallback. */
113
+ export function resolveCSharpImport(rawImportPath, filePath, ctx) {
114
+ const csharpConfigs = ctx.configs.csharpConfigs;
115
+ if (csharpConfigs.length > 0) {
116
+ const resolvedFiles = resolveCSharpImportInternal(rawImportPath, csharpConfigs, ctx.normalizedFileList, ctx.allFileList, ctx.index);
117
+ if (resolvedFiles.length > 1) {
118
+ const dirSuffix = resolveCSharpNamespaceDir(rawImportPath, csharpConfigs);
119
+ if (dirSuffix) {
120
+ return { kind: 'package', files: resolvedFiles, dirSuffix };
121
+ }
122
+ }
123
+ if (resolvedFiles.length > 0)
124
+ return { kind: 'files', files: resolvedFiles };
125
+ }
126
+ return resolveStandard(rawImportPath, filePath, ctx, SupportedLanguages.CSharp);
127
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Dart import resolution.
3
+ * Handles package: imports (local packages) and relative imports.
4
+ * SDK imports (dart:*) and external packages are skipped.
5
+ */
6
+ import type { ImportResult, ResolveCtx } from './types.js';
7
+ export declare function resolveDartImport(rawImportPath: string, filePath: string, ctx: ResolveCtx): ImportResult;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Dart import resolution.
3
+ * Handles package: imports (local packages) and relative imports.
4
+ * SDK imports (dart:*) and external packages are skipped.
5
+ */
6
+ import { resolveStandard } from './standard.js';
7
+ import { SupportedLanguages } from '../../../config/supported-languages.js';
8
+ export function resolveDartImport(rawImportPath, filePath, ctx) {
9
+ // Strip surrounding quotes from configurable_uri capture
10
+ const stripped = rawImportPath.replace(/^['"]|['"]$/g, '');
11
+ // Skip dart: SDK imports (dart:async, dart:io, etc.)
12
+ if (stripped.startsWith('dart:'))
13
+ return null;
14
+ // Local package: imports → resolve to lib/<path>
15
+ if (stripped.startsWith('package:')) {
16
+ const slashIdx = stripped.indexOf('/');
17
+ if (slashIdx === -1)
18
+ return null;
19
+ const relPath = stripped.slice(slashIdx + 1);
20
+ const candidates = [`lib/${relPath}`, relPath];
21
+ const files = [];
22
+ for (const candidate of candidates) {
23
+ for (const fp of ctx.allFileList) {
24
+ if (fp.endsWith('/' + candidate) || fp === candidate) {
25
+ files.push(fp);
26
+ break;
27
+ }
28
+ }
29
+ if (files.length > 0)
30
+ break;
31
+ }
32
+ if (files.length > 0)
33
+ return { kind: 'files', files };
34
+ return null;
35
+ }
36
+ // Relative imports — use standard resolution.
37
+ // Dart relative imports don't require a leading "./" (e.g. `import 'models.dart'`).
38
+ // The standard resolver only recognises paths starting with "." as relative, so
39
+ // prepend "./" when the path doesn't already start with "." to ensure correct
40
+ // same-directory resolution (without this, "models.dart" would be mangled by the
41
+ // generic dot-to-slash conversion intended for Java-style package imports).
42
+ const relPath = stripped.startsWith('.') ? stripped : './' + stripped;
43
+ return resolveStandard(relPath, filePath, ctx, SupportedLanguages.Dart);
44
+ }
@@ -2,11 +2,8 @@
2
2
  * Go package import resolution.
3
3
  * Handles Go module path-based package imports.
4
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
- }
5
+ import type { ImportResult, ResolveCtx } from './types.js';
6
+ import type { GoModuleConfig } from '../language-config.js';
10
7
  /**
11
8
  * Extract the package directory suffix from a Go import path.
12
9
  * Returns the suffix string (e.g., "/internal/auth/") or null if invalid.
@@ -17,3 +14,5 @@ export declare function resolveGoPackageDir(importPath: string, goModule: GoModu
17
14
  * Returns an array of file paths.
18
15
  */
19
16
  export declare function resolveGoPackage(importPath: string, goModule: GoModuleConfig, normalizedFileList: string[], allFileList: string[]): string[];
17
+ /** Go: package-level imports via go.mod module path. */
18
+ export declare function resolveGoImport(rawImportPath: string, filePath: string, ctx: ResolveCtx): ImportResult;
@@ -2,6 +2,8 @@
2
2
  * Go package import resolution.
3
3
  * Handles Go module path-based package imports.
4
4
  */
5
+ import { SupportedLanguages } from '../../../config/supported-languages.js';
6
+ import { resolveStandard } from './standard.js';
5
7
  /**
6
8
  * Extract the package directory suffix from a Go import path.
7
9
  * Returns the suffix string (e.g., "/internal/auth/") or null if invalid.
@@ -40,3 +42,18 @@ export function resolveGoPackage(importPath, goModule, normalizedFileList, allFi
40
42
  }
41
43
  return matches;
42
44
  }
45
+ /** Go: package-level imports via go.mod module path. */
46
+ export function resolveGoImport(rawImportPath, filePath, ctx) {
47
+ const goModule = ctx.configs.goModule;
48
+ if (goModule && rawImportPath.startsWith(goModule.modulePath)) {
49
+ const pkgSuffix = resolveGoPackageDir(rawImportPath, goModule);
50
+ if (pkgSuffix) {
51
+ const pkgFiles = resolveGoPackage(rawImportPath, goModule, ctx.normalizedFileList, ctx.allFileList);
52
+ if (pkgFiles.length > 0) {
53
+ return { kind: 'package', files: pkgFiles, dirSuffix: pkgSuffix };
54
+ }
55
+ }
56
+ // Fall through if no files found (package might be external)
57
+ }
58
+ return resolveStandard(rawImportPath, filePath, ctx, SupportedLanguages.Go);
59
+ }