Skip to content

Commit e0a0e91

Browse files
nwoltmantrevnorris
authored andcommitted
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: nodejs#8724 Reviewed-by: Trevor Norris <[email protected]>
1 parent 9d9ed61 commit e0a0e91

File tree

1 file changed

+23
-41
lines changed

1 file changed

+23
-41
lines changed

lib/path.js

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,30 @@ var util = require('util');
2525

2626

2727
// resolves . and .. elements in a path array with directory names there
28-
// must be no slashes, empty elements, or device names (c:\) in the array
28+
// must be no slashes or device names (c:\) in the array
2929
// (so also no leading and trailing slashes - it does not distinguish
3030
// relative and absolute paths)
3131
function normalizeArray(parts, allowAboveRoot) {
32-
// if the path tries to go above the root, `up` ends up > 0
33-
var up = 0;
34-
for (var i = parts.length - 1; i >= 0; i--) {
35-
var last = parts[i];
36-
if (last === '.') {
37-
parts.splice(i, 1);
38-
} else if (last === '..') {
39-
parts.splice(i, 1);
40-
up++;
41-
} else if (up) {
42-
parts.splice(i, 1);
43-
up--;
44-
}
45-
}
32+
var res = [];
33+
for (var i = 0; i < parts.length; i++) {
34+
var p = parts[i];
35+
36+
// ignore empty parts
37+
if (!p || p === '.')
38+
continue;
4639

47-
// if the path is allowed to go above the root, restore leading ..s
48-
if (allowAboveRoot) {
49-
for (; up--; up) {
50-
parts.unshift('..');
40+
if (p === '..') {
41+
if (res.length && res[res.length - 1] !== '..') {
42+
res.pop();
43+
} else if (allowAboveRoot) {
44+
res.push('..');
45+
}
46+
} else {
47+
res.push(p);
5148
}
5249
}
5350

54-
return parts;
51+
return res;
5552
}
5653

5754
// Regex to split a windows path into three parts: [*, device, slash,
@@ -153,12 +150,7 @@ win32.resolve = function() {
153150
// fails)
154151

155152
// Normalize the tail path
156-
157-
function f(p) {
158-
return !!p;
159-
}
160-
161-
resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/).filter(f),
153+
resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/),
162154
!resolvedAbsolute).join('\\');
163155

164156
// If device is a drive letter, we'll normalize to lower case.
@@ -186,9 +178,7 @@ win32.normalize = function(path) {
186178
}
187179

188180
// Normalize the tail path
189-
tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) {
190-
return !!p;
191-
}), !isAbsolute).join('\\');
181+
tail = normalizeArray(tail.split(/[\\\/]+/), !isAbsolute).join('\\');
192182

193183
if (!tail && !isAbsolute) {
194184
tail = '.';
@@ -453,9 +443,8 @@ posix.resolve = function() {
453443
// handle relative paths to be safe (might happen when process.cwd() fails)
454444

455445
// Normalize the path
456-
resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) {
457-
return !!p;
458-
}), !resolvedAbsolute).join('/');
446+
resolvedPath = normalizeArray(resolvedPath.split('/'),
447+
!resolvedAbsolute).join('/');
459448

460449
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
461450
};
@@ -464,17 +453,10 @@ posix.resolve = function() {
464453
// posix version
465454
posix.normalize = function(path) {
466455
var isAbsolute = posix.isAbsolute(path),
467-
trailingSlash = path.substr(-1) === '/',
468-
segments = path.split('/'),
469-
nonEmptySegments = [];
456+
trailingSlash = path.substr(-1) === '/';
470457

471458
// Normalize the path
472-
for (var i = 0; i < segments.length; i++) {
473-
if (segments[i]) {
474-
nonEmptySegments.push(segments[i]);
475-
}
476-
}
477-
path = normalizeArray(nonEmptySegments, !isAbsolute).join('/');
459+
path = normalizeArray(path.split('/'), !isAbsolute).join('/');
478460

479461
if (!path && !isAbsolute) {
480462
path = '.';

0 commit comments

Comments
 (0)