From 372c208691e0fe8ea3f7a63f31b0a71c94706ade Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Tue, 6 Sep 2011 04:41:52 +0200 Subject: [PATCH] pathfix --- lib/path.js | 64 ++++++++++++++++++++++++++-------------- test/simple/test-path.js | 32 ++++++++++++++++++++ 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/lib/path.js b/lib/path.js index 1c601809633..a47a3052bd2 100644 --- a/lib/path.js +++ b/lib/path.js @@ -55,15 +55,28 @@ function normalizeArray(parts, allowAboveRoot) { if (isWindows) { - - // Regex to split a filename into [*, dir, basename, ext] - // windows version - var splitPathRe = /^(.+(?:[\\\/](?!$)|:)|[\\\/])?((?:.+?)?(\.[^.]*)?)$/; - // Regex to split a windows path into three parts: [*, device, slash, // tail] windows-only var splitDeviceRe = - /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?(.*?)$/; + /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?([\s\S]*?)$/; + + // Regex to split the tail part of the above into [*, dir, basename, ext] + var splitTailRe = /^([\s\S]+[\\\/](?!$)|[\\\/])?((?:[\s\S]+?)?(\.[^.]*)?)$/; + + // Function to split a filename into [root, dir, basename, ext] + // windows version + var splitPath = function(filename) { + // Separate device+slash from tail + var result = splitDeviceRe.exec(filename), + device = (result[1] || '') + (result[2] || ''), + tail = result[3] || ''; + // Split the tail into dir, basename and extension + var result2 = splitTailRe.exec(tail), + dir = result2[1] || '', + basename = result2[2] || '', + ext = result2[3] || ''; + return [device, dir, basename, ext]; + } // path.resolve([from ...], to) // windows version @@ -245,9 +258,13 @@ if (isWindows) { } else /* posix */ { - // Regex to split a filename into [*, dir, basename, ext] - // posix version - var splitPathRe = /^([\s\S]+\/(?!$)|\/)?((?:[\s\S]+?)?(\.[^.]*)?)$/; + // Split a filename into [root, dir, basename, ext], unix version + // 'root' is just a slash, or nothing. + var splitPathRe = /^(\/?)([\s\S]+\/(?!$)|\/)?((?:[\s\S]+?)?(\.[^.]*)?)$/; + var splitPath = function(filename) { + var result = splitPathRe.exec(filename); + return [result[1] || '', result[2] || '', result[3] || '', result[4] || '']; + }; // path.resolve([from ...], to) // posix version @@ -356,23 +373,26 @@ if (isWindows) { exports.dirname = function(path) { - var dir = splitPathRe.exec(path)[1] || ''; - if (!dir) { - // No dirname + var result = splitPath(path), + root = result[0], + dir = result[1]; + + if (!root && !dir) { + // No dirname whatsoever return '.'; - } else if (dir.length === 1 || - (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) { - // It is just a slash or a drive letter with a slash - return dir; - } else { - // It is a full dirname, strip trailing slash - return dir.substring(0, dir.length - 1); } + + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.substring(0, dir.length - 1); + } + + return root + dir; }; exports.basename = function(path, ext) { - var f = splitPathRe.exec(path)[2] || ''; + var f = splitPath(path)[2]; // TODO: make this comparison case-insensitive on windows? if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); @@ -381,8 +401,8 @@ exports.basename = function(path, ext) { }; -exports.extname = function(path) { - return splitPathRe.exec(path)[3] || ''; +exports.extname = function (path) { + return splitPath(path)[3]; }; diff --git a/test/simple/test-path.js b/test/simple/test-path.js index 3d72ad733e7..7fe80ecd538 100644 --- a/test/simple/test-path.js +++ b/test/simple/test-path.js @@ -39,11 +39,43 @@ if (!isWindows) { } assert.equal(path.extname(f), '.js'); + assert.equal(path.dirname(f).substr(-11), isWindows ? 'test\\simple' : 'test/simple'); assert.equal(path.dirname('/a/b/'), '/a'); assert.equal(path.dirname('/a/b'), '/a'); assert.equal(path.dirname('/a'), '/'); assert.equal(path.dirname('/'), '/'); + +if (isWindows) { + assert.equal(path.dirname('c:\\'), 'c:\\'); + assert.equal(path.dirname('c:\\foo'), 'c:\\'); + assert.equal(path.dirname('c:\\foo\\'), 'c:\\'); + assert.equal(path.dirname('c:\\foo\\bar'), 'c:\\foo'); + assert.equal(path.dirname('c:\\foo\\bar\\'), 'c:\\foo'); + assert.equal(path.dirname('c:\\foo\\bar\\baz'), 'c:\\foo\\bar'); + assert.equal(path.dirname('\\'), '\\'); + assert.equal(path.dirname('\\foo'), '\\'); + assert.equal(path.dirname('\\foo\\'), '\\'); + assert.equal(path.dirname('\\foo\\bar'), '\\foo'); + assert.equal(path.dirname('\\foo\\bar\\'), '\\foo'); + assert.equal(path.dirname('\\foo\\bar\\baz'), '\\foo\\bar'); + assert.equal(path.dirname('c:'), 'c:'); + assert.equal(path.dirname('c:foo'), 'c:'); + assert.equal(path.dirname('c:foo\\'), 'c:'); + assert.equal(path.dirname('c:foo\\bar'), 'c:foo'); + assert.equal(path.dirname('c:foo\\bar\\'), 'c:foo'); + assert.equal(path.dirname('c:foo\\bar\\baz'), 'c:foo\\bar'); + assert.equal(path.dirname('\\\\unc\\share'), '\\\\unc\\share'); + assert.equal(path.dirname('\\\\unc\\share\\foo'), '\\\\unc\\share\\'); + assert.equal(path.dirname('\\\\unc\\share\\foo\\'), '\\\\unc\\share\\'); + assert.equal(path.dirname('\\\\unc\\share\\foo\\bar'), + '\\\\unc\\share\\foo'); + assert.equal(path.dirname('\\\\unc\\share\\foo\\bar\\'), + '\\\\unc\\share\\foo'); + assert.equal(path.dirname('\\\\unc\\share\\foo\\bar\\baz'), + '\\\\unc\\share\\foo\\bar'); +} + path.exists(f, function(y) { assert.equal(y, true) }); assert.equal(path.existsSync(f), true);