| /*! |
| * extglob <https://github.com/jonschlinkert/extglob> |
| * |
| * Copyright (c) 2015, Jon Schlinkert. |
| * Licensed under the MIT License. |
| */ |
| |
| 'use strict'; |
| |
| /** |
| * Module dependencies |
| */ |
| |
| var isExtglob = require('is-extglob'); |
| var re, cache = {}; |
| |
| /** |
| * Expose `extglob` |
| */ |
| |
| module.exports = extglob; |
| |
| /** |
| * Convert the given extglob `string` to a regex-compatible |
| * string. |
| * |
| * ```js |
| * var extglob = require('extglob'); |
| * extglob('!(a?(b))'); |
| * //=> '(?!a(?:b)?)[^/]*?' |
| * ``` |
| * |
| * @param {String} `str` The string to convert. |
| * @param {Object} `options` |
| * @option {Boolean} [options] `esc` If `false` special characters will not be escaped. Defaults to `true`. |
| * @option {Boolean} [options] `regex` If `true` a regular expression is returned instead of a string. |
| * @return {String} |
| * @api public |
| */ |
| |
| |
| function extglob(str, opts) { |
| opts = opts || {}; |
| var o = {}, i = 0; |
| |
| // fix common character reversals |
| // '*!(.js)' => '*.!(js)' |
| str = str.replace(/!\(([^\w*()])/g, '$1!('); |
| |
| // support file extension negation |
| str = str.replace(/([*\/])\.!\([*]\)/g, function (m, ch) { |
| if (ch === '/') { |
| return escape('\\/[^.]+'); |
| } |
| return escape('[^.]+'); |
| }); |
| |
| // create a unique key for caching by |
| // combining the string and options |
| var key = str |
| + String(!!opts.regex) |
| + String(!!opts.contains) |
| + String(!!opts.escape); |
| |
| if (cache.hasOwnProperty(key)) { |
| return cache[key]; |
| } |
| |
| if (!(re instanceof RegExp)) { |
| re = regex(); |
| } |
| |
| opts.negate = false; |
| var m; |
| |
| while (m = re.exec(str)) { |
| var prefix = m[1]; |
| var inner = m[3]; |
| if (prefix === '!') { |
| opts.negate = true; |
| } |
| |
| var id = '__EXTGLOB_' + (i++) + '__'; |
| // use the prefix of the _last_ (outtermost) pattern |
| o[id] = wrap(inner, prefix, opts.escape); |
| str = str.split(m[0]).join(id); |
| } |
| |
| var keys = Object.keys(o); |
| var len = keys.length; |
| |
| // we have to loop again to allow us to convert |
| // patterns in reverse order (starting with the |
| // innermost/last pattern first) |
| while (len--) { |
| var prop = keys[len]; |
| str = str.split(prop).join(o[prop]); |
| } |
| |
| var result = opts.regex |
| ? toRegex(str, opts.contains, opts.negate) |
| : str; |
| |
| result = result.split('.').join('\\.'); |
| |
| // cache the result and return it |
| return (cache[key] = result); |
| } |
| |
| /** |
| * Convert `string` to a regex string. |
| * |
| * @param {String} `str` |
| * @param {String} `prefix` Character that determines how to wrap the string. |
| * @param {Boolean} `esc` If `false` special characters will not be escaped. Defaults to `true`. |
| * @return {String} |
| */ |
| |
| function wrap(inner, prefix, esc) { |
| if (esc) inner = escape(inner); |
| |
| switch (prefix) { |
| case '!': |
| return '(?!' + inner + ')[^/]' + (esc ? '%%%~' : '*?'); |
| case '@': |
| return '(?:' + inner + ')'; |
| case '+': |
| return '(?:' + inner + ')+'; |
| case '*': |
| return '(?:' + inner + ')' + (esc ? '%%' : '*') |
| case '?': |
| return '(?:' + inner + '|)'; |
| default: |
| return inner; |
| } |
| } |
| |
| function escape(str) { |
| str = str.split('*').join('[^/]%%%~'); |
| str = str.split('.').join('\\.'); |
| return str; |
| } |
| |
| /** |
| * extglob regex. |
| */ |
| |
| function regex() { |
| return /(\\?[@?!+*$]\\?)(\(([^()]*?)\))/; |
| } |
| |
| /** |
| * Negation regex |
| */ |
| |
| function negate(str) { |
| return '(?!^' + str + ').*$'; |
| } |
| |
| /** |
| * Create the regex to do the matching. If |
| * the leading character in the `pattern` is `!` |
| * a negation regex is returned. |
| * |
| * @param {String} `pattern` |
| * @param {Boolean} `contains` Allow loose matching. |
| * @param {Boolean} `isNegated` True if the pattern is a negation pattern. |
| */ |
| |
| function toRegex(pattern, contains, isNegated) { |
| var prefix = contains ? '^' : ''; |
| var after = contains ? '$' : ''; |
| pattern = ('(?:' + pattern + ')' + after); |
| if (isNegated) { |
| pattern = prefix + negate(pattern); |
| } |
| return new RegExp(prefix + pattern); |
| } |