Browse Source

Improve path parsing on windows

Closes #650
Bert Belder 14 years ago
parent
commit
8153a21613
  1. 62
      lib/path.js
  2. 32
      test/simple/test-path.js

62
lib/path.js

@ -55,15 +55,28 @@ function normalizeArray(parts, allowAboveRoot) {
if (isWindows) { 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, // Regex to split a windows path into three parts: [*, device, slash,
// tail] windows-only // tail] windows-only
var splitDeviceRe = 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) // path.resolve([from ...], to)
// windows version // windows version
@ -245,9 +258,13 @@ if (isWindows) {
} else /* posix */ { } else /* posix */ {
// Regex to split a filename into [*, dir, basename, ext] // Split a filename into [root, dir, basename, ext], unix version
// posix version // 'root' is just a slash, or nothing.
var splitPathRe = /^([\s\S]+\/(?!$)|\/)?((?:[\s\S]+?)?(\.[^.]*)?)$/; 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) // path.resolve([from ...], to)
// posix version // posix version
@ -356,23 +373,26 @@ if (isWindows) {
exports.dirname = function(path) { exports.dirname = function(path) {
var dir = splitPathRe.exec(path)[1] || ''; var result = splitPath(path),
if (!dir) { root = result[0],
// No dirname dir = result[1];
if (!root && !dir) {
// No dirname whatsoever
return '.'; 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) { exports.basename = function(path, ext) {
var f = splitPathRe.exec(path)[2] || ''; var f = splitPath(path)[2];
// TODO: make this comparison case-insensitive on windows? // TODO: make this comparison case-insensitive on windows?
if (ext && f.substr(-1 * ext.length) === ext) { if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length); f = f.substr(0, f.length - ext.length);
@ -382,7 +402,7 @@ exports.basename = function(path, ext) {
exports.extname = function(path) { exports.extname = function(path) {
return splitPathRe.exec(path)[3] || ''; return splitPath(path)[3];
}; };

32
test/simple/test-path.js

@ -39,11 +39,43 @@ if (!isWindows) {
} }
assert.equal(path.extname(f), '.js'); assert.equal(path.extname(f), '.js');
assert.equal(path.dirname(f).substr(-11), isWindows ? 'test\\simple' : 'test/simple'); 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/b'), '/a'); assert.equal(path.dirname('/a/b'), '/a');
assert.equal(path.dirname('/a'), '/'); assert.equal(path.dirname('/a'), '/');
assert.equal(path.dirname('/'), '/'); 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) }); path.exists(f, function(y) { assert.equal(y, true) });
assert.equal(path.existsSync(f), true); assert.equal(path.existsSync(f), true);

Loading…
Cancel
Save