diff --git a/src/path.js b/src/path.js index ad71c61..38eeffa 100644 --- a/src/path.js +++ b/src/path.js @@ -19,18 +19,8 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -// https://github.com/joyent/node/blob/41e53e557992a7d552a8e23de035f9463da25c99/lib/path.js - -define(function(require) { - - // Split a filename into [root, dir, basename, ext], unix version - // 'root' is just a slash, or nothing. - var splitPathRe = - /^(\/?)([\s\S]+\/(?!$)|\/)?((?:\.{1,2}$|[\s\S]+?)?(\.[^.\/]*)?)$/; - var splitPath = function(filename) { - var result = splitPathRe.exec(filename); - return [result[1] || '', result[2] || '', result[3] || '', result[4] || '']; - }; +// Based on https://github.com/joyent/node/blob/41e53e557992a7d552a8e23de035f9463da25c99/lib/path.js +define(function() { // resolves . and .. elements in a path array with directory names there // must be no slashes, empty elements, or device names (c:\) in the array @@ -62,11 +52,47 @@ define(function(require) { return parts; } + // Split a filename into [root, dir, basename, ext], unix version + // 'root' is just a slash, or nothing. + var splitPathRe = + /^(\/?)([\s\S]+\/(?!$)|\/)?((?:\.{1,2}$|[\s\S]+?)?(\.[^.\/]*)?)$/; + var splitPath = function(filename) { + var result = splitPathRe.exec(filename); + return [result[1] || '', result[2] || '', result[3] || '', result[4] || '']; + }; + + // path.resolve([from ...], to) + function resolve() { + var resolvedPath = '', + resolvedAbsolute = false; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = arguments[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) || '.'; + } + // path.normalize(path) - // posix version function normalize(path) { - var isAbsolute = path.charAt(0) === '/'; - // var trailingSlash = path.substr(-1) === '/'; + var isAbsolute = path.charAt(0) === '/', + trailingSlash = path.substr(-1) === '/'; // Normalize the path path = normalizeArray(path.split('/').filter(function(p) { @@ -76,14 +102,61 @@ define(function(require) { if (!path && !isAbsolute) { path = '.'; } - /* if (path && trailingSlash) { path += '/'; } - */ return (isAbsolute ? '/' : '') + path; - }; + } + + function join() { + var paths = Array.prototype.slice.call(arguments, 0); + return normalize(paths.filter(function(p, index) { + return p && typeof p === 'string'; + }).join('/')); + } + + // path.relative(from, to) + function relative(from, to) { + from = exports.resolve(from).substr(1); + to = exports.resolve(to).substr(1); + + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + + return outputParts.join('/'); + } function dirname(path) { var result = splitPath(path), @@ -101,8 +174,7 @@ define(function(require) { } return root + dir; - }; - + } function basename(path, ext) { var f = splitPath(path)[2]; @@ -110,18 +182,26 @@ define(function(require) { if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } - return f === "" ? "/" : f; - }; - - function isAbsolute(path) { - return path.charAt(0) === '/'; + return f; } + function extname(path) { + return splitPath(path)[3]; + } + + // NOTE: we don't support path.exists() or path.existsSync(), which are deprecated, + // and need a FileSystem instance to work. Use fs.stat(). + return { normalize: normalize, + resolve: resolve, + join: join, + relative: relative, + sep: '/', + delimiter: ':', dirname: dirname, basename: basename, - isAbsolute: isAbsolute - } + extname: extname + }; -}); \ No newline at end of file +});