|
|
/*! * fill-range <https://github.com/jonschlinkert/fill-range>
* * Copyright (c) 2014-2015, 2017, Jon Schlinkert. * Released under the MIT License. */
'use strict';
var util = require('util'); var isNumber = require('is-number'); var extend = require('extend-shallow'); var repeat = require('repeat-string'); var toRegex = require('to-regex-range');
/** * Return a range of numbers or letters. * * @param {String} `start` Start of the range * @param {String} `stop` End of the range * @param {String} `step` Increment or decrement to use. * @param {Function} `fn` Custom function to modify each element in the range. * @return {Array} */
function fillRange(start, stop, step, options) { if (typeof start === 'undefined') { return []; }
if (typeof stop === 'undefined' || start === stop) { // special case, for handling negative zero
var isString = typeof start === 'string'; if (isNumber(start) && !toNumber(start)) { return [isString ? '0' : 0]; } return [start]; }
if (typeof step !== 'number' && typeof step !== 'string') { options = step; step = undefined; }
if (typeof options === 'function') { options = { transform: options }; }
var opts = extend({step: step}, options); if (opts.step && !isValidNumber(opts.step)) { if (opts.strictRanges === true) { throw new TypeError('expected options.step to be a number'); } return []; }
opts.isNumber = isValidNumber(start) && isValidNumber(stop); if (!opts.isNumber && !isValid(start, stop)) { if (opts.strictRanges === true) { throw new RangeError('invalid range arguments: ' + util.inspect([start, stop])); } return []; }
opts.isPadded = isPadded(start) || isPadded(stop); opts.toString = opts.stringify || typeof opts.step === 'string' || typeof start === 'string' || typeof stop === 'string' || !opts.isNumber;
if (opts.isPadded) { opts.maxLength = Math.max(String(start).length, String(stop).length); }
// support legacy minimatch/fill-range options
if (typeof opts.optimize === 'boolean') opts.toRegex = opts.optimize; if (typeof opts.makeRe === 'boolean') opts.toRegex = opts.makeRe; return expand(start, stop, opts); }
function expand(start, stop, options) { var a = options.isNumber ? toNumber(start) : start.charCodeAt(0); var b = options.isNumber ? toNumber(stop) : stop.charCodeAt(0);
var step = Math.abs(toNumber(options.step)) || 1; if (options.toRegex && step === 1) { return toRange(a, b, start, stop, options); }
var zero = {greater: [], lesser: []}; var asc = a < b; var arr = new Array(Math.round((asc ? b - a : a - b) / step)); var idx = 0;
while (asc ? a <= b : a >= b) { var val = options.isNumber ? a : String.fromCharCode(a); if (options.toRegex && (val >= 0 || !options.isNumber)) { zero.greater.push(val); } else { zero.lesser.push(Math.abs(val)); }
if (options.isPadded) { val = zeros(val, options); }
if (options.toString) { val = String(val); }
if (typeof options.transform === 'function') { arr[idx++] = options.transform(val, a, b, step, idx, arr, options); } else { arr[idx++] = val; }
if (asc) { a += step; } else { a -= step; } }
if (options.toRegex === true) { return toSequence(arr, zero, options); } return arr; }
function toRange(a, b, start, stop, options) { if (options.isPadded) { return toRegex(start, stop, options); }
if (options.isNumber) { return toRegex(Math.min(a, b), Math.max(a, b), options); }
var start = String.fromCharCode(Math.min(a, b)); var stop = String.fromCharCode(Math.max(a, b)); return '[' + start + '-' + stop + ']'; }
function toSequence(arr, zeros, options) { var greater = '', lesser = ''; if (zeros.greater.length) { greater = zeros.greater.join('|'); } if (zeros.lesser.length) { lesser = '-(' + zeros.lesser.join('|') + ')'; } var res = greater && lesser ? greater + '|' + lesser : greater || lesser;
if (options.capture) { return '(' + res + ')'; } return res; }
function zeros(val, options) { if (options.isPadded) { var str = String(val); var len = str.length; var dash = ''; if (str.charAt(0) === '-') { dash = '-'; str = str.slice(1); } var diff = options.maxLength - len; var pad = repeat('0', diff); val = (dash + pad + str); } if (options.stringify) { return String(val); } return val; }
function toNumber(val) { return Number(val) || 0; }
function isPadded(str) { return /^-?0\d/.test(str); }
function isValid(min, max) { return (isValidNumber(min) || isValidLetter(min)) && (isValidNumber(max) || isValidLetter(max)); }
function isValidLetter(ch) { return typeof ch === 'string' && ch.length === 1 && /^\w+$/.test(ch); }
function isValidNumber(n) { return isNumber(n) && !/\./.test(n); }
/** * Expose `fillRange` * @type {Function} */
module.exports = fillRange;
|