Permalink
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
codeql-action/node_modules/fill-range/index.js
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
249 lines (197 sloc)
6.17 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* 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; |