123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- 'use strict';
- var splitString = require('split-string');
- var utils = module.exports;
- /**
- * Module dependencies
- */
- utils.define = require('define-property');
- 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');
- /**
- * 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');
- };
|