Section 2.6.4Source:
server/src/parser/extractors/RelationshipExtractor.tsImport 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.tsThree Import Resolution Strategies
When an ImportDeclaration is encountered, extractImportRelationship() evaluates 3 strategies sequentially:
| Strategy | Condition | Resolution Mechanism |
|---|---|---|
| 1. Relative Import | Import 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 Import | Matches compilerOptions.paths alias (e.g. @/*) | Finds nearest tsconfig.json/jsconfig.json, expands prefix/suffix wildcards, and computes absolute path. |
| 3. External Import | Non-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:
| Step | Matching Rule | Code / Behavior | Ambiguity Guard |
|---|---|---|---|
| Step 1: Exact Match | parsedFile.filePath === resolvedImportPath | Handles imports with exact extensions (e.g., import './utils/index.ts'). Returns immediately. | N/A |
| Step 2: Extension Detection | path.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 Match | Strip extensions, compare base paths | Matches compatible variants (e.g. import './file.js' matching file.ts on disk). | If >1 file matches base name, returns undefined. |
| Step 4: Extensionless Match | candidate.slice(0, -ext) === resolvedPath | Resolves extensionless imports (e.g. import './utils' matching ./utils.ts). | If >1 file matches base name, returns undefined. |
| Step 5: Directory / Index Match | dirname(candidate) === path && basename is index | Resolves 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
1234567// 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.