You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					250 lines
				
				6.2 KiB
			
		
		
			
		
	
	
					250 lines
				
				6.2 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								 * fill-range <https://github.com/jonschlinkert/fill-range>
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Copyright (c) 2014-present, Jon Schlinkert.
							 | 
						||
| 
								 | 
							
								 * Licensed under the MIT License.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const util = require('util');
							 | 
						||
| 
								 | 
							
								const toRegexRange = require('to-regex-range');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const transform = toNumber => {
							 | 
						||
| 
								 | 
							
								  return value => toNumber === true ? Number(value) : String(value);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const isValidValue = value => {
							 | 
						||
| 
								 | 
							
								  return typeof value === 'number' || (typeof value === 'string' && value !== '');
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const isNumber = num => Number.isInteger(+num);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const zeros = input => {
							 | 
						||
| 
								 | 
							
								  let value = `${input}`;
							 | 
						||
| 
								 | 
							
								  let index = -1;
							 | 
						||
| 
								 | 
							
								  if (value[0] === '-') value = value.slice(1);
							 | 
						||
| 
								 | 
							
								  if (value === '0') return false;
							 | 
						||
| 
								 | 
							
								  while (value[++index] === '0');
							 | 
						||
| 
								 | 
							
								  return index > 0;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const stringify = (start, end, options) => {
							 | 
						||
| 
								 | 
							
								  if (typeof start === 'string' || typeof end === 'string') {
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return options.stringify === true;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const pad = (input, maxLength, toNumber) => {
							 | 
						||
| 
								 | 
							
								  if (maxLength > 0) {
							 | 
						||
| 
								 | 
							
								    let dash = input[0] === '-' ? '-' : '';
							 | 
						||
| 
								 | 
							
								    if (dash) input = input.slice(1);
							 | 
						||
| 
								 | 
							
								    input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0'));
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  if (toNumber === false) {
							 | 
						||
| 
								 | 
							
								    return String(input);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return input;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const toMaxLen = (input, maxLength) => {
							 | 
						||
| 
								 | 
							
								  let negative = input[0] === '-' ? '-' : '';
							 | 
						||
| 
								 | 
							
								  if (negative) {
							 | 
						||
| 
								 | 
							
								    input = input.slice(1);
							 | 
						||
| 
								 | 
							
								    maxLength--;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  while (input.length < maxLength) input = '0' + input;
							 | 
						||
| 
								 | 
							
								  return negative ? ('-' + input) : input;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const toSequence = (parts, options) => {
							 | 
						||
| 
								 | 
							
								  parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
							 | 
						||
| 
								 | 
							
								  parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let prefix = options.capture ? '' : '?:';
							 | 
						||
| 
								 | 
							
								  let positives = '';
							 | 
						||
| 
								 | 
							
								  let negatives = '';
							 | 
						||
| 
								 | 
							
								  let result;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (parts.positives.length) {
							 | 
						||
| 
								 | 
							
								    positives = parts.positives.join('|');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (parts.negatives.length) {
							 | 
						||
| 
								 | 
							
								    negatives = `-(${prefix}${parts.negatives.join('|')})`;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (positives && negatives) {
							 | 
						||
| 
								 | 
							
								    result = `${positives}|${negatives}`;
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    result = positives || negatives;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (options.wrap) {
							 | 
						||
| 
								 | 
							
								    return `(${prefix}${result})`;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return result;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const toRange = (a, b, isNumbers, options) => {
							 | 
						||
| 
								 | 
							
								  if (isNumbers) {
							 | 
						||
| 
								 | 
							
								    return toRegexRange(a, b, { wrap: false, ...options });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let start = String.fromCharCode(a);
							 | 
						||
| 
								 | 
							
								  if (a === b) return start;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let stop = String.fromCharCode(b);
							 | 
						||
| 
								 | 
							
								  return `[${start}-${stop}]`;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const toRegex = (start, end, options) => {
							 | 
						||
| 
								 | 
							
								  if (Array.isArray(start)) {
							 | 
						||
| 
								 | 
							
								    let wrap = options.wrap === true;
							 | 
						||
| 
								 | 
							
								    let prefix = options.capture ? '' : '?:';
							 | 
						||
| 
								 | 
							
								    return wrap ? `(${prefix}${start.join('|')})` : start.join('|');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return toRegexRange(start, end, options);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const rangeError = (...args) => {
							 | 
						||
| 
								 | 
							
								  return new RangeError('Invalid range arguments: ' + util.inspect(...args));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const invalidRange = (start, end, options) => {
							 | 
						||
| 
								 | 
							
								  if (options.strictRanges === true) throw rangeError([start, end]);
							 | 
						||
| 
								 | 
							
								  return [];
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const invalidStep = (step, options) => {
							 | 
						||
| 
								 | 
							
								  if (options.strictRanges === true) {
							 | 
						||
| 
								 | 
							
								    throw new TypeError(`Expected step "${step}" to be a number`);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return [];
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const fillNumbers = (start, end, step = 1, options = {}) => {
							 | 
						||
| 
								 | 
							
								  let a = Number(start);
							 | 
						||
| 
								 | 
							
								  let b = Number(end);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!Number.isInteger(a) || !Number.isInteger(b)) {
							 | 
						||
| 
								 | 
							
								    if (options.strictRanges === true) throw rangeError([start, end]);
							 | 
						||
| 
								 | 
							
								    return [];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // fix negative zero
							 | 
						||
| 
								 | 
							
								  if (a === 0) a = 0;
							 | 
						||
| 
								 | 
							
								  if (b === 0) b = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let descending = a > b;
							 | 
						||
| 
								 | 
							
								  let startString = String(start);
							 | 
						||
| 
								 | 
							
								  let endString = String(end);
							 | 
						||
| 
								 | 
							
								  let stepString = String(step);
							 | 
						||
| 
								 | 
							
								  step = Math.max(Math.abs(step), 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let padded = zeros(startString) || zeros(endString) || zeros(stepString);
							 | 
						||
| 
								 | 
							
								  let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0;
							 | 
						||
| 
								 | 
							
								  let toNumber = padded === false && stringify(start, end, options) === false;
							 | 
						||
| 
								 | 
							
								  let format = options.transform || transform(toNumber);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (options.toRegex && step === 1) {
							 | 
						||
| 
								 | 
							
								    return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let parts = { negatives: [], positives: [] };
							 | 
						||
| 
								 | 
							
								  let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num));
							 | 
						||
| 
								 | 
							
								  let range = [];
							 | 
						||
| 
								 | 
							
								  let index = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (descending ? a >= b : a <= b) {
							 | 
						||
| 
								 | 
							
								    if (options.toRegex === true && step > 1) {
							 | 
						||
| 
								 | 
							
								      push(a);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      range.push(pad(format(a, index), maxLen, toNumber));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    a = descending ? a - step : a + step;
							 | 
						||
| 
								 | 
							
								    index++;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (options.toRegex === true) {
							 | 
						||
| 
								 | 
							
								    return step > 1
							 | 
						||
| 
								 | 
							
								      ? toSequence(parts, options)
							 | 
						||
| 
								 | 
							
								      : toRegex(range, null, { wrap: false, ...options });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return range;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const fillLetters = (start, end, step = 1, options = {}) => {
							 | 
						||
| 
								 | 
							
								  if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) {
							 | 
						||
| 
								 | 
							
								    return invalidRange(start, end, options);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let format = options.transform || (val => String.fromCharCode(val));
							 | 
						||
| 
								 | 
							
								  let a = `${start}`.charCodeAt(0);
							 | 
						||
| 
								 | 
							
								  let b = `${end}`.charCodeAt(0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let descending = a > b;
							 | 
						||
| 
								 | 
							
								  let min = Math.min(a, b);
							 | 
						||
| 
								 | 
							
								  let max = Math.max(a, b);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (options.toRegex && step === 1) {
							 | 
						||
| 
								 | 
							
								    return toRange(min, max, false, options);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let range = [];
							 | 
						||
| 
								 | 
							
								  let index = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  while (descending ? a >= b : a <= b) {
							 | 
						||
| 
								 | 
							
								    range.push(format(a, index));
							 | 
						||
| 
								 | 
							
								    a = descending ? a - step : a + step;
							 | 
						||
| 
								 | 
							
								    index++;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (options.toRegex === true) {
							 | 
						||
| 
								 | 
							
								    return toRegex(range, null, { wrap: false, options });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return range;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const fill = (start, end, step, options = {}) => {
							 | 
						||
| 
								 | 
							
								  if (end == null && isValidValue(start)) {
							 | 
						||
| 
								 | 
							
								    return [start];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!isValidValue(start) || !isValidValue(end)) {
							 | 
						||
| 
								 | 
							
								    return invalidRange(start, end, options);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof step === 'function') {
							 | 
						||
| 
								 | 
							
								    return fill(start, end, 1, { transform: step });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (isObject(step)) {
							 | 
						||
| 
								 | 
							
								    return fill(start, end, 0, step);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  let opts = { ...options };
							 | 
						||
| 
								 | 
							
								  if (opts.capture === true) opts.wrap = true;
							 | 
						||
| 
								 | 
							
								  step = step || opts.step || 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!isNumber(step)) {
							 | 
						||
| 
								 | 
							
								    if (step != null && !isObject(step)) return invalidStep(step, opts);
							 | 
						||
| 
								 | 
							
								    return fill(start, end, 1, step);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (isNumber(start) && isNumber(end)) {
							 | 
						||
| 
								 | 
							
								    return fillNumbers(start, end, step, opts);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return fillLetters(start, end, Math.max(Math.abs(step), 1), opts);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = fill;
							 |