| 'use strict'; | 
|   | 
| var splitString = require('split-string'); | 
| var utils = module.exports; | 
|   | 
| /** | 
|  * Module dependencies | 
|  */ | 
|   | 
| utils.extend = require('extend-shallow'); | 
| utils.flatten = require('arr-flatten'); | 
| utils.isObject = require('isobject'); | 
| utils.fillRange = require('fill-range'); | 
| utils.repeat = require('repeat-element'); | 
| utils.unique = require('array-unique'); | 
|   | 
| utils.define = function(obj, key, val) { | 
|   Object.defineProperty(obj, key, { | 
|     writable: true, | 
|     configurable: true, | 
|     enumerable: false, | 
|     value: val | 
|   }); | 
| }; | 
|   | 
| /** | 
|  * Returns true if the given string contains only empty brace sets. | 
|  */ | 
|   | 
| utils.isEmptySets = function(str) { | 
|   return /^(?:\{,\})+$/.test(str); | 
| }; | 
|   | 
| /** | 
|  * Returns true if the given string contains only empty brace sets. | 
|  */ | 
|   | 
| utils.isQuotedString = function(str) { | 
|   var open = str.charAt(0); | 
|   if (open === '\'' || open === '"' || open === '`') { | 
|     return str.slice(-1) === open; | 
|   } | 
|   return false; | 
| }; | 
|   | 
| /** | 
|  * Create the key to use for memoization. The unique key is generated | 
|  * by iterating over the options and concatenating key-value pairs | 
|  * to the pattern string. | 
|  */ | 
|   | 
| utils.createKey = function(pattern, options) { | 
|   var id = pattern; | 
|   if (typeof options === 'undefined') { | 
|     return id; | 
|   } | 
|   var keys = Object.keys(options); | 
|   for (var i = 0; i < keys.length; i++) { | 
|     var key = keys[i]; | 
|     id += ';' + key + '=' + String(options[key]); | 
|   } | 
|   return id; | 
| }; | 
|   | 
| /** | 
|  * Normalize options | 
|  */ | 
|   | 
| utils.createOptions = function(options) { | 
|   var opts = utils.extend.apply(null, arguments); | 
|   if (typeof opts.expand === 'boolean') { | 
|     opts.optimize = !opts.expand; | 
|   } | 
|   if (typeof opts.optimize === 'boolean') { | 
|     opts.expand = !opts.optimize; | 
|   } | 
|   if (opts.optimize === true) { | 
|     opts.makeRe = true; | 
|   } | 
|   return opts; | 
| }; | 
|   | 
| /** | 
|  * Join patterns in `a` to patterns in `b` | 
|  */ | 
|   | 
| utils.join = function(a, b, options) { | 
|   options = options || {}; | 
|   a = utils.arrayify(a); | 
|   b = utils.arrayify(b); | 
|   | 
|   if (!a.length) return b; | 
|   if (!b.length) return a; | 
|   | 
|   var len = a.length; | 
|   var idx = -1; | 
|   var arr = []; | 
|   | 
|   while (++idx < len) { | 
|     var val = a[idx]; | 
|     if (Array.isArray(val)) { | 
|       for (var i = 0; i < val.length; i++) { | 
|         val[i] = utils.join(val[i], b, options); | 
|       } | 
|       arr.push(val); | 
|       continue; | 
|     } | 
|   | 
|     for (var j = 0; j < b.length; j++) { | 
|       var bval = b[j]; | 
|   | 
|       if (Array.isArray(bval)) { | 
|         arr.push(utils.join(val, bval, options)); | 
|       } else { | 
|         arr.push(val + bval); | 
|       } | 
|     } | 
|   } | 
|   return arr; | 
| }; | 
|   | 
| /** | 
|  * Split the given string on `,` if not escaped. | 
|  */ | 
|   | 
| utils.split = function(str, options) { | 
|   var opts = utils.extend({sep: ','}, options); | 
|   if (typeof opts.keepQuotes !== 'boolean') { | 
|     opts.keepQuotes = true; | 
|   } | 
|   if (opts.unescape === false) { | 
|     opts.keepEscaping = true; | 
|   } | 
|   return splitString(str, opts, utils.escapeBrackets(opts)); | 
| }; | 
|   | 
| /** | 
|  * Expand ranges or sets in the given `pattern`. | 
|  * | 
|  * @param {String} `str` | 
|  * @param {Object} `options` | 
|  * @return {Object} | 
|  */ | 
|   | 
| utils.expand = function(str, options) { | 
|   var opts = utils.extend({rangeLimit: 10000}, options); | 
|   var segs = utils.split(str, opts); | 
|   var tok = { segs: segs }; | 
|   | 
|   if (utils.isQuotedString(str)) { | 
|     return tok; | 
|   } | 
|   | 
|   if (opts.rangeLimit === true) { | 
|     opts.rangeLimit = 10000; | 
|   } | 
|   | 
|   if (segs.length > 1) { | 
|     if (opts.optimize === false) { | 
|       tok.val = segs[0]; | 
|       return tok; | 
|     } | 
|   | 
|     tok.segs = utils.stringifyArray(tok.segs); | 
|   } else if (segs.length === 1) { | 
|     var arr = str.split('..'); | 
|   | 
|     if (arr.length === 1) { | 
|       tok.val = tok.segs[tok.segs.length - 1] || tok.val || str; | 
|       tok.segs = []; | 
|       return tok; | 
|     } | 
|   | 
|     if (arr.length === 2 && arr[0] === arr[1]) { | 
|       tok.escaped = true; | 
|       tok.val = arr[0]; | 
|       tok.segs = []; | 
|       return tok; | 
|     } | 
|   | 
|     if (arr.length > 1) { | 
|       if (opts.optimize !== false) { | 
|         opts.optimize = true; | 
|         delete opts.expand; | 
|       } | 
|   | 
|       if (opts.optimize !== true) { | 
|         var min = Math.min(arr[0], arr[1]); | 
|         var max = Math.max(arr[0], arr[1]); | 
|         var step = arr[2] || 1; | 
|   | 
|         if (opts.rangeLimit !== false && ((max - min) / step >= opts.rangeLimit)) { | 
|           throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); | 
|         } | 
|       } | 
|   | 
|       arr.push(opts); | 
|       tok.segs = utils.fillRange.apply(null, arr); | 
|   | 
|       if (!tok.segs.length) { | 
|         tok.escaped = true; | 
|         tok.val = str; | 
|         return tok; | 
|       } | 
|   | 
|       if (opts.optimize === true) { | 
|         tok.segs = utils.stringifyArray(tok.segs); | 
|       } | 
|   | 
|       if (tok.segs === '') { | 
|         tok.val = str; | 
|       } else { | 
|         tok.val = tok.segs[0]; | 
|       } | 
|       return tok; | 
|     } | 
|   } else { | 
|     tok.val = str; | 
|   } | 
|   return tok; | 
| }; | 
|   | 
| /** | 
|  * Ensure commas inside brackets and parens are not split. | 
|  * @param {Object} `tok` Token from the `split-string` module | 
|  * @return {undefined} | 
|  */ | 
|   | 
| utils.escapeBrackets = function(options) { | 
|   return function(tok) { | 
|     if (tok.escaped && tok.val === 'b') { | 
|       tok.val = '\\b'; | 
|       return; | 
|     } | 
|   | 
|     if (tok.val !== '(' && tok.val !== '[') return; | 
|     var opts = utils.extend({}, options); | 
|     var brackets = []; | 
|     var parens = []; | 
|     var stack = []; | 
|     var val = tok.val; | 
|     var str = tok.str; | 
|     var i = tok.idx - 1; | 
|   | 
|     while (++i < str.length) { | 
|       var ch = str[i]; | 
|   | 
|       if (ch === '\\') { | 
|         val += (opts.keepEscaping === false ? '' : ch) + str[++i]; | 
|         continue; | 
|       } | 
|   | 
|       if (ch === '(') { | 
|         parens.push(ch); | 
|         stack.push(ch); | 
|       } | 
|   | 
|       if (ch === '[') { | 
|         brackets.push(ch); | 
|         stack.push(ch); | 
|       } | 
|   | 
|       if (ch === ')') { | 
|         parens.pop(); | 
|         stack.pop(); | 
|         if (!stack.length) { | 
|           val += ch; | 
|           break; | 
|         } | 
|       } | 
|   | 
|       if (ch === ']') { | 
|         brackets.pop(); | 
|         stack.pop(); | 
|         if (!stack.length) { | 
|           val += ch; | 
|           break; | 
|         } | 
|       } | 
|       val += ch; | 
|     } | 
|   | 
|     tok.split = false; | 
|     tok.val = val.slice(1); | 
|     tok.idx = i; | 
|   }; | 
| }; | 
|   | 
| /** | 
|  * Returns true if the given string looks like a regex quantifier | 
|  * @return {Boolean} | 
|  */ | 
|   | 
| utils.isQuantifier = function(str) { | 
|   return /^(?:[0-9]?,[0-9]|[0-9],)$/.test(str); | 
| }; | 
|   | 
| /** | 
|  * Cast `val` to an array. | 
|  * @param {*} `val` | 
|  */ | 
|   | 
| utils.stringifyArray = function(arr) { | 
|   return [utils.arrayify(arr).join('|')]; | 
| }; | 
|   | 
| /** | 
|  * Cast `val` to an array. | 
|  * @param {*} `val` | 
|  */ | 
|   | 
| utils.arrayify = function(arr) { | 
|   if (typeof arr === 'undefined') { | 
|     return []; | 
|   } | 
|   if (typeof arr === 'string') { | 
|     return [arr]; | 
|   } | 
|   return arr; | 
| }; | 
|   | 
| /** | 
|  * Returns true if the given `str` is a non-empty string | 
|  * @return {Boolean} | 
|  */ | 
|   | 
| utils.isString = function(str) { | 
|   return str != null && typeof str === 'string'; | 
| }; | 
|   | 
| /** | 
|  * Get the last element from `array` | 
|  * @param {Array} `array` | 
|  * @return {*} | 
|  */ | 
|   | 
| utils.last = function(arr, n) { | 
|   return arr[arr.length - (n || 1)]; | 
| }; | 
|   | 
| utils.escapeRegex = function(str) { | 
|   return str.replace(/\\?([!^*?()[\]{}+?/])/g, '\\$1'); | 
| }; |