type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; /** * Group digits. */ export type GroupDigits = `${Digit}${Digit}${Digit}`; /** * Group place. */ export type GroupPlace = bigint; /** * Group of digits and its place. * * The place refers to the order which the digits are grouped, e.g. for a number like * * 1,234,567 * * The groups would be: * * ['001', 2] * ['234', 1] * ['567', 0] * * Note that groups do not necessarily have the same length of digits, such in the case of * South Asian numbering system: * * 1,00,00,000 * * The groups would be: * * ['01', 3] * ['00', 2] * ['00', 1] * ['000', 0] */ export type Group = [GroupDigits, GroupPlace]; /** * Index of the group digits in a {@link Group|group}. */ export const GROUP_DIGITS_INDEX = 0 as const; /** * Index of the group place in a {@link Group|group}. */ export const GROUP_PLACE_INDEX = 1 as const; /** * Result of parsing a number string. */ export interface ParseResult { /** * The parsed groups. */ groups: Group[]; /** * Whether the number is negative. */ negative: boolean; } /** * System for stringifying and parsing numbers. */ export interface NumberNameSystem { /** * Creates a negative string. * @param s - The string to make negative. * @returns string The negative string. */ makeNegative: (s: string) => string; /** * Splits a string into groups. * @param value - The string to group. * @see {NumberNameSystem.combineGroups} * @returns Group[] The groups. */ splitIntoGroups: (value: string) => Group[]; /** * Creates a group string. * @param groups - The groups. * @param options - Options to use when creating the group. * @see {NumberNameSystem.parseGroups} * @returns string[] The groups represented into strings. */ stringifyGroups: (groups: Group[], options?: T) => string[]; /** * Merges tokens from stringified groups to a string. * @param tokens - The tokens to finalize. * @see {NumberNameSystem.tokenize} * @returns string The merged tokens. */ mergeTokens: (tokens: string[], options?: T) => string; /** * Tokenizes a string. * @param value - The string to tokenize. * @see {NumberNameSystem.mergeTokens} * @returns string[] The tokens. */ tokenize: (value: string) => string[]; /** * Parses groups from a string. * @param tokens - The string to parse groups from. * @see {NumberNameSystem.stringifyGroups} * @returns ParseResult The parsed groups as well as an indicator if the number is Boolean. */ parseGroups: (tokens: string[]) => ParseResult; /** * Combines groups into a string. * @param groups - The groups to combine. * @param negative - Whether the number is negative. * @see {NumberNameSystem.splitIntoGroups} * @returns string The combined groups in exponential form. */ combineGroups: (groups: Group[], negative: boolean) => string; } /** * Allowed value type for {@link stringify}. */ export type AllowedValue = string | number | bigint; /** * Array of allowed types for {@link parse}. */ export const ALLOWED_PARSE_RESULT_TYPES = [ 'string', 'number', 'bigint', ] as const; /** * Allowed type for {@link parse}. */ export type ParseResultType = typeof ALLOWED_PARSE_RESULT_TYPES[number]; /** * Error thrown when an invalid token is encountered. */ export class InvalidTokenError extends Error { constructor(token: string) { super(`Invalid token: ${token}`); } } /** * Gets the maximum value from a list of bigints. * @param b - The bigints to get the maximum value from. * @returns bigint The maximum value. */ export const bigIntMax = (...b: bigint[]) => b.reduce( (previousMax, current) => { if (typeof previousMax === 'undefined') { return current; } return previousMax > current ? previousMax : current; }, undefined as bigint | undefined, ); /** * Gets the minimum value from a list of bigints. * @param b - The bigints to get the minimum value from. * @returns bigint The minimum value. */ export const bigIntMin = (...b: bigint[]) => b.reduce( (previousMin, current) => { if (typeof previousMin === 'undefined') { return current; } return previousMin < current ? previousMin : current; }, undefined as bigint | undefined, );