@w3ux/utils
Version:
A collection of reusable utilities for manipulating data
1 lines • 33.2 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/base.ts","../src/convert.ts","../src/unit.ts"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nexport * from './base'\nexport * from './convert'\nexport * from './unit'\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { encodeAddress } from 'dedot/utils'\n\n/**\n * Ensures a number has at least the specified number of decimal places, retaining commas in the output if they are present in the input.\n *\n * @function minDecimalPlaces\n * @param {string | number | BigInt} val - The input number, which can be a `string` with or without commas, a `number`, or a `BigInt`.\n * @param {number} minDecimals - The minimum number of decimal places to enforce.\n * @returns {string} The formatted number as a string, padded with zeros if needed to meet `minDecimals`, retaining commas if originally provided.\n * If `val` is invalid, returns \"0\".\n * @example\n * // Pads \"1,234.5\" to have at least 3 decimal places, with commas\n * minDecimalPlaces(\"1,234.5\", 3); // returns \"1,234.500\"\n *\n * // Returns \"1234.56\" unchanged\n * minDecimalPlaces(1234.56, 2); // returns \"1234.56\"\n *\n * // Pads BigInt 1234 with 2 decimals\n * minDecimalPlaces(BigInt(1234), 2); // returns \"1234.00\"\n */\nexport const minDecimalPlaces = (\n val: string | number | bigint,\n minDecimals: number\n): string => {\n try {\n // Determine if we should retain commas based on original input type\n const retainCommas = typeof val === 'string' && val.includes(',')\n\n // Convert `val` to a plain string for processing\n const strVal =\n typeof val === 'string' ? val.replace(/,/g, '') : val.toString()\n\n // Separate integer and decimal parts\n const [integerPart, fractionalPart = ''] = strVal.split('.')\n\n // Parse the integer part as a BigInt\n const whole = BigInt(integerPart || '0')\n\n // Calculate missing decimal places\n const missingDecimals = minDecimals - fractionalPart.length\n\n // Format the integer part back with commas only if the input had commas\n const formattedWhole = retainCommas\n ? Intl.NumberFormat('en-US').format(whole)\n : whole.toString()\n\n // If missing decimals are needed, pad with zeros; otherwise, return the original value\n return missingDecimals > 0\n ? `${formattedWhole}.${fractionalPart}${'0'.repeat(missingDecimals)}`\n : `${formattedWhole}.${fractionalPart}`\n } catch (e) {\n // The provided value is not a valid number, return \"0\".\n return '0'\n }\n}\n\n/**\n * @name camelize\n * @summary Converts a string of text to camelCase.\n */\nexport const camelize = (str: string) => {\n const convertToString = (string: string) => {\n if (string) {\n if (typeof string === 'string') {\n return string\n }\n return String(string)\n }\n return ''\n }\n\n const toWords = (inp: string) =>\n convertToString(inp).match(\n /[A-Z\\xC0-\\xD6\\xD8-\\xDE]?[a-z\\xDF-\\xF6\\xF8-\\xFF]+|[A-Z\\xC0-\\xD6\\xD8-\\xDE]+(?![a-z\\xDF-\\xF6\\xF8-\\xFF])|\\d+/g\n )\n\n const simpleCamelCase = (inp: string[]) => {\n let result = ''\n for (let i = 0; i < inp?.length; i++) {\n const currString = inp[i]\n let tmpStr = currString.toLowerCase()\n if (i != 0) {\n tmpStr =\n tmpStr.slice(0, 1).toUpperCase() + tmpStr.slice(1, tmpStr.length)\n }\n result += tmpStr\n }\n return result\n }\n\n const w = toWords(str)?.map((a) => a.toLowerCase())\n return simpleCamelCase(w || [])\n}\n\n/**\n * @name ellipsisFn\n * @summary Receives an address and creates ellipsis on the given string, based on parameters.\n * @param str - The string to apply the ellipsis on\n * @param amount - The amount of characters that the ellipsis will be\n * @param position - where the ellipsis will apply; if center the amount of character is the\n * same for beginning and end; if \"start\" or \"end\" then its only once the amount; defaults to \"start\"\n */\nexport const ellipsisFn = (\n str: string,\n amount = 6,\n position: 'start' | 'end' | 'center' = 'center'\n) => {\n const half = str.length / 2\n\n // having an amount less than 4 is a bit extreme so we default there\n if (amount <= 4) {\n if (position === 'center') {\n return str.slice(0, 4) + '...' + str.slice(-4)\n }\n if (position === 'end') {\n return str.slice(0, 4) + '...'\n }\n return '...' + str.slice(-4)\n }\n // if the amount requested is in a \"logical\" amount - meaning that it can display the address\n // without repeating the same information twice - then go for it;\n if (position === 'center') {\n return amount >= (str.length - 2) / 2\n ? str.slice(0, half - 3) + '...' + str.slice(-(half - 3))\n : str.slice(0, amount) + '...' + str.slice(-amount)\n }\n // else, the user has been mistaskenly extreme, so just show the maximum possible amount\n if (amount >= str.length) {\n if (position === 'end') {\n return str.slice(0, str.length - 3) + '...'\n }\n return '...' + str.slice(-(str.length - 3))\n } else {\n if (position === 'end') {\n return str.slice(0, amount) + '...'\n }\n return '...' + str.slice(amount)\n }\n}\n\n/**\n * @name pageFromUri\n * @summary Use url variables to load the default components upon the first page visit.\n */\nexport const pageFromUri = (pathname: string, fallback: string) => {\n const lastUriItem = pathname.substring(pathname.lastIndexOf('/') + 1)\n const page = lastUriItem.trim() === '' ? fallback : lastUriItem\n return page.trim()\n}\n\n/**\n * @name rmCommas\n * @summary Removes the commas from a string.\n */\nexport const rmCommas = (val: string): string => val.replace(/,/g, '')\n\n/**\n * @name rmDecimals\n * @summary Removes the decimal point and decimals from a string.\n */\nexport const rmDecimals = (str: string) => str.split('.')[0]\n\n/**\n * @name shuffle\n * @summary Shuffle a set of objects.\n */\nexport const shuffle = <T>(array: T[]) => {\n let currentIndex = array.length\n let randomIndex\n while (currentIndex !== 0) {\n randomIndex = Math.floor(Math.random() * currentIndex)\n currentIndex--\n ;[array[currentIndex], array[randomIndex]] = [\n array[randomIndex],\n array[currentIndex],\n ]\n }\n return array\n}\n\n/**\n * @name withTimeout\n * @summary Timeout a promise after a specified number of milliseconds.\n */\nexport const withTimeout = (\n ms: number,\n promise: Promise<unknown>,\n options?: {\n onTimeout?: () => void\n }\n) => {\n const timeout = new Promise((resolve) =>\n setTimeout(async () => {\n if (typeof options?.onTimeout === 'function') {\n options.onTimeout()\n }\n resolve(undefined)\n }, ms)\n )\n return Promise.race([promise, timeout])\n}\n\n/**\n * @name withTimeoutThrow\n * @summary Timeout a promise after a specified number of milliseconds by throwing an error\n */\nexport const withTimeoutThrow = <T>(\n ms: number,\n promise: Promise<T>,\n options?: {\n onTimeout?: () => void\n }\n) => {\n const timeout = new Promise((reject) =>\n setTimeout(async () => {\n if (typeof options?.onTimeout === 'function') {\n options.onTimeout()\n }\n reject('Function timeout')\n }, ms)\n )\n return Promise.race([promise, timeout])\n}\n\n/**\n * @name appendOrEmpty\n * @summary Returns ` value` if a condition is truthy, or an empty string otherwise.\n */\nexport const appendOrEmpty = (\n condition: boolean | string | undefined,\n value: string\n) => (condition ? ` ${value}` : '')\n\n/**\n * @name appendOr\n * @summary Returns ` value` if condition is truthy, or ` fallback` otherwise.\n */\nexport const appendOr = (\n condition: boolean | string | undefined,\n value: string,\n fallback: string\n) => (condition ? ` ${value}` : ` ${fallback}`)\n\n/**\n * @name formatAccountSs58\n * @summary Formats an address with the supplied ss58 prefix, or returns null if invalid.\n */\nexport const formatAccountSs58 = (\n address: string,\n ss58Prefix: number\n): string | null => {\n try {\n return encodeAddress(address, ss58Prefix)\n } catch (e) {\n return null\n }\n}\n\n/**\n * @name removeHexPrefix\n * @summary Takes a string str as input and returns a new string with the \"0x\" prefix removed if it\n * exists at the beginning of the input string.\n */\nexport const removeHexPrefix = (str: string): string => str.replace(/^0x/, '')\n\n// Check if 2 sets contain the same elements.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const eqSet = (xs: Set<any>, ys: Set<any>) =>\n xs.size === ys.size && [...xs].every((x) => ys.has(x))\n\n// Check if one set contains all the elements of another set.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const isSuperset = (set: Set<any>, subset: Set<any>) => {\n for (const elem of subset) {\n if (!set.has(elem)) {\n return false\n }\n }\n return true\n}\n\n/**\n * Finds the maximum value among a list of BigInt values.\n *\n * @function maxBigInt\n * @param {...bigint} values - A list of BigInt values to compare.\n * @returns {bigint} The largest BigInt value in the provided list.\n * @example\n * // Returns the maximum BigInt value\n * maxBigInt(10n, 50n, 30n, 100n, 20n); // 100n\n */\nexport const maxBigInt = (...values: bigint[]): bigint =>\n values.reduce((max, current) => (current > max ? current : max))\n\n/**\n * Finds the minimum value among a list of BigInt values.\n *\n * @function minBigInt\n * @param {...bigint} values - A list of BigInt values to compare.\n * @returns {bigint} The smallest BigInt value in the provided list.\n * @example\n * // Returns the minimum BigInt value\n * minBigInt(10n, 50n, 30n, 100n, 20n); // 10n\n */\nexport const minBigInt = (...values: bigint[]): bigint =>\n values.reduce((min, current) => (current < min ? current : min))\n","// /* @license Copyright 2024 w3ux authors & contributors\n// SPDX-License-Identifier: GPL-3.0-only */\n\n/**\n * Concatenates multiple Uint8Array instances into a single Uint8Array.\n *\n * @param {Uint8Array[]} u8as - An array of Uint8Array instances to concatenate.\n * @returns {Uint8Array} A new Uint8Array containing all the input arrays concatenated.\n */\nexport const u8aConcat = (...u8as: Uint8Array[]): Uint8Array => {\n // Calculate the total length of the resulting Uint8Array\n const totalLength = u8as.reduce((sum, u8a) => sum + u8a.length, 0)\n\n // Create a new Uint8Array with the total length\n const result = new Uint8Array(totalLength)\n\n let offset = 0 // Initialize the offset for placing elements\n for (const u8a of u8as) {\n result.set(u8a, offset) // Set the current Uint8Array at the current offset\n offset += u8a.length // Update the offset for the next Uint8Array\n }\n\n return result\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { decodeAddress } from 'dedot/utils'\nimport type { RefObject } from 'react'\nimport { rmCommas, rmDecimals } from './base'\nimport type { AnyObject } from './types'\n\n/**\n * Converts an on-chain balance value from planck to a decimal value in token units.\n *\n * @function planckToUnit\n * @param {number | BigInt | string} val - The balance value in planck. Accepts a `number`, `BigInt`, or `string`.\n * @param {number} units - The number of decimal places in the token unit (10^units planck per 1 token).\n * @returns {string} The equivalent token unit value as a decimal string.\n * @example\n * // Convert 1500000000000 planck to tokens with 12 decimal places\n * planckToUnit(\"1500000000000\", 12); // returns \"1.5\"\n */\nexport const planckToUnit = (\n val: number | bigint | string,\n units: number\n): string => {\n try {\n // Ensure `units` is a positive integer.\n units = Math.max(Math.round(units), 0)\n\n // Convert `val` to BigInt based on its type\n const bigIntVal =\n typeof val === 'bigint'\n ? val\n : BigInt(\n typeof val === 'number'\n ? Math.floor(val).toString()\n : rmDecimals(rmCommas(val))\n )\n\n const divisor = units === 0 ? 1n : BigInt(10) ** BigInt(units)\n\n // Integer division and remainder for the fractional part\n const integerPart = bigIntVal / divisor\n const fractionalPart = bigIntVal % divisor\n\n // Format fractional part with leading zeros to maintain `units` decimal places\n const fractionalStr =\n units > 0 ? `.${fractionalPart.toString().padStart(units, '0')}` : ``\n\n // Combine integer and fractional parts as a decimal string\n return `${integerPart}${fractionalStr}`\n } catch (e) {\n return '0'\n }\n}\n\n/**\n * Converts a token unit value to an integer value in planck.\n *\n * @function unitToPlanck\n * @param {string | number | BigInt} val - The token unit value to convert. Accepts a string, number, or BigInt.\n * @param {number} units - The number of decimal places for conversion (10^units planck per 1 token).\n * @returns {BigInt} The equivalent value in planck as a BigInt.\n * @example\n * // Convert \"1.5\" tokens to planck with 12 decimal places\n * unitToPlanck(\"1.5\", 12); // returns BigInt(\"1500000000000\")\n */\nexport const unitToPlanck = (\n val: string | number | bigint,\n units: number\n): bigint => {\n try {\n // Ensure `units` is a positive integer.\n units = Math.max(Math.round(units), 0)\n\n // Convert `val` to a string; if empty or invalid, default to \"0\"\n const strVal =\n (typeof val === 'string' ? rmCommas(val) : val.toString()) || '0'\n\n // Split into integer and fractional parts\n const [integerPart, fractionalPart = ''] = strVal.split('.')\n\n // Process the integer part by converting to BigInt and scaling it to the given units\n let bigIntValue = BigInt(integerPart) * BigInt(10) ** BigInt(units)\n\n // Process the fractional part if it exists\n if (fractionalPart) {\n let fractionalValue: bigint\n\n if (fractionalPart.length > units) {\n // If fractional part exceeds units, truncate it\n fractionalValue = BigInt(fractionalPart.slice(0, units))\n } else {\n // Otherwise, pad the fractional part to match units\n fractionalValue = BigInt(fractionalPart.padEnd(units, '0'))\n }\n\n bigIntValue += fractionalValue\n }\n\n return bigIntValue\n } catch (e) {\n return BigInt(0)\n }\n}\n\n/**\n * @name remToUnit\n * @summary Converts a rem string to a number.\n */\nexport const remToUnit = (rem: string) =>\n Number(rem.slice(0, rem.length - 3)) *\n parseFloat(getComputedStyle(document.documentElement).fontSize)\n\n/**\n * @name capitalizeFirstLetter\n * @summary Capitalize the first letter of a string.\n */\nexport const capitalizeFirstLetter = (string: string) =>\n string.charAt(0).toUpperCase() + string.slice(1)\n\n/**\n * @name snakeToCamel\n * @summary converts a string from snake / kebab-case to camel-case.\n */\nexport const snakeToCamel = (str: string) =>\n str\n .toLowerCase()\n .replace(/([-_][a-z])/g, (group) =>\n group.toUpperCase().replace('-', '').replace('_', '')\n )\n\n/**\n * @name setStateWithRef\n * @summary Synchronize React state and its reference with the provided value.\n */\nexport const setStateWithRef = <T>(\n value: T,\n setState: (_state: T) => void,\n ref: RefObject<T>\n): void => {\n setState(value)\n ref.current = value\n}\n\n/**\n * @name localStorageOrDefault\n * @summary Retrieve the local stroage value with the key, return defult value if it is not\n * found.\n */\nexport const localStorageOrDefault = <T>(\n key: string,\n _default: T,\n parse = false\n): T | string => {\n const val: string | null = localStorage.getItem(key)\n\n if (val === null) {\n return _default\n }\n\n if (parse) {\n return JSON.parse(val) as T\n }\n return val\n}\n\n/**\n * @name isValidAddress\n * @summary Return whether an address is valid Substrate address.\n */\nexport const isValidAddress = (address: string): boolean => {\n try {\n decodeAddress(address)\n return true\n } catch (e) {\n return false\n }\n}\n\n/**\n * @name extractUrlValue\n * @summary Extracts a URL value from a URL string.\n */\nexport const extractUrlValue = (key: string, url?: string) => {\n if (typeof url === 'undefined') {\n url = window.location.href\n }\n const match = url.match(`[?&]${key}=([^&]+)`)\n return match ? match[1] : null\n}\n\n/**\n * @name varToUrlHash\n * @summary Puts a variable into the URL hash as a param.\n * @description\n * Since url variables are added to the hash and are not treated as URL params, the params are split\n * and parsed into a `URLSearchParams`.\n */\nexport const varToUrlHash = (\n key: string,\n val: string,\n addIfMissing: boolean\n) => {\n const hash = window.location.hash\n const [page, params] = hash.split('?')\n const searchParams = new URLSearchParams(params)\n\n if (searchParams.get(key) === null && !addIfMissing) {\n return\n }\n searchParams.set(key, val)\n window.location.hash = `${page}?${searchParams.toString()}`\n}\n\n/**\n * @name removeVarFromUrlHash\n * @summary\n * Removes a variable `key` from the URL hash if it exists. Removes dangling `?` if no URL variables\n * exist.\n */\nexport const removeVarFromUrlHash = (key: string) => {\n const hash = window.location.hash\n const [page, params] = hash.split('?')\n const searchParams = new URLSearchParams(params)\n if (searchParams.get(key) === null) {\n return\n }\n searchParams.delete(key)\n const paramsAsStr = searchParams.toString()\n window.location.hash = `${page}${paramsAsStr ? `?${paramsAsStr}` : ``}`\n}\n\n/**\n * @name sortWithNull\n * @summary Sorts an array with nulls last.\n */\nexport const sortWithNull =\n (ascending: boolean) => (a: unknown, b: unknown) => {\n // if both items are undefined, treat them as equal\n if (typeof a === 'undefined' && typeof b === 'undefined') {\n return 0\n }\n // if either item is undefined, sort it last\n if (typeof a === 'undefined' || typeof b === 'undefined') {\n return typeof a === 'undefined' ? 1 : -1\n }\n // equal items sort equally\n if (a === b) {\n return 0\n }\n // nulls sort after anything else\n if (a === null) {\n return 1\n }\n if (b === null) {\n return -1\n }\n // otherwise, if we're ascending, lowest sorts first\n if (ascending) {\n return a < b ? -1 : 1\n }\n // if descending, highest sorts first\n return a < b ? 1 : -1\n }\n\n/**\n * @name applyWidthAsPadding\n * @summary Applies width of subject to paddingRight of container.\n */\nexport const applyWidthAsPadding = (\n subjectRef: RefObject<HTMLDivElement | null>,\n containerRef: RefObject<HTMLDivElement | null>\n) => {\n if (containerRef.current && subjectRef.current) {\n containerRef.current.style.paddingRight = `${\n subjectRef.current.offsetWidth + remToUnit('1rem')\n }px`\n }\n}\n\n/**\n * @name unescape\n * @summary Replaces \\” with “\n */\nexport const unescape = (val: string) => val.replace(/\\\\\"/g, '\"')\n\n/**\n * @name inChrome\n * @summary Whether the application is rendering in Chrome.\n */\nexport const inChrome = () => {\n const isChromium = (window as Window & { chrome?: boolean })?.chrome || null\n const winNav = (window as Window)?.navigator || null\n const isOpera =\n typeof (window as Window & { opr?: boolean })?.opr !== 'undefined'\n const isIEedge = winNav?.userAgent.indexOf('Edg') > -1 || false\n const isIOSChrome = winNav?.userAgent.match('CriOS') || false\n\n if (isIOSChrome) {\n return true\n }\n if (\n isChromium !== null &&\n typeof isChromium !== 'undefined' &&\n isOpera === false &&\n isIEedge === false\n ) {\n return true\n }\n return false\n}\n\n/**\n * @name addedTo\n * @summary Given 2 objects and some keys, return items in the fresh object that do not exist in the\n * stale object by matching the given common key values of both objects.\n */\nexport const addedTo = (\n fresh: AnyObject[],\n stale: AnyObject[],\n keys: string[]\n): AnyObject[] =>\n typeof fresh !== 'object' || typeof stale !== 'object' || !keys.length\n ? []\n : fresh.filter(\n (freshItem) =>\n !stale.find((staleItem) =>\n keys.every((key) =>\n !(key in staleItem) || !(key in freshItem)\n ? false\n : staleItem[key] === freshItem[key]\n )\n )\n )\n\n/**\n * @name removedFrom\n * @summary Given 2 objects and some keys, return items in the stale object that do not exist in the\n * fresh object by matching the given common key values of both objects.\n */\nexport const removedFrom = (\n fresh: AnyObject[],\n stale: AnyObject[],\n keys: string[]\n): AnyObject[] =>\n typeof fresh !== 'object' || typeof stale !== 'object' || !keys.length\n ? []\n : stale.filter(\n (staleItem) =>\n !fresh.find((freshItem) =>\n keys.every((key) =>\n !(key in staleItem) || !(key in freshItem)\n ? false\n : freshItem[key] === staleItem[key]\n )\n )\n )\n\n/**\n * @name matchedProperties\n * @summary Given 2 objects and some keys, return items in object 1 that also exist in object 2 by\n * matching the given common key values of both objects.\n */\nexport const matchedProperties = (\n objX: AnyObject[],\n objY: AnyObject[],\n keys: string[]\n): AnyObject[] =>\n typeof objX !== 'object' || typeof objY !== 'object' || !keys.length\n ? []\n : objY.filter((x) =>\n objX.find((y) =>\n keys.every((key) =>\n !(key in x) || !(key in y) ? false : y[key] === x[key]\n )\n )\n )\n\n/**\n * @name isValidHttpUrl\n * @summary Give a string, return whether it is a valid http URL.\n * @param string - The string to check.\n */\nexport const isValidHttpUrl = (string: string) => {\n let url: URL\n try {\n url = new URL(string)\n } catch (_) {\n return false\n }\n return url.protocol === 'http:' || url.protocol === 'https:'\n}\n\n/**\n * @name makeCancelable\n * @summary Makes a promise cancellable.\n * @param promise - The promise to make cancellable.\n */\nexport const makeCancelable = (promise: Promise<AnyObject>) => {\n let hasCanceled = false\n\n const wrappedPromise = new Promise((resolve, reject) => {\n promise.then((val) =>\n hasCanceled ? reject(Error('Cancelled')) : resolve(val)\n )\n promise.catch((error) =>\n hasCanceled ? reject(Error('Cancelled')) : reject(error)\n )\n })\n\n return {\n promise: wrappedPromise,\n cancel: () => {\n hasCanceled = true\n },\n }\n}\n\n/**\n * @name unimplemented\n * @summary A placeholder function to signal a deliberate unimplementation.\n * Consumes an arbitrary number of props.\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport const unimplemented = ({ ...props }) => {\n /* unimplemented */\n}\n\n/**\n * Deep merge two objects.\n * @param target\n * @param ...sources\n */\n\nexport const mergeDeep = (\n target: AnyObject,\n ...sources: AnyObject[]\n): AnyObject => {\n if (!sources.length) {\n return target\n }\n\n const isObject = (item: AnyObject) =>\n item && typeof item === 'object' && !Array.isArray(item)\n const source = sources.shift()\n\n if (isObject(target) && isObject(source)) {\n for (const key in source) {\n if (isObject(source[key])) {\n if (!target[key]) {\n Object.assign(target, { [key]: {} })\n }\n mergeDeep(target[key], source[key])\n } else {\n Object.assign(target, { [key]: source[key] })\n }\n }\n }\n return mergeDeep(target, ...sources)\n}\n"],"mappings":"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","names":["import_utils"]}