-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
path: fix bugs and inconsistencies #54224
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -186,6 +186,7 @@ const win32 = { | |
let resolvedDevice = ''; | ||
let resolvedTail = ''; | ||
let resolvedAbsolute = false; | ||
let slashCheck = false; | ||
|
||
for (let i = args.length - 1; i >= -1; i--) { | ||
let path; | ||
|
@@ -217,6 +218,10 @@ const win32 = { | |
} | ||
} | ||
|
||
if (i === args.length - 1 && | ||
isPathSeparator(StringPrototypeCharCodeAt(path, path.length - 1))) { | ||
slashCheck = true; | ||
} | ||
const len = path.length; | ||
let rootEnd = 0; | ||
let device = ''; | ||
|
@@ -264,10 +269,16 @@ const win32 = { | |
j++; | ||
} | ||
if (j === len || j !== last) { | ||
// We matched a UNC root | ||
device = | ||
`\\\\${firstPart}\\${StringPrototypeSlice(path, last, j)}`; | ||
rootEnd = j; | ||
if (firstPart !== '.' && firstPart !== '?') { | ||
// We matched a UNC root | ||
device = | ||
`\\\\${firstPart}\\${StringPrototypeSlice(path, last, j)}`; | ||
rootEnd = j; | ||
} else { | ||
// We matched a device root (e.g. \\\\.\\PHYSICALDRIVE0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it should also handle There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the review. Fixed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are other inconsistencies: path.resolve('\\\\?\\c:/') // \\?\c:
path.toNamespacedPath('c:/') // \\?\c:\
path.normalize('\\\\.\\foo') // \\.\foo\
path.resolve('\\\\.\\foo\\') // \\.\foo There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I'll try to fix these inconsistencies. I have a question. path.resolve("C:\\") // C:\\
path.resolve("//server/share") // \\\\server\\share\\ But, I think it should be: path.resolve("C:\\") // C:
path.resolve("//server/share") // \\\\server\\share If I change these ones, path.resolve("//server/share/folder") // \\\\server\\share\\folder
path.resolve("//server/share") // \\\\server\\share\\ What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it should respect the original input. If there is a trailing slash, keep it, otherwise do not add it.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My latest commit fixes the inconsistencies in |
||
device = `\\\\${firstPart}`; | ||
rootEnd = 4; | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -319,9 +330,21 @@ const win32 = { | |
resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', | ||
isPathSeparator); | ||
|
||
return resolvedAbsolute ? | ||
`${resolvedDevice}\\${resolvedTail}` : | ||
`${resolvedDevice}${resolvedTail}` || '.'; | ||
if (!resolvedAbsolute) { | ||
return `${resolvedDevice}${resolvedTail}` || '.'; | ||
} | ||
|
||
if (resolvedTail.length === 0) { | ||
return slashCheck ? `${resolvedDevice}\\` : resolvedDevice; | ||
} | ||
|
||
if (slashCheck) { | ||
return resolvedTail === '\\' ? | ||
`${resolvedDevice}\\` : | ||
`${resolvedDevice}\\${resolvedTail}\\`; | ||
} | ||
|
||
return `${resolvedDevice}\\${resolvedTail}`; | ||
}, | ||
|
||
/** | ||
|
@@ -377,17 +400,22 @@ const win32 = { | |
!isPathSeparator(StringPrototypeCharCodeAt(path, j))) { | ||
j++; | ||
} | ||
if (j === len) { | ||
// We matched a UNC root only | ||
// Return the normalized version of the UNC root since there | ||
// is nothing left to process | ||
return `\\\\${firstPart}\\${StringPrototypeSlice(path, last)}\\`; | ||
} | ||
if (j !== last) { | ||
// We matched a UNC root with leftovers | ||
device = | ||
`\\\\${firstPart}\\${StringPrototypeSlice(path, last, j)}`; | ||
rootEnd = j; | ||
if (j === len || j !== last) { | ||
if (firstPart === '.' || firstPart === '?') { | ||
// We matched a device root (e.g. \\\\.\\PHYSICALDRIVE0) | ||
device = `\\\\${firstPart}`; | ||
rootEnd = 4; | ||
} else if (j === len) { | ||
// We matched a UNC root only | ||
// Return the normalized version of the UNC root since there | ||
// is nothing left to process | ||
return `\\\\${firstPart}\\${StringPrototypeSlice(path, last)}\\`; | ||
} else { | ||
// We matched a UNC root with leftovers | ||
device = | ||
`\\\\${firstPart}\\${StringPrototypeSlice(path, last, j)}`; | ||
rootEnd = j; | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -1122,6 +1150,7 @@ const posix = { | |
resolve(...args) { | ||
let resolvedPath = ''; | ||
let resolvedAbsolute = false; | ||
let slashCheck = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
|
||
for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { | ||
const path = i >= 0 ? args[i] : posixCwd(); | ||
|
@@ -1131,8 +1160,17 @@ const posix = { | |
if (path.length === 0) { | ||
continue; | ||
} | ||
if (i === args.length - 1 && | ||
isPosixPathSeparator(StringPrototypeCharCodeAt(path, | ||
path.length - 1))) { | ||
slashCheck = true; | ||
} | ||
|
||
resolvedPath = `${path}/${resolvedPath}`; | ||
if (resolvedPath.length !== 0) { | ||
resolvedPath = `${path}/${resolvedPath}`; | ||
} else { | ||
resolvedPath = path; | ||
} | ||
resolvedAbsolute = | ||
StringPrototypeCharCodeAt(path, 0) === CHAR_FORWARD_SLASH; | ||
} | ||
|
@@ -1144,10 +1182,20 @@ const posix = { | |
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', | ||
isPosixPathSeparator); | ||
|
||
if (resolvedAbsolute) { | ||
return `/${resolvedPath}`; | ||
if (!resolvedAbsolute) { | ||
if (resolvedPath.length === 0) { | ||
return '.'; | ||
} | ||
if (slashCheck) { | ||
return `${resolvedPath}/`; | ||
} | ||
return resolvedPath; | ||
} | ||
|
||
if (resolvedPath.length === 0 || resolvedPath === '/') { | ||
return '/'; | ||
} | ||
return resolvedPath.length > 0 ? resolvedPath : '.'; | ||
return slashCheck ? `/${resolvedPath}/` : `/${resolvedPath}`; | ||
}, | ||
|
||
/** | ||
|
@@ -1231,11 +1279,35 @@ const posix = { | |
if (from === to) | ||
return ''; | ||
|
||
const fromStart = 1; | ||
const fromEnd = from.length; | ||
// Trim any leading slashes | ||
let fromStart = 0; | ||
while (fromStart < from.length && | ||
StringPrototypeCharCodeAt(from, fromStart) === CHAR_FORWARD_SLASH) { | ||
fromStart++; | ||
} | ||
// Trim trailing slashes | ||
let fromEnd = from.length; | ||
while ( | ||
fromEnd - 1 > fromStart && | ||
StringPrototypeCharCodeAt(from, fromEnd - 1) === CHAR_FORWARD_SLASH | ||
) { | ||
fromEnd--; | ||
} | ||
const fromLen = fromEnd - fromStart; | ||
const toStart = 1; | ||
const toLen = to.length - toStart; | ||
|
||
// Trim any leading slashes | ||
let toStart = 0; | ||
while (toStart < to.length && | ||
StringPrototypeCharCodeAt(to, toStart) === CHAR_FORWARD_SLASH) { | ||
toStart++; | ||
} | ||
// Trim trailing slashes | ||
let toEnd = to.length; | ||
while (toEnd - 1 > toStart && | ||
StringPrototypeCharCodeAt(to, toEnd - 1) === CHAR_FORWARD_SLASH) { | ||
toEnd--; | ||
} | ||
const toLen = toEnd - toStart; | ||
|
||
// Compare paths to find the longest common path from root | ||
const length = (fromLen < toLen ? fromLen : toLen); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,6 +97,7 @@ std::string PathResolve(Environment* env, | |
std::string resolvedDevice = ""; | ||
std::string resolvedTail = ""; | ||
bool resolvedAbsolute = false; | ||
bool slashCheck = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar as above |
||
const size_t numArgs = paths.size(); | ||
auto cwd = env->GetCwd(env->exec_path()); | ||
|
||
|
@@ -126,6 +127,10 @@ std::string PathResolve(Environment* env, | |
} | ||
} | ||
|
||
if (static_cast<size_t>(i) == numArgs - 1 && | ||
IsPathSeparator(path[path.length() - 1])) { | ||
slashCheck = true; | ||
} | ||
const size_t len = path.length(); | ||
int rootEnd = 0; | ||
std::string device = ""; | ||
|
@@ -170,9 +175,16 @@ std::string PathResolve(Environment* env, | |
j++; | ||
} | ||
if (j == len || j != last) { | ||
// We matched a UNC root | ||
device = "\\\\" + firstPart + "\\" + path.substr(last, j - last); | ||
rootEnd = j; | ||
if (firstPart != "." && firstPart != "?") { | ||
// We matched a UNC root | ||
device = | ||
"\\\\" + firstPart + "\\" + path.substr(last, j - last); | ||
rootEnd = j; | ||
} else { | ||
// We matched a device root (e.g. \\\\.\\PHYSICALDRIVE0) | ||
device = "\\\\" + firstPart; | ||
rootEnd = 4; | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -220,15 +232,27 @@ std::string PathResolve(Environment* env, | |
// Normalize the tail path | ||
resolvedTail = NormalizeString(resolvedTail, !resolvedAbsolute, "\\"); | ||
|
||
if (resolvedAbsolute) { | ||
return resolvedDevice + "\\" + resolvedTail; | ||
if (!resolvedAbsolute) { | ||
if (!resolvedDevice.empty() || !resolvedTail.empty()) { | ||
return resolvedDevice + resolvedTail; | ||
} | ||
return "."; | ||
} | ||
|
||
if (!resolvedDevice.empty() || !resolvedTail.empty()) { | ||
return resolvedDevice + resolvedTail; | ||
if (resolvedTail.empty()) { | ||
if (slashCheck) { | ||
return resolvedDevice + "\\"; | ||
} | ||
return resolvedDevice; | ||
} | ||
|
||
return "."; | ||
if (slashCheck) { | ||
if (resolvedTail == "\\") { | ||
return resolvedDevice + "\\"; | ||
} | ||
return resolvedDevice + "\\" + resolvedTail + "\\"; | ||
} | ||
return resolvedDevice + "\\" + resolvedTail; | ||
} | ||
#else // _WIN32 | ||
std::string PathResolve(Environment* env, | ||
|
@@ -237,10 +261,15 @@ std::string PathResolve(Environment* env, | |
bool resolvedAbsolute = false; | ||
auto cwd = env->GetCwd(env->exec_path()); | ||
const size_t numArgs = paths.size(); | ||
bool slashCheck = false; | ||
|
||
for (int i = numArgs - 1; i >= -1 && !resolvedAbsolute; i--) { | ||
const std::string& path = (i >= 0) ? std::string(paths[i]) : cwd; | ||
|
||
if (static_cast<size_t>(i) == numArgs - 1 && path.back() == '/') { | ||
slashCheck = true; | ||
} | ||
|
||
if (!path.empty()) { | ||
resolvedPath = std::string(path) + "/" + resolvedPath; | ||
|
||
|
@@ -254,15 +283,21 @@ std::string PathResolve(Environment* env, | |
// Normalize the path | ||
auto normalizedPath = NormalizeString(resolvedPath, !resolvedAbsolute, "/"); | ||
|
||
if (resolvedAbsolute) { | ||
return "/" + normalizedPath; | ||
if (!resolvedAbsolute) { | ||
if (normalizedPath.empty()) { | ||
return "."; | ||
} | ||
if (slashCheck) { | ||
return normalizedPath + "/"; | ||
} | ||
return normalizedPath; | ||
} | ||
|
||
if (normalizedPath.empty()) { | ||
return "."; | ||
if (normalizedPath.empty() || normalizedPath == "/") { | ||
return "/"; | ||
} | ||
|
||
return normalizedPath; | ||
return slashCheck ? "/" + normalizedPath + "/" : "/" + normalizedPath; | ||
} | ||
#endif // _WIN32 | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it is possible to simplify the code by changing this to a string that we always append to the output and that is either an empty string or the slash.