diff options
Diffstat (limited to 'node_modules/braces/index.js')
-rw-r--r-- | node_modules/braces/index.js | 545 |
1 files changed, 232 insertions, 313 deletions
diff --git a/node_modules/braces/index.js b/node_modules/braces/index.js index 3b4c58d7a..048e1c233 100644 --- a/node_modules/braces/index.js +++ b/node_modules/braces/index.js @@ -1,399 +1,318 @@ -/*! - * braces <https://github.com/jonschlinkert/braces> - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT license. - */ - 'use strict'; /** * Module dependencies */ -var expand = require('expand-range'); -var repeat = require('repeat-element'); -var tokens = require('preserve'); +var toRegex = require('to-regex'); +var unique = require('array-unique'); +var extend = require('extend-shallow'); /** - * Expose `braces` + * Local dependencies */ -module.exports = function(str, options) { - if (typeof str !== 'string') { - throw new Error('braces expects a string'); - } - return braces(str, options); -}; +var compilers = require('./lib/compilers'); +var parsers = require('./lib/parsers'); +var Braces = require('./lib/braces'); +var utils = require('./lib/utils'); +var MAX_LENGTH = 1024 * 64; +var cache = {}; /** - * Expand `{foo,bar}` or `{1..5}` braces in the - * given `string`. + * Convert the given `braces` pattern into a regex-compatible string. By default, only one string is generated for every input string. Set `options.expand` to true to return an array of patterns (similar to Bash or minimatch. Before using `options.expand`, it's recommended that you read the [performance notes](#performance)). * - * @param {String} `str` - * @param {Array} `arr` - * @param {Object} `options` - * @return {Array} + * ```js + * var braces = require('braces'); + * console.log(braces('{a,b,c}')); + * //=> ['(a|b|c)'] + * + * console.log(braces('{a,b,c}', {expand: true})); + * //=> ['a', 'b', 'c'] + * ``` + * @param {String} `str` + * @param {Object} `options` + * @return {String} + * @api public */ -function braces(str, arr, options) { - if (str === '') { - return []; - } - - if (!Array.isArray(arr)) { - options = arr; - arr = []; - } - - var opts = options || {}; - arr = arr || []; - - if (typeof opts.nodupes === 'undefined') { - opts.nodupes = true; - } - - var fn = opts.fn; - var es6; - - if (typeof opts === 'function') { - fn = opts; - opts = {}; - } - - if (!(patternRe instanceof RegExp)) { - patternRe = patternRegex(); - } - - var matches = str.match(patternRe) || []; - var m = matches[0]; - - switch(m) { - case '\\,': - return escapeCommas(str, arr, opts); - case '\\.': - return escapeDots(str, arr, opts); - case '\/.': - return escapePaths(str, arr, opts); - case ' ': - return splitWhitespace(str); - case '{,}': - return exponential(str, opts, braces); - case '{}': - return emptyBraces(str, arr, opts); - case '\\{': - case '\\}': - return escapeBraces(str, arr, opts); - case '${': - if (!/\{[^{]+\{/.test(str)) { - return arr.concat(str); - } else { - es6 = true; - str = tokens.before(str, es6Regex()); - } - } - - if (!(braceRe instanceof RegExp)) { - braceRe = braceRegex(); - } +function braces(pattern, options) { + var key = utils.createKey(String(pattern), options); + var arr = []; - var match = braceRe.exec(str); - if (match == null) { - return [str]; + var disabled = options && options.cache === false; + if (!disabled && cache.hasOwnProperty(key)) { + return cache[key]; } - var outter = match[1]; - var inner = match[2]; - if (inner === '') { return [str]; } - - var segs, segsLength; - - if (inner.indexOf('..') !== -1) { - segs = expand(inner, opts, fn) || inner.split(','); - segsLength = segs.length; - - } else if (inner[0] === '"' || inner[0] === '\'') { - return arr.concat(str.split(/['"]/).join('')); - - } else { - segs = inner.split(','); - if (opts.makeRe) { - return braces(str.replace(outter, wrap(segs, '|')), opts); - } - - segsLength = segs.length; - if (segsLength === 1 && opts.bash) { - segs[0] = wrap(segs[0], '\\'); + if (Array.isArray(pattern)) { + for (var i = 0; i < pattern.length; i++) { + arr.push.apply(arr, braces.create(pattern[i], options)); } + } else { + arr = braces.create(pattern, options); } - var len = segs.length; - var i = 0, val; - - while (len--) { - var path = segs[i++]; - - if (/(\.[^.\/])/.test(path)) { - if (segsLength > 1) { - return segs; - } else { - return [str]; - } - } - - val = splice(str, outter, path); - - if (/\{[^{}]+?\}/.test(val)) { - arr = braces(val, arr, opts); - } else if (val !== '') { - if (opts.nodupes && arr.indexOf(val) !== -1) { continue; } - arr.push(es6 ? tokens.after(val) : val); - } + if (options && options.nodupes === true) { + arr = unique(arr); } - if (opts.strict) { return filter(arr, filterEmpty); } + if (!disabled) { + cache[key] = arr; + } return arr; } /** - * Expand exponential ranges + * Expands a brace pattern into an array. This method is called by the main [braces](#braces) function when `options.expand` is true. Before using this method it's recommended that you read the [performance notes](#performance)) and advantages of using [.optimize](#optimize) instead. * - * `a{,}{,}` => ['a', 'a', 'a', 'a'] + * ```js + * var braces = require('braces'); + * console.log(braces.expand('a/{b,c}/d')); + * //=> ['a/b/d', 'a/c/d']; + * ``` + * @param {String} `pattern` Brace pattern + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public */ -function exponential(str, options, fn) { - if (typeof options === 'function') { - fn = options; - options = null; - } - - var opts = options || {}; - var esc = '__ESC_EXP__'; - var exp = 0; - var res; - - var parts = str.split('{,}'); - if (opts.nodupes) { - return fn(parts.join(''), opts); - } - - exp = parts.length - 1; - res = fn(parts.join(esc), opts); - var len = res.length; - var arr = []; - var i = 0; - - while (len--) { - var ele = res[i++]; - var idx = ele.indexOf(esc); - - if (idx === -1) { - arr.push(ele); - - } else { - ele = ele.split('__ESC_EXP__').join(''); - if (!!ele && opts.nodupes !== false) { - arr.push(ele); - - } else { - var num = Math.pow(2, exp); - arr.push.apply(arr, repeat(ele, num)); - } - } - } - return arr; -} +braces.expand = function(pattern, options) { + return braces.create(pattern, extend({}, options, {expand: true})); +}; /** - * Wrap a value with parens, brackets or braces, - * based on the given character/separator. + * Expands a brace pattern into a regex-compatible, optimized string. This method is called by the main [braces](#braces) function by default. * - * @param {String|Array} `val` - * @param {String} `ch` - * @return {String} + * ```js + * var braces = require('braces'); + * console.log(braces.expand('a/{b,c}/d')); + * //=> ['a/(b|c)/d'] + * ``` + * @param {String} `pattern` Brace pattern + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public */ -function wrap(val, ch) { - if (ch === '|') { - return '(' + val.join(ch) + ')'; - } - if (ch === ',') { - return '{' + val.join(ch) + '}'; - } - if (ch === '-') { - return '[' + val.join(ch) + ']'; - } - if (ch === '\\') { - return '\\{' + val + '\\}'; - } -} +braces.optimize = function(pattern, options) { + return braces.create(pattern, options); +}; /** - * Handle empty braces: `{}` + * Processes a brace pattern and returns either an expanded array (if `options.expand` is true), a highly optimized regex-compatible string. This method is called by the main [braces](#braces) function. + * + * ```js + * var braces = require('braces'); + * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}')) + * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)' + * ``` + * @param {String} `pattern` Brace pattern + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public */ -function emptyBraces(str, arr, opts) { - return braces(str.split('{}').join('\\{\\}'), arr, opts); -} +braces.create = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); + } -/** - * Filter out empty-ish values - */ + var maxLength = (options && options.maxLength) || MAX_LENGTH; + if (pattern.length >= maxLength) { + throw new Error('expected pattern to be less than ' + maxLength + ' characters'); + } -function filterEmpty(ele) { - return !!ele && ele !== '\\'; -} + function create() { + if (pattern === '' || pattern.length < 3) { + return [pattern]; + } -/** - * Handle patterns with whitespace - */ + if (utils.isEmptySets(pattern)) { + return []; + } -function splitWhitespace(str) { - var segs = str.split(' '); - var len = segs.length; - var res = []; - var i = 0; + if (utils.isQuotedString(pattern)) { + return [pattern.slice(1, -1)]; + } - while (len--) { - res.push.apply(res, braces(segs[i++])); - } - return res; -} + var proto = new Braces(options); + var result = !options || options.expand !== true + ? proto.optimize(pattern, options) + : proto.expand(pattern, options); -/** - * Handle escaped braces: `\\{foo,bar}` - */ + // get the generated pattern(s) + var arr = result.output; -function escapeBraces(str, arr, opts) { - if (!/\{[^{]+\{/.test(str)) { - return arr.concat(str.split('\\').join('')); - } else { - str = str.split('\\{').join('__LT_BRACE__'); - str = str.split('\\}').join('__RT_BRACE__'); - return map(braces(str, arr, opts), function(ele) { - ele = ele.split('__LT_BRACE__').join('{'); - return ele.split('__RT_BRACE__').join('}'); - }); - } -} + // filter out empty strings if specified + if (options && options.noempty === true) { + arr = arr.filter(Boolean); + } -/** - * Handle escaped dots: `{1\\.2}` - */ + // filter out duplicates if specified + if (options && options.nodupes === true) { + arr = unique(arr); + } -function escapeDots(str, arr, opts) { - if (!/[^\\]\..+\\\./.test(str)) { - return arr.concat(str.split('\\').join('')); - } else { - str = str.split('\\.').join('__ESC_DOT__'); - return map(braces(str, arr, opts), function(ele) { - return ele.split('__ESC_DOT__').join('.'); + Object.defineProperty(arr, 'result', { + enumerable: false, + value: result }); - } -} -/** - * Handle escaped dots: `{1\\.2}` - */ + return arr; + } -function escapePaths(str, arr, opts) { - str = str.split('\/.').join('__ESC_PATH__'); - return map(braces(str, arr, opts), function(ele) { - return ele.split('__ESC_PATH__').join('\/.'); - }); -} + return memoize('create', pattern, options, create); +}; /** - * Handle escaped commas: `{a\\,b}` + * Create a regular expression from the given string `pattern`. + * + * ```js + * var braces = require('braces'); + * + * console.log(braces.makeRe('id-{200..300}')); + * //=> /^(?:id-(20[0-9]|2[1-9][0-9]|300))$/ + * ``` + * @param {String} `pattern` The pattern to convert to regex. + * @param {Object} `options` + * @return {RegExp} + * @api public */ -function escapeCommas(str, arr, opts) { - if (!/\w,/.test(str)) { - return arr.concat(str.split('\\').join('')); - } else { - str = str.split('\\,').join('__ESC_COMMA__'); - return map(braces(str, arr, opts), function(ele) { - return ele.split('__ESC_COMMA__').join(','); - }); +braces.makeRe = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); } -} -/** - * Regex for common patterns - */ + var maxLength = (options && options.maxLength) || MAX_LENGTH; + if (pattern.length >= maxLength) { + throw new Error('expected pattern to be less than ' + maxLength + ' characters'); + } -function patternRegex() { - return /\${|( (?=[{,}])|(?=[{,}]) )|{}|{,}|\\,(?=.*[{}])|\/\.(?=.*[{}])|\\\.(?={)|\\{|\\}/; -} + function makeRe() { + var arr = braces(pattern, options); + var opts = extend({strictErrors: false}, options); + return toRegex(arr, opts); + } + + return memoize('makeRe', pattern, options, makeRe); +}; /** - * Braces regex. + * Parse the given `str` with the given `options`. + * + * ```js + * var braces = require('braces'); + * var ast = braces.parse('a/{b,c}/d'); + * console.log(ast); + * // { type: 'root', + * // errors: [], + * // input: 'a/{b,c}/d', + * // nodes: + * // [ { type: 'bos', val: '' }, + * // { type: 'text', val: 'a/' }, + * // { type: 'brace', + * // nodes: + * // [ { type: 'brace.open', val: '{' }, + * // { type: 'text', val: 'b,c' }, + * // { type: 'brace.close', val: '}' } ] }, + * // { type: 'text', val: '/d' }, + * // { type: 'eos', val: '' } ] } + * ``` + * @param {String} `pattern` Brace pattern to parse + * @param {Object} `options` + * @return {Object} Returns an AST + * @api public */ -function braceRegex() { - return /.*(\\?\{([^}]+)\})/; -} +braces.parse = function(pattern, options) { + var proto = new Braces(options); + return proto.parse(pattern, options); +}; /** - * es6 delimiter regex. + * Compile the given `ast` or string with the given `options`. + * + * ```js + * var braces = require('braces'); + * var ast = braces.parse('a/{b,c}/d'); + * console.log(braces.compile(ast)); + * // { options: { source: 'string' }, + * // state: {}, + * // compilers: + * // { eos: [Function], + * // noop: [Function], + * // bos: [Function], + * // brace: [Function], + * // 'brace.open': [Function], + * // text: [Function], + * // 'brace.close': [Function] }, + * // output: [ 'a/(b|c)/d' ], + * // ast: + * // { ... }, + * // parsingErrors: [] } + * ``` + * @param {Object|String} `ast` AST from [.parse](#parse). If a string is passed it will be parsed first. + * @param {Object} `options` + * @return {Object} Returns an object that has an `output` property with the compiled string. + * @api public */ -function es6Regex() { - return /\$\{([^}]+)\}/; -} - -var braceRe; -var patternRe; +braces.compile = function(ast, options) { + var proto = new Braces(options); + return proto.compile(ast, options); +}; /** - * Faster alternative to `String.replace()` when the - * index of the token to be replaces can't be supplied + * Clear the regex cache. + * + * ```js + * braces.clearCache(); + * ``` + * @api public */ -function splice(str, token, replacement) { - var i = str.indexOf(token); - return str.substr(0, i) + replacement - + str.substr(i + token.length); -} +braces.clearCache = function() { + cache = braces.cache = {}; +}; /** - * Fast array map + * Memoize a generated regex or function. A unique key is generated + * from the method name, pattern, and user-defined options. Set + * options.memoize to false to disable. */ -function map(arr, fn) { - if (arr == null) { - return []; +function memoize(type, pattern, options, fn) { + var key = utils.createKey(type + ':' + pattern, options); + var disabled = options && options.cache === false; + if (disabled) { + braces.clearCache(); + return fn(pattern, options); } - var len = arr.length; - var res = new Array(len); - var i = -1; - - while (++i < len) { - res[i] = fn(arr[i], i, arr); + if (cache.hasOwnProperty(key)) { + return cache[key]; } + var res = fn(pattern, options); + cache[key] = res; return res; } /** - * Fast array filter + * Expose `Braces` constructor and methods + * @type {Function} */ -function filter(arr, cb) { - if (arr == null) return []; - if (typeof cb !== 'function') { - throw new TypeError('braces: filter expects a callback function.'); - } +braces.Braces = Braces; +braces.compilers = compilers; +braces.parsers = parsers; +braces.cache = cache; - var len = arr.length; - var res = arr.slice(); - var i = 0; +/** + * Expose `braces` + * @type {Function} + */ - while (len--) { - if (!cb(arr[len], i++)) { - res.splice(len, 1); - } - } - return res; -} +module.exports = braces; |