| /* |
| Copyright 2012-2015, Yahoo Inc. |
| Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. |
| */ |
| 'use strict'; |
| |
| var path = require('path'), |
| parsePath = path.parse, |
| SEP = path.sep || /* istanbul ignore next */ '/', |
| origParser = parsePath, |
| origSep = SEP; |
| |
| function makeRelativeNormalizedPath(str, sep) { |
| var parsed = parsePath(str), |
| root = parsed.root, |
| dir, |
| file = parsed.base, |
| quoted, |
| pos; |
| |
| // handle a weird windows case separately |
| if (sep === '\\') { |
| pos = root.indexOf(':\\'); |
| if (pos >= 0) { |
| root = root.substring(0, pos + 2); |
| } |
| } |
| dir = parsed.dir.substring(root.length); |
| |
| if (str === '') { |
| return []; |
| } |
| |
| if (sep !== '/') { |
| quoted = new RegExp(sep.replace(/\W/g, '\\$&'), 'g'); |
| dir = dir.replace(quoted, '/'); |
| file = file.replace(quoted, '/'); // excessively paranoid? |
| } |
| |
| if (dir !== '') { |
| dir = dir + '/' + file; |
| } else { |
| dir = file; |
| } |
| if (dir.substring(0, 1) === '/') { |
| dir = dir.substring(1); |
| } |
| dir = dir.split(/\/+/); |
| return dir; |
| } |
| |
| function Path(strOrArray) { |
| if (Array.isArray(strOrArray)) { |
| this.v = strOrArray; |
| } else if (typeof strOrArray === 'string') { |
| this.v = makeRelativeNormalizedPath(strOrArray, SEP); |
| } else { |
| throw new Error( |
| 'Invalid Path argument must be string or array:' + strOrArray |
| ); |
| } |
| } |
| |
| Path.prototype.toString = function() { |
| return this.v.join('/'); |
| }; |
| |
| Path.prototype.hasParent = function() { |
| return this.v.length > 0; |
| }; |
| |
| Path.prototype.parent = function() { |
| if (!this.hasParent()) { |
| throw new Error('Unable to get parent for 0 elem path'); |
| } |
| var p = this.v.slice(); |
| p.pop(); |
| return new Path(p); |
| }; |
| |
| Path.prototype.elements = function() { |
| return this.v.slice(); |
| }; |
| |
| Path.prototype.contains = function(other) { |
| var i; |
| if (other.length > this.length) { |
| return false; |
| } |
| for (i = 0; i < other.length; i += 1) { |
| if (this.v[i] !== other.v[i]) { |
| return false; |
| } |
| } |
| return true; |
| }; |
| |
| Path.prototype.ancestorOf = function(other) { |
| return other.contains(this) && other.length !== this.length; |
| }; |
| |
| Path.prototype.descendantOf = function(other) { |
| return this.contains(other) && other.length !== this.length; |
| }; |
| |
| Path.prototype.commonPrefixPath = function(other) { |
| var len = this.length > other.length ? other.length : this.length, |
| i, |
| ret = []; |
| |
| for (i = 0; i < len; i += 1) { |
| if (this.v[i] === other.v[i]) { |
| ret.push(this.v[i]); |
| } else { |
| break; |
| } |
| } |
| return new Path(ret); |
| }; |
| |
| ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(function(f) { |
| Path.prototype[f] = function() { |
| var args = Array.prototype.slice.call(arguments), |
| v = this.v; |
| return v[f].apply(v, args); |
| }; |
| }); |
| |
| Path.compare = function(a, b) { |
| var al = a.length, |
| bl = b.length, |
| astr, |
| bstr; |
| if (al < bl) { |
| return -1; |
| } |
| if (al > bl) { |
| return 1; |
| } |
| astr = a.toString(); |
| bstr = b.toString(); |
| return astr < bstr ? -1 : astr > bstr ? 1 : 0; |
| }; |
| |
| Object.defineProperty(Path.prototype, 'length', { |
| enumerable: true, |
| get: function() { |
| return this.v.length; |
| } |
| }); |
| |
| module.exports = Path; |
| Path.tester = { |
| setParserAndSep: function(p, sep) { |
| parsePath = p; |
| SEP = sep; |
| }, |
| reset: function() { |
| parsePath = origParser; |
| SEP = origSep; |
| } |
| }; |