UNPKG

@alexaegis/common

Version:
431 lines (430 loc) 14.7 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const isPromiseFulfilled = (promiseResult) => { return promiseResult.status === "fulfilled"; }; const asyncFilterMap = async (array, map) => { const checks = await Promise.allSettled(array.map(map)); return checks.filter(isPromiseFulfilled).map((item) => item.value).filter(isNotNullish); }; const filterMark = {}; const asyncFilter = async (array, predicate) => { const checks = await Promise.allSettled( array.map((item, i) => { return predicate(item, i).then((result) => result ? item : filterMark); }) ); return checks.filter(isPromiseFulfilled).map((item) => item.value).filter((result) => result !== filterMark); }; const asyncMap = async (array, map) => { return Promise.all(array.map(map)); }; const bufferedAllSettled = async (tasks, bufferSize = 25) => { const buffer = /* @__PURE__ */ new Map(); const results = []; while (tasks.length > 0) { while (buffer.size < bufferSize) { const task = tasks.shift(); const promise = task().then((value) => { results.push({ status: "fulfilled", value }); buffer.delete(task); return value; }).catch((error) => { results.push({ status: "rejected", reason: error }); buffer.delete(task); return error; }); buffer.set(task, promise); } await Promise.any(buffer.values()); } await Promise.allSettled(buffer.values()); return results; }; const DEFAULT_ES_TARGET_YEAR = 2022; const DEFAULT_ES_TARGET_NAME = `es${DEFAULT_ES_TARGET_YEAR.toString()}`; const groupBy = (elements, groupKey) => { return elements.reduce((acc, next) => { const key = groupKey(next); if (key) { let group = acc[key]; if (group) { group.push(next); } else { const newGroup = [next]; group = newGroup; acc[key] = newGroup; } } return acc; }, {}); }; const identity = (r) => r; const identityAsync = async (value, mode = "micro") => new Promise((resolve) => { if (mode === "micro") { resolve(value); } else { setTimeout(() => { resolve(value); }, 0); } }); const normalizeMemoizeOptions = (options) => { return { argHasher: options?.argHasher ?? JSON.stringify, thisContext: options?.thisContext, maxCacheEntries: options?.maxCacheEntries ?? Number.POSITIVE_INFINITY, cache: options?.cache ?? /* @__PURE__ */ new Map() }; }; const memoize = (fn, rawOptions) => { const options = normalizeMemoizeOptions(rawOptions); const dropQueue = []; return (...args) => { const hash = options.argHasher(args); if (options.cache.has(hash)) { return options.cache.get(hash); } else { const result = fn.apply(options.thisContext, args); options.cache.set(hash, result); if (options.maxCacheEntries > 0 && options.maxCacheEntries < Number.POSITIVE_INFINITY) { dropQueue.push(hash); if (dropQueue.length > options.maxCacheEntries) { const cacheToDrop = dropQueue.shift(); options.cache.delete(cacheToDrop); } } return result; } }; }; const noop = () => void 0; const noopAsync = (mode = "micro") => new Promise((resolve) => { if (mode === "micro") { resolve(void 0); } else { setTimeout(() => { resolve(void 0); }, 0); } }); const normalizeRegExpLikeToRegExp = (regExpLike) => { return typeof regExpLike === "string" ? new RegExp(regExpLike) : regExpLike; }; const sleep = (ms) => { return ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve(); }; const yes = () => true; const yesAsync = (mode = "micro") => new Promise((resolve) => { if (mode === "micro") { resolve(true); } else { setTimeout(() => { resolve(true); }, 0); } }); const closestNumber = (numbers, target) => numbers.reduce( (prev, curr) => Math.abs(curr - target) < Math.abs(prev - target) ? curr : prev ); function random(min, max) { if (min > max) { [min, max] = [max, min]; } return Math.floor(Math.random() * (max - min + 1) + min); } const deepFreeze = (object, dontFreeze = /* @__PURE__ */ new Set()) => { dontFreeze.add(object); const propNames = Reflect.ownKeys(object); for (const name of propNames) { const value = object[name]; if ((value && typeof value === "object" || typeof value === "function") && !dontFreeze.has(value)) { deepFreeze(value, dontFreeze); } } return Object.freeze(object); }; function isObject(item) { return item !== null && item !== void 0 && typeof item === "object" && !Array.isArray(item); } const deepMapObject = (o, mapper) => { const target = { ...o }; if (isObject(target)) { for (const key in target) { const value = target[key]; if (isObject(value)) { Object.assign(target, { [key]: deepMapObject(value, mapper) }); } else { const mapResult = mapper(key, value); if (mapResult === void 0) { delete target[key]; } else { Object.assign(target, { [key]: mapResult }); } } } } return target; }; const defaultDropKeyMatcher = (value, _key) => value === void 0; const dropKeys = (t, matcher = defaultDropKeyMatcher) => { for (const key in t) { if (matcher(t[key], key)) { delete t[key]; } if (isObject(t[key])) { dropKeys(t[key], matcher); } } return t; }; const deepMergeInternal = (sources, options, visited = /* @__PURE__ */ new Set()) => { const firstSource = sources.shift(); visited.add(firstSource); const merged = structuredClone(firstSource); for (const source of sources) { visited.add(source); if (Array.isArray(source) && Array.isArray(merged)) { for (const element of source) { if (!merged.includes(element)) { merged.push(element); } } } else if (isObject(source) && isObject(merged)) { for (const key in source) { const sourceValue = source[key]; if (Object.hasOwn(merged, key) && merged[key] === void 0 && options?.preferUndefined) { continue; } if (isObject(sourceValue)) { if (merged[key]) { merged[key] = deepMergeInternal( [merged[key], structuredClone(sourceValue)], options, visited ); } else { Object.assign(merged, { [key]: structuredClone(sourceValue) }); } } else { Object.assign(merged, { [key]: structuredClone(sourceValue) }); } } } } if (options?.dropKeys) { const matcher = typeof options.dropKeys === "function" ? options.dropKeys : defaultDropKeyMatcher; dropKeys(merged, matcher); } return merged; }; const deepMerge = (sources, options) => { return deepMergeInternal(sources, options); }; const fillStringWithTemplateVariables = (value, variables) => { return Object.entries(variables).reduce((acc, [variableKey, variableValue]) => { return acc.replaceAll("${" + variableKey + "}", variableValue); }, value); }; const fillObjectWithTemplateVariables = (target, variables) => { return deepMapObject(target, (_key, value) => { return typeof value === "string" ? fillStringWithTemplateVariables(value, variables) : value; }); }; const isNotNullish = (o) => o !== void 0 && o !== null; const isNullish = (o) => o === void 0 || o === null; const isPromiseLike = (candidate) => { return isNotNullish(candidate) && typeof candidate === "object" && typeof candidate["then"] === "function" && typeof candidate["catch"] === "function"; }; const mapObject = (o, map) => { return Object.fromEntries( Object.entries(o).map(([key, value]) => { return [key, map(value, key)]; }) ); }; const drySync = (isDry, whenWet, dryDefault = true) => { return isDry ? () => identity(dryDefault) : whenWet; }; const dry = (isDry, whenWet, dryDefault = true) => { return isDry ? () => identityAsync(dryDefault) : whenWet; }; const normalizeDryOption = (options) => { return { dry: options?.dry ?? false }; }; const normalizeForceOption = (options) => { return { force: options?.force ?? false }; }; const normalizeSafeOption = (options) => { return { safe: options?.safe ?? false }; }; const measureRegExpSpecificity = (r, v) => { return [...v].filter((c) => r.includes(c)).length; }; function shuffleArray(array) { let currentIndex = array.length; while (0 !== currentIndex) { const randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; const temporaryValue = array[currentIndex]; const randomValue = array[randomIndex]; if (isNotNullish(temporaryValue) && isNotNullish(randomValue)) { array[currentIndex] = randomValue; array[randomIndex] = temporaryValue; } } return array; } const arrayToObject = (a) => { return a.reduce((acc, next) => { acc[next] = next; return acc; }, {}); }; const regexpSorterOne = (a, b) => a.test(b.source) || b.test(a.source) ? -1 : a.source.localeCompare(b.source); const findMostSensibleMatch = (matchers, key) => { const matcherIndices = matchers.map((matcher, i) => matcher.test(key) ? i : void 0).filter(isNotNullish); const deviations = matcherIndices.map((matcherIndice) => { const scenario = [...matchers]; const originalMatcher = scenario[matcherIndice]; const matcherSpecificity = measureRegExpSpecificity(originalMatcher.source, key); scenario[matcherIndice] = new RegExp(key); scenario.sort(regexpSorterOne); const scenarioSortIndex = scenario.findIndex((v) => v.source === key); const deviation = Math.abs(scenarioSortIndex - matcherIndice); return { deviation, originalMatcher, matcherIndice, matcherSpecificity }; }); deviations.sort( (a, b) => a.deviation === b.deviation ? a.matcherSpecificity === b.matcherSpecificity ? a.matcherIndice === b.matcherIndice ? a.originalMatcher.source.localeCompare(b.originalMatcher.source) : b.matcherIndice - a.matcherIndice : b.matcherSpecificity - a.matcherSpecificity : a.deviation - b.deviation // The smaller the better ); return deviations[0]?.matcherIndice ?? -1; }; const findMostSensibleMatchIdeaTwo = (matchers, key) => { const matchingIndices = matchers.map( (matcher) => matcher.test(key) ? new RegExp(key) : matcher ); const sortedMatchers = [...matchingIndices]; sortedMatchers.sort(regexpSorterOne); return -1; }; const sortObject = (o, sortPreferences = []) => { const plainLevelOrder = sortPreferences.map( (pref) => typeof pref === "object" ? pref.key : pref ); const regexpLevelOrder = plainLevelOrder.map((pref) => new RegExp(pref)); const isArray = Array.isArray(o); let obj = o; if (isArray) { obj = arrayToObject(o); } const ordered = Object.entries(obj).map(([key, value]) => { let order = Number.POSITIVE_INFINITY; const plainIndex = plainLevelOrder.indexOf(key); if (plainIndex >= 0) { order = plainIndex; } else { const regexpIndices = regexpLevelOrder.map((orderingRegExp, i) => orderingRegExp.test(key) ? i : -1).filter((index) => index > -1); if (regexpIndices.length > 1) { order = findMostSensibleMatch(regexpLevelOrder, key); } else if (regexpIndices[0]) { order = regexpIndices[0]; } } if (value !== void 0 && value !== null && typeof value === "object") { const subOrdering = sortPreferences.filter((pref) => typeof pref === "object").find((preference) => new RegExp(preference.key).test(key)); return [key, sortObject(value, subOrdering?.order), order]; } else { return [key, value, order]; } }).sort(([ak, _av, aOrder], [bk, _bv, bOrder]) => { return aOrder >= 0 && bOrder >= 0 && aOrder !== bOrder ? aOrder - bOrder : ak.localeCompare(bk); }); return isArray ? ordered.map((item) => item[1]) : Object.fromEntries(ordered); }; const capitalize = (s) => { return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); }; const splitByCasing = (input) => { return input ? input.split(/(?=[A-Z][a-z])|[\s_-]+/).map((word) => word.toLowerCase()) : []; }; function camelCase(input) { const [first, ...rest] = splitByCasing(input); return (first ?? "") + rest.map(capitalize).join(""); } function kebabCase(input) { return splitByCasing(input).join("-"); } function snakeCase(input) { return splitByCasing(input).join("_"); } function upperSnakeCase(input) { return splitByCasing(input).join("_").toUpperCase(); } function pascalCase(input) { return splitByCasing(input).map(capitalize).join(""); } function trainCase(input) { return splitByCasing(input).map(capitalize).join("-"); } exports.DEFAULT_ES_TARGET_NAME = DEFAULT_ES_TARGET_NAME; exports.DEFAULT_ES_TARGET_YEAR = DEFAULT_ES_TARGET_YEAR; exports.asyncFilter = asyncFilter; exports.asyncFilterMap = asyncFilterMap; exports.asyncMap = asyncMap; exports.bufferedAllSettled = bufferedAllSettled; exports.camelCase = camelCase; exports.capitalize = capitalize; exports.closestNumber = closestNumber; exports.deepFreeze = deepFreeze; exports.deepMapObject = deepMapObject; exports.deepMerge = deepMerge; exports.defaultDropKeyMatcher = defaultDropKeyMatcher; exports.dropKeys = dropKeys; exports.dry = dry; exports.drySync = drySync; exports.fillObjectWithTemplateVariables = fillObjectWithTemplateVariables; exports.fillStringWithTemplateVariables = fillStringWithTemplateVariables; exports.findMostSensibleMatch = findMostSensibleMatch; exports.findMostSensibleMatchIdeaTwo = findMostSensibleMatchIdeaTwo; exports.groupBy = groupBy; exports.identity = identity; exports.identityAsync = identityAsync; exports.isNotNullish = isNotNullish; exports.isNullish = isNullish; exports.isObject = isObject; exports.isPromiseFulfilled = isPromiseFulfilled; exports.isPromiseLike = isPromiseLike; exports.kebabCase = kebabCase; exports.mapObject = mapObject; exports.measureRegExpSpecificity = measureRegExpSpecificity; exports.memoize = memoize; exports.noop = noop; exports.noopAsync = noopAsync; exports.normalizeDryOption = normalizeDryOption; exports.normalizeForceOption = normalizeForceOption; exports.normalizeMemoizeOptions = normalizeMemoizeOptions; exports.normalizeRegExpLikeToRegExp = normalizeRegExpLikeToRegExp; exports.normalizeSafeOption = normalizeSafeOption; exports.pascalCase = pascalCase; exports.random = random; exports.shuffleArray = shuffleArray; exports.sleep = sleep; exports.snakeCase = snakeCase; exports.sortObject = sortObject; exports.splitByCasing = splitByCasing; exports.trainCase = trainCase; exports.upperSnakeCase = upperSnakeCase; exports.yes = yes; exports.yesAsync = yesAsync;