|
|
|
|
|
|
|
var isWindows = process.platform === 'win32';
|
|
|
|
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
for (; up--; up) {
|
|
|
|
parts.unshift('..');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return parts;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?(.*?)$/;
|
|
|
|
|
|
|
|
// path.resolve([from ...], to)
|
|
|
|
// windows version
|
|
|
|
exports.resolve = function() {
|
|
|
|
var resolvedDevice = '',
|
|
|
|
resolvedTail = '',
|
|
|
|
resolvedAbsolute = false;
|
|
|
|
|
|
|
|
for (var i = arguments.length; i >= -1; i--) {
|
|
|
|
var path = (i >= 0)
|
|
|
|
? arguments[i]
|
|
|
|
: process.cwd();
|
|
|
|
|
|
|
|
// Skip empty and invalid entries
|
|
|
|
if (typeof path !== 'string' || !path) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
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);
|
|
|
|
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, '\\');
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
function f(p) {
|
|
|
|
return !!p;
|
|
|
|
}
|
|
|
|
|
|
|
|
resolvedTail = normalizeArray(resolvedTail.split(/[\\\/]+/).filter(f),
|
|
|
|
!resolvedAbsolute).join('\\');
|
|
|
|
|
|
|
|
return (resolvedDevice + (resolvedAbsolute ? '\\' : '') + resolvedTail) ||
|
|
|
|
'.';
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// Normalize the tail path
|
|
|
|
tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) {
|
|
|
|
return !!p;
|
|
|
|
}), !isAbsolute).join('\\');
|
|
|
|
|
|
|
|
if (!tail && !isAbsolute) {
|
|
|
|
tail = '.';
|
|
|
|
}
|
|
|
|
if (tail && trailingSlash) {
|
|
|
|
tail += '\\';
|
|
|
|
}
|
|
|
|
|
|
|
|
return device + (isAbsolute ? '\\' : '') + tail;
|
|
|
|
};
|
|
|
|
|
|
|
|
// windows version
|
|
|
|
exports.join = function() {
|
|
|
|
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);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
} else /* posix */ {
|
|
|
|
|
|
|
|
// Regex to split a filename into [*, dir, basename, ext]
|
|
|
|
// posix version
|
|
|
|
var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/;
|
|
|
|
|
|
|
|
// path.resolve([from ...], to)
|
|
|
|
// posix version
|
|
|
|
exports.resolve = function() {
|
|
|
|
var resolvedPath = '',
|
|
|
|
resolvedAbsolute = false;
|
|
|
|
|
|
|
|
for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) {
|
|
|
|
var path = (i >= 0)
|
|
|
|
? arguments[i]
|
|
|
|
: process.cwd();
|
|
|
|
|
|
|
|
// 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) || '.';
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
path = '.';
|
|
|
|
}
|
|
|
|
if (path && trailingSlash) {
|
|
|
|
path += '/';
|
|
|
|
}
|
|
|
|
|
|
|
|
return (isAbsolute ? '/' : '') + path;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// posix version
|
|
|
|
exports.join = function() {
|
|
|
|
var paths = Array.prototype.slice.call(arguments, 0);
|
|
|
|
return exports.normalize(paths.filter(function(p, index) {
|
|
|
|
return p && typeof p === 'string';
|
|
|
|
}).join('/'));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
exports.dirname = function(path) {
|
|
|
|
var dir = splitPathRe.exec(path)[1] || '';
|
|
|
|
if (!dir) {
|
|
|
|
// No dirname
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
exports.basename = function(path, ext) {
|
|
|
|
var f = splitPathRe.exec(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);
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
exports.extname = function(path) {
|
|
|
|
return splitPathRe.exec(path)[3] || '';
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
exports.exists = function(path, callback) {
|
|
|
|
process.binding('fs').stat(path, function(err, stats) {
|
|
|
|
if (callback) callback(err ? false : true);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
exports.existsSync = function(path) {
|
|
|
|
try {
|
|
|
|
process.binding('fs').stat(path);
|
|
|
|
return true;
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|