Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
path.join stuff
(and some minor fixing in path.resolve)
  • Loading branch information
piscisaureus committed Aug 21, 2012
1 parent 7c75ca7 commit 6e71b65
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 10 deletions.
38 changes: 29 additions & 9 deletions lib/path.js
Expand Up @@ -59,7 +59,7 @@ if (isWindows) {
// Regex to split a windows path into three parts: [*, device, slash,
// tail] windows-only
var splitDeviceRe =
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?([\s\S]*?)$/;
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;

// Regex to split the tail part of the above into [*, dir, basename, ext]
var splitTailRe =
Expand All @@ -80,6 +80,10 @@ if (isWindows) {
return [device, dir, basename, ext];
};

function normalizeUNCRoot(device) {
return '\\\\' + device.replace(/^[\\\/]+/, '').replace(/[\\\/]+/g, '\\');
}

// path.resolve([from ...], to)
// windows version
exports.resolve = function() {
Expand Down Expand Up @@ -138,8 +142,11 @@ if (isWindows) {
}
}

// Replace slashes (in UNC share name) by backslashes
resolvedDevice = resolvedDevice.replace(/\//g, '\\');
// Convert slashes to backslashes when `resolvedDevice` points to an UNC
// root. Also squash multiple slashes into a single one where appropriate.
if (isUnc) {
resolvedDevice = normalizeUNCRoot(resolvedDevice);
}

// At this point the path should be resolved to a full absolute path,
// but handle relative paths to be safe (might happen when process.cwd()
Expand Down Expand Up @@ -180,7 +187,10 @@ if (isWindows) {
}

// Convert slashes to backslashes when `device` points to an UNC root.
device = device.replace(/\//g, '\\');
// Also squash multiple slashes into a single one where appropriate.
if (isUnc) {
device = normalizeUNCRoot(device);
}

return device + (isAbsolute ? '\\' : '') + tail;
};
Expand All @@ -194,11 +204,21 @@ if (isWindows) {
var paths = Array.prototype.slice.call(arguments, 0).filter(f);
var joined = paths.join('\\');

// Make sure that the joined path doesn't start with two slashes
// - it will be mistaken for an unc path by normalize() -
// unless the paths[0] also starts with two slashes
if (/^[\\\/]{2}/.test(joined) && !/^[\\\/]{2}/.test(paths[0])) {
joined = joined.slice(1);
// Make sure that the joined path doesn't start with two slashes, because
// normalize() will mistake it for an UNC path then.
//
// This step is skipped when it is very clear that the user actually
// intended to point at an UNC path. This is assumed when the first
// non-empty string arguments starts with exactly two slashes followed by
// at least one more non-slash character.
//
// Note that for normalize() to treat a path as an UNC path it needs to
// have at least 2 components, so we don't filter for that here.
// This means that the user can use join to construct UNC paths from
// a server name and a share name; for example:
// path.join('//server', 'share') -> '\\\\server\\share\')
if (!/^[\\\/]{2}[^\\\/]/.test(paths[0])) {
joined = joined.replace(/^[\\\/]{2,}/, '\\');
}

return exports.normalize(joined);
Expand Down
66 changes: 65 additions & 1 deletion test/simple/test-path.js
Expand Up @@ -172,9 +172,67 @@ var joinTests =
[[' ', '.'], ' '],
[[' ', '/'], ' /'],
[[' ', ''], ' '],
[['/', 'foo'], '/foo'],
[['/', '/foo'], '/foo'],
[['/', '//foo'], '/foo'],
[['/', '', '/foo'], '/foo'],
[['', '/', 'foo'], '/foo'],
[['', '/', '/foo'], '/foo'],
// filtration of non-strings.
[['x', true, 7, 'y', null, {}], 'x/y']
];

// Windows-specific join tests
if (isWindows) {
joinTests = joinTests.concat(
[// UNC path expected
[['//foo/bar'], '//foo/bar/'],
[['\\/foo/bar'], '//foo/bar/'],
[['\\\\foo/bar'], '//foo/bar/'],
// UNC path expected - server and share separate
[['//foo', 'bar'], '//foo/bar/'],
[['//foo/', 'bar'], '//foo/bar/'],
[['//foo', '/bar'], '//foo/bar/'],
// UNC path expected - questionable
[['//foo', '', 'bar'], '//foo/bar/'],
[['//foo/', '', 'bar'], '//foo/bar/'],
[['//foo/', '', '/bar'], '//foo/bar/'],
// UNC path expected - even more questionable
[['', '//foo', 'bar'], '//foo/bar/'],
[['', '//foo/', 'bar'], '//foo/bar/'],
[['', '//foo/', '/bar'], '//foo/bar/'],
// No UNC path expected (no double slash in first component)
[['\\', 'foo/bar'], '/foo/bar'],
[['\\', '/foo/bar'], '/foo/bar'],
[['', '/', '/foo/bar'], '/foo/bar'],
// No UNC path expected (no non-slashes in first component - questionable)
[['//', 'foo/bar'], '/foo/bar'],
[['//', '/foo/bar'], '/foo/bar'],
[['\\\\', '/', '/foo/bar'], '/foo/bar'],
[['//'], '/'],
// No UNC path expected (share name missing - questionable).
[['//foo'], '/foo'],
[['//foo/'], '/foo/'],
[['//foo', '/'], '/foo/'],
[['//foo', '', '/'], '/foo/'],
// No UNC path expected (too many leading slashes - questionable)
[['///foo/bar'], '/foo/bar'],
[['////foo', 'bar'], '/foo/bar'],
[['\\\\\\/foo/bar'], '/foo/bar'],
// Drive-relative vs drive-absolute paths. This merely describes the
// status quo, rather than being obviously right
[['c:'], 'c:.'],
[['c:.'], 'c:.'],
[['c:', ''], 'c:.'],
[['', 'c:'], 'c:.'],
[['c:.', '/'], 'c:./'],
[['c:.', 'file'], 'c:file'],
[['c:', '/'], 'c:/'],
[['c:', 'file'], 'c:/file']
]);
}

// Run the join tests.
joinTests.forEach(function(test) {
var actual = path.join.apply(path, test[0]);
var expected = isWindows ? test[1].replace(/\//g, '\\') : test[1];
Expand Down Expand Up @@ -215,7 +273,13 @@ if (isWindows) {
[['c:/ignore', 'c:/some/file'], 'c:\\some\\file'],
[['d:/ignore', 'd:some/dir//'], 'd:\\ignore\\some\\dir'],
[['.'], process.cwd()],
[['//server/share', '..', 'relative\\'], '\\\\server\\share\\relative']];
[['//server/share', '..', 'relative\\'], '\\\\server\\share\\relative'],
[['c:/', '//'], 'c:\\'],
[['c:/', '//dir'], 'c:\\dir'],
[['c:/', '//server/share'], '\\\\server\\share\\'],
[['c:/', '//server//share'], '\\\\server\\share\\'],
[['c:/', '///some//dir'], 'c:\\some\\dir']
];
} else {
// Posix
var resolveTests =
Expand Down

2 comments on commit 6e71b65

@piscisaureus
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@isaacs I suggest landing this in master and marking #3610 WONTFIX for 0.8.

@piscisaureus
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@isaacs Did you manage to review this yet?

Please sign in to comment.