* Resolve an aliased/absolute import. * * Tries, in order: * 1. Project-defined `compilerOptions.paths` (tsconfig/jsconfig). * Each pattern can have multiple replacements; tried in tsconfig * priority order with extension permutations. * 2. The legacy hard-coded fallback list (`@
( importPath: string, projectRoot: string, language: Language, context: ResolutionContext )
| 438 | * 3. Direct path lookup (with extensions). |
| 439 | */ |
| 440 | function resolveAliasedImport( |
| 441 | importPath: string, |
| 442 | projectRoot: string, |
| 443 | language: Language, |
| 444 | context: ResolutionContext |
| 445 | ): string | null { |
| 446 | const extensions = EXTENSION_RESOLUTION[language] || []; |
| 447 | const tryWithExt = (basePath: string): string | null => { |
| 448 | for (const ext of extensions) { |
| 449 | const candidate = basePath + ext; |
| 450 | if (context.fileExists(candidate)) return candidate; |
| 451 | } |
| 452 | if (context.fileExists(basePath)) return basePath; |
| 453 | return null; |
| 454 | }; |
| 455 | |
| 456 | // 1. Project tsconfig/jsconfig paths. |
| 457 | const aliasMap = context.getProjectAliases?.(); |
| 458 | if (aliasMap) { |
| 459 | const candidates = applyAliases(importPath, aliasMap, projectRoot); |
| 460 | for (const c of candidates) { |
| 461 | const hit = tryWithExt(c); |
| 462 | if (hit) return hit; |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | // 1.5 Workspace packages (`@scope/ui/widgets` → `packages/ui/widgets`). |
| 467 | // Resolves a monorepo member import to the member's directory; the |
| 468 | // extension/index permutations below then find its barrel (#629). |
| 469 | const workspaces = context.getWorkspacePackages?.(); |
| 470 | if (workspaces) { |
| 471 | const base = resolveWorkspaceImport(importPath, workspaces); |
| 472 | if (base) { |
| 473 | const hit = tryWithExt(base); |
| 474 | if (hit) return hit; |
| 475 | } |
| 476 | } |
| 477 | |
| 478 | // 2. Hard-coded fallback list. Kept for projects that use these |
| 479 | // conventional aliases without declaring them in tsconfig. |
| 480 | const fallbackAliases: Record<string, string> = { |
| 481 | '@/': 'src/', |
| 482 | '~/': 'src/', |
| 483 | '@src/': 'src/', |
| 484 | 'src/': 'src/', |
| 485 | '@app/': 'app/', |
| 486 | 'app/': 'app/', |
| 487 | }; |
| 488 | for (const [alias, replacement] of Object.entries(fallbackAliases)) { |
| 489 | if (importPath.startsWith(alias)) { |
| 490 | const hit = tryWithExt(importPath.replace(alias, replacement)); |
| 491 | if (hit) return hit; |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | // 3. Direct path. |
| 496 | return tryWithExt(importPath); |
| 497 | } |
no test coverage detected