From 0584d411e7c65c7c7ee627a1b6d01752faec495d Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 27 Jan 2019 04:17:08 +0100 Subject: [PATCH 1/8] path: minor refactoring 1) This uses some ternary expressions instead of if else to assign some variables. 2) Use template strings instead of concat. 3) Use the object shortand notation. 4) Some var to let / const. 5) Removed some double line breaks. 6) Less brackets around statements if not necessary. --- lib/path.js | 117 ++++++++++++++++++---------------------------------- 1 file changed, 41 insertions(+), 76 deletions(-) diff --git a/lib/path.js b/lib/path.js index 7ea431d1d00bb4..2df23f750ccc56 100644 --- a/lib/path.js +++ b/lib/path.js @@ -91,17 +91,11 @@ function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { } } if (allowAboveRoot) { - if (res.length > 0) - res += `${separator}..`; - else - res = '..'; + res += res.length > 0 ? `${separator}..` : '..'; lastSegmentLength = 2; } } else { - if (res.length > 0) - res += separator + path.slice(lastSlash + 1, i); - else - res = path.slice(lastSlash + 1, i); + res += (res.length > 0 ? separator : '') + path.slice(lastSlash + 1, i); lastSegmentLength = i - lastSlash - 1; } lastSlash = i; @@ -118,14 +112,11 @@ function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { function _format(sep, pathObject) { const dir = pathObject.dir || pathObject.root; const base = pathObject.base || - ((pathObject.name || '') + (pathObject.ext || '')); + `${pathObject.name || ''}${pathObject.ext || ''}`; if (!dir) { return base; } - if (dir === pathObject.root) { - return dir + base; - } - return dir + sep + base; + return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`; } const win32 = { @@ -147,7 +138,7 @@ const win32 = { // absolute path, get cwd for that drive, or the process cwd if // the drive cwd is not available. We're sure the device is not // a UNC path at this points, because UNC paths are always absolute. - path = process.env['=' + resolvedDevice] || process.cwd(); + path = process.env[`=${resolvedDevice}`] || process.cwd(); // Verify that a cwd was found and that it actually points // to our drive. If not, default to the drive's root. @@ -272,18 +263,19 @@ const win32 = { resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', isPathSeparator); - return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) || - '.'; + return resolvedAbsolute ? + `${resolvedDevice}\\${resolvedTail}` : + `${resolvedDevice}${resolvedTail}` || '.'; }, - normalize: function normalize(path) { + normalize(path) { validateString(path, 'path'); const len = path.length; if (len === 0) return '.'; - var rootEnd = 0; - var device; - var isAbsolute = false; + let rootEnd = 0; + let device; + let isAbsolute = false; const code = path.charCodeAt(0); // Try to match a root @@ -360,42 +352,20 @@ const win32 = { return '\\'; } - var tail; - if (rootEnd < len) { - tail = normalizeString(path.slice(rootEnd), !isAbsolute, '\\', - isPathSeparator); - } else { - tail = ''; - } + let tail = rootEnd < len ? + normalizeString(path.slice(rootEnd), !isAbsolute, '\\', isPathSeparator) : + ''; if (tail.length === 0 && !isAbsolute) tail = '.'; if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) tail += '\\'; if (device === undefined) { - if (isAbsolute) { - if (tail.length > 0) - return '\\' + tail; - else - return '\\'; - } else if (tail.length > 0) { - return tail; - } else { - return ''; - } - } else if (isAbsolute) { - if (tail.length > 0) - return device + '\\' + tail; - else - return device + '\\'; - } else if (tail.length > 0) { - return device + tail; - } else { - return device; + return isAbsolute ? `\\${tail}` : tail; } + return isAbsolute ? `${device}\\${tail}` : `${device}${tail}`; }, - - isAbsolute: function isAbsolute(path) { + isAbsolute(path) { validateString(path, 'path'); const len = path.length; if (len === 0) @@ -429,7 +399,7 @@ const win32 = { if (joined === undefined) joined = firstPart = arg; else - joined += '\\' + arg; + joined += `\\${arg}`; } } @@ -449,8 +419,8 @@ const win32 = { // This means that the user can use join to construct UNC paths from // a server name and a share name; for example: // path.join('//server', 'share') -> '\\\\server\\share\\') - var needsReplace = true; - var slashCount = 0; + let needsReplace = true; + let slashCount = 0; if (isPathSeparator(firstPart.charCodeAt(0))) { ++slashCount; const firstLen = firstPart.length; @@ -477,26 +447,25 @@ const win32 = { // Replace the slashes if needed if (slashCount >= 2) - joined = '\\' + joined.slice(slashCount); + joined = `\\${joined.slice(slashCount)}`; } return win32.normalize(joined); }, - // It will solve the relative path from `from` to `to`, for instance: // from = 'C:\\orandea\\test\\aaa' // to = 'C:\\orandea\\impl\\bbb' // The output of the function should be: '..\\..\\impl\\bbb' - relative: function relative(from, to) { + relative(from, to) { validateString(from, 'from'); validateString(to, 'to'); if (from === to) return ''; - var fromOrig = win32.resolve(from); - var toOrig = win32.resolve(to); + const fromOrig = win32.resolve(from); + const toOrig = win32.resolve(to); if (fromOrig === toOrig) return ''; @@ -519,7 +488,7 @@ const win32 = { if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) break; } - var fromLen = (fromEnd - fromStart); + const fromLen = fromEnd - fromStart; // Trim any leading backslashes var toStart = 0; @@ -533,7 +502,7 @@ const win32 = { if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) break; } - var toLen = (toEnd - toStart); + const toLen = toEnd - toStart; // Compare paths to find the longest common path from root var length = (fromLen < toLen ? fromLen : toLen); @@ -579,17 +548,14 @@ const win32 = { return toOrig; } - var out = ''; + let out = ''; if (lastCommonSep === -1) lastCommonSep = 0; // Generate the relative path based on the path difference between `to` and // `from` for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) { - if (out.length === 0) - out += '..'; - else - out += '\\..'; + out += out.length === 0 ? '..' : '\\..'; } } @@ -606,7 +572,7 @@ const win32 = { }, - toNamespacedPath: function toNamespacedPath(path) { + toNamespacedPath(path) { // Note: this will *probably* throw somewhere. if (typeof path !== 'string') return path; @@ -642,7 +608,7 @@ const win32 = { return path; }, - dirname: function dirname(path) { + dirname(path) { validateString(path, 'path'); const len = path.length; if (len === 0) @@ -731,14 +697,13 @@ const win32 = { if (end === -1) { if (rootEnd === -1) return '.'; - else - end = rootEnd; + + end = rootEnd; } return path.slice(0, end); }, - - basename: function basename(path, ext) { + basename(path, ext) { if (ext !== undefined) validateString(ext, 'ext'); validateString(path, 'path'); @@ -902,7 +867,7 @@ const win32 = { parse: function parse(path) { validateString(path, 'path'); - var ret = { root: '', dir: '', base: '', ext: '', name: '' }; + const ret = { root: '', dir: '', base: '', ext: '', name: '' }; if (path.length === 0) return ret; @@ -1177,8 +1142,8 @@ const posix = { if (from.charCodeAt(fromStart) !== CHAR_FORWARD_SLASH) break; } - var fromEnd = from.length; - var fromLen = (fromEnd - fromStart); + const fromEnd = from.length; + const fromLen = (fromEnd - fromStart); // Trim any leading backslashes var toStart = 1; @@ -1186,8 +1151,8 @@ const posix = { if (to.charCodeAt(toStart) !== CHAR_FORWARD_SLASH) break; } - var toEnd = to.length; - var toLen = (toEnd - toStart); + const toEnd = to.length; + const toLen = (toEnd - toStart); // Compare paths to find the longest common path from root var length = (fromLen < toLen ? fromLen : toLen); @@ -1425,10 +1390,10 @@ const posix = { parse: function parse(path) { validateString(path, 'path'); - var ret = { root: '', dir: '', base: '', ext: '', name: '' }; + const ret = { root: '', dir: '', base: '', ext: '', name: '' }; if (path.length === 0) return ret; - var isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; + const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; var start; if (isAbsolute) { ret.root = '/'; From 317013c9a5a812cfa8514fbbb8a14913b32f3b36 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 27 Jan 2019 13:29:00 +0100 Subject: [PATCH 2/8] path: more small refactorings 1) Refactor for loops to while loops that were only meant to count up a variable. 2) Refactor some `var` statements to `let` / `const`. 3) Simplify return conditions. 4) Use template strings where possible instead of concat. 5) Use ternary expressions for variable assignments instead of if / else. 6) Use the object shorthand notation for the function declarations. 7) Consolidate if else case where possible. 8) Remove double line breaks. --- lib/path.js | 227 +++++++++++++++++++++------------------------------- 1 file changed, 91 insertions(+), 136 deletions(-) diff --git a/lib/path.js b/lib/path.js index 2df23f750ccc56..51f62eafa46e53 100644 --- a/lib/path.js +++ b/lib/path.js @@ -143,9 +143,9 @@ const win32 = { // Verify that a cwd was found and that it actually points // to our drive. If not, default to the drive's root. if (path === undefined || - path.slice(0, 3).toLowerCase() !== - resolvedDevice.toLowerCase() + '\\') { - path = resolvedDevice + '\\'; + path.slice(0, 2).toLowerCase() !== resolvedDevice.toLowerCase() && + path.charCodeAt(2) === CHAR_BACKWARD_SLASH) { + path = `${resolvedDevice}\\`; } } @@ -173,39 +173,30 @@ const win32 = { if (isPathSeparator(path.charCodeAt(1))) { // Matched double path separator at beginning - var j = 2; - var last = j; + let j = 2; + let last = j; // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) - break; + while (j < len && !isPathSeparator(path.charCodeAt(j))) { + j++; } if (j < len && j !== last) { const firstPart = path.slice(last, j); // Matched! last = j; // Match 1 or more path separators - for (; j < len; ++j) { - if (!isPathSeparator(path.charCodeAt(j))) - break; + while (j < len && isPathSeparator(path.charCodeAt(j))) { + j++; } if (j < len && j !== last) { // Matched! last = j; // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) - break; + while (j < len && !isPathSeparator(path.charCodeAt(j))) { + j++; } - if (j === len) { - // We matched a UNC root only - - device = '\\\\' + firstPart + '\\' + path.slice(last); - rootEnd = j; - } else if (j !== last) { - // We matched a UNC root with leftovers - - device = '\\\\' + firstPart + '\\' + path.slice(last, j); + if (j === len || j !== last) { + // We matched a UNC root + device = `\\\\${firstPart}\\${path.slice(last, j)}`; rootEnd = j; } } @@ -372,28 +363,22 @@ const win32 = { return false; const code = path.charCodeAt(0); - if (isPathSeparator(code)) { - return true; - } else if (isWindowsDeviceRoot(code)) { + return isPathSeparator(code) || // Possible device root - - if (len > 2 && path.charCodeAt(1) === CHAR_COLON) { - if (isPathSeparator(path.charCodeAt(2))) - return true; - } - } - return false; + len > 2 && + isWindowsDeviceRoot(code) && + path.charCodeAt(1) === CHAR_COLON && + isPathSeparator(path.charCodeAt(2)); }, - - join: function join() { - if (arguments.length === 0) + join(...args) { + if (args.length === 0) return '.'; - var joined; - var firstPart; - for (var i = 0; i < arguments.length; ++i) { - var arg = arguments[i]; + let joined; + let firstPart; + for (var i = 0; i < args.length; ++i) { + const arg = args[i]; validateString(arg, 'path'); if (arg.length > 0) { if (joined === undefined) @@ -440,9 +425,9 @@ const win32 = { } if (needsReplace) { // Find any more consecutive slashes we need to replace - for (; slashCount < joined.length; ++slashCount) { - if (!isPathSeparator(joined.charCodeAt(slashCount))) - break; + while (slashCount < joined.length && + isPathSeparator(joined.charCodeAt(slashCount))) { + slashCount++; } // Replace the slashes if needed @@ -477,30 +462,30 @@ const win32 = { return ''; // Trim any leading backslashes - var fromStart = 0; - for (; fromStart < from.length; ++fromStart) { - if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) - break; + let fromStart = 0; + while (fromStart < from.length && + from.charCodeAt(fromStart) === CHAR_BACKWARD_SLASH) { + fromStart++; } // Trim trailing backslashes (applicable to UNC paths only) - var fromEnd = from.length; - for (; fromEnd - 1 > fromStart; --fromEnd) { - if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) - break; + let fromEnd = from.length; + while (fromEnd - 1 > fromStart && + from.charCodeAt(fromEnd - 1) === CHAR_BACKWARD_SLASH) { + fromEnd--; } const fromLen = fromEnd - fromStart; // Trim any leading backslashes - var toStart = 0; - for (; toStart < to.length; ++toStart) { - if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) - break; + let toStart = 0; + while (toStart < to.length && + to.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) { + toStart++; } // Trim trailing backslashes (applicable to UNC paths only) - var toEnd = to.length; - for (; toEnd - 1 > toStart; --toEnd) { - if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) - break; + let toEnd = to.length; + while (toEnd - 1 > toStart && + to.charCodeAt(toEnd - 1) === CHAR_BACKWARD_SLASH) { + toEnd--; } const toLen = toEnd - toStart; @@ -559,18 +544,17 @@ const win32 = { } } + toStart += lastCommonSep; + // Lastly, append the rest of the destination (`to`) path that comes after // the common path parts if (out.length > 0) - return out + toOrig.slice(toStart + lastCommonSep, toEnd); - else { - toStart += lastCommonSep; - if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) - ++toStart; - return toOrig.slice(toStart, toEnd); - } - }, + return `${out}${toOrig.slice(toStart, toEnd)}`; + if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) + ++toStart; + return toOrig.slice(toStart, toEnd); + }, toNamespacedPath(path) { // Note: this will *probably* throw somewhere. @@ -791,7 +775,7 @@ const win32 = { }, - extname: function extname(path) { + extname(path) { validateString(path, 'path'); var start = 0; var startDot = -1; @@ -1020,27 +1004,20 @@ const win32 = { return ret; }, - sep: '\\', delimiter: ';', win32: null, posix: null }; - const posix = { // path.resolve([from ...], to) - resolve: function resolve() { - var resolvedPath = ''; - var resolvedAbsolute = false; + resolve(...args) { + let resolvedPath = ''; + let resolvedAbsolute = false; - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path; - if (i >= 0) - path = arguments[i]; - else { - path = process.cwd(); - } + for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { + const path = i >= 0 ? args[i] : process.cwd(); validateString(path, 'path'); @@ -1049,7 +1026,7 @@ const posix = { continue; } - resolvedPath = path + '/' + resolvedPath; + resolvedPath = `${path}/${resolvedPath}`; resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; } @@ -1061,19 +1038,12 @@ const posix = { isPosixPathSeparator); if (resolvedAbsolute) { - if (resolvedPath.length > 0) - return '/' + resolvedPath; - else - return '/'; - } else if (resolvedPath.length > 0) { - return resolvedPath; - } else { - return '.'; + return `/${resolvedPath}`; } + return resolvedPath.length > 0 ? resolvedPath : '.'; }, - - normalize: function normalize(path) { + normalize(path) { validateString(path, 'path'); if (path.length === 0) @@ -1091,30 +1061,26 @@ const posix = { if (path.length > 0 && trailingSeparator) path += '/'; - if (isAbsolute) - return '/' + path; - return path; + return isAbsolute ? `/${path}` : path; }, - - isAbsolute: function isAbsolute(path) { + isAbsolute(path) { validateString(path, 'path'); return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; }, - - join: function join() { - if (arguments.length === 0) + join(...args) { + if (args.length === 0) return '.'; - var joined; - for (var i = 0; i < arguments.length; ++i) { - var arg = arguments[i]; + let joined; + for (var i = 0; i < args.length; ++i) { + const arg = args[i]; validateString(arg, 'path'); if (arg.length > 0) { if (joined === undefined) joined = arg; else - joined += '/' + arg; + joined += `/${arg}`; } } if (joined === undefined) @@ -1122,8 +1088,7 @@ const posix = { return posix.normalize(joined); }, - - relative: function relative(from, to) { + relative(from, to) { validateString(from, 'from'); validateString(to, 'to'); @@ -1137,19 +1102,19 @@ const posix = { return ''; // Trim any leading backslashes - var fromStart = 1; - for (; fromStart < from.length; ++fromStart) { - if (from.charCodeAt(fromStart) !== CHAR_FORWARD_SLASH) - break; + let fromStart = 1; + while (fromStart < from.length && + from.charCodeAt(fromStart) === CHAR_FORWARD_SLASH) { + fromStart++; } const fromEnd = from.length; const fromLen = (fromEnd - fromStart); // Trim any leading backslashes - var toStart = 1; - for (; toStart < to.length; ++toStart) { - if (to.charCodeAt(toStart) !== CHAR_FORWARD_SLASH) - break; + let toStart = 1; + while (toStart < to.length && + to.charCodeAt(toStart) === CHAR_FORWARD_SLASH) { + toStart++; } const toEnd = to.length; const toLen = (toEnd - toStart); @@ -1196,32 +1161,28 @@ const posix = { // and `from` for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { if (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) { - if (out.length === 0) - out += '..'; - else - out += '/..'; + out += out.length === 0 ? '..' : '/..'; } } + toStart += lastCommonSep; + // Lastly, append the rest of the destination (`to`) path that comes after // the common path parts if (out.length > 0) - return out + to.slice(toStart + lastCommonSep); - else { - toStart += lastCommonSep; - if (to.charCodeAt(toStart) === CHAR_FORWARD_SLASH) - ++toStart; - return to.slice(toStart); - } - }, + return `${out}${to.slice(toStart)}`; + if (to.charCodeAt(toStart) === CHAR_FORWARD_SLASH) + ++toStart; + return to.slice(toStart); + }, - toNamespacedPath: function toNamespacedPath(path) { + toNamespacedPath(path) { // Non-op on posix systems return path; }, - dirname: function dirname(path) { + dirname(path) { validateString(path, 'path'); if (path.length === 0) return '.'; @@ -1247,8 +1208,7 @@ const posix = { return path.slice(0, end); }, - - basename: function basename(path, ext) { + basename(path, ext) { if (ext !== undefined) validateString(ext, 'ext'); validateString(path, 'path'); @@ -1326,7 +1286,7 @@ const posix = { }, - extname: function extname(path) { + extname(path) { validateString(path, 'path'); var startDot = -1; var startPart = 0; @@ -1475,14 +1435,12 @@ const posix = { return ret; }, - sep: '/', delimiter: ':', win32: null, posix: null }; - posix.win32 = win32.win32 = win32; posix.posix = win32.posix = posix; @@ -1490,7 +1448,4 @@ posix.posix = win32.posix = posix; win32._makeLong = win32.toNamespacedPath; posix._makeLong = posix.toNamespacedPath; -if (process.platform === 'win32') - module.exports = win32; -else - module.exports = posix; +module.exports = process.platform === 'win32' ? win32 : posix; From 471192bd28435c1a52e69dfb67e0dba33fecbf55 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 27 Jan 2019 14:23:46 +0100 Subject: [PATCH 3/8] path: refactor more path code for simplicity 1) Consolidate format to a single function. 2) Move some code that can only be reached in some code branches that was formerly executed in all cases. 3) Explicitly check for the string length of zero instead of converting the string to a boolean. 4) Consolidate nested if statements if possible e.g., if (foo) { if (bar) { /* do stuff */ } } to reduce indentation depth. 5) Simplify checks by removing extra length checks when comparing two strings. 6) Use object shorthand notation where possible. --- lib/path.js | 103 +++++++++++++++++++++++----------------------------- 1 file changed, 45 insertions(+), 58 deletions(-) diff --git a/lib/path.js b/lib/path.js index 51f62eafa46e53..b43a1ec0eb3372 100644 --- a/lib/path.js +++ b/lib/path.js @@ -110,6 +110,9 @@ function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { } function _format(sep, pathObject) { + if (pathObject === null || typeof pathObject !== 'object') { + throw new ERR_INVALID_ARG_TYPE('pathObject', 'Object', pathObject); + } const dir = pathObject.dir || pathObject.root; const base = pathObject.base || `${pathObject.name || ''}${pathObject.ext || ''}`; @@ -121,16 +124,22 @@ function _format(sep, pathObject) { const win32 = { // path.resolve([from ...], to) - resolve: function resolve() { - var resolvedDevice = ''; - var resolvedTail = ''; - var resolvedAbsolute = false; + resolve(...args) { + let resolvedDevice = ''; + let resolvedTail = ''; + let resolvedAbsolute = false; - for (var i = arguments.length - 1; i >= -1; i--) { - var path; + for (var i = args.length - 1; i >= -1; i--) { + let path; if (i >= 0) { - path = arguments[i]; - } else if (!resolvedDevice) { + path = args[i]; + validateString(path, 'path'); + + // Skip empty entries + if (path.length === 0) { + continue; + } + } else if (resolvedDevice.length === 0) { path = process.cwd(); } else { // Windows has the concept of drive-specific current working @@ -149,17 +158,10 @@ const win32 = { } } - validateString(path, 'path'); - - // Skip empty entries - if (path.length === 0) { - continue; - } - - var len = path.length; - var rootEnd = 0; - var device = ''; - var isAbsolute = false; + const len = path.length; + let rootEnd = 0; + let device = ''; + let isAbsolute = false; const code = path.charCodeAt(0); // Try to match a root @@ -409,16 +411,14 @@ const win32 = { if (isPathSeparator(firstPart.charCodeAt(0))) { ++slashCount; const firstLen = firstPart.length; - if (firstLen > 1) { - if (isPathSeparator(firstPart.charCodeAt(1))) { - ++slashCount; - if (firstLen > 2) { - if (isPathSeparator(firstPart.charCodeAt(2))) - ++slashCount; - else { - // We matched a UNC path in the first part - needsReplace = false; - } + if (firstLen > 1 && isPathSeparator(firstPart.charCodeAt(1))) { + ++slashCount; + if (firstLen > 2) { + if (isPathSeparator(firstPart.charCodeAt(2))) + ++slashCount; + else { + // We matched a UNC path in the first part + needsReplace = false; } } } @@ -699,16 +699,14 @@ const win32 = { // Check for a drive letter prefix so as not to mistake the following // path separator as an extra separator at the end of the path that can be // disregarded - if (path.length >= 2) { - const drive = path.charCodeAt(0); - if (isWindowsDeviceRoot(drive)) { - if (path.charCodeAt(1) === CHAR_COLON) - start = 2; - } + if (path.length >= 2 && + isWindowsDeviceRoot(path.charCodeAt(0)) && + path.charCodeAt(1) === CHAR_COLON) { + start = 2; } if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { - if (ext.length === path.length && ext === path) + if (ext === path) return ''; var extIdx = ext.length - 1; var firstNonSlashEnd = -1; @@ -839,16 +837,9 @@ const win32 = { return path.slice(startDot, end); }, + format: _format.bind(null, '\\'), - format: function format(pathObject) { - if (pathObject === null || typeof pathObject !== 'object') { - throw new ERR_INVALID_ARG_TYPE('pathObject', 'Object', pathObject); - } - return _format('\\', pathObject); - }, - - - parse: function parse(path) { + parse(path) { validateString(path, 'path'); const ret = { root: '', dir: '', base: '', ext: '', name: '' }; @@ -1056,9 +1047,12 @@ const posix = { // Normalize the path path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator); - if (path.length === 0 && !isAbsolute) - path = '.'; - if (path.length > 0 && trailingSeparator) + if (path.length === 0) { + if (isAbsolute) + return '/'; + return trailingSeparator ? './' : '.'; + } + if (trailingSeparator) path += '/'; return isAbsolute ? `/${path}` : path; @@ -1219,7 +1213,7 @@ const posix = { var i; if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { - if (ext.length === path.length && ext === path) + if (ext === path) return ''; var extIdx = ext.length - 1; var firstNonSlashEnd = -1; @@ -1338,16 +1332,9 @@ const posix = { return path.slice(startDot, end); }, + format: _format.bind(null, '/'), - format: function format(pathObject) { - if (pathObject === null || typeof pathObject !== 'object') { - throw new ERR_INVALID_ARG_TYPE('pathObject', 'Object', pathObject); - } - return _format('/', pathObject); - }, - - - parse: function parse(path) { + parse(path) { validateString(path, 'path'); const ret = { root: '', dir: '', base: '', ext: '', name: '' }; From ace92152ad85963134d3eec46b9eb5bd95ab6674 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 27 Jan 2019 15:23:21 +0100 Subject: [PATCH 4/8] path: minor refactoring 1) Consolidate nested if statements if possible `if (foo) { if bar () { /* do stuff */ } }`) to reduce indentation depth. 2) Remove obsolete else cases to reduce indentation. --- lib/path.js | 125 ++++++++++++++++++++++++---------------------------- 1 file changed, 57 insertions(+), 68 deletions(-) diff --git a/lib/path.js b/lib/path.js index b43a1ec0eb3372..ec27f280a59a61 100644 --- a/lib/path.js +++ b/lib/path.js @@ -206,20 +206,16 @@ const win32 = { } else { rootEnd = 1; } - } else if (isWindowsDeviceRoot(code)) { + } else if (isWindowsDeviceRoot(code) && + path.charCodeAt(1) === CHAR_COLON) { // Possible device root - - if (path.charCodeAt(1) === CHAR_COLON) { - device = path.slice(0, 2); - rootEnd = 2; - if (len > 2) { - if (isPathSeparator(path.charCodeAt(2))) { - // Treat separator following drive name as an absolute path - // indicator - isAbsolute = true; - rootEnd = 3; - } - } + device = path.slice(0, 2); + rootEnd = 2; + if (len > 2 && isPathSeparator(path.charCodeAt(2))) { + // Treat separator following drive name as an absolute path + // indicator + isAbsolute = true; + rootEnd = 3; } } } else if (isPathSeparator(code)) { @@ -567,26 +563,23 @@ const win32 = { const resolvedPath = win32.resolve(path); - if (resolvedPath.length >= 3) { - if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) { - // Possible UNC root - - if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) { - const code = resolvedPath.charCodeAt(2); - if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) { - // Matched non-long UNC root, convert the path to a long UNC path - return '\\\\?\\UNC\\' + resolvedPath.slice(2); - } - } - } else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) { - // Possible device root + if (resolvedPath.length <= 2) + return path; - if (resolvedPath.charCodeAt(1) === CHAR_COLON && - resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) { - // Matched device root, convert the path to a long UNC path - return '\\\\?\\' + resolvedPath; + if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) { + // Possible UNC root + if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) { + const code = resolvedPath.charCodeAt(2); + if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) { + // Matched non-long UNC root, convert the path to a long UNC path + return `\\\\?\\UNC\\${resolvedPath.slice(2)}`; } } + } else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0)) && + resolvedPath.charCodeAt(1) === CHAR_COLON && + resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) { + // Matched device root, convert the path to a long UNC path + return `\\\\?\\${resolvedPath}`; } return path; @@ -749,29 +742,27 @@ const win32 = { else if (end === -1) end = path.length; return path.slice(start, end); - } else { - for (i = path.length - 1; i >= start; --i) { - if (isPathSeparator(path.charCodeAt(i))) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - start = i + 1; - break; - } - } else if (end === -1) { - // We saw the first non-path separator, mark this as the end of our - // path component - matchedSlash = false; - end = i + 1; + } + for (i = path.length - 1; i >= start; --i) { + if (isPathSeparator(path.charCodeAt(i))) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; } - - if (end === -1) - return ''; - return path.slice(start, end); } - }, + if (end === -1) + return ''; + return path.slice(start, end); + }, extname(path) { validateString(path, 'path'); @@ -1256,29 +1247,27 @@ const posix = { else if (end === -1) end = path.length; return path.slice(start, end); - } else { - for (i = path.length - 1; i >= 0; --i) { - if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { - // If we reached a path separator that was not part of a set of path - // separators at the end of the string, stop now - if (!matchedSlash) { - start = i + 1; - break; - } - } else if (end === -1) { - // We saw the first non-path separator, mark this as the end of our - // path component - matchedSlash = false; - end = i + 1; + } + for (i = path.length - 1; i >= 0; --i) { + if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; } - - if (end === -1) - return ''; - return path.slice(start, end); } - }, + if (end === -1) + return ''; + return path.slice(start, end); + }, extname(path) { validateString(path, 'path'); From 6b2c7a2fdcc39c8bec9696d336830f168526b4f1 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 27 Jan 2019 15:27:28 +0100 Subject: [PATCH 5/8] path: refactor logic for to reduce code branches This refactoring makes sure some code branches will not be hit if they do not have to be reached. --- lib/path.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/path.js b/lib/path.js index ec27f280a59a61..d39f4f5d72dcf7 100644 --- a/lib/path.js +++ b/lib/path.js @@ -224,23 +224,25 @@ const win32 = { isAbsolute = true; } - if (device.length > 0 && - resolvedDevice.length > 0 && - device.toLowerCase() !== resolvedDevice.toLowerCase()) { - // This path points to another device so it is not applicable - continue; + if (device.length > 0) { + if (resolvedDevice.length > 0) { + if (device.toLowerCase() !== resolvedDevice.toLowerCase()) + // This path points to another device so it is not applicable + continue; + } else { + resolvedDevice = device; + } } - if (resolvedDevice.length === 0 && device.length > 0) { - resolvedDevice = device; - } - if (!resolvedAbsolute) { - resolvedTail = path.slice(rootEnd) + '\\' + resolvedTail; + if (resolvedAbsolute) { + if (resolvedDevice.length > 0) + break; + } else { + resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`; resolvedAbsolute = isAbsolute; - } - - if (resolvedDevice.length > 0 && resolvedAbsolute) { - break; + if (isAbsolute && resolvedDevice.length > 0) { + break; + } } } From a815e209e48fe6a7edc232a9473a4745f869fbfd Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 27 Jan 2019 15:35:40 +0100 Subject: [PATCH 6/8] path: simplify code and remove obsolete checks Either `end` is `-1` or `startPart` is not `0`. Therefore it's possible to move the conditions in a way that we eliminate a few code branches. --- lib/path.js | 59 +++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/lib/path.js b/lib/path.js index d39f4f5d72dcf7..b7b3788d84fad8 100644 --- a/lib/path.js +++ b/lib/path.js @@ -960,21 +960,20 @@ const win32 = { } } - if (startDot === -1 || - end === -1 || - // We saw a non-dot character immediately before the dot - preDotState === 0 || - // The (right-most) trimmed path component is exactly '..' - (preDotState === 1 && - startDot === end - 1 && - startDot === startPart + 1)) { - if (end !== -1) { + if (end !== -1) { + if (startDot === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { ret.base = ret.name = path.slice(startPart, end); + } else { + ret.name = path.slice(startPart, startDot); + ret.base = path.slice(startPart, end); + ret.ext = path.slice(startDot, end); } - } else { - ret.name = path.slice(startPart, startDot); - ret.base = path.slice(startPart, end); - ret.ext = path.slice(startDot, end); } // If the directory is the root, use the entire root as the `dir` including @@ -1380,29 +1379,21 @@ const posix = { } } - if (startDot === -1 || - end === -1 || - // We saw a non-dot character immediately before the dot - preDotState === 0 || - // The (right-most) trimmed path component is exactly '..' - (preDotState === 1 && - startDot === end - 1 && - startDot === startPart + 1)) { - if (end !== -1) { - if (startPart === 0 && isAbsolute) - ret.base = ret.name = path.slice(1, end); - else - ret.base = ret.name = path.slice(startPart, end); - } - } else { - if (startPart === 0 && isAbsolute) { - ret.name = path.slice(1, startDot); - ret.base = path.slice(1, end); + if (end !== -1) { + const start = startPart === 0 && isAbsolute ? 1 : startPart; + if (startDot === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + (preDotState === 1 && + startDot === end - 1 && + startDot === startPart + 1)) { + ret.base = ret.name = path.slice(start, end); } else { - ret.name = path.slice(startPart, startDot); - ret.base = path.slice(startPart, end); + ret.name = path.slice(start, startDot); + ret.base = path.slice(start, end); + ret.ext = path.slice(startDot, end); } - ret.ext = path.slice(startDot, end); } if (startPart > 0) From 5b5cebb2d30d30d92fa77d92217bd588d915e190 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 27 Jan 2019 16:03:16 +0100 Subject: [PATCH 7/8] path: refactor for less indentation This moves the `if (len === 1)` case to the top of the function. That way it is possible to reduce the indentation level due to returning early in that case. On top of that the following was done: 1) For clarity refactored for loops which were meant to count up a variable into a while loop. 2) Used template strings instead of string concat. 3) Consolidating nested if statements. 4) Using tenary expressions if applicable when assigning variables to reduce the code overhead. --- lib/path.js | 321 ++++++++++++++++++++++++---------------------------- 1 file changed, 147 insertions(+), 174 deletions(-) diff --git a/lib/path.js b/lib/path.js index b7b3788d84fad8..64cd5eee92c8e3 100644 --- a/lib/path.js +++ b/lib/path.js @@ -270,77 +270,67 @@ const win32 = { const code = path.charCodeAt(0); // Try to match a root - if (len > 1) { - if (isPathSeparator(code)) { - // Possible UNC root - - // If we started with a separator, we know we at least have an absolute - // path of some kind (UNC or otherwise) - isAbsolute = true; + if (len === 1) { + // `path` contains just a single char, exit early to avoid + // unnecessary work + return isPosixPathSeparator(code) ? '\\' : path; + } + if (isPathSeparator(code)) { + // Possible UNC root - if (isPathSeparator(path.charCodeAt(1))) { - // Matched double path separator at beginning - var j = 2; - var last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) - break; + // If we started with a separator, we know we at least have an absolute + // path of some kind (UNC or otherwise) + isAbsolute = true; + + if (isPathSeparator(path.charCodeAt(1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + while (j < len && !isPathSeparator(path.charCodeAt(j))) { + j++; + } + if (j < len && j !== last) { + const firstPart = path.slice(last, j); + // Matched! + last = j; + // Match 1 or more path separators + while (j < len && isPathSeparator(path.charCodeAt(j))) { + j++; } if (j < len && j !== last) { - const firstPart = path.slice(last, j); // Matched! last = j; - // Match 1 or more path separators - for (; j < len; ++j) { - if (!isPathSeparator(path.charCodeAt(j))) - break; + // Match 1 or more non-path separators + while (j < len && !isPathSeparator(path.charCodeAt(j))) { + j++; } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) - break; - } - 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 + '\\' + path.slice(last) + '\\'; - } else if (j !== last) { - // We matched a UNC root with leftovers - - device = '\\\\' + firstPart + '\\' + path.slice(last, j); - rootEnd = 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}\\${path.slice(last)}\\`; } - } - } else { - rootEnd = 1; - } - } else if (isWindowsDeviceRoot(code)) { - // Possible device root - - if (path.charCodeAt(1) === CHAR_COLON) { - device = path.slice(0, 2); - rootEnd = 2; - if (len > 2) { - if (isPathSeparator(path.charCodeAt(2))) { - // Treat separator following drive name as an absolute path - // indicator - isAbsolute = true; - rootEnd = 3; + if (j !== last) { + // We matched a UNC root with leftovers + device = `\\\\${firstPart}\\${path.slice(last, j)}`; + rootEnd = j; } } } + } else { + rootEnd = 1; + } + } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) { + // Possible device root + device = path.slice(0, 2); + rootEnd = 2; + if (len > 2 && isPathSeparator(path.charCodeAt(2))) { + // Treat separator following drive name as an absolute path + // indicator + isAbsolute = true; + rootEnd = 3; } - } else if (isPathSeparator(code)) { - // `path` contains just a path separator, exit early to avoid unnecessary - // work - return '\\'; } let tail = rootEnd < len ? @@ -592,75 +582,66 @@ const win32 = { const len = path.length; if (len === 0) return '.'; - var rootEnd = -1; - var end = -1; - var matchedSlash = true; - var offset = 0; + let rootEnd = -1; + let offset = 0; const code = path.charCodeAt(0); + if (len === 1) { + // `path` contains just a path separator, exit early to avoid + // unnecessary work or a dot. + return isPathSeparator(code) ? path : '.'; + } + // Try to match a root - if (len > 1) { - if (isPathSeparator(code)) { - // Possible UNC root - - rootEnd = offset = 1; - - if (isPathSeparator(path.charCodeAt(1))) { - // Matched double path separator at beginning - var j = 2; - var last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) - break; + if (isPathSeparator(code)) { + // Possible UNC root + + rootEnd = offset = 1; + + if (isPathSeparator(path.charCodeAt(1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + while (j < len && !isPathSeparator(path.charCodeAt(j))) { + j++; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more path separators + while (j < len && isPathSeparator(path.charCodeAt(j))) { + j++; } if (j < len && j !== last) { // Matched! last = j; - // Match 1 or more path separators - for (; j < len; ++j) { - if (!isPathSeparator(path.charCodeAt(j))) - break; + // Match 1 or more non-path separators + while (j < len && !isPathSeparator(path.charCodeAt(j))) { + j++; } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) - break; - } - if (j === len) { - // We matched a UNC root only - return path; - } - if (j !== last) { - // We matched a UNC root with leftovers + if (j === len) { + // We matched a UNC root only + return path; + } + if (j !== last) { + // We matched a UNC root with leftovers - // Offset by 1 to include the separator after the UNC root to - // treat it as a "normal root" on top of a (UNC) root - rootEnd = offset = j + 1; - } + // Offset by 1 to include the separator after the UNC root to + // treat it as a "normal root" on top of a (UNC) root + rootEnd = offset = j + 1; } } } - } else if (isWindowsDeviceRoot(code)) { - // Possible device root - - if (path.charCodeAt(1) === CHAR_COLON) { - rootEnd = offset = 2; - if (len > 2) { - if (isPathSeparator(path.charCodeAt(2))) - rootEnd = offset = 3; - } - } } - } else if (isPathSeparator(code)) { - // `path` contains just a path separator, exit early to avoid - // unnecessary work - return path; + // Possible device root + } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) { + rootEnd = len > 2 && isPathSeparator(path.charCodeAt(2)) ? 3 : 2; + offset = rootEnd; } + let end = -1; + let matchedSlash = true; for (var i = len - 1; i >= offset; --i) { if (isPathSeparator(path.charCodeAt(i))) { if (!matchedSlash) { @@ -843,79 +824,71 @@ const win32 = { var rootEnd = 0; let code = path.charCodeAt(0); - // Try to match a root - if (len > 1) { + if (len === 1) { if (isPathSeparator(code)) { - // Possible UNC root + // `path` contains just a path separator, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; + } + return ret; + } + // Try to match a root + if (isPathSeparator(code)) { + // Possible UNC root - rootEnd = 1; - if (isPathSeparator(path.charCodeAt(1))) { - // Matched double path separator at beginning - var j = 2; - var last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) - break; + rootEnd = 1; + if (isPathSeparator(path.charCodeAt(1))) { + // Matched double path separator at beginning + let j = 2; + let last = j; + // Match 1 or more non-path separators + while (j < len && !isPathSeparator(path.charCodeAt(j))) { + j++; + } + if (j < len && j !== last) { + // Matched! + last = j; + // Match 1 or more path separators + while (j < len && isPathSeparator(path.charCodeAt(j))) { + j++; } if (j < len && j !== last) { // Matched! last = j; - // Match 1 or more path separators - for (; j < len; ++j) { - if (!isPathSeparator(path.charCodeAt(j))) - break; + // Match 1 or more non-path separators + while (j < len && !isPathSeparator(path.charCodeAt(j))) { + j++; } - if (j < len && j !== last) { - // Matched! - last = j; - // Match 1 or more non-path separators - for (; j < len; ++j) { - if (isPathSeparator(path.charCodeAt(j))) - break; - } - if (j === len) { - // We matched a UNC root only - - rootEnd = j; - } else if (j !== last) { - // We matched a UNC root with leftovers - - rootEnd = j + 1; - } + if (j === len) { + // We matched a UNC root only + rootEnd = j; + } else if (j !== last) { + // We matched a UNC root with leftovers + rootEnd = j + 1; } } } - } else if (isWindowsDeviceRoot(code)) { - // Possible device root - - if (path.charCodeAt(1) === CHAR_COLON) { - rootEnd = 2; - if (len > 2) { - if (isPathSeparator(path.charCodeAt(2))) { - if (len === 3) { - // `path` contains just a drive root, exit early to avoid - // unnecessary work - ret.root = ret.dir = path; - return ret; - } - rootEnd = 3; - } - } else { - // `path` contains just a drive root, exit early to avoid - // unnecessary work - ret.root = ret.dir = path; - return ret; - } + } + } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) { + // Possible device root + if (len <= 2) { + // `path` contains just a drive root, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; + } + rootEnd = 2; + if (isPathSeparator(path.charCodeAt(2))) { + if (len === 3) { + // `path` contains just a drive root, exit early to avoid + // unnecessary work + ret.root = ret.dir = path; + return ret; } + rootEnd = 3; } - } else if (isPathSeparator(code)) { - // `path` contains just a path separator, exit early to avoid - // unnecessary work - ret.root = ret.dir = path; - return ret; } - if (rootEnd > 0) ret.root = path.slice(0, rootEnd); From 5da1b223f03bf0ada9060585cd09c548cc335f01 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sun, 27 Jan 2019 16:07:00 +0100 Subject: [PATCH 8/8] path: refactor code for clarity This moves a condition inside of a for loop which can only be triggered at the very end of the for loop outside of the loop. That way the for loop itself is much simpler and easier to understand and the code itself is less indented which should increase the readability. It also refactors some `var` to `let` and `const`. --- lib/path.js | 128 ++++++++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 65 deletions(-) diff --git a/lib/path.js b/lib/path.js index 64cd5eee92c8e3..6ac65cfe4a7a3f 100644 --- a/lib/path.js +++ b/lib/path.js @@ -478,38 +478,12 @@ const win32 = { const toLen = toEnd - toStart; // Compare paths to find the longest common path from root - var length = (fromLen < toLen ? fromLen : toLen); - var lastCommonSep = -1; - var i = 0; - for (; i <= length; ++i) { - if (i === length) { - if (toLen > length) { - if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) { - // We get here if `from` is the exact base path for `to`. - // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz' - return toOrig.slice(toStart + i + 1); - } else if (i === 2) { - // We get here if `from` is the device root. - // For example: from='C:\\'; to='C:\\foo' - return toOrig.slice(toStart + i); - } - } - if (fromLen > length) { - if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) { - // We get here if `to` is the exact base path for `from`. - // For example: from='C:\\foo\\bar'; to='C:\\foo' - lastCommonSep = i; - } else if (i === 2) { - // We get here if `to` is the device root. - // For example: from='C:\\foo\\bar'; to='C:\\' - lastCommonSep = 3; - } - } - break; - } - var fromCode = from.charCodeAt(fromStart + i); - var toCode = to.charCodeAt(toStart + i); - if (fromCode !== toCode) + const length = fromLen < toLen ? fromLen : toLen; + let lastCommonSep = -1; + let i = 0; + for (; i < length; i++) { + const fromCode = from.charCodeAt(fromStart + i); + if (fromCode !== to.charCodeAt(toStart + i)) break; else if (fromCode === CHAR_BACKWARD_SLASH) lastCommonSep = i; @@ -517,8 +491,33 @@ const win32 = { // We found a mismatch before the first common path separator was seen, so // return the original `to`. - if (i !== length && lastCommonSep === -1) { - return toOrig; + if (i !== length) { + if (lastCommonSep === -1) + return toOrig; + } else { + if (toLen > length) { + if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) { + // We get here if `from` is the exact base path for `to`. + // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz' + return toOrig.slice(toStart + i + 1); + } + if (i === 2) { + // We get here if `from` is the device root. + // For example: from='C:\\'; to='C:\\foo' + return toOrig.slice(toStart + i); + } + } + if (fromLen > length) { + if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) { + // We get here if `to` is the exact base path for `from`. + // For example: from='C:\\foo\\bar'; to='C:\\foo' + lastCommonSep = i; + } else if (i === 2) { + // We get here if `to` is the device root. + // For example: from='C:\\foo\\bar'; to='C:\\' + lastCommonSep = 3; + } + } } let out = ''; @@ -1079,41 +1078,40 @@ const posix = { const toLen = (toEnd - toStart); // Compare paths to find the longest common path from root - var length = (fromLen < toLen ? fromLen : toLen); - var lastCommonSep = -1; - var i = 0; - for (; i <= length; ++i) { - if (i === length) { - if (toLen > length) { - if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) { - // We get here if `from` is the exact base path for `to`. - // For example: from='/foo/bar'; to='/foo/bar/baz' - return to.slice(toStart + i + 1); - } else if (i === 0) { - // We get here if `from` is the root - // For example: from='/'; to='/foo' - return to.slice(toStart + i); - } - } else if (fromLen > length) { - if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) { - // We get here if `to` is the exact base path for `from`. - // For example: from='/foo/bar/baz'; to='/foo/bar' - lastCommonSep = i; - } else if (i === 0) { - // We get here if `to` is the root. - // For example: from='/foo'; to='/' - lastCommonSep = 0; - } - } - break; - } - var fromCode = from.charCodeAt(fromStart + i); - var toCode = to.charCodeAt(toStart + i); - if (fromCode !== toCode) + const length = (fromLen < toLen ? fromLen : toLen); + let lastCommonSep = -1; + let i = 0; + for (; i < length; i++) { + const fromCode = from.charCodeAt(fromStart + i); + if (fromCode !== to.charCodeAt(toStart + i)) break; else if (fromCode === CHAR_FORWARD_SLASH) lastCommonSep = i; } + if (i === length) { + if (toLen > length) { + if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) { + // We get here if `from` is the exact base path for `to`. + // For example: from='/foo/bar'; to='/foo/bar/baz' + return to.slice(toStart + i + 1); + } + if (i === 0) { + // We get here if `from` is the root + // For example: from='/'; to='/foo' + return to.slice(toStart + i); + } + } else if (fromLen > length) { + if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) { + // We get here if `to` is the exact base path for `from`. + // For example: from='/foo/bar/baz'; to='/foo/bar' + lastCommonSep = i; + } else if (i === 0) { + // We get here if `to` is the root. + // For example: from='/foo'; to='/' + lastCommonSep = 0; + } + } + } var out = ''; // Generate the relative path based on the path difference between `to`