@kodus/kodus-graph 0.2.8 → 0.2.10

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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +252 -0
  3. package/dist/analysis/blast-radius.d.ts +2 -0
  4. package/dist/analysis/blast-radius.js +55 -0
  5. package/dist/analysis/communities.d.ts +28 -0
  6. package/dist/analysis/communities.js +100 -0
  7. package/dist/analysis/context-builder.d.ts +34 -0
  8. package/dist/analysis/context-builder.js +92 -0
  9. package/dist/analysis/diff.d.ts +41 -0
  10. package/dist/analysis/diff.js +155 -0
  11. package/dist/analysis/enrich.d.ts +5 -0
  12. package/dist/analysis/enrich.js +126 -0
  13. package/dist/analysis/flows.d.ts +27 -0
  14. package/dist/analysis/flows.js +86 -0
  15. package/dist/analysis/inheritance.d.ts +3 -0
  16. package/dist/analysis/inheritance.js +31 -0
  17. package/dist/analysis/prompt-formatter.d.ts +2 -0
  18. package/dist/analysis/prompt-formatter.js +173 -0
  19. package/dist/analysis/risk-score.d.ts +4 -0
  20. package/dist/analysis/risk-score.js +51 -0
  21. package/dist/analysis/search.d.ts +11 -0
  22. package/dist/analysis/search.js +64 -0
  23. package/dist/analysis/test-gaps.d.ts +2 -0
  24. package/dist/analysis/test-gaps.js +14 -0
  25. package/dist/cli.d.ts +2 -0
  26. package/dist/cli.js +210 -0
  27. package/dist/commands/analyze.d.ts +9 -0
  28. package/dist/commands/analyze.js +116 -0
  29. package/dist/commands/communities.d.ts +8 -0
  30. package/dist/commands/communities.js +9 -0
  31. package/dist/commands/context.d.ts +12 -0
  32. package/dist/commands/context.js +130 -0
  33. package/dist/commands/diff.d.ts +9 -0
  34. package/dist/commands/diff.js +89 -0
  35. package/dist/commands/flows.d.ts +8 -0
  36. package/dist/commands/flows.js +9 -0
  37. package/dist/commands/parse.d.ts +11 -0
  38. package/dist/commands/parse.js +101 -0
  39. package/dist/commands/search.d.ts +12 -0
  40. package/dist/commands/search.js +27 -0
  41. package/dist/commands/update.d.ts +7 -0
  42. package/dist/commands/update.js +154 -0
  43. package/dist/graph/builder.d.ts +6 -0
  44. package/dist/graph/builder.js +248 -0
  45. package/dist/graph/edges.d.ts +23 -0
  46. package/dist/graph/edges.js +159 -0
  47. package/dist/graph/json-writer.d.ts +9 -0
  48. package/dist/graph/json-writer.js +38 -0
  49. package/dist/graph/loader.d.ts +13 -0
  50. package/dist/graph/loader.js +101 -0
  51. package/dist/graph/merger.d.ts +7 -0
  52. package/dist/graph/merger.js +18 -0
  53. package/dist/graph/types.d.ts +252 -0
  54. package/dist/graph/types.js +1 -0
  55. package/dist/parser/batch.d.ts +5 -0
  56. package/dist/parser/batch.js +93 -0
  57. package/dist/parser/discovery.d.ts +7 -0
  58. package/dist/parser/discovery.js +61 -0
  59. package/dist/parser/extractor.d.ts +4 -0
  60. package/dist/parser/extractor.js +33 -0
  61. package/dist/parser/extractors/generic.d.ts +8 -0
  62. package/dist/parser/extractors/generic.js +471 -0
  63. package/dist/parser/extractors/python.d.ts +8 -0
  64. package/dist/parser/extractors/python.js +133 -0
  65. package/dist/parser/extractors/ruby.d.ts +8 -0
  66. package/dist/parser/extractors/ruby.js +153 -0
  67. package/dist/parser/extractors/typescript.d.ts +10 -0
  68. package/dist/parser/extractors/typescript.js +365 -0
  69. package/dist/parser/languages.d.ts +32 -0
  70. package/dist/parser/languages.js +304 -0
  71. package/dist/resolver/call-resolver.d.ts +36 -0
  72. package/dist/resolver/call-resolver.js +178 -0
  73. package/dist/resolver/external-detector.d.ts +11 -0
  74. package/dist/resolver/external-detector.js +820 -0
  75. package/dist/resolver/fs-cache.d.ts +8 -0
  76. package/dist/resolver/fs-cache.js +36 -0
  77. package/dist/resolver/import-map.d.ts +12 -0
  78. package/dist/resolver/import-map.js +21 -0
  79. package/dist/resolver/import-resolver.d.ts +19 -0
  80. package/dist/resolver/import-resolver.js +310 -0
  81. package/dist/resolver/languages/csharp.d.ts +3 -0
  82. package/dist/resolver/languages/csharp.js +94 -0
  83. package/dist/resolver/languages/go.d.ts +3 -0
  84. package/dist/resolver/languages/go.js +197 -0
  85. package/dist/resolver/languages/java.d.ts +1 -0
  86. package/dist/resolver/languages/java.js +193 -0
  87. package/dist/resolver/languages/php.d.ts +3 -0
  88. package/dist/resolver/languages/php.js +75 -0
  89. package/dist/resolver/languages/python.d.ts +11 -0
  90. package/dist/resolver/languages/python.js +127 -0
  91. package/dist/resolver/languages/ruby.d.ts +24 -0
  92. package/dist/resolver/languages/ruby.js +110 -0
  93. package/dist/resolver/languages/rust.d.ts +1 -0
  94. package/dist/resolver/languages/rust.js +197 -0
  95. package/dist/resolver/languages/typescript.d.ts +35 -0
  96. package/dist/resolver/languages/typescript.js +416 -0
  97. package/dist/resolver/re-export-resolver.d.ts +24 -0
  98. package/dist/resolver/re-export-resolver.js +57 -0
  99. package/dist/resolver/symbol-table.d.ts +17 -0
  100. package/dist/resolver/symbol-table.js +60 -0
  101. package/dist/shared/extract-calls.d.ts +26 -0
  102. package/dist/shared/extract-calls.js +57 -0
  103. package/dist/shared/file-hash.d.ts +3 -0
  104. package/dist/shared/file-hash.js +10 -0
  105. package/dist/shared/filters.d.ts +3 -0
  106. package/dist/shared/filters.js +240 -0
  107. package/dist/shared/logger.d.ts +6 -0
  108. package/dist/shared/logger.js +17 -0
  109. package/dist/shared/qualified-name.d.ts +1 -0
  110. package/dist/shared/qualified-name.js +9 -0
  111. package/dist/shared/safe-path.d.ts +6 -0
  112. package/dist/shared/safe-path.js +29 -0
  113. package/dist/shared/schemas.d.ts +43 -0
  114. package/dist/shared/schemas.js +30 -0
  115. package/dist/shared/temp.d.ts +11 -0
  116. package/{src/shared/temp.ts → dist/shared/temp.js} +4 -5
  117. package/package.json +20 -6
  118. package/src/analysis/blast-radius.ts +0 -54
  119. package/src/analysis/communities.ts +0 -135
  120. package/src/analysis/context-builder.ts +0 -130
  121. package/src/analysis/diff.ts +0 -169
  122. package/src/analysis/enrich.ts +0 -110
  123. package/src/analysis/flows.ts +0 -112
  124. package/src/analysis/inheritance.ts +0 -34
  125. package/src/analysis/prompt-formatter.ts +0 -175
  126. package/src/analysis/risk-score.ts +0 -62
  127. package/src/analysis/search.ts +0 -76
  128. package/src/analysis/test-gaps.ts +0 -21
  129. package/src/cli.ts +0 -210
  130. package/src/commands/analyze.ts +0 -128
  131. package/src/commands/communities.ts +0 -19
  132. package/src/commands/context.ts +0 -182
  133. package/src/commands/diff.ts +0 -96
  134. package/src/commands/flows.ts +0 -19
  135. package/src/commands/parse.ts +0 -124
  136. package/src/commands/search.ts +0 -41
  137. package/src/commands/update.ts +0 -166
  138. package/src/graph/builder.ts +0 -209
  139. package/src/graph/edges.ts +0 -101
  140. package/src/graph/json-writer.ts +0 -43
  141. package/src/graph/loader.ts +0 -113
  142. package/src/graph/merger.ts +0 -25
  143. package/src/graph/types.ts +0 -283
  144. package/src/parser/batch.ts +0 -82
  145. package/src/parser/discovery.ts +0 -75
  146. package/src/parser/extractor.ts +0 -37
  147. package/src/parser/extractors/generic.ts +0 -132
  148. package/src/parser/extractors/python.ts +0 -133
  149. package/src/parser/extractors/ruby.ts +0 -147
  150. package/src/parser/extractors/typescript.ts +0 -350
  151. package/src/parser/languages.ts +0 -122
  152. package/src/resolver/call-resolver.ts +0 -244
  153. package/src/resolver/import-map.ts +0 -27
  154. package/src/resolver/import-resolver.ts +0 -72
  155. package/src/resolver/languages/csharp.ts +0 -7
  156. package/src/resolver/languages/go.ts +0 -7
  157. package/src/resolver/languages/java.ts +0 -7
  158. package/src/resolver/languages/php.ts +0 -7
  159. package/src/resolver/languages/python.ts +0 -35
  160. package/src/resolver/languages/ruby.ts +0 -21
  161. package/src/resolver/languages/rust.ts +0 -7
  162. package/src/resolver/languages/typescript.ts +0 -168
  163. package/src/resolver/re-export-resolver.ts +0 -66
  164. package/src/resolver/symbol-table.ts +0 -67
  165. package/src/shared/extract-calls.ts +0 -75
  166. package/src/shared/file-hash.ts +0 -12
  167. package/src/shared/filters.ts +0 -243
  168. package/src/shared/logger.ts +0 -17
  169. package/src/shared/qualified-name.ts +0 -5
  170. package/src/shared/safe-path.ts +0 -31
  171. package/src/shared/schemas.ts +0 -32
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Ruby import resolver.
3
+ *
4
+ * Handles require_relative paths, Gemfile path: gems, and Zeitwerk autoload.
5
+ */
6
+ import { readFileSync } from 'fs';
7
+ import { dirname, join, resolve as resolvePath } from 'path';
8
+ import { cachedExists } from '../fs-cache';
9
+ /** Cache parsed Gemfile path gems per repo root. */
10
+ const gemfileCache = new Map();
11
+ /**
12
+ * Parse Gemfile for path: gems and return their lib directories (absolute).
13
+ */
14
+ function getGemPathLibDirs(repoRoot) {
15
+ if (gemfileCache.has(repoRoot)) {
16
+ return gemfileCache.get(repoRoot);
17
+ }
18
+ const gemfilePath = join(repoRoot, 'Gemfile');
19
+ const libDirs = [];
20
+ if (cachedExists(gemfilePath)) {
21
+ const content = readFileSync(gemfilePath, 'utf-8');
22
+ // Match lines like: gem 'mylib', path: './libs/mylib'
23
+ const regex = /^\s*gem\s+['"][^'"]+['"]\s*,\s*path:\s*['"]([^'"]+)['"]/gm;
24
+ let match = regex.exec(content);
25
+ while (match !== null) {
26
+ const gemPath = match[1];
27
+ libDirs.push(resolvePath(join(repoRoot, gemPath, 'lib')));
28
+ match = regex.exec(content);
29
+ }
30
+ }
31
+ gemfileCache.set(repoRoot, libDirs);
32
+ return libDirs;
33
+ }
34
+ /**
35
+ * Resolve a Ruby require/require_relative to a file path.
36
+ */
37
+ export function resolve(fromAbsFile, modulePath, repoRoot) {
38
+ if (!modulePath) {
39
+ return null;
40
+ }
41
+ // 1. Try relative resolution (require_relative style)
42
+ const base = join(dirname(fromAbsFile), modulePath);
43
+ if (cachedExists(`${base}.rb`)) {
44
+ return resolvePath(`${base}.rb`);
45
+ }
46
+ if (cachedExists(base)) {
47
+ return resolvePath(base);
48
+ }
49
+ // 2. Try Gemfile path: gems
50
+ for (const libDir of getGemPathLibDirs(repoRoot)) {
51
+ const candidate = join(libDir, modulePath);
52
+ if (cachedExists(`${candidate}.rb`)) {
53
+ return resolvePath(`${candidate}.rb`);
54
+ }
55
+ if (cachedExists(candidate)) {
56
+ return resolvePath(candidate);
57
+ }
58
+ }
59
+ return null;
60
+ }
61
+ /** Common Rails autoload paths that Zeitwerk watches. */
62
+ const ZEITWERK_AUTOLOAD_PATHS = [
63
+ 'app/models',
64
+ 'app/controllers',
65
+ 'app/services',
66
+ 'app/jobs',
67
+ 'app/mailers',
68
+ 'app/helpers',
69
+ 'lib',
70
+ ];
71
+ /**
72
+ * Convert a CamelCase segment to snake_case.
73
+ * E.g., "AuthService" → "auth_service", "UsersController" → "users_controller"
74
+ */
75
+ function camelToSnake(name) {
76
+ return name
77
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
78
+ .replace(/([a-z\d])([A-Z])/g, '$1_$2')
79
+ .toLowerCase();
80
+ }
81
+ /**
82
+ * Resolve a Ruby class/module constant name to a file path using Zeitwerk conventions.
83
+ *
84
+ * Zeitwerk maps constant names to file paths:
85
+ * - `User` → `user.rb`
86
+ * - `AuthService` → `auth_service.rb`
87
+ * - `Admin::UsersController` → `admin/users_controller.rb`
88
+ *
89
+ * This searches common Rails autoload paths for a matching file.
90
+ *
91
+ * @param className - The fully-qualified constant name (e.g., "Admin::UsersController")
92
+ * @param repoRoot - The root of the repository / Rails project
93
+ * @returns Absolute path to the resolved file, or null if not found
94
+ */
95
+ export function resolveZeitwerk(className, repoRoot) {
96
+ if (!className) {
97
+ return null;
98
+ }
99
+ // Split on :: and convert each segment from CamelCase to snake_case
100
+ const segments = className.split('::');
101
+ const relativePath = segments.map(camelToSnake).join('/');
102
+ // Search each autoload path
103
+ for (const autoloadPath of ZEITWERK_AUTOLOAD_PATHS) {
104
+ const candidate = join(repoRoot, autoloadPath, `${relativePath}.rb`);
105
+ if (cachedExists(candidate)) {
106
+ return resolvePath(candidate);
107
+ }
108
+ }
109
+ return null;
110
+ }
@@ -0,0 +1 @@
1
+ export declare function resolve(fromAbsFile: string, modulePath: string, repoRoot: string): string | null;
@@ -0,0 +1,197 @@
1
+ import { readFileSync } from 'fs';
2
+ import { basename, dirname, join, resolve as resolvePath } from 'path';
3
+ import { cachedExists } from '../fs-cache';
4
+ function probeRustPath(baseDir, relPath) {
5
+ const asFile = join(baseDir, `${relPath}.rs`);
6
+ if (cachedExists(asFile)) {
7
+ return resolvePath(asFile);
8
+ }
9
+ const asMod = join(baseDir, relPath, 'mod.rs');
10
+ if (cachedExists(asMod)) {
11
+ return resolvePath(asMod);
12
+ }
13
+ const asLib = join(baseDir, relPath, 'lib.rs');
14
+ if (cachedExists(asLib)) {
15
+ return resolvePath(asLib);
16
+ }
17
+ return null;
18
+ }
19
+ export function resolve(fromAbsFile, modulePath, repoRoot) {
20
+ if (modulePath.startsWith('std::')) {
21
+ return null;
22
+ }
23
+ if (modulePath.startsWith('crate::')) {
24
+ const rest = modulePath.slice('crate::'.length).replace(/::/g, '/');
25
+ return probeRustPath(join(repoRoot, 'src'), rest);
26
+ }
27
+ if (modulePath.startsWith('super::')) {
28
+ const rest = modulePath.slice('super::'.length).replace(/::/g, '/');
29
+ const fileName = basename(fromAbsFile);
30
+ // mod.rs and lib.rs represent their parent directory, so super:: goes up two levels
31
+ const parentDir = fileName === 'mod.rs' || fileName === 'lib.rs' ? dirname(dirname(fromAbsFile)) : dirname(fromAbsFile);
32
+ return probeRustPath(parentDir, rest);
33
+ }
34
+ if (modulePath.startsWith('self::')) {
35
+ const rest = modulePath.slice('self::'.length).replace(/::/g, '/');
36
+ return probeRustPath(dirname(fromAbsFile), rest);
37
+ }
38
+ // Try workspace path dependency resolution
39
+ const firstSep = modulePath.indexOf('::');
40
+ if (firstSep !== -1) {
41
+ const crateName = modulePath.slice(0, firstSep);
42
+ const rest = modulePath.slice(firstSep + 2).replace(/::/g, '/');
43
+ const depPath = resolveWorkspacePathDep(fromAbsFile, crateName);
44
+ if (depPath) {
45
+ const srcDir = join(depPath, 'src');
46
+ // Try the full path first, then progressively strip trailing segments
47
+ // (they may be items like functions/structs inside a module file)
48
+ const segments = rest.split('/');
49
+ for (let i = segments.length; i >= 1; i--) {
50
+ const partial = segments.slice(0, i).join('/');
51
+ const result = probeRustPath(srcDir, partial);
52
+ if (result) {
53
+ return result;
54
+ }
55
+ }
56
+ }
57
+ // bin+lib same crate: if the first segment matches the local [package] name,
58
+ // treat it like a crate:: import (resolve from src/)
59
+ const localPkgName = findLocalPackageName(fromAbsFile);
60
+ if (localPkgName && crateName === localPkgName) {
61
+ const srcDir = join(findCrateDir(fromAbsFile), 'src');
62
+ const segments = rest.split('/');
63
+ for (let i = segments.length; i >= 1; i--) {
64
+ const partial = segments.slice(0, i).join('/');
65
+ const result = probeRustPath(srcDir, partial);
66
+ if (result) {
67
+ return result;
68
+ }
69
+ }
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+ /** Cache: crate dir → parsed {depName → resolved absolute path} */
75
+ const pathDepCache = new Map();
76
+ /**
77
+ * Walk up from `fromAbsFile` to find the nearest Cargo.toml,
78
+ * parse its [dependencies] for `path = "..."` entries,
79
+ * and return the absolute path of the dependency crate if it matches `depName`.
80
+ */
81
+ function resolveWorkspacePathDep(fromAbsFile, depName) {
82
+ const crateDir = findCrateDir(fromAbsFile);
83
+ if (!crateDir) {
84
+ return null;
85
+ }
86
+ let deps = pathDepCache.get(crateDir);
87
+ if (!deps) {
88
+ deps = parsePathDeps(crateDir);
89
+ pathDepCache.set(crateDir, deps);
90
+ }
91
+ return deps.get(depName) ?? null;
92
+ }
93
+ /**
94
+ * Walk up from a file to find the nearest directory containing Cargo.toml.
95
+ */
96
+ function findCrateDir(fromAbsFile) {
97
+ let dir = dirname(fromAbsFile);
98
+ const root = resolvePath('/');
99
+ while (dir !== root) {
100
+ if (cachedExists(join(dir, 'Cargo.toml'))) {
101
+ return dir;
102
+ }
103
+ const parent = dirname(dir);
104
+ if (parent === dir) {
105
+ break;
106
+ }
107
+ dir = parent;
108
+ }
109
+ return null;
110
+ }
111
+ /** Cache: crate dir → parsed package name */
112
+ const pkgNameCache = new Map();
113
+ /**
114
+ * Find the [package] name from the nearest Cargo.toml for the given file.
115
+ * Used to detect bin+lib same-crate imports (e.g. `use myapp::foo` from main.rs).
116
+ */
117
+ function findLocalPackageName(fromAbsFile) {
118
+ const crateDir = findCrateDir(fromAbsFile);
119
+ if (!crateDir) {
120
+ return null;
121
+ }
122
+ const cached = pkgNameCache.get(crateDir);
123
+ if (cached !== undefined) {
124
+ return cached;
125
+ }
126
+ const cargoPath = join(crateDir, 'Cargo.toml');
127
+ if (!cachedExists(cargoPath)) {
128
+ pkgNameCache.set(crateDir, null);
129
+ return null;
130
+ }
131
+ const content = readFileSync(cargoPath, 'utf-8');
132
+ const match = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
133
+ // Cargo crate names use hyphens but Rust imports use underscores
134
+ const name = match ? match[1].replace(/-/g, '_') : null;
135
+ pkgNameCache.set(crateDir, name);
136
+ return name;
137
+ }
138
+ /**
139
+ * Parse Cargo.toml in `crateDir` for path dependencies.
140
+ * Returns a map of dependency name → resolved absolute directory.
141
+ *
142
+ * Handles both inline table and multi-line table forms:
143
+ * shared = { path = "../shared" }
144
+ * [dependencies.shared]
145
+ * path = "../shared"
146
+ */
147
+ function parsePathDeps(crateDir) {
148
+ const result = new Map();
149
+ const cargoPath = join(crateDir, 'Cargo.toml');
150
+ if (!cachedExists(cargoPath)) {
151
+ return result;
152
+ }
153
+ const content = readFileSync(cargoPath, 'utf-8');
154
+ const lines = content.split('\n');
155
+ let inDepsSection = false;
156
+ let depsTableDep = null; // for [dependencies.foo] style
157
+ for (const line of lines) {
158
+ const trimmed = line.trim();
159
+ // Detect section headers
160
+ if (trimmed.startsWith('[')) {
161
+ // Check for [dependencies.foo] form
162
+ const subMatch = trimmed.match(/^\[dependencies\.(\S+)\]$/);
163
+ if (subMatch) {
164
+ depsTableDep = subMatch[1];
165
+ inDepsSection = false;
166
+ continue;
167
+ }
168
+ depsTableDep = null;
169
+ if (trimmed === '[dependencies]') {
170
+ inDepsSection = true;
171
+ continue;
172
+ }
173
+ // Any other section header ends [dependencies]
174
+ inDepsSection = false;
175
+ continue;
176
+ }
177
+ // Inside [dependencies.foo], look for path = "..."
178
+ if (depsTableDep) {
179
+ const pathMatch = trimmed.match(/^path\s*=\s*"([^"]+)"/);
180
+ if (pathMatch) {
181
+ const resolved = resolvePath(crateDir, pathMatch[1]);
182
+ result.set(depsTableDep, resolved);
183
+ }
184
+ continue;
185
+ }
186
+ // Inside [dependencies], look for inline table with path
187
+ if (inDepsSection && trimmed.length > 0 && !trimmed.startsWith('#')) {
188
+ // name = { path = "..." ... }
189
+ const inlineMatch = trimmed.match(/^(\S+)\s*=\s*\{[^}]*path\s*=\s*"([^"]+)"[^}]*\}/);
190
+ if (inlineMatch) {
191
+ const resolved = resolvePath(crateDir, inlineMatch[2]);
192
+ result.set(inlineMatch[1], resolved);
193
+ }
194
+ }
195
+ }
196
+ return result;
197
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * TypeScript/JavaScript import resolver.
3
+ *
4
+ * Handles:
5
+ * - Relative imports with extension probing (.ts, .tsx, .js, .jsx)
6
+ * - ESM .js → .ts remapping
7
+ * - Directory index files
8
+ * - tsconfig path aliases
9
+ */
10
+ /**
11
+ * Load aliases from webpack.config.ts/js and vite.config.ts/js.
12
+ * These are NOT in tsconfig — many large projects use bundler aliases instead.
13
+ *
14
+ * Parses simple alias patterns from resolve.alias blocks.
15
+ * Returns Map<prefix, absoluteDir> — same format as tsconfig aliases.
16
+ */
17
+ export declare function loadBundlerAliases(repoRoot: string): Map<string, string[]>;
18
+ /**
19
+ * Resolve a TypeScript/JavaScript relative import to an absolute file path.
20
+ * Returns null for non-relative (external package) imports.
21
+ */
22
+ export declare function resolve(fromAbsFile: string, modulePath: string, repoRoot: string): string | null;
23
+ /**
24
+ * Load and parse tsconfig.json path aliases.
25
+ *
26
+ * Tries tsconfig.json first, then tsconfig.base.json.
27
+ * Converts alias patterns like "@libs/*" into prefix → resolved dirs.
28
+ */
29
+ export declare function loadTsconfigAliases(repoRoot: string): Map<string, string[]>;
30
+ /**
31
+ * Resolve an import path using tsconfig aliases.
32
+ *
33
+ * Tries each alias prefix, and for matches, probes extensions and index files.
34
+ */
35
+ export declare function resolveWithAliases(modulePath: string, aliases: Map<string, string[]>, _repoRoot: string): string | null;