|
|
'use strict';
var utils = module.exports; var path = require('path');
/** * Module dependencies */
var isWindows = require('is-windows')(); var Snapdragon = require('snapdragon'); utils.define = require('define-property'); utils.diff = require('arr-diff'); utils.extend = require('extend-shallow'); utils.pick = require('object.pick'); utils.typeOf = require('kind-of'); utils.unique = require('array-unique');
/** * Returns true if the given value is effectively an empty string */
utils.isEmptyString = function(val) { return String(val) === '' || String(val) === './'; };
/** * Returns true if the platform is windows, or `path.sep` is `\\`. * This is defined as a function to allow `path.sep` to be set in unit tests, * or by the user, if there is a reason to do so. * @return {Boolean} */
utils.isWindows = function() { return path.sep === '\\' || isWindows === true; };
/** * Return the last element from an array */
utils.last = function(arr, n) { return arr[arr.length - (n || 1)]; };
/** * Get the `Snapdragon` instance to use */
utils.instantiate = function(ast, options) { var snapdragon; // if an instance was created by `.parse`, use that instance
if (utils.typeOf(ast) === 'object' && ast.snapdragon) { snapdragon = ast.snapdragon; // if the user supplies an instance on options, use that instance
} else if (utils.typeOf(options) === 'object' && options.snapdragon) { snapdragon = options.snapdragon; // create a new instance
} else { snapdragon = new Snapdragon(options); }
utils.define(snapdragon, 'parse', function(str, options) { var parsed = Snapdragon.prototype.parse.call(this, str, options); parsed.input = str;
// escape unmatched brace/bracket/parens
var last = this.parser.stack.pop(); if (last && this.options.strictErrors !== true) { var open = last.nodes[0]; var inner = last.nodes[1]; if (last.type === 'bracket') { if (inner.val.charAt(0) === '[') { inner.val = '\\' + inner.val; }
} else { open.val = '\\' + open.val; var sibling = open.parent.nodes[1]; if (sibling.type === 'star') { sibling.loose = true; } } }
// add non-enumerable parser reference
utils.define(parsed, 'parser', this.parser); return parsed; });
return snapdragon; };
/** * Create the key to use for memoization. The key is generated * by iterating over the options and concatenating key-value pairs * to the pattern string. */
utils.createKey = function(pattern, options) { if (typeof options === 'undefined') { return pattern; } var key = pattern; for (var prop in options) { if (options.hasOwnProperty(prop)) { key += ';' + prop + '=' + String(options[prop]); } } return key; };
/** * Cast `val` to an array * @return {Array} */
utils.arrayify = function(val) { if (typeof val === 'string') return [val]; return val ? (Array.isArray(val) ? val : [val]) : []; };
/** * Return true if `val` is a non-empty string */
utils.isString = function(val) { return typeof val === 'string'; };
/** * Return true if `val` is a non-empty string */
utils.isRegex = function(val) { return utils.typeOf(val) === 'regexp'; };
/** * Return true if `val` is a non-empty string */
utils.isObject = function(val) { return utils.typeOf(val) === 'object'; };
/** * Escape regex characters in the given string */
utils.escapeRegex = function(str) { return str.replace(/[-[\]{}()^$|*+?.\\/\s]/g, '\\$&'); };
/** * Combines duplicate characters in the provided `input` string. * @param {String} `input` * @returns {String} */
utils.combineDupes = function(input, patterns) { patterns = utils.arrayify(patterns).join('|').split('|'); patterns = patterns.map(function(s) { return s.replace(/\\?([+*\\/])/g, '\\$1'); }); var substr = patterns.join('|'); var regex = new RegExp('(' + substr + ')(?=\\1)', 'g'); return input.replace(regex, ''); };
/** * Returns true if the given `str` has special characters */
utils.hasSpecialChars = function(str) { return /(?:(?:(^|\/)[!.])|[*?+()|[\]{}]|[+@]\()/.test(str); };
/** * Normalize slashes in the given filepath. * * @param {String} `filepath` * @return {String} */
utils.toPosixPath = function(str) { return str.replace(/\\+/g, '/'); };
/** * Strip backslashes before special characters in a string. * * @param {String} `str` * @return {String} */
utils.unescape = function(str) { return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); };
/** * Strip the drive letter from a windows filepath * @param {String} `fp` * @return {String} */
utils.stripDrive = function(fp) { return utils.isWindows() ? fp.replace(/^[a-z]:[\\/]+?/i, '/') : fp; };
/** * Strip the prefix from a filepath * @param {String} `fp` * @return {String} */
utils.stripPrefix = function(str) { if (str.charAt(0) === '.' && (str.charAt(1) === '/' || str.charAt(1) === '\\')) { return str.slice(2); } return str; };
/** * Returns true if `str` is a common character that doesn't need * to be processed to be used for matching. * @param {String} `str` * @return {Boolean} */
utils.isSimpleChar = function(str) { return str.trim() === '' || str === '.'; };
/** * Returns true if the given str is an escaped or * unescaped path character */
utils.isSlash = function(str) { return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; };
/** * Returns a function that returns true if the given * pattern matches or contains a `filepath` * * @param {String} `pattern` * @return {Function} */
utils.matchPath = function(pattern, options) { return (options && options.contains) ? utils.containsPattern(pattern, options) : utils.equalsPattern(pattern, options); };
/** * Returns true if the given (original) filepath or unixified path are equal * to the given pattern. */
utils._equals = function(filepath, unixPath, pattern) { return pattern === filepath || pattern === unixPath; };
/** * Returns true if the given (original) filepath or unixified path contain * the given pattern. */
utils._contains = function(filepath, unixPath, pattern) { return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; };
/** * Returns a function that returns true if the given * pattern is the same as a given `filepath` * * @param {String} `pattern` * @return {Function} */
utils.equalsPattern = function(pattern, options) { var unixify = utils.unixify(options); options = options || {};
return function fn(filepath) { var equal = utils._equals(filepath, unixify(filepath), pattern); if (equal === true || options.nocase !== true) { return equal; } var lower = filepath.toLowerCase(); return utils._equals(lower, unixify(lower), pattern); }; };
/** * Returns a function that returns true if the given * pattern contains a `filepath` * * @param {String} `pattern` * @return {Function} */
utils.containsPattern = function(pattern, options) { var unixify = utils.unixify(options); options = options || {};
return function(filepath) { var contains = utils._contains(filepath, unixify(filepath), pattern); if (contains === true || options.nocase !== true) { return contains; } var lower = filepath.toLowerCase(); return utils._contains(lower, unixify(lower), pattern); }; };
/** * Returns a function that returns true if the given * regex matches the `filename` of a file path. * * @param {RegExp} `re` Matching regex * @return {Function} */
utils.matchBasename = function(re) { return function(filepath) { return re.test(filepath) || re.test(path.basename(filepath)); }; };
/** * Returns the given value unchanced. * @return {any} */
utils.identity = function(val) { return val; };
/** * Determines the filepath to return based on the provided options. * @return {any} */
utils.value = function(str, unixify, options) { if (options && options.unixify === false) { return str; } if (options && typeof options.unixify === 'function') { return options.unixify(str); } return unixify(str); };
/** * Returns a function that normalizes slashes in a string to forward * slashes, strips `./` from beginning of paths, and optionally unescapes * special characters. * @return {Function} */
utils.unixify = function(options) { var opts = options || {}; return function(filepath) { if (opts.stripPrefix !== false) { filepath = utils.stripPrefix(filepath); } if (opts.unescape === true) { filepath = utils.unescape(filepath); } if (opts.unixify === true || utils.isWindows()) { filepath = utils.toPosixPath(filepath); } return filepath; }; };
|