diff --git a/lib/src/legacy/importer.ts b/lib/src/legacy/importer.ts index 09438e38..35e6f384 100644 --- a/lib/src/legacy/importer.ts +++ b/lib/src/legacy/importer.ts @@ -11,6 +11,7 @@ import * as util from 'util'; import {resolvePath} from './resolve-path'; import { fileUrlToPathCrossPlatform, + isErrnoException, thenOr, PromiseOr, SyncBoolean, @@ -93,10 +94,29 @@ export class LegacyImporterWrapper // sure that all normal loads are preceded by exactly one relative load. if (this.expectingRelativeLoad) { if (url.startsWith('file:')) { - const resolved = resolvePath( - fileUrlToPathCrossPlatform(url), - options.fromImport - ); + let resolved: string | null = null; + + try { + const path = fileUrlToPathCrossPlatform(url); + resolved = resolvePath(path, options.fromImport); + } catch (error: unknown) { + if ( + error instanceof TypeError && + isErrnoException(error) && + (error.code === 'ERR_INVALID_URL' || + error.code === 'ERR_INVALID_FILE_URL_PATH') + ) { + // It's possible for `url` to represent an invalid path for the + // current platform. For example, `@import "/foo/bar/baz"` will + // resolve to `file:///foo/bar/baz` which is an invalid URL on + // Windows. In that case, we treat it as though the file doesn't + // exist so that the user's custom importer can still handle the + // URL. + } else { + throw error; + } + } + if (resolved !== null) { this.prev.push({url: resolved, path: true}); return pathToFileURL(resolved); diff --git a/lib/src/utils.ts b/lib/src/utils.ts index 7153faec..56c02dfa 100644 --- a/lib/src/utils.ts +++ b/lib/src/utils.ts @@ -133,6 +133,13 @@ export function protofySyntax( } } +/** Returns whether `error` is a NodeJS-style exception with an error code. */ +export function isErrnoException( + error: unknown +): error is NodeJS.ErrnoException { + return error instanceof Error && ('errno' in error || 'code' in error); +} + /** * Dart-style utility. See * http://go/dart-api/stable/2.8.4/dart-core/Map/putIfAbsent.html.