From b770526818cb6b7dcd3e6133ff328d14759c97f1 Mon Sep 17 00:00:00 2001 From: Nathan Woltman Date: Wed, 25 Feb 2015 23:51:10 -0800 Subject: [PATCH] path: refactor for performance and consistency Improve performance by: + Not leaking the `arguments` object! + Getting the last character of a string by index, instead of with `.substr()` or `.slice()` Improve code consistency by: + Using `[]` instead of `.charAt()` where possible + Using a function declaration instead of a var declaration + Using `.slice()` with clearer arguments Improve both by: + Making the reusable `trimArray()` function + Standardizing getting certain path statistics with the new `win32StatPath()` function --- lib/path.js | 131 +++++++++++++++++++++++++++------------------------- 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/lib/path.js b/lib/path.js index 27c148ab535f..a69d7cfd76da 100644 --- a/lib/path.js +++ b/lib/path.js @@ -51,6 +51,29 @@ function normalizeArray(parts, allowAboveRoot) { return res; } +// returns an array with empty elements removed from either end of the input +// array or the original array if no elements need to be removed +function trimArray(arr) { + var lastIndex = arr.length - 1; + var start = 0; + for (; start <= lastIndex; start++) { + if (arr[start]) + break; + } + + var end = lastIndex; + for (; end >= 0; end--) { + if (arr[end]) + break; + } + + if (start === 0 && end === lastIndex) + return arr; + if (start > end) + return []; + return arr.slice(start, end + 1); +} + // Regex to split a windows path into three parts: [*, device, slash, // tail] windows-only var splitDeviceRe = @@ -76,9 +99,21 @@ function win32SplitPath(filename) { return [device, dir, basename, ext]; } -var normalizeUNCRoot = function(device) { +function win32StatPath(path) { + var result = splitDeviceRe.exec(path), + device = result[1] || '', + isUnc = !!device && device[1] !== ':'; + return { + device: device, + isUnc: isUnc, + isAbsolute: isUnc || !!result[2], // UNC paths are always absolute + tail: result[3] + }; +} + +function normalizeUNCRoot(device) { return '\\\\' + device.replace(/^[\\\/]+/, '').replace(/[\\\/]+/g, '\\'); -}; +} // path.resolve([from ...], to) win32.resolve = function() { @@ -113,11 +148,11 @@ win32.resolve = function() { continue; } - var result = splitDeviceRe.exec(path), - device = result[1] || '', - isUnc = device && device.charAt(1) !== ':', - isAbsolute = win32.isAbsolute(path), - tail = result[3]; + var result = win32StatPath(path), + device = result.device, + isUnc = result.isUnc, + isAbsolute = result.isAbsolute, + tail = result.tail; if (device && resolvedDevice && @@ -159,11 +194,11 @@ win32.resolve = function() { win32.normalize = function(path) { - var result = splitDeviceRe.exec(path), - device = result[1] || '', - isUnc = device && device.charAt(1) !== ':', - isAbsolute = win32.isAbsolute(path), - tail = result[3], + var result = win32StatPath(path), + device = result.device, + isUnc = result.isUnc, + isAbsolute = result.isAbsolute, + tail = result.tail, trailingSlash = /[\\\/]$/.test(tail); // Normalize the tail path @@ -187,22 +222,21 @@ win32.normalize = function(path) { win32.isAbsolute = function(path) { - var result = splitDeviceRe.exec(path), - device = result[1] || '', - isUnc = !!device && device.charAt(1) !== ':'; - // UNC paths are always absolute - return !!result[2] || isUnc; + return win32StatPath(path).isAbsolute; }; win32.join = function() { - function f(p) { - if (!util.isString(p)) { + var paths = []; + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + if (!util.isString(arg)) { throw new TypeError('Arguments to path.join must be strings'); } - return p; + if (arg) { + paths.push(arg); + } } - var paths = Array.prototype.filter.call(arguments, f); var joined = paths.join('\\'); // Make sure that the joined path doesn't start with two slashes, because @@ -239,25 +273,10 @@ win32.relative = function(from, to) { var lowerFrom = from.toLowerCase(); var lowerTo = to.toLowerCase(); - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end + 1); - } - - var toParts = trim(to.split('\\')); + var toParts = trimArray(to.split('\\')); - var lowerFromParts = trim(lowerFrom.split('\\')); - var lowerToParts = trim(lowerTo.split('\\')); + var lowerFromParts = trimArray(lowerFrom.split('\\')); + var lowerToParts = trimArray(lowerTo.split('\\')); var length = Math.min(lowerFromParts.length, lowerToParts.length); var samePartsLength = length; @@ -360,11 +379,10 @@ win32.format = function(pathObject) { var dir = pathObject.dir; var base = pathObject.base || ''; - if (dir.slice(dir.length - 1, dir.length) === win32.sep) { - return dir + base; - } - if (dir) { + if (dir[dir.length - 1] === win32.sep) { + return dir + base; + } return dir + win32.sep + base; } @@ -384,7 +402,7 @@ win32.parse = function(pathString) { } return { root: allParts[0], - dir: allParts[0] + allParts[1].slice(0, allParts[1].length - 1), + dir: allParts[0] + allParts[1].slice(0, -1), base: allParts[2], ext: allParts[3], name: allParts[2].slice(0, allParts[2].length - allParts[3].length) @@ -425,7 +443,7 @@ posix.resolve = function() { } resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; + resolvedAbsolute = path[0] === '/'; } // At this point the path should be resolved to a full absolute path, but @@ -442,7 +460,7 @@ posix.resolve = function() { // posix version posix.normalize = function(path) { var isAbsolute = posix.isAbsolute(path), - trailingSlash = path.substr(-1) === '/'; + trailingSlash = path && path[path.length - 1] === '/'; // Normalize the path path = normalizeArray(path.split('/'), !isAbsolute).join('/'); @@ -488,23 +506,8 @@ posix.relative = function(from, to) { from = posix.resolve(from).substr(1); to = posix.resolve(to).substr(1); - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); + var fromParts = trimArray(from.split('/')); + var toParts = trimArray(to.split('/')); var length = Math.min(fromParts.length, toParts.length); var samePartsLength = length; @@ -603,7 +606,7 @@ posix.parse = function(pathString) { return { root: allParts[0], - dir: allParts[0] + allParts[1].slice(0, allParts[1].length - 1), + dir: allParts[0] + allParts[1].slice(0, -1), base: allParts[2], ext: allParts[3], name: allParts[2].slice(0, allParts[2].length - allParts[3].length)