0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
nodejs/lib/path.js

286 lines
7.6 KiB
JavaScript
Raw Normal View History

var isWindows = process.platform === 'win32';
2011-01-07 01:06:27 +01:00
// resolves . and .. elements in a path array with directory names there
// must be no slashes, empty elements, or device names (c:\) in the array
// (so also no leading and trailing slashes - it does not distinguish
// relative and absolute paths)
function normalizeArray(parts, allowAboveRoot) {
// if the path tries to go above the root, `up` ends up > 0
var up = 0;
for (var i = parts.length; i >= 0; i--) {
var last = parts[i];
if (last == '.') {
parts.splice(i, 1);
} else if (last === '..') {
parts.splice(i, 1);
up++;
} else if (up) {
parts.splice(i, 1);
up--;
}
}
// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {
2011-01-07 01:06:27 +01:00
for (; up--; up) {
parts.unshift('..');
}
}
return parts;
}
2010-11-21 23:13:54 +01:00
if (isWindows) {
2010-11-21 23:13:54 +01:00
// Regex to split a filename into [*, dir, basename, ext]
// windows version
var splitPathRe = /^(.+(?:[\\\/](?!$)|:)|[\\\/])?((?:.+?)?(\.[^.]*)?)$/;
2010-11-21 23:13:54 +01:00
2011-01-07 01:06:27 +01:00
// Regex to split a windows path into three parts: [*, device, slash,
// tail] windows-only
var splitDeviceRe =
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?(.*?)$/;
2010-11-21 23:13:54 +01:00
// path.resolve([from ...], to)
// windows version
exports.resolve = function() {
// Prepend cwd to provided paths
2011-01-07 01:06:27 +01:00
var paths = [process.cwd()].concat(
Array.prototype.slice.call(arguments, 0));
2010-11-21 23:13:54 +01:00
2011-01-07 01:06:27 +01:00
var resolvedDevice = '',
resolvedTail = '',
resolvedAbsolute = false;
2010-11-21 23:13:54 +01:00
for (var i = paths.length; i >= 0; i--) {
var path = paths[i];
2010-11-21 23:13:54 +01:00
// Skip empty and invalid entries
if (typeof path !== 'string' || !path) {
continue;
}
2010-11-21 23:13:54 +01:00
var result = splitDeviceRe.exec(path),
device = result[1] || '',
isUnc = device && device.charAt(1) !== ':',
isAbsolute = !!result[2] || isUnc, // UNC paths are always absolute
tail = result[3];
2011-01-07 01:06:27 +01:00
if (device &&
resolvedDevice &&
device.toLowerCase() !== resolvedDevice.toLowerCase()) {
// This path points to another device so it is not applicable
continue;
}
if (!resolvedDevice) {
resolvedDevice = device;
}
if (!resolvedAbsolute) {
resolvedTail = tail + '\\' + resolvedTail;
resolvedAbsolute = isAbsolute;
}
if (resolvedDevice && resolvedAbsolute) {
break;
}
}
if (!resolvedAbsolute && resolvedDevice) {
// If we still don't have an absolute path,
// prepend the current path for the device found.
// TODO
// Windows stores the current directories for 'other' drives
// as hidden environment variables like =C:=c:\windows (literally)
// var deviceCwd = os.getCwdForDrive(resolvedDevice);
2011-01-07 01:06:27 +01:00
var deviceCwd = '';
// If there is no cwd set for the drive, it is at root
resolvedTail = deviceCwd + '\\' + resolvedTail;
resolvedAbsolute = true;
}
// Replace slashes (in UNC share name) by backslashes
resolvedDevice = resolvedDevice.replace(/\//g, '\\');
2011-01-07 01:06:27 +01:00
// 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()
// fails)
// Normalize the tail path
2011-01-07 01:06:27 +01:00
function f(p) {
return !!p;
2011-01-07 01:06:27 +01:00
}
2011-01-07 01:06:27 +01:00
resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/).filter(f),
!resolvedAbsolute).join('\\');
return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) ||
'.';
};
2010-11-21 23:13:54 +01:00
// windows version
exports.normalize = function(path) {
var result = splitDeviceRe.exec(path),
device = result[1] || '',
isUnc = device && device.charAt(1) !== ':',
isAbsolute = !!result[2] || isUnc, // UNC paths are always absolute
tail = result[3],
trailingSlash = /[\\\/]$/.test(tail);
2010-11-21 23:13:54 +01:00
// Normalize the tail path
tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) {
return !!p;
}), !isAbsolute).join('\\');
2010-11-21 23:13:54 +01:00
if (!tail && !isAbsolute) {
2011-01-07 01:06:27 +01:00
tail = '.';
}
if (tail && trailingSlash) {
2011-01-07 01:06:27 +01:00
tail += '\\';
2010-04-21 03:17:54 +02:00
}
return device + (isAbsolute ? '\\' : '') + tail;
2011-01-07 01:06:27 +01:00
};
// windows version
exports.join = function() {
2011-01-07 01:06:27 +01:00
function f(p) {
return p && typeof p === 'string';
}
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);
}
return exports.normalize(joined);
2011-01-07 01:06:27 +01:00
};
} else /* posix */ {
// Regex to split a filename into [*, dir, basename, ext]
// posix version
var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/;
// path.resolve([from ...], to)
// posix version
exports.resolve = function() {
// Prepend cwd to provided paths
2011-01-07 01:06:27 +01:00
var paths = [process.cwd()].concat(
Array.prototype.slice.call(arguments, 0));
2011-01-07 01:06:27 +01:00
var resolvedPath = '',
resolvedAbsolute = false;
for (var i = paths.length; i >= 0 && !resolvedAbsolute; i--) {
var path = paths[i];
// Skip empty and invalid entries
if (typeof path !== 'string' || !path) {
continue;
}
resolvedPath = path + '/' + resolvedPath;
resolvedAbsolute = path.charAt(0) === '/';
}
// 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() fails)
// Normalize the path
resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) {
return !!p;
}), !resolvedAbsolute).join('/');
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
2011-01-07 01:06:27 +01:00
};
// path.normalize(path)
// posix version
exports.normalize = function(path) {
var isAbsolute = path.charAt(0) === '/',
trailingSlash = path.slice(-1) === '/';
// Normalize the path
path = normalizeArray(path.split('/').filter(function(p) {
return !!p;
}), !isAbsolute).join('/');
if (!path && !isAbsolute) {
2011-01-07 01:06:27 +01:00
path = '.';
}
if (path && trailingSlash) {
path += '/';
}
return (isAbsolute ? '/' : '') + path;
2011-01-07 01:06:27 +01:00
};
2010-04-21 03:17:54 +02:00
2010-11-21 23:13:54 +01:00
// posix version
exports.join = function() {
var paths = Array.prototype.slice.call(arguments, 0);
return exports.normalize(paths.filter(function(p, index) {
2011-01-07 01:06:27 +01:00
return p && typeof p === 'string';
}).join('/'));
2011-01-07 01:06:27 +01:00
};
}
2010-04-21 03:17:54 +02:00
2010-11-21 23:13:54 +01:00
2010-12-02 03:07:20 +01:00
exports.dirname = function(path) {
var dir = splitPathRe.exec(path)[1] || '';
if (!dir) {
// No dirname
2011-01-07 01:06:27 +01:00
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);
}
2010-04-21 03:17:54 +02:00
};
2010-11-21 23:13:54 +01:00
2010-12-02 03:07:20 +01:00
exports.basename = function(path, ext) {
var f = splitPathRe.exec(path)[2] || '';
// TODO: make this comparison case-insensitive on windows?
2010-04-21 03:17:54 +02:00
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
return f;
};
2010-11-21 23:13:54 +01:00
2010-12-02 03:07:20 +01:00
exports.extname = function(path) {
return splitPathRe.exec(path)[3] || '';
2010-04-21 03:17:54 +02:00
};
2010-11-21 23:13:54 +01:00
2010-12-02 03:07:20 +01:00
exports.exists = function(path, callback) {
process.binding('fs').stat(path, function(err, stats) {
2010-04-21 03:17:54 +02:00
if (callback) callback(err ? false : true);
});
};
2010-06-16 15:51:19 +02:00
2010-11-21 23:13:54 +01:00
2010-12-02 03:07:20 +01:00
exports.existsSync = function(path) {
2010-06-16 15:51:19 +02:00
try {
2010-10-07 05:05:23 +02:00
process.binding('fs').stat(path);
2010-06-16 15:51:19 +02:00
return true;
2010-12-02 03:07:20 +01:00
} catch (e) {
2010-06-16 15:51:19 +02:00
return false;
}
};