114 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			114 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const fill = require('fill-range');
							 | 
						||
| 
								 | 
							
								const stringify = require('./stringify');
							 | 
						||
| 
								 | 
							
								const utils = require('./utils');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const append = (queue = '', stash = '', enclose = false) => {
							 | 
						||
| 
								 | 
							
								  let result = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  queue = [].concat(queue);
							 | 
						||
| 
								 | 
							
								  stash = [].concat(stash);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!stash.length) return queue;
							 | 
						||
| 
								 | 
							
								  if (!queue.length) {
							 | 
						||
| 
								 | 
							
								    return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (let item of queue) {
							 | 
						||
| 
								 | 
							
								    if (Array.isArray(item)) {
							 | 
						||
| 
								 | 
							
								      for (let value of item) {
							 | 
						||
| 
								 | 
							
								        result.push(append(value, stash, enclose));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      for (let ele of stash) {
							 | 
						||
| 
								 | 
							
								        if (enclose === true && typeof ele === 'string') ele = `{${ele}}`;
							 | 
						||
| 
								 | 
							
								        result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return utils.flatten(result);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const expand = (ast, options = {}) => {
							 | 
						||
| 
								 | 
							
								  let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let walk = (node, parent = {}) => {
							 | 
						||
| 
								 | 
							
								    node.queue = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    let p = parent;
							 | 
						||
| 
								 | 
							
								    let q = parent.queue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    while (p.type !== 'brace' && p.type !== 'root' && p.parent) {
							 | 
						||
| 
								 | 
							
								      p = p.parent;
							 | 
						||
| 
								 | 
							
								      q = p.queue;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (node.invalid || node.dollar) {
							 | 
						||
| 
								 | 
							
								      q.push(append(q.pop(), stringify(node, options)));
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) {
							 | 
						||
| 
								 | 
							
								      q.push(append(q.pop(), ['{}']));
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (node.nodes && node.ranges > 0) {
							 | 
						||
| 
								 | 
							
								      let args = utils.reduce(node.nodes);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (utils.exceedsLimit(...args, options.step, rangeLimit)) {
							 | 
						||
| 
								 | 
							
								        throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.');
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      let range = fill(...args, options);
							 | 
						||
| 
								 | 
							
								      if (range.length === 0) {
							 | 
						||
| 
								 | 
							
								        range = stringify(node, options);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      q.push(append(q.pop(), range));
							 | 
						||
| 
								 | 
							
								      node.nodes = [];
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    let enclose = utils.encloseBrace(node);
							 | 
						||
| 
								 | 
							
								    let queue = node.queue;
							 | 
						||
| 
								 | 
							
								    let block = node;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    while (block.type !== 'brace' && block.type !== 'root' && block.parent) {
							 | 
						||
| 
								 | 
							
								      block = block.parent;
							 | 
						||
| 
								 | 
							
								      queue = block.queue;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (let i = 0; i < node.nodes.length; i++) {
							 | 
						||
| 
								 | 
							
								      let child = node.nodes[i];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (child.type === 'comma' && node.type === 'brace') {
							 | 
						||
| 
								 | 
							
								        if (i === 1) queue.push('');
							 | 
						||
| 
								 | 
							
								        queue.push('');
							 | 
						||
| 
								 | 
							
								        continue;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (child.type === 'close') {
							 | 
						||
| 
								 | 
							
								        q.push(append(q.pop(), queue, enclose));
							 | 
						||
| 
								 | 
							
								        continue;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (child.value && child.type !== 'open') {
							 | 
						||
| 
								 | 
							
								        queue.push(append(queue.pop(), child.value));
							 | 
						||
| 
								 | 
							
								        continue;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (child.nodes) {
							 | 
						||
| 
								 | 
							
								        walk(child, node);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return queue;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return utils.flatten(walk(ast));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = expand;
							 |