MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / loadProjectAliases

Function loadProjectAliases

src/resolution/path-aliases.ts:253–322  ·  view source on GitHub ↗
(projectRoot: string)

Source from the content-addressed store, hash-verified

251 * resolver does it via {@link aliasCache}).
252 */
253export function loadProjectAliases(projectRoot: string): AliasMap | null {
254 // `tsconfig.base.json` comes last on purpose: when a root `tsconfig.json`
255 // exists it stays authoritative and reaches the base through `extends`.
256 // The fallback is for the Nx layouts where that never happens — a
257 // solution-style root config (`references`, no `extends`, no `paths`), or
258 // no root `tsconfig.json` at all.
259 const candidates = ['tsconfig.json', 'jsconfig.json', 'tsconfig.base.json'];
260 let effective: EffectiveOptions | null = null;
261 let usedFile: string | null = null;
262 for (const name of candidates) {
263 const p = path.join(projectRoot, name);
264 if (!fs.existsSync(p)) continue;
265 const opts = loadEffectiveOptions(p, new Set(), 0);
266 if (!opts) continue;
267 // Remember the first readable config so a `paths`-less project still
268 // logs the file it was judged on, but keep looking: a config that
269 // contributes no aliases must not shadow one that does.
270 if (!effective) {
271 effective = opts;
272 usedFile = name;
273 }
274 if (opts.paths) {
275 effective = opts;
276 usedFile = name;
277 break;
278 }
279 }
280 if (!effective) return null;
281
282 // With no explicit baseUrl, `paths` targets are relative to the config that
283 // declared them — which is the project root only when that config is the
284 // root one (the pre-`extends` assumption).
285 const baseUrl = effective.baseUrl ?? effective.pathsDir ?? projectRoot;
286
287 const paths = effective.paths;
288 if (!paths || typeof paths !== 'object') {
289 // baseUrl alone isn't an "alias" per se; with no paths we'd just
290 // be redirecting the whole tree. Skip — the existing resolver
291 // already handles relative imports.
292 return null;
293 }
294
295 const patterns: AliasPattern[] = [];
296 for (const [pattern, targets] of Object.entries(paths)) {
297 if (!Array.isArray(targets) || targets.length === 0) continue;
298 const filtered = targets.filter((t): t is string => typeof t === 'string');
299 if (filtered.length === 0) continue;
300 const { prefix, suffix, hasWildcard } = splitWildcard(pattern);
301 patterns.push({ prefix, suffix, hasWildcard, replacements: filtered });
302 }
303
304 if (patterns.length === 0) return null;
305
306 // Specificity sort: longer prefix first; literal patterns before
307 // wildcard patterns of the same prefix length. TypeScript itself
308 // uses a similar "most specific match wins" rule.
309 patterns.sort((a, b) => {
310 if (a.prefix.length !== b.prefix.length) return b.prefix.length - a.prefix.length;

Callers 2

createContextMethod · 0.90

Calls 5

logDebugFunction · 0.90
loadEffectiveOptionsFunction · 0.85
splitWildcardFunction · 0.85
pushMethod · 0.80
joinMethod · 0.45

Tested by

no test coverage detected