( specifier: string, currentFile: string, files: FileSet, )
| 140 | * @returns The resolved path or null if not found |
| 141 | */ |
| 142 | export function resolveRelativeImport( |
| 143 | specifier: string, |
| 144 | currentFile: string, |
| 145 | files: FileSet, |
| 146 | ): ResolvedImport | null { |
| 147 | // Remove quotes if present |
| 148 | const cleanSpecifier = specifier.replace(/^['"]|['"]$/g, '').trim() |
| 149 | |
| 150 | // Only handle relative imports |
| 151 | if (!cleanSpecifier.startsWith('.')) { |
| 152 | return null |
| 153 | } |
| 154 | |
| 155 | // Get the directory of the current file |
| 156 | const currentDir = dirname(currentFile) |
| 157 | |
| 158 | // Resolve the path relative to current directory |
| 159 | const basePath = currentDir |
| 160 | ? normalizePath(`${currentDir}/${cleanSpecifier}`) |
| 161 | : normalizePath(cleanSpecifier) |
| 162 | |
| 163 | // If path is empty or goes above root, return null |
| 164 | if (!basePath || basePath.startsWith('..')) { |
| 165 | return null |
| 166 | } |
| 167 | |
| 168 | // Get extension priority based on source file |
| 169 | const extensionGroups = getExtensionPriority(currentFile) |
| 170 | const indexExtensions = getIndexExtensions(currentFile) |
| 171 | |
| 172 | // Try each extension group in priority order |
| 173 | for (const extensions of extensionGroups) { |
| 174 | if (extensions.length === 0) { |
| 175 | // Try exact match |
| 176 | if (files.has(basePath)) { |
| 177 | return { path: basePath } |
| 178 | } |
| 179 | } else { |
| 180 | // Try with extensions |
| 181 | for (const ext of extensions) { |
| 182 | const pathWithExt = basePath + ext |
| 183 | if (files.has(pathWithExt)) { |
| 184 | return { path: pathWithExt } |
| 185 | } |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | // Try as directory with index file |
| 191 | for (const indexFile of indexExtensions) { |
| 192 | const indexPath = `${basePath}/${indexFile}` |
| 193 | if (files.has(indexPath)) { |
| 194 | return { path: indexPath } |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | return null |
| 199 | } |
no test coverage detected