From 8f7e000641b37c423e31b7564f7bda588c17afcd Mon Sep 17 00:00:00 2001 From: Rob Hogan Date: Mon, 23 Sep 2024 10:02:47 -0700 Subject: [PATCH] Resolver: allow drive-less absolute paths on Windows Summary: Fix a mostly Meta-specific edge case in Windows resolution. When using absolute paths without a drive letter on Windows, eg `\my\project`, don't use `path.resolve` to normalise to system separators, as this has the unwanted side-effect of prepending the the CWD's drive letter, even when the input is known to be absolute (according to `path.isAbsolute`): On a Windows machine: ``` C:\> node -p "path.isAbsolute('/my/project')" true C:\> node -p "path.isAbsolute('\\my\\project')" true C:\> node -p "path.resolve('/my/project')" C:\my\project ``` This preserves drive-less original paths. It also makes absolute path handling slightly stricter on Windows by not fully normalising the input (e.g., not normalising `C:\foo/../foo/.//bar` to `C:\foo\bar`, but instead using a simple `replaceAll`), which brings it into line with posix path handling - I'm considering this a "fix" rather than breaking, as behaviour for poorly-formed inputs is undefined. Changelog: ``` - **[Fix]**: Treat absolute path specifiers on Windows with the same strictness as posix, and allow absolute paths without drive letters. ``` Reviewed By: huntie Differential Revision: D63175565 fbshipit-source-id: 35ab129f4846579dfe6ae8860d6d49b09cadc4e8 --- packages/metro-resolver/src/PackageResolve.js | 4 +++- packages/metro-resolver/src/resolve.js | 15 ++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/metro-resolver/src/PackageResolve.js b/packages/metro-resolver/src/PackageResolve.js index 187da7e1e2..f42d63b1ae 100644 --- a/packages/metro-resolver/src/PackageResolve.js +++ b/packages/metro-resolver/src/PackageResolve.js @@ -134,7 +134,9 @@ export function redirectModulePath( // BRITTLE ASSUMPTION: This is always treated as a package-relative path // and is converted back, even if the redirected path is a specifier // referring to another package. - redirectedPath = path.resolve(containingPackage.rootPath, redirectedPath); + redirectedPath = path.isAbsolute(redirectedPath) + ? path.normalize(redirectedPath) + : path.join(containingPackage.rootPath, redirectedPath); } } else { // Otherwise, `modulePath` may be an unprefixed relative path or a bare diff --git a/packages/metro-resolver/src/resolve.js b/packages/metro-resolver/src/resolve.js index 3aa4c4f899..1799358c00 100644 --- a/packages/metro-resolver/src/resolve.js +++ b/packages/metro-resolver/src/resolve.js @@ -220,8 +220,11 @@ function resolveModulePath( toModuleName: string, platform: string | null, ): Result { + // System-separated absolute path const modulePath = path.isAbsolute(toModuleName) - ? resolveWindowsPath(toModuleName) + ? path.sep === '/' + ? toModuleName + : toModuleName.replaceAll('/', '\\') : path.join(path.dirname(context.originModulePath), toModuleName); const redirectedPath = context.redirectModulePath(modulePath); if (redirectedPath === false) { @@ -584,16 +587,6 @@ function resolveSourceFileForExt( return null; } -// HasteFS stores paths with backslashes on Windows, this ensures the path is in -// the proper format. Will also add drive letter if not present so `/root` will -// resolve to `C:\root`. Noop on other platforms. -function resolveWindowsPath(modulePath: string) { - if (path.sep !== '\\') { - return modulePath; - } - return path.resolve(modulePath); -} - function isRelativeImport(filePath: string) { return /^[.][.]?(?:[/]|$)/.test(filePath); }