path: refactor normalizeArray()

The normalizeArray() function now avoids using the slow Array#splice()
method to improve performance and now also filters out empty path parts.

Code that pre-filtered empty parts has been removed.

PR-URL: https://github.com/joyent/node/pull/8724
Reviewed-by: Trevor Norris <trev.norris@gmail.com>
This commit is contained in:
Nathan Woltman 2014-11-21 03:22:07 -05:00 committed by Bert Belder
parent 9483bfe6e3
commit 50d7401244

View File

@ -26,33 +26,30 @@ var util = require('util');
// resolves . and .. elements in a path array with directory names there // resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array // must be no slashes or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish // (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths) // relative and absolute paths)
function normalizeArray(parts, allowAboveRoot) { function normalizeArray(parts, allowAboveRoot) {
// if the path tries to go above the root, `up` ends up > 0 var res = [];
var up = 0; for (var i = 0; i < parts.length; i++) {
for (var i = parts.length - 1; i >= 0; i--) { var p = parts[i];
var last = parts[i];
if (last === '.') { // ignore empty parts
parts.splice(i, 1); if (!p || p === '.')
} else if (last === '..') { continue;
parts.splice(i, 1);
up++; if (p === '..') {
} else if (up) { if (res.length && res[res.length - 1] !== '..') {
parts.splice(i, 1); res.pop();
up--; } else if (allowAboveRoot) {
res.push('..');
}
} else {
res.push(p);
} }
} }
// if the path is allowed to go above the root, restore leading ..s return res;
if (allowAboveRoot) {
for (; up--; up) {
parts.unshift('..');
}
}
return parts;
} }
// Regex to split a windows path into three parts: [*, device, slash, // Regex to split a windows path into three parts: [*, device, slash,
@ -154,12 +151,7 @@ win32.resolve = function() {
// fails) // fails)
// Normalize the tail path // Normalize the tail path
resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/),
function f(p) {
return !!p;
}
resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/).filter(f),
!resolvedAbsolute).join('\\'); !resolvedAbsolute).join('\\');
return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) || return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) ||
@ -176,9 +168,7 @@ win32.normalize = function(path) {
trailingSlash = /[\\\/]$/.test(tail); trailingSlash = /[\\\/]$/.test(tail);
// Normalize the tail path // Normalize the tail path
tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) { tail = normalizeArray(tail.split(/[\\\/]+/), !isAbsolute).join('\\');
return !!p;
}), !isAbsolute).join('\\');
if (!tail && !isAbsolute) { if (!tail && !isAbsolute) {
tail = '.'; tail = '.';
@ -443,9 +433,8 @@ posix.resolve = function() {
// handle relative paths to be safe (might happen when process.cwd() fails) // handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path // Normalize the path
resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) { resolvedPath = normalizeArray(resolvedPath.split('/'),
return !!p; !resolvedAbsolute).join('/');
}), !resolvedAbsolute).join('/');
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
}; };
@ -454,17 +443,10 @@ posix.resolve = function() {
// posix version // posix version
posix.normalize = function(path) { posix.normalize = function(path) {
var isAbsolute = posix.isAbsolute(path), var isAbsolute = posix.isAbsolute(path),
trailingSlash = path.substr(-1) === '/', trailingSlash = path.substr(-1) === '/';
segments = path.split('/'),
nonEmptySegments = [];
// Normalize the path // Normalize the path
for (var i = 0; i < segments.length; i++) { path = normalizeArray(path.split('/'), !isAbsolute).join('/');
if (segments[i]) {
nonEmptySegments.push(segments[i]);
}
}
path = normalizeArray(nonEmptySegments, !isAbsolute).join('/');
if (!path && !isAbsolute) { if (!path && !isAbsolute) {
path = '.'; path = '.';