UNPKG

@bluelovers/fill-range

Version:

Fill in a range of numbers or letters, optionally passing an increment or `step` to use, or create a regex-compatible range with `options.toRegex`

357 lines (270 loc) 8.67 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('util'), require('@bluelovers/to-regex-range2')) : typeof define === 'function' && define.amd ? define(['exports', 'util', '@bluelovers/to-regex-range2'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.BlueloversFillRange = {}, global.util, global.toRegexRange2)); })(this, (function (exports, util, toRegexRange2) { 'use strict'; var EnumNegative; (function (EnumNegative) { EnumNegative["negative"] = "-"; EnumNegative["none"] = ""; })(EnumNegative || (EnumNegative = {})); function isObject(val) { return val !== null && typeof val === 'object' && !Array.isArray(val); } const transform = toNumber => { if (toNumber === true) return value => Number(value); return 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) { input = toMaxLen(input, maxLength); } if (toNumber === false) { return String(input); } return input; }; const toMaxLen = (input, _maxLength) => { let { result, negative, maxLength } = _prefixNegative(input, _maxLength); return negative + result.padStart(maxLength, '0'); }; function _partsSort(part) { part.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); } function _partsCapturePrefix(options) { return options.capture ? '' : '?:'; } function _prefixNegative(input, maxLength) { const negative = input[0] === "-" ? "-" : ""; if (negative === "-") { input = input.slice(1); maxLength--; } return { result: input, negative, maxLength }; } function _join(part) { return part.join('|'); } const toSequence = (parts, options) => { _partsSort(parts.negatives); _partsSort(parts.positives); let prefix = _partsCapturePrefix(options); let positives = ''; let negatives = ''; let result; if (parts.positives.length) { positives = _join(parts.positives); } if (parts.negatives.length) { negatives = `-(${prefix}${_join(parts.negatives)})`; } 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 toRegexRange2.toRegexRange(a, b, { wrap: false, ...options }); } const start = String.fromCharCode(a); if (a === b) return start; const stop = String.fromCharCode(b); return `[${start}-${stop}]`; }; const toRegex = (start, end, options) => { if (Array.isArray(start)) { const wrap = options.wrap === true; const prefix = _partsCapturePrefix(options); start = _join(start); return wrap ? `(${prefix}${start})` : start; } return toRegexRange2.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], options); return []; }; const invalidStep = (step, options) => { if (options.strictRanges === true) { throw new TypeError(`Expected step "${step}" to be a number`); } return []; }; function _handleLimit(options) { return options.limit > 0 ? options.limit : Infinity; } function _handleStep(step) { return Math.max(Math.abs(step), 1); } function _handleOptions(opts, clone) { if (clone === true) { opts = { ...opts }; } if (opts.capture === true) opts.wrap = true; return opts; } function _handleDescending(start, end, options) { const descending = start > end; if (descending === true && options.strictOrder) { throw rangeError([start, end], options); } return descending; } 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], options); return []; } if (a === 0) a = 0; if (b === 0) b = 0; const descending = _handleDescending(a, b, options); const startString = String(start); const endString = String(end); const stepString = String(step); step = _handleStep(step); const padded = zeros(startString) || zeros(endString) || zeros(stepString); const maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0; const toNumber = padded === false && stringify(start, end, options) === false; const format = options.transform || transform(toNumber); if (options.toRegex && step === 1) { return toRange(toMaxLen(String(start), maxLen), toMaxLen(String(end), maxLen), true, options); } const parts = { negatives: [], positives: [] }; const push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); const range = []; let index = 0; const limit = _handleLimit(options); 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 (index >= limit) break; } if (options.toRegex === true) { return step > 1 ? toSequence(parts, options) : toRegex(range, null, { wrap: false, ...options }); } return range; }; function fillLetters(start, end, step = 1, options = {}) { if (!isNumber(start) && start.length > 1 || !isNumber(end) && end.length > 1) { return invalidRange(start, end, options); } const format = options.transform || (val => String.fromCharCode(val)); let a = `${start}`.charCodeAt(0); let b = `${end}`.charCodeAt(0); const descending = _handleDescending(a, b, options); const min = Math.min(a, b); const max = Math.max(a, b); if (options.toRegex === true && step === 1) { return toRange(min, max, false, options); } const range = []; let index = 0; const limit = _handleLimit(options); while (descending ? a >= b : a <= b) { range.push(format(a, index)); a = descending ? a - step : a + step; index++; if (index >= limit) break; } if (options.toRegex === true) { return toRegex(range, null, { wrap: false, ...options }); } return range; } function fill(start, end, step, options = {}) { const _s = isValidValue(start); if ((typeof end === 'undefined' || end === null) && _s) { return [start]; } if (!_s || !isValidValue(end)) { return invalidRange(start, end, options); } if (typeof step === 'function') { [step, options] = [1, { transform: step }]; } if (isObject(step)) { [step, options] = [0, step]; } let opts = options; step = step || opts.step || 1; if (!isNumber(step)) { if (step != null && !isObject(step)) return invalidStep(step, opts); [step, opts] = [1, opts]; } opts = _handleOptions(opts, true); if (isNumber(start) && isNumber(end)) { return fillNumbers(start, end, step, opts); } return fillLetters(start, end, _handleStep(step), opts); } Object.defineProperty(fill, '__esModule', { value: true }); Object.defineProperty(fill, 'fill', { value: fill }); Object.defineProperty(fill, 'default', { value: fill }); exports["default"] = fill; exports.fill = fill; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=index.umd.development.cjs.map