@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`
1 lines • 18.4 kB
Source Map (JSON)
{"version":3,"file":"index.cjs.production.min.cjs","sources":["../src/index.ts","../src/index.cts"],"sourcesContent":["import { inspect } from 'util';\nimport { toRegexRange, IOptions as IOptionsToRegexRange } from '@bluelovers/to-regex-range2';\n\nexport interface IOptions<V = string | number> extends IOptionsToRegexRange\n{\n /**\n * The increment to use for the range. Can be used with letters or numbers.\n * @example\n * // numbers\n * console.log(fill('1', '10', 2)); //=> [ '1', '3', '5', '7', '9' ]\n * console.log(fill('1', '10', 3)); //=> [ '1', '4', '7', '10' ]\n * console.log(fill('1', '10', 4)); //=> [ '1', '5', '9' ]\n *\n * // letters\n * console.log(fill('a', 'z', 5)); //=> [ 'a', 'f', 'k', 'p', 'u', 'z' ]\n * console.log(fill('a', 'z', 7)); //=> [ 'a', 'h', 'o', 'v' ]\n * console.log(fill('a', 'z', 9)); //=> [ 'a', 'j', 's' ]\n */\n step?: number,\n\n /**\n * By default, null is returned when an invalid range is passed. Enable this option to throw a RangeError on invalid ranges.\n */\n strictRanges?: boolean,\n\n /**\n * Cast all returned values to strings. By default, integers are returned as numbers.\n * @example\n * console.log(fill(1, 5)); //=> [ 1, 2, 3, 4, 5 ]\n * console.log(fill(1, 5, { stringify: true })); //=> [ '1', '2', '3', '4', '5' ]\n *\n */\n stringify?: boolean,\n /**\n * Create a regex-compatible source string, instead of expanding values to an array.\n * @example\n * // alphabetical range\n * console.log(fill('a', 'e', { toRegex: true })); //=> '[a-e]'\n * // alphabetical with step\n * console.log(fill('a', 'z', 3, { toRegex: true })); //=> 'a|d|g|j|m|p|s|v|y'\n * // numerical range\n * console.log(fill('1', '100', { toRegex: true })); //=> '[1-9]|[1-9][0-9]|100'\n * // numerical range with zero padding\n * console.log(fill('000001', '100000', { toRegex: true }));\n * //=> '0{5}[1-9]|0{4}[1-9][0-9]|0{3}[1-9][0-9]{2}|0{2}[1-9][0-9]{3}|0[1-9][0-9]{4}|100000'\n */\n toRegex?: boolean,\n\n /**\n * Customize each value in the returned array (or string). (you can also pass this function as the last argument to fill()).\n * @example\n * // add zero padding\n * console.log(fill(1, 5, value => String(value).padStart(4, '0')));\n * //=> ['0001', '0002', '0003', '0004', '0005']\n */\n transform?(val: number, index?: number): V,\n\n /**\n * set limit size\n */\n limit?: number,\n /**\n * only allow start < stop\n */\n strictOrder?: boolean,\n}\n\ninterface IParts\n{\n negatives: number[],\n positives: number[],\n}\n\nconst enum EnumNegative\n{\n negative = '-',\n none = '',\n}\n\nfunction isObject(val: unknown): val is IOptions {\n return val !== null && typeof val === 'object' && !Array.isArray(val);\n}\n\nconst transform = (toNumber: boolean) => {\n if (toNumber === true) return value => Number(value);\n return value => String(value);\n};\n\nconst isValidValue = (value): value is number | string => {\n return typeof value === 'number' || (typeof value === 'string' && value !== '');\n};\n\nconst isNumber = (num: unknown): num is number => Number.isInteger(+num);\n\nconst zeros = input => {\n let value = `${input}`;\n let index = -1;\n if (value[0] === '-') value = value.slice(1);\n if (value === '0') return false;\n while (value[++index] === '0');\n return index > 0;\n};\n\nconst stringify = (start, end, options: IOptions) => {\n if (typeof start === 'string' || typeof end === 'string') {\n return true;\n }\n return options.stringify === true;\n};\n\nconst pad = (input: any, maxLength: number, toNumber: boolean) => {\n if (maxLength > 0) {\n input = toMaxLen(input, maxLength);\n }\n if (toNumber === false) {\n return String(input);\n }\n return input;\n};\n\nconst toMaxLen = (input: string, _maxLength: number) => {\n let { result, negative, maxLength } = _prefixNegative(input, _maxLength);\n return negative + result.padStart(maxLength, '0')\n};\n\nfunction _partsSort(part: number[])\n{\n part.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);\n}\n\nfunction _partsCapturePrefix(options: IOptions)\n{\n return options.capture ? '' as const : '?:' as const;\n}\n\nfunction _prefixNegative(input: string, maxLength: number)\n{\n const negative = input[0] === EnumNegative.negative ? EnumNegative.negative : EnumNegative.none;\n\n if (negative === EnumNegative.negative)\n {\n input = input.slice(1);\n maxLength--;\n }\n\n return {\n result: input,\n negative,\n maxLength,\n }\n}\n\nfunction _join(part: (string|number)[])\n{\n return part.join('|')\n}\n\nconst toSequence = (parts: IParts, options: IOptions) => {\n _partsSort(parts.negatives);\n _partsSort(parts.positives);\n\n let prefix = _partsCapturePrefix(options);\n let positives = '';\n let negatives = '';\n let result: string;\n\n if (parts.positives.length) {\n positives = _join(parts.positives);\n }\n\n if (parts.negatives.length) {\n negatives = `-(${prefix}${_join(parts.negatives)})`;\n }\n\n if (positives && negatives) {\n result = `${positives}|${negatives}`;\n } else {\n result = positives || negatives;\n }\n\n if (options.wrap) {\n return `(${prefix}${result})`;\n }\n\n return result;\n};\n\nconst toRange = (a, b, isNumbers, options: IOptions) => {\n if (isNumbers) {\n return toRegexRange(a, b, { wrap: false, ...options });\n }\n\n const start = String.fromCharCode(a);\n if (a === b) return start;\n\n const stop = String.fromCharCode(b);\n return `[${start}-${stop}]`;\n};\n\nconst toRegex = (start, end, options: IOptions): string => {\n if (Array.isArray(start)) {\n const wrap = options.wrap === true;\n const prefix = _partsCapturePrefix(options);\n start = _join(start);\n return wrap ? `(${prefix}${start})` : start;\n }\n return toRegexRange(start, end, options);\n};\n\nconst rangeError = (...args) => {\n // @ts-ignore\n return new RangeError('Invalid range arguments: ' + inspect(...args));\n};\n\nconst invalidRange = (start, end, options: IOptions): string[] => {\n if (options.strictRanges === true) throw rangeError([start, end], options);\n return [];\n};\n\nconst invalidStep = (step, options: IOptions): string[] => {\n if (options.strictRanges === true) {\n throw new TypeError(`Expected step \"${step}\" to be a number`);\n }\n return [];\n};\n\nfunction _handleLimit(options: IOptions)\n{\n return options.limit > 0 ? options.limit! : Infinity;\n}\n\nfunction _handleStep(step: number)\n{\n return Math.max(Math.abs(step), 1)\n}\n\nfunction _handleOptions(opts: IOptions, clone?: boolean)\n{\n if (clone === true)\n {\n opts = { ...opts };\n }\n if (opts.capture === true) opts.wrap = true;\n return opts;\n}\n\nfunction _handleDescending(start: number, end: number, options: IOptions)\n{\n const descending = start > end;\n\n if (descending === true && options.strictOrder)\n {\n throw rangeError([start, end], options);\n }\n\n return descending\n}\n\nconst fillNumbers = (start, end, step = 1, options: IOptions = {}): string[] | string => {\n let a = Number(start);\n let b = Number(end);\n\n if (!Number.isInteger(a) || !Number.isInteger(b)) {\n if (options.strictRanges === true) throw rangeError([start, end], options);\n return [];\n }\n\n // fix negative zero\n if (a === 0) a = 0;\n if (b === 0) b = 0;\n\n const descending = _handleDescending(a, b, options);\n const startString = String(start);\n const endString = String(end);\n const stepString = String(step);\n step = _handleStep(step);\n\n const padded = zeros(startString) || zeros(endString) || zeros(stepString);\n const maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0;\n const toNumber = padded === false && stringify(start, end, options) === false;\n const format = options.transform || transform(toNumber);\n\n if (options.toRegex && step === 1) {\n return toRange(toMaxLen(String(start), maxLen), toMaxLen(String(end), maxLen), true, options);\n }\n\n const parts: IParts = { negatives: [], positives: [] };\n const push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num));\n const range: any[] = [];\n let index = 0;\n const limit = _handleLimit(options);\n\n while (descending ? a >= b : a <= b) {\n if (options.toRegex === true && step > 1) {\n push(a);\n } else {\n range.push(pad(format(a, index), maxLen, toNumber));\n }\n a = descending ? a - step : a + step;\n index++;\n if (index >= limit) break;\n }\n\n if (options.toRegex === true) {\n return step > 1\n ? toSequence(parts, options)\n : toRegex(range, null, { wrap: false, ...options });\n }\n\n return range;\n};\n\nfunction fillLetters(start, end, step: number, options: IOptions & {\n toRegex: true,\n}): string\nfunction fillLetters<V>(start, end, step?: number, options?: IOptions<V>): V[] | string\nfunction fillLetters(start, end, step = 1, options: IOptions = {}): any[] | string\n{\n if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1))\n {\n return invalidRange(start, end, options) as any;\n }\n\n const format = options.transform || (val => String.fromCharCode(val));\n let a = `${start}`.charCodeAt(0);\n let b = `${end}`.charCodeAt(0);\n\n const descending = _handleDescending(a, b, options);\n const min = Math.min(a, b);\n const max = Math.max(a, b);\n\n if (options.toRegex === true && step === 1)\n {\n return toRange(min, max, false, options);\n }\n\n const range: any[] = [];\n let index = 0;\n const limit = _handleLimit(options);\n\n while (descending ? a >= b : a <= b)\n {\n range.push(format(a, index));\n a = descending ? a - step : a + step;\n index++;\n if (index >= limit) break;\n }\n\n if (options.toRegex === true)\n {\n return toRegex(range, null, { wrap: false, ...options });\n }\n\n return range;\n}\n\nexport function fill<V = number | string>(start: number | string,\n end: number | string,\n step: IOptions<V> & {\n toRegex?: false,\n },\n options?: never\n): V[]\nexport function fill<V = number | string>(start: number | string,\n end: number | string,\n step: number,\n options?: IOptions<V> & {\n toRegex?: false,\n }\n): V[]\nexport function fill<V = number | string>(start: number | string,\n end: number | string,\n step: IOptions<V>[\"transform\"],\n options?: never\n): V[]\nexport function fill(start: number | string,\n end: number | string,\n step: IOptions & {\n toRegex: true,\n },\n options?: IOptions\n): string\nexport function fill(start: number | string,\n end: number | string,\n step: number | IOptions[\"transform\"],\n options: IOptions & {\n toRegex: true,\n }\n): string\nexport function fill<R extends any[] | string = string[] | string>(start: number | string,\n end?: number | string,\n step?: number | IOptions[\"transform\"] | IOptions,\n options?: IOptions\n): R\nexport function fill(start: number | string, end?: number | string, step?: number | IOptions[\"transform\"] | IOptions, options: IOptions = {}): any[] | string\n{\n const _s = isValidValue(start);\n if ((typeof end === 'undefined' || end === null) && _s)\n {\n return [start] as any;\n }\n\n if (!_s || !isValidValue(end))\n {\n return invalidRange(start, end, options);\n }\n\n if (typeof step === 'function')\n {\n //return fill(start, end, 1, { transform: step });\n [step, options] = [1, { transform: step }];\n }\n\n if (isObject(step))\n {\n //return fill(start, end, 0, step);\n [step, options] = [0, step];\n }\n\n let opts: IOptions = options;\n step = step || opts.step || 1;\n\n if (!isNumber(step))\n {\n if (step != null && !isObject(step)) return invalidStep(step, opts);\n //return fill(start, end, 1, step as IOptions);\n [step, opts] = [1, opts];\n }\n\n opts = _handleOptions(opts, true);\n\n if (isNumber(start) && isNumber(end))\n {\n return fillNumbers(start, end, step, opts);\n }\n\n return fillLetters(start, end, _handleStep(step), opts);\n}\n\nObject.defineProperty(fill, '__esModule', { value: true });\nObject.defineProperty(fill, 'fill', { value: fill });\nObject.defineProperty(fill, 'default', { value: fill });\n\nexport default fill;\n","import { fill } from './index';\n\n// @ts-ignore\nexport = fill;\n"],"names":["EnumNegative","isObject","val","Array","isArray","isValidValue","value","isNumber","num","Number","isInteger","zeros","input","index","slice","pad","maxLength","toNumber","toMaxLen","String","_maxLength","result","negative","_prefixNegative","padStart","_partsSort","part","sort","a","b","_partsCapturePrefix","options","capture","_join","join","toRange","isNumbers","toRegexRange","wrap","start","fromCharCode","toRegex","end","prefix","rangeError","args","RangeError","inspect","invalidRange","strictRanges","_handleLimit","limit","Infinity","_handleStep","step","Math","max","abs","_handleDescending","descending","strictOrder","fill","_s","transform","opts","TypeError","invalidStep","_handleOptions","clone","startString","endString","stepString","padded","maxLen","length","stringify","format","parts","negatives","positives","range","push","toSequence","fillNumbers","fillLetters","charCodeAt","min","Object","defineProperty"],"mappings":"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"}