UNPKG

numeric-quantity

Version:

Number parser with support for mixed numbers, vulgar fractions, and Roman numerals

245 lines 10.2 kB
//#region src/types.d.ts interface NumericQuantityOptions { /** * Round the result to this many decimal places. Defaults to 3; must * be greater than or equal to zero. * * @default 3 */ round?: number | false; /** * Allow and ignore trailing invalid characters _à la_ `parseFloat`. * * @default false */ allowTrailingInvalid?: boolean; /** * Attempt to parse Roman numerals if Arabic numeral parsing fails. * * @default false */ romanNumerals?: boolean; /** * Generates a `bigint` value if the string represents * a valid integer too large for the `number` type. */ bigIntOnOverflow?: boolean; /** * Specifies which character ("." or ",") to treat as the decimal separator. * * @default "." */ decimalSeparator?: "," | "."; /** * Allow and strip currency symbols (Unicode `\p{Sc}` category) from the * start and/or end of the string. * * @default false */ allowCurrency?: boolean; /** * Parse percentage strings by stripping the `%` suffix. * - `'decimal'` or `true`: `"50%"` → `0.5` (divide by 100) * - `'number'`: `"50%"` → `50` (strip `%`, keep value) * - `false` or omitted: `"50%"` → `NaN` (default behavior) * * @default false */ percentage?: "decimal" | "number" | boolean; /** * Return a verbose result object with additional parsing metadata. * * @default false */ verbose?: boolean; } /** * Resolves the return type of {@link numericQuantity} based on the options provided. */ type NumericQuantityReturnType<T extends NumericQuantityOptions | undefined = undefined> = T extends { verbose: true; } ? NumericQuantityVerboseResult : T extends { bigIntOnOverflow: true; } ? number | bigint : number; /** * Verbose result returned when `verbose: true` is set. */ interface NumericQuantityVerboseResult { /** The parsed numeric value (NaN if invalid). */ value: number | bigint; /** The original input string. */ input: string; /** Currency symbol(s) stripped from the start, if any. */ currencyPrefix?: string; /** Currency symbol(s) stripped from the end, if any. */ currencySuffix?: string; /** True if a `%` suffix was stripped. */ percentageSuffix?: boolean; /** Trailing invalid (usually non-numeric) characters detected in the input, if any. Populated even when `allowTrailingInvalid` is `false`. */ trailingInvalid?: string; /** The leading sign character (`'-'` or `'+'`), if present. Omitted when no explicit sign was in the input. */ sign?: "-" | "+"; /** The whole-number part of a mixed fraction (e.g. `1` from `"1 2/3"`). Omitted for pure fractions, decimals, and integers. */ whole?: number; /** The numerator of a fraction (e.g. `2` from `"1 2/3"`, or `1` from `"1/2"`). Always unsigned. */ numerator?: number; /** The denominator of a fraction (e.g. `3` from `"1 2/3"`, or `2` from `"1/2"`). Always unsigned. */ denominator?: number; } /** * Unicode vulgar fraction code points. */ type VulgarFraction = "¼" | "½" | "¾" | "⅐" | "⅑" | "⅒" | "⅓" | "⅔" | "⅕" | "⅖" | "⅗" | "⅘" | "⅙" | "⅚" | "⅛" | "⅜" | "⅝" | "⅞" | "⅟"; /** * Unicode superscript digit code points. */ type SuperscriptDigit = "⁰" | "¹" | "²" | "³" | "⁴" | "⁵" | "⁶" | "⁷" | "⁸" | "⁹"; /** * Unicode subscript digit code points. */ type SubscriptDigit = "₀" | "₁" | "₂" | "₃" | "₄" | "₅" | "₆" | "₇" | "₈" | "₉"; /** * Allowable Roman numeral characters (ASCII, uppercase only). */ type RomanNumeralAscii = "I" | "V" | "X" | "L" | "C" | "D" | "M"; /** * Unicode Roman numeral code points (uppercase and lowercase, * representing 1-12, 50, 100, 500, and 1000). */ type RomanNumeralUnicode = "Ⅰ" | "Ⅱ" | "Ⅲ" | "Ⅳ" | "Ⅴ" | "Ⅵ" | "Ⅶ" | "Ⅷ" | "Ⅸ" | "Ⅹ" | "Ⅺ" | "Ⅻ" | "Ⅼ" | "Ⅽ" | "Ⅾ" | "Ⅿ" | "ⅰ" | "ⅱ" | "ⅲ" | "ⅳ" | "ⅴ" | "ⅵ" | "ⅶ" | "ⅷ" | "ⅸ" | "ⅹ" | "ⅺ" | "ⅻ" | "ⅼ" | "ⅽ" | "ⅾ" | "ⅿ"; /** * Union of ASCII and Unicode Roman numeral characters/code points. */ type RomanNumeral = RomanNumeralAscii | RomanNumeralUnicode; //#endregion //#region src/constants.d.ts /** * Normalizes non-ASCII decimal digits to ASCII digits. * Converts characters from Unicode decimal digit blocks (e.g., Arabic-Indic, * Devanagari, Bengali) to their ASCII equivalents (0-9). * * All current Unicode \p{Nd} blocks are included in decimalDigitBlockStarts. */ declare const normalizeDigits: (str: string) => string; /** * Map of Unicode superscript and subscript digit code points to ASCII digits. */ declare const superSubDigitToAsciiMap: Record<SuperscriptDigit | SubscriptDigit, string>; /** * Captures Unicode superscript and subscript digits. */ declare const superSubDigitsRegex: RegExp; /** * Map of Unicode fraction code points to their ASCII equivalents. */ declare const vulgarFractionToAsciiMap: Record<VulgarFraction, `${number}/${number | ""}`>; /** * Captures the individual elements of a numeric string. Commas and underscores are allowed * as separators, as long as they appear between digits and are not consecutive. * * Capture groups: * * | # | Description | Example(s) | * | --- | ------------------------------------------------ | ------------------------------------------------------------------- | * | `0` | entire string | `"2 1/3"` from `"2 1/3"` | * | `1` | sign (`-` or `+`) | `"-"` from `"-2 1/3"` | * | `2` | whole number or numerator | `"2"` from `"2 1/3"`; `"1"` from `"1/3"` | * | `3` | entire fraction, decimal portion, or denominator | `" 1/3"` from `"2 1/3"`; `".33"` from `"2.33"`; `"/3"` from `"1/3"` | * * _Capture group 2 may include comma/underscore separators._ * * @example * * ```ts * numericRegex.exec("1") // [ "1", "1", null, null ] * numericRegex.exec("1.23") // [ "1.23", "1", ".23", null ] * numericRegex.exec("1 2/3") // [ "1 2/3", "1", " 2/3", " 2" ] * numericRegex.exec("2/3") // [ "2/3", "2", "/3", null ] * numericRegex.exec("2 / 3") // [ "2 / 3", "2", "/ 3", null ] * ``` */ declare const numericRegex: RegExp; /** * Same as {@link numericRegex}, but allows (and ignores) trailing invalid characters. * Capture group 7 contains the trailing invalid portion. */ declare const numericRegexWithTrailingInvalid: RegExp; /** * Captures any Unicode vulgar fractions. */ declare const vulgarFractionsRegex: RegExp; type RomanNumeralSequenceFragment = `${RomanNumeralAscii}` | `${RomanNumeralAscii}${RomanNumeralAscii}` | `${RomanNumeralAscii}${RomanNumeralAscii}${RomanNumeralAscii}` | `${RomanNumeralAscii}${RomanNumeralAscii}${RomanNumeralAscii}${RomanNumeralAscii}`; /** * Map of Roman numeral sequences to their decimal equivalents. */ declare const romanNumeralValues: { [k in RomanNumeralSequenceFragment]?: number }; /** * Map of Unicode Roman numeral code points to their ASCII equivalents. */ declare const romanNumeralUnicodeToAsciiMap: Record<RomanNumeralUnicode, keyof typeof romanNumeralValues>; /** * Captures all Unicode Roman numeral code points. */ declare const romanNumeralUnicodeRegex: RegExp; /** * Captures a valid Roman numeral sequence. * * Capture groups: * * | # | Description | Example | * | --- | --------------- | ------------------------ | * | `0` | Entire string | "MCCXIV" from "MCCXIV" | * | `1` | Thousands | "M" from "MCCXIV" | * | `2` | Hundreds | "CC" from "MCCXIV" | * | `3` | Tens | "X" from "MCCXIV" | * | `4` | Ones | "IV" from "MCCXIV" | * * @example * * ```ts * romanNumeralRegex.exec("M") // [ "M", "M", "", "", "" ] * romanNumeralRegex.exec("XII") // [ "XII", "", "", "X", "II" ] * romanNumeralRegex.exec("MCCXIV") // [ "MCCXIV", "M", "CC", "X", "IV" ] * ``` */ declare const romanNumeralRegex: RegExp; /** * Default options for {@link numericQuantity}. */ declare const defaultOptions: Required<NumericQuantityOptions>; //#endregion //#region src/isNumericQuantity.d.ts /** * Checks if a string represents a valid numeric quantity. * * Returns `true` if the string can be parsed as a number, `false` otherwise. * Accepts the same options as `numericQuantity`. */ declare const isNumericQuantity: (quantity: string | number, options?: NumericQuantityOptions) => boolean; //#endregion //#region src/numericQuantity.d.ts /** * Converts a string to a number, like an enhanced version of `parseFloat`. * * The string can include mixed numbers, vulgar fractions, or Roman numerals. * Input is expected to be a `string`, but will be coerced to `string` if necessary. * * @param quantity - The value to parse as a numeric quantity. * @param options - Optional settings to control parsing behavior. */ declare function numericQuantity(quantity: unknown): number; declare function numericQuantity<T extends NumericQuantityOptions>(quantity: unknown, options: T): NumericQuantityReturnType<T>; declare function numericQuantity(quantity: unknown, options?: NumericQuantityOptions): number; //#endregion //#region src/parseRomanNumerals.d.ts /** * Converts a string of Roman numerals to a number, like `parseInt` * for Roman numerals. Uses modern, strict rules (only 1 to 3999). * * The string can include ASCII representations of Roman numerals * or Unicode Roman numeral code points (`U+2160` through `U+217F`). */ declare const parseRomanNumerals: (romanNumerals: string) => number; //#endregion export { NumericQuantityOptions, NumericQuantityReturnType, NumericQuantityVerboseResult, RomanNumeral, RomanNumeralAscii, RomanNumeralUnicode, SubscriptDigit, SuperscriptDigit, VulgarFraction, defaultOptions, isNumericQuantity, normalizeDigits, numericQuantity, numericRegex, numericRegexWithTrailingInvalid, parseRomanNumerals, romanNumeralRegex, romanNumeralUnicodeRegex, romanNumeralUnicodeToAsciiMap, romanNumeralValues, superSubDigitToAsciiMap, superSubDigitsRegex, vulgarFractionToAsciiMap, vulgarFractionsRegex }; //# sourceMappingURL=numeric-quantity.production.d.mts.map