CodeGraph/docs
Section 2.6.4

Import Resolution & 5-Step Waterfall

How CodeGraph resolves module import strings to local files, path aliases, external npm packages, and Node.js built-in modules using a deterministic 5-step waterfall.

Source: server/src/parser/extractors/RelationshipExtractor.ts

Three Import Resolution Strategies

When an ImportDeclaration is encountered, extractImportRelationship() evaluates 3 strategies sequentially:

StrategyConditionResolution Mechanism
1. Relative ImportImport source starts with '.' (./ or ../)Resolved against importing file's directory using path.resolve(), then passed to the 5-step file matching waterfall.
2. Path Alias ImportMatches compilerOptions.paths alias (e.g. @/*)Finds nearest tsconfig.json/jsconfig.json, expands prefix/suffix wildcards, and computes absolute path.
3. External ImportNon-relative, non-aliased (e.g. express, fs)Checks nearest package.json: if present in dependencies -> targetKind: 'dependency'; if Node built-in -> targetKind: 'module'.

The 5-Step `findParsedFileByResolvedPath` Lookup Waterfall

Both relative imports and path-aliased imports pass their resolved absolute path to this private waterfall to locate the target file in the in-memory parsedFiles[] array:

StepMatching RuleCode / BehaviorAmbiguity Guard
Step 1: Exact MatchparsedFile.filePath === resolvedImportPathHandles imports with exact extensions (e.g., import './utils/index.ts'). Returns immediately.N/A
Step 2: Extension Detectionpath.extname(resolvedImportPath)Detects if import ends in .ts, .tsx, .js, .jsx to branch between Steps 3 and 4.N/A
Step 3: Base-Name Compatible MatchStrip extensions, compare base pathsMatches compatible variants (e.g. import './file.js' matching file.ts on disk).If >1 file matches base name, returns undefined.
Step 4: Extensionless Matchcandidate.slice(0, -ext) === resolvedPathResolves extensionless imports (e.g. import './utils' matching ./utils.ts).If >1 file matches base name, returns undefined.
Step 5: Directory / Index Matchdirname(candidate) === path && basename is indexResolves directory imports (e.g. import './components' matching ./components/index.tsx).If >1 index file matches, returns undefined.

Wildcard Path Alias Matching

Path aliases from tsconfig.json (such as "@/*": ["src/*"]) are expanded by splitting on the * wildcard:

Wildcard Expansion Logic
1
2
3
4
5
6
7
// Example: import from "@/utils/auth" with alias "@/*" -> "src/*" const [prefix, suffix] = alias.split("*"); if (importSource.startsWith(prefix) && importSource.endsWith(suffix)) { const wildcardValue = importSource.slice(prefix.length, importSource.length - suffix.length); const targetPath = aliasPath.replace("*", wildcardValue); // "src/utils/auth" const resolvedPath = path.resolve(baseDirectory, baseUrl, targetPath); }
Ambiguity Safety Guarantee
If a codebase has multiple conflicting files sharing a base name (e.g. both auth.js andauth.ts exist side-by-side), Steps 3, 4, and 5 return undefined. CodeGraph deliberately avoids creating an incorrect relationship edge rather than guessing.