@alexaegis/common
Version:
Common utility functions
1 lines • 38.3 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","names":[],"sources":["../src/async/is-promise-fulfilled.function.ts","../src/async/async-filter-map.function.ts","../src/async/async-filter.function.ts","../src/async/async-map.function.ts","../src/async/buffered-all-settled.function.ts","../src/es/default-es-target.const.ts","../src/functions/group-by.function.ts","../src/functions/identity.function.ts","../src/functions/memoize.function.options.ts","../src/functions/memoize.function.ts","../src/functions/noop.function.ts","../src/functions/normalize-regexplike-into-regexp.function.ts","../src/functions/sleep.function.ts","../src/functions/yes.function.ts","../src/math/closest-number.function.ts","../src/math/random.function.ts","../src/objects/deep-freeze.function.ts","../src/objects/is-object.function.ts","../src/objects/deep-map-object.function.ts","../src/objects/drop-keys.function.ts","../src/objects/deep-merge.function.ts","../src/objects/fill-string-with-template-variables.function.ts","../src/objects/fill-object-with-template-variables.function.ts","../src/objects/is-not-nullish.function.ts","../src/objects/is-nullish.function.ts","../src/objects/is-promise-like.function.ts","../src/objects/map-object.function.ts","../src/options/dry.function.ts","../src/options/dry.option.ts","../src/options/force.option.ts","../src/options/safe.option.ts","../src/sorting/regex-specificity.function.ts","../src/sorting/shuffle-array.function.ts","../src/sorting/sort-object.function.ts","../src/string/capitalize.function.ts","../src/string/case-conversion.ts"],"sourcesContent":["export const isPromiseFulfilled = <T>(\n\tpromiseResult: PromiseSettledResult<T>,\n): promiseResult is PromiseFulfilledResult<T> => {\n\treturn promiseResult.status === 'fulfilled';\n};\n","import { isNotNullish } from '../index.js';\nimport { isPromiseFulfilled } from './is-promise-fulfilled.function.js';\n\nexport const asyncFilterMap = async <T, R>(\n\tarray: T[],\n\tmap: (t: T, i: number) => Promise<R | undefined>,\n): Promise<R[]> => {\n\tconst checks = await Promise.allSettled(array.map(map));\n\n\treturn checks\n\t\t.filter(isPromiseFulfilled)\n\t\t.map((item) => item.value)\n\t\t.filter(isNotNullish);\n};\n","import { isPromiseFulfilled } from './is-promise-fulfilled.function.js';\n\nconst filterMark = {};\n\nexport const asyncFilter = async <T>(\n\tarray: T[],\n\tpredicate: (t: T, i: number) => Promise<boolean>,\n): Promise<T[]> => {\n\tconst checks = await Promise.allSettled(\n\t\tarray.map((item, i) => {\n\t\t\treturn predicate(item, i).then((result) => (result ? item : filterMark));\n\t\t}),\n\t);\n\n\treturn checks\n\t\t.filter(isPromiseFulfilled)\n\t\t.map((item) => item.value)\n\t\t.filter((result): result is Awaited<T> => result !== filterMark);\n};\n","import type { Awaitable } from '../objects/awaitable.type.js';\n\nexport const asyncMap = async <T, R>(\n\tarray: T[],\n\tmap: (t: T, i: number) => Awaitable<R>,\n): Promise<R[]> => {\n\treturn Promise.all(array.map(map));\n};\n","/**\n * This function will process async tasks in batches, limited by the bufferSize.\n * Since it needs to have control over when promises start (and since promises\n * are always hot) instead of promises you need to pass functions that return\n * the promises.\n *\n * @param tasks an array of Promise factories (async functions)\n * @param bufferSize (default 25) at most, this many tasks will be running at a time\n * @returns the results of each promise in the order they resolved or rejected\n */\nexport const bufferedAllSettled = async <T>(\n\ttasks: (() => Promise<T>)[],\n\tbufferSize = 25,\n): Promise<PromiseSettledResult<T>[]> => {\n\tconst buffer = new Map<() => Promise<T>, Promise<unknown>>();\n\tconst results: PromiseSettledResult<T>[] = [];\n\twhile (tasks.length > 0) {\n\t\twhile (buffer.size < bufferSize) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst task = tasks.shift()!;\n\t\t\tconst promise = task()\n\t\t\t\t.then((value) => {\n\t\t\t\t\tresults.push({ status: 'fulfilled', value });\n\t\t\t\t\tbuffer.delete(task);\n\t\t\t\t\treturn value;\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\tresults.push({ status: 'rejected', reason: error });\n\t\t\t\t\tbuffer.delete(task);\n\t\t\t\t\treturn error;\n\t\t\t\t});\n\t\t\tbuffer.set(task, promise);\n\t\t}\n\t\tawait Promise.any(buffer.values());\n\t}\n\tawait Promise.allSettled(buffer.values());\n\treturn results;\n};\n","export const DEFAULT_ES_TARGET_YEAR = 2022;\nexport const DEFAULT_ES_TARGET_NAME = `es${DEFAULT_ES_TARGET_YEAR.toString()}`;\n","/**\n * groups an array of elements into multiple arrays on an object where the\n * key is the string returned by the groupKey function.\n *\n * If the groupKey function returns undefined, the value won't be included\n * in the result. This can be used to filter out values from the initial array.\n *\n * There's also an ECMAScript proposal that will add a very similar function\n * on Object and Array: https://github.com/tc39/proposal-array-grouping\n *\n * This function can be deprecated once it's widely released.\n */\nexport const groupBy = <T, K extends string>(\n\telements: T[],\n\tgroupKey: (element: T) => K | undefined,\n): Record<K, T[]> => {\n\treturn elements.reduce<Record<string, T[]>>((acc, next) => {\n\t\tconst key = groupKey(next);\n\t\tif (key) {\n\t\t\tlet group: T[] | undefined = acc[key];\n\t\t\tif (group) {\n\t\t\t\tgroup.push(next);\n\t\t\t} else {\n\t\t\t\tconst newGroup: T[] = [next];\n\t\t\t\tgroup = newGroup;\n\t\t\t\tacc[key] = newGroup;\n\t\t\t}\n\t\t}\n\t\treturn acc;\n\t}, {});\n};\n","/**\n * Returns whatever you pass to it.\n */\nexport const identity = <V>(r?: V) => r;\n\n/**\n * Returns whatever you pass to it. Asynchronously. While the regular\n * `identity` function is already awaitable, this one is always thenable.\n */\nexport const identityAsync = async <V>(value?: V, mode: 'micro' | 'macro' = 'micro') =>\n\tnew Promise((resolve) => {\n\t\tif (mode === 'micro') {\n\t\t\tresolve(value);\n\t\t} else {\n\t\t\tsetTimeout(() => {\n\t\t\t\tresolve(value);\n\t\t\t}, 0);\n\t\t}\n\t});\n","// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface MemoizeOptions<F extends (...args: any) => unknown, T = unknown> {\n\t/**\n\t * @defaultValue undefined\n\t */\n\tthisContext?: T | undefined;\n\t/**\n\t *\n\t * @defaultValue JSON.stringify\n\t */\n\targHasher?: (args: Parameters<F>) => string;\n\t/**\n\t * @defaultValue Infinity\n\t */\n\tmaxCacheEntries?: number;\n\n\tcache?: Map<string, ReturnType<F>>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type NormalizedMemoizeOptions<F extends (...args: any) => unknown, T = unknown> = Required<\n\tOmit<MemoizeOptions<F, T>, 'thisContext'>\n> &\n\tPick<MemoizeOptions<F, T>, 'thisContext'>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const normalizeMemoizeOptions = <F extends (...args: any) => unknown, T>(\n\toptions?: MemoizeOptions<F, T>,\n): NormalizedMemoizeOptions<F, T> => {\n\treturn {\n\t\targHasher: options?.argHasher ?? JSON.stringify,\n\t\tthisContext: options?.thisContext,\n\t\tmaxCacheEntries: options?.maxCacheEntries ?? Number.POSITIVE_INFINITY,\n\t\tcache: options?.cache ?? new Map<string, ReturnType<F>>(),\n\t};\n};\n","import type { Fn } from './fn.type.js';\nimport { normalizeMemoizeOptions, type MemoizeOptions } from './memoize.function.options.js';\n\n/**\n * By default the cache does not start growing, the limit is infinite.\n * To set otherwise, use the options object.\n *\n * @param fn to be memoized\n * @param rawOptions options to customize cache behavior\n * @returns the memoized version of the function that will either return a cached value\n * or call the original function when one does not exist.\n */\nexport const memoize = <F extends (...args: never) => unknown, T = unknown>(\n\tfn: F,\n\trawOptions?: MemoizeOptions<F, T>,\n): Fn<Parameters<F>, ReturnType<F>> => {\n\tconst options = normalizeMemoizeOptions(rawOptions);\n\tconst dropQueue: string[] = [];\n\n\treturn (...args: Parameters<F>): ReturnType<F> => {\n\t\tconst hash = options.argHasher(args);\n\t\t// Checking for the existence of a key instead of just using get\n\t\t// and checking if it's nullish or not, to avoid preventing nullish\n\t\t// results from being cached.\n\t\tif (options.cache.has(hash)) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\treturn options.cache.get(hash)!;\n\t\t} else {\n\t\t\tconst result = fn.apply(options.thisContext, args as never) as ReturnType<F>;\n\t\t\toptions.cache.set(hash, result);\n\n\t\t\tif (options.maxCacheEntries > 0 && options.maxCacheEntries < Number.POSITIVE_INFINITY) {\n\t\t\t\tdropQueue.push(hash);\n\t\t\t\tif (dropQueue.length > options.maxCacheEntries) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\tconst cacheToDrop = dropQueue.shift()!;\n\t\t\t\t\toptions.cache.delete(cacheToDrop);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t};\n};\n","/**\n * Does nothing.\n */\nexport const noop = () => undefined;\n\n/**\n * Does nothing asynchronously as a macro-task.\n *\n */\nexport const noopAsync = (mode: 'micro' | 'macro' = 'micro') =>\n\tnew Promise((resolve) => {\n\t\tif (mode === 'micro') {\n\t\t\tresolve(undefined);\n\t\t} else {\n\t\t\tsetTimeout(() => {\n\t\t\t\tresolve(undefined);\n\t\t\t}, 0);\n\t\t}\n\t});\n","export const normalizeRegExpLikeToRegExp = (regExpLike: string | RegExp): RegExp => {\n\treturn typeof regExpLike === 'string' ? new RegExp(regExpLike) : regExpLike;\n};\n","export const sleep = (ms: number): Promise<void> => {\n\treturn ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();\n};\n","export const yes = () => true;\n\nexport const yesAsync = (mode: 'micro' | 'macro' = 'micro') =>\n\tnew Promise((resolve) => {\n\t\tif (mode === 'micro') {\n\t\t\tresolve(true);\n\t\t} else {\n\t\t\tsetTimeout(() => {\n\t\t\t\tresolve(true);\n\t\t\t}, 0);\n\t\t}\n\t});\n","/**\n * It biases towards the smaller number. If the `<` would be `<=` then it\n * would bias towards the larger.\n */\nexport const closestNumber = (numbers: number[], target: number): number =>\n\tnumbers.reduce((prev, curr) =>\n\t\tMath.abs(curr - target) < Math.abs(prev - target) ? curr : prev,\n\t);\n","export function random(min: number, max: number): number {\n\tif (min > max) {\n\t\t[min, max] = [max, min];\n\t}\n\n\treturn Math.floor(Math.random() * (max - min + 1) + min);\n}\n","/**\n * Applies Object.freeze deeply, as seen on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze\n *\n * @returns the same object but frozen.\n */\nexport const deepFreeze = <T>(object: T, dontFreeze = new Set()): T => {\n\tdontFreeze.add(object);\n\tconst propNames = Reflect.ownKeys(object as object);\n\tfor (const name of propNames) {\n\t\tconst value = (object as Record<string | number | symbol, unknown>)[name];\n\n\t\tif (\n\t\t\t((value && typeof value === 'object') || typeof value === 'function') &&\n\t\t\t!dontFreeze.has(value)\n\t\t) {\n\t\t\tdeepFreeze(value as T, dontFreeze);\n\t\t}\n\t}\n\n\treturn Object.freeze(object);\n};\n","import type { SimpleObjectKey } from '../objects/struct.type.js';\n\n/**\n * Simple object check.\n * @param item\n * @returns {boolean}\n */\nexport function isObject(item: unknown): item is Record<SimpleObjectKey, unknown> {\n\treturn item !== null && item !== undefined && typeof item === 'object' && !Array.isArray(item);\n}\n","import { isObject } from './is-object.function.js';\n\nexport const deepMapObject = <T>(\n\to: T,\n\tmapper: (key: string | number, value: unknown) => unknown,\n): T => {\n\tconst target = { ...o };\n\n\tif (isObject(target)) {\n\t\tfor (const key in target) {\n\t\t\tconst value = target[key];\n\t\t\tif (isObject(value)) {\n\t\t\t\tObject.assign(target, { [key]: deepMapObject(value, mapper) });\n\t\t\t} else {\n\t\t\t\tconst mapResult = mapper(key, value);\n\t\t\t\tif (mapResult === undefined) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\t\t\tdelete target[key];\n\t\t\t\t} else {\n\t\t\t\t\tObject.assign(target, { [key]: mapResult });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn target;\n};\n","import { isObject } from './is-object.function.js';\n\nexport type DropKeyMatcher = (value: unknown, key: string | number | symbol) => boolean;\n\nexport const defaultDropKeyMatcher: DropKeyMatcher = (\n\tvalue: unknown,\n\t_key: string | number | symbol,\n): value is undefined => value === undefined;\n\n/**\n * Drops all keys that resolve to true using a matcher.\n * By default it drops keys set as undefined\n *\n * Mutates the object! Use `structuredClone` before if you don't want that.\n */\nexport const dropKeys = <T>(t: T, matcher: DropKeyMatcher = defaultDropKeyMatcher): T => {\n\tfor (const key in t) {\n\t\tif (matcher(t[key], key)) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\t\tdelete t[key];\n\t\t}\n\n\t\tif (isObject(t[key])) {\n\t\t\tdropKeys(t[key], matcher);\n\t\t}\n\t}\n\n\treturn t;\n};\n","import { defaultDropKeyMatcher, dropKeys, type DropKeyMatcher } from './drop-keys.function.js';\nimport { isObject } from './is-object.function.js';\nimport type { MergeTuple } from './tuple.type.js';\n\nexport interface DeepMergeOptions {\n\t/**\n\t * When set to true, if any of the sources set something to undefined\n\t * @default false\n\t */\n\tpreferUndefined?: boolean;\n\n\t/**\n\t * Wether or not to drop undefineds from the resulting merge before return\n\t * When set to true it will drop keys that are set to undefined.\n\t * When set to a matcher function it will drop only those keys.\n\t *\n\t * To use this functionally elsewhere see the\n\t * [`dropKeys`](./drop-keys.function.ts) function.\n\t *\n\t * This will happen at the last step\n\t *\n\t * @default false\n\t */\n\tdropKeys?: boolean | DropKeyMatcher;\n}\n\nconst deepMergeInternal = <T extends unknown[]>(\n\tsources: [...T],\n\toptions?: DeepMergeOptions,\n\tvisited = new Set<unknown>(),\n): MergeTuple<T> => {\n\tconst firstSource = sources.shift();\n\tvisited.add(firstSource);\n\tconst merged: unknown = structuredClone(firstSource);\n\n\tfor (const source of sources) {\n\t\tvisited.add(source);\n\n\t\tif (Array.isArray(source) && Array.isArray(merged)) {\n\t\t\tfor (const element of source) {\n\t\t\t\tif (!merged.includes(element)) {\n\t\t\t\t\tmerged.push(element);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (isObject(source) && isObject(merged)) {\n\t\t\tfor (const key in source) {\n\t\t\t\tconst sourceValue = source[key];\n\n\t\t\t\tif (\n\t\t\t\t\tObject.hasOwn(merged, key) &&\n\t\t\t\t\tmerged[key] === undefined &&\n\t\t\t\t\toptions?.preferUndefined\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (isObject(sourceValue)) {\n\t\t\t\t\tif (merged[key]) {\n\t\t\t\t\t\tmerged[key] = deepMergeInternal(\n\t\t\t\t\t\t\t[merged[key] as T, structuredClone(sourceValue)],\n\t\t\t\t\t\t\toptions,\n\t\t\t\t\t\t\tvisited,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tObject.assign(merged, { [key]: structuredClone(sourceValue) });\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tObject.assign(merged, { [key]: structuredClone(sourceValue) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (options?.dropKeys) {\n\t\tconst matcher =\n\t\t\ttypeof options.dropKeys === 'function' ? options.dropKeys : defaultDropKeyMatcher;\n\t\tdropKeys(merged, matcher);\n\t}\n\n\treturn merged as MergeTuple<T>;\n};\n\n/**\n * Merges multiple objects in order into the first argument.\n * It mutates the target! Arrays are merged naively using === equality.\n *\n * Keys that are explicitly set to `undefined` among sources are dropped from\n * the target object.\n */\nexport const deepMerge = <T extends unknown[]>(\n\tsources: [...T],\n\toptions?: DeepMergeOptions,\n): MergeTuple<T> => {\n\treturn deepMergeInternal(sources, options);\n};\n","import type { SimpleObjectKey } from './struct.type.js';\n\n/**\n * Maps and fills a single string value in an object based on a variableMap.\n *\n * If the target object has a string value containing `\"${variableName}\"`, the\n * corresponding value from the variableMap will be substitued into it.\n */\nexport const fillStringWithTemplateVariables = <VariableKeys extends SimpleObjectKey>(\n\tvalue: string,\n\tvariables: Record<VariableKeys, string>,\n): string => {\n\treturn Object.entries<string>(variables).reduce((acc, [variableKey, variableValue]) => {\n\t\treturn acc.replaceAll('${' + variableKey + '}', variableValue);\n\t}, value);\n};\n","import { deepMapObject } from './deep-map-object.function.js';\nimport { fillStringWithTemplateVariables } from './fill-string-with-template-variables.function.js';\nimport type { SimpleObjectKey } from './struct.type.js';\n\n/**\n * Maps and fills every string value in an object based on a variableMap.\n *\n * If the target object has a string value containing `\"${variableName}\"`, the\n * corresponding value from the variableMap will be substitued into it.\n */\nexport const fillObjectWithTemplateVariables = <\n\tVariableKeys extends SimpleObjectKey,\n\tT extends Record<string | number, unknown> = Record<string | number, unknown>,\n>(\n\ttarget: T,\n\tvariables: Record<VariableKeys, string>,\n): T => {\n\treturn deepMapObject(target, (_key, value) => {\n\t\treturn typeof value === 'string'\n\t\t\t? fillStringWithTemplateVariables(value, variables)\n\t\t\t: value;\n\t});\n};\n","export const isNotNullish = <T>(o: T | undefined | null): o is NonNullable<T> =>\n\to !== undefined && o !== null;\n","export const isNullish = <T>(o: T | undefined | null): o is undefined | null =>\n\to === undefined || o === null;\n","import { isNotNullish } from './is-not-nullish.function.js';\n\nexport const isPromiseLike = <T>(candidate: unknown): candidate is PromiseLike<T> => {\n\treturn (\n\t\tisNotNullish(candidate) &&\n\t\ttypeof candidate === 'object' &&\n\t\ttypeof (candidate as Record<string, unknown>)['then'] === 'function' &&\n\t\ttypeof (candidate as Record<string, unknown>)['catch'] === 'function'\n\t);\n};\n","import type { SimpleObjectKey } from './struct.type.js';\n\nexport const mapObject = <T extends Record<SimpleObjectKey, unknown>, K>(\n\to: T,\n\tmap: (value: T[keyof T], key: keyof T) => K,\n): Record<keyof T, K> => {\n\treturn Object.fromEntries(\n\t\tObject.entries(o).map(([key, value]) => {\n\t\t\treturn [key, map(value as T[keyof T], key)];\n\t\t}),\n\t) as Record<keyof T, K>;\n};\n","import { identity, identityAsync } from '../index.js';\n\nexport interface DrySync {\n\t<T extends (...args: never) => unknown>(\n\t\tisDry: boolean,\n\t\twhenWet: T,\n\t\tdryDefault: ReturnType<T>,\n\t): T;\n\t<T extends (...args: never) => unknown>(isDry: true, whenWet: T, dryDefault?: ReturnType<T>): T;\n\t<T extends (...args: never) => unknown>(isDry: false, whenWet: T): T;\n}\n\n/**\n * Conditionally dries up a function. When a function is dry it will\n * no longer be called, instead it will return true\n */\nexport const drySync: DrySync = <T>(isDry: boolean, whenWet: T, dryDefault = true) => {\n\treturn isDry ? () => identity(dryDefault) : whenWet;\n};\n\nexport interface DryAsync {\n\t<T extends (...args: never) => Promise<unknown>>(\n\t\tisDry: boolean,\n\t\twhenWet: T,\n\t\tdryDefault?: Awaited<ReturnType<T>>,\n\t): T;\n\t<T extends (...args: never) => Promise<unknown>>(\n\t\tisDry: true,\n\t\twhenWet: T,\n\t\tdryDefault?: Awaited<ReturnType<T>>,\n\t): () => Promise<true>;\n\t<T extends (...args: never) => Promise<unknown>>(isDry: false, whenWet: T): T;\n}\n\nexport const dry: DryAsync = <T>(isDry: boolean, whenWet: T, dryDefault = true) => {\n\treturn isDry ? () => identityAsync(dryDefault) : whenWet;\n};\n","export interface DryOption {\n\t/**\n\t * Actual operations are turned off when `dry` is set to true.\n\t *\n\t * For example\n\t * Post requests won't be made, filesystem operations won't write,\n\t * but still send get requests and read from filesystem.\n\t *\n\t * @defaultValue false\n\t */\n\tdry?: boolean;\n}\n\nexport type NormalizedDryOption = Required<DryOption>;\n\nexport const normalizeDryOption = (options?: DryOption): NormalizedDryOption => {\n\treturn {\n\t\tdry: options?.dry ?? false,\n\t};\n};\n","export interface ForceOption {\n\t/**\n\t * Ignore caches, guards, overwrite files\n\t *\n\t * @defaultValue false\n\t */\n\tforce?: boolean;\n}\n\nexport type NormalizedForceOption = Required<ForceOption>;\n\nexport const normalizeForceOption = (options?: ForceOption): NormalizedForceOption => {\n\treturn {\n\t\tforce: options?.force ?? false,\n\t};\n};\n","export interface SafeOption {\n\t/**\n\t * Perform extra safety checks, could result in much less actions taken\n\t *\n\t * @defaultValue false\n\t */\n\tsafe?: boolean;\n}\n\nexport type NormalizedSafeOption = Required<SafeOption>;\n\nexport const normalizeSafeOption = (options?: SafeOption): NormalizedSafeOption => {\n\treturn {\n\t\tsafe: options?.safe ?? false,\n\t};\n};\n","/**\n * Getting a proper specificity measure is a hard problem, this is but a very\n * simple solution, that is good-enough for this usecase.\n * It's just counting how many of the matched words letters are actually in\n * the regex.\n *\n * For RegExp's pass in the `.source`\n */\nexport const measureRegExpSpecificity = (r: string, v: string): number => {\n\treturn [...v].filter((c) => r.includes(c)).length;\n};\n","import { isNotNullish } from '../objects/is-not-nullish.function.js';\n\n/**\n * Randomizes the placement of elements within an array, shuffling it.\n *\n * It mutates the input array!\n */\nexport function shuffleArray<T>(array: T[]): T[] {\n\tlet currentIndex = array.length;\n\n\t// While there remain elements to shuffle...\n\twhile (0 !== currentIndex) {\n\t\t// Pick a remaining element...\n\t\tconst randomIndex = Math.floor(Math.random() * currentIndex);\n\t\tcurrentIndex--;\n\n\t\t// And swap it with the current element.\n\t\tconst temporaryValue = array[currentIndex];\n\t\tconst randomValue = array[randomIndex];\n\t\tif (isNotNullish(temporaryValue) && isNotNullish(randomValue)) {\n\t\t\tarray[currentIndex] = randomValue;\n\t\t\tarray[randomIndex] = temporaryValue;\n\t\t}\n\t}\n\n\treturn array;\n}\n","import { isNotNullish } from '../objects/is-not-nullish.function.js';\nimport type { SimpleObjectKey } from '../objects/struct.type.js';\nimport type { DetailedObjectKeyOrder, ObjectKeyOrder } from './object-key-order.type.js';\nimport { measureRegExpSpecificity } from './regex-specificity.function.js';\n\nconst arrayToObject = <T extends SimpleObjectKey>(a: T[]): Record<SimpleObjectKey, T> => {\n\treturn a.reduce<Record<SimpleObjectKey, T>>((acc, next) => {\n\t\tacc[next] = next;\n\t\treturn acc;\n\t}, {});\n};\n\nconst regexpSorterOne = (a: RegExp, b: RegExp): number =>\n\ta.test(b.source) || b.test(a.source) ? -1 : a.source.localeCompare(b.source);\n\n/**\n *\n * Among multiple `matchers` like ['.*', 'b', '.*'], when trying to fit in\n * a `key`, which slot would maintain order the best? For example fitting\n * 'a' into the above matcher order, it should go to the left slot, but fitting\n * 'c' should make it go to the right slot.\n */\nexport const findMostSensibleMatch = (matchers: RegExp[], key: string): number => {\n\t// find all matchers, for afterEach, replace the matcher with the key. rank them which is better by sorting them and measure how much it moved\n\tconst matcherIndices = matchers\n\t\t.map((matcher, i) => (matcher.test(key) ? i : undefined))\n\t\t.filter(isNotNullish);\n\n\tconst deviations = matcherIndices.map((matcherIndice) => {\n\t\tconst scenario = [...matchers];\n\t\t// It is definitely in it\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst originalMatcher = scenario[matcherIndice]!;\n\t\tconst matcherSpecificity = measureRegExpSpecificity(originalMatcher.source, key);\n\t\tscenario[matcherIndice] = new RegExp(key);\n\t\tscenario.sort(regexpSorterOne);\n\t\tconst scenarioSortIndex = scenario.findIndex((v) => v.source === key);\n\t\tconst deviation = Math.abs(scenarioSortIndex - matcherIndice);\n\n\t\treturn {\n\t\t\tdeviation,\n\t\t\toriginalMatcher,\n\t\t\tmatcherIndice,\n\t\t\tmatcherSpecificity,\n\t\t};\n\t});\n\n\tdeviations.sort(\n\t\t(a, b) =>\n\t\t\ta.deviation === b.deviation\n\t\t\t\t? a.matcherSpecificity === b.matcherSpecificity\n\t\t\t\t\t? a.matcherIndice === b.matcherIndice\n\t\t\t\t\t\t? a.originalMatcher.source.localeCompare(b.originalMatcher.source)\n\t\t\t\t\t\t: b.matcherIndice - a.matcherIndice // the larger the better\n\t\t\t\t\t: b.matcherSpecificity - a.matcherSpecificity // The larger the better\n\t\t\t\t: a.deviation - b.deviation, // The smaller the better\n\t);\n\n\treturn deviations[0]?.matcherIndice ?? -1;\n};\n\nexport const findMostSensibleMatchIdeaTwo = (matchers: RegExp[], key: string): number => {\n\t// find all matchers, for afterEach, replace the matcher with the key. rank them which is better by sorting them and measure how much it moved\n\tconst matchingIndices = matchers.map((matcher) =>\n\t\tmatcher.test(key) ? new RegExp(key) : matcher,\n\t);\n\n\tconst sortedMatchers = [...matchingIndices];\n\tsortedMatchers.sort(regexpSorterOne);\n\t// mnaybe this is a bad idea\n\treturn -1;\n};\n/**\n * Creates a copy of an object with its keys ordered according to a\n * preferred ordering\n */\nexport const sortObject = <T extends object | unknown[]>(\n\to: T,\n\tsortPreferences: ObjectKeyOrder = [],\n): T => {\n\tconst plainLevelOrder = sortPreferences.map((pref) =>\n\t\ttypeof pref === 'object' ? pref.key : pref,\n\t);\n\n\tconst regexpLevelOrder = plainLevelOrder.map((pref) => new RegExp(pref));\n\t// Turn arrays into objects too, they will be turned back into arrays\n\tconst isArray = Array.isArray(o);\n\tlet obj: T = o;\n\tif (isArray) {\n\t\tobj = arrayToObject(o) as T;\n\t}\n\n\tconst ordered = Object.entries(obj)\n\t\t.map<[string, unknown, number]>(([key, value]) => {\n\t\t\t// Could fill multiple spots\n\t\t\tlet order = Number.POSITIVE_INFINITY;\n\n\t\t\tconst plainIndex = plainLevelOrder.indexOf(key);\n\t\t\tif (plainIndex >= 0) {\n\t\t\t\t// If it's directly there, use that\n\t\t\t\torder = plainIndex;\n\t\t\t} else {\n\t\t\t\tconst regexpIndices = regexpLevelOrder\n\t\t\t\t\t.map((orderingRegExp, i) => (orderingRegExp.test(key) ? i : -1))\n\t\t\t\t\t.filter((index) => index > -1);\n\n\t\t\t\t// If not, let's find the closest match, the sorting order itself is sorted\n\t\t\t\tif (regexpIndices.length > 1) {\n\t\t\t\t\torder = findMostSensibleMatch(regexpLevelOrder, key);\n\t\t\t\t} else if (regexpIndices[0]) {\n\t\t\t\t\torder = regexpIndices[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (value !== undefined && value !== null && typeof value === 'object') {\n\t\t\t\tconst subOrdering = sortPreferences\n\t\t\t\t\t.filter((pref): pref is DetailedObjectKeyOrder => typeof pref === 'object')\n\t\t\t\t\t.find((preference) => new RegExp(preference.key).test(key));\n\t\t\t\treturn [key, sortObject(value, subOrdering?.order), order];\n\t\t\t} else {\n\t\t\t\treturn [key, value, order];\n\t\t\t}\n\t\t})\n\t\t.sort(([ak, _av, aOrder], [bk, _bv, bOrder]) => {\n\t\t\treturn aOrder >= 0 && bOrder >= 0 && aOrder !== bOrder\n\t\t\t\t? aOrder - bOrder\n\t\t\t\t: ak.localeCompare(bk);\n\t\t});\n\n\treturn isArray ? (ordered.map((item) => item[1]) as T) : (Object.fromEntries(ordered) as T);\n};\n","/**\n * Turns the first letter into upper case and the rest lowercase\n */\nexport const capitalize = (s: string): string => {\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n};\n","import { capitalize } from './capitalize.function.js';\n\n/**\n * Splits a string apart into it's individial words. It treats ' ', '_' and '-'\n * as word boundaries as well as when a lower case character is followed by an\n * upper case character.\n *\n * An empty string will result in an empty array.\n */\nexport const splitByCasing = (input: string): string[] => {\n\treturn input ? input.split(/(?=[A-Z][a-z])|[\\s_-]+/).map((word) => word.toLowerCase()) : [];\n};\n\n/**\n * Turns an input string to camelCase from any input casing\n */\nexport function camelCase(input: string): string {\n\tconst [first, ...rest] = splitByCasing(input);\n\treturn (first ?? '') + rest.map(capitalize).join('');\n}\n\n/**\n * Turns an input string to kebab-case from any input casing\n */\nexport function kebabCase(input: string): string {\n\treturn splitByCasing(input).join('-');\n}\n\n/**\n * Turns an input string to snake_case from any input casing\n */\nexport function snakeCase(input: string): string {\n\treturn splitByCasing(input).join('_');\n}\n\n/**\n * Turns an input string to UPPER_SNAKE_CASE from any input casing\n */\nexport function upperSnakeCase(input: string): string {\n\treturn splitByCasing(input).join('_').toUpperCase();\n}\n\n/**\n * Turns an input string to PascalCase from any input casing\n */\nexport function pascalCase(input: string): string {\n\treturn splitByCasing(input).map(capitalize).join('');\n}\n\n/**\n * Turns an input string to Train-Case from any input casing\n */\nexport function trainCase(input: string): string {\n\treturn splitByCasing(input).map(capitalize).join('-');\n}\n"],"mappings":"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"}