UNPKG

@visulima/humanizer

Version:

Humanizer is a library for humanizing data in a human-readable form.

244 lines (242 loc) 6.01 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); const BYTE_SIZES = { iec: [ { long: "Bytes", short: "B" }, { long: "Kibibytes", short: "KiB" }, { long: "Mebibytes", short: "MiB" }, { long: "Gibibytes", short: "GiB" }, { long: "Tebibytes", short: "TiB" }, { long: "Pebibytes", short: "PiB" }, { long: "Exbibytes", short: "EiB" }, { long: "Zebibytes", short: "ZiB" }, { long: "Yobibytes", short: "YiB" } ], iec_octet: [ { long: "Octets", short: "o" }, { long: "Kibioctets", short: "Kio" }, { long: "Mebioctets", short: "Mio" }, { long: "Gibioctets", short: "Gio" }, { long: "Tebioctets", short: "Tio" }, { long: "Pebioctets", short: "Pio" }, { long: "Exbioctets", short: "Eio" }, { long: "Zebioctets", short: "Zio" }, { long: "Yobioctets", short: "Yio" } ], metric: [ { long: "Bytes", short: "Bytes" }, { long: "Kilobytes", short: "KB" }, { long: "Megabytes", short: "MB" }, { long: "Gigabytes", short: "GB" }, { long: "Terabytes", short: "TB" }, { long: "Petabytes", short: "PB" }, { long: "Exabytes", short: "EB" }, { long: "Zettabytes", short: "ZB" }, { long: "Yottabytes", short: "YB" } ], metric_octet: [ { long: "Octets", short: "o" }, { long: "Kilo-octets", short: "ko" }, { long: "Mega-octets", short: "Mo" }, { long: "Giga-octets", short: "Go" }, { long: "Tera-octets", short: "To" }, { long: "Peta-octets", short: "Po" }, { long: "Exa-octets", short: "Eo" }, { long: "Zetta-octets", short: "Zo" }, { long: "Yotta-octets", short: "Yo" } ] }; const parseLocalizedNumber = /* @__PURE__ */ __name((stringNumber, locale) => { const thousandSeparator = new Intl.NumberFormat(locale).format(11111).replaceAll(new RegExp("\\p{Number}", "gu"), ""); const decimalSeparator = new Intl.NumberFormat(locale).format(1.1).replaceAll(new RegExp("\\p{Number}", "gu"), ""); return Number.parseFloat(stringNumber.replaceAll(new RegExp(`\\${thousandSeparator}`, "g"), "").replace(new RegExp(`\\${decimalSeparator}`), ".")); }, "parseLocalizedNumber"); const fromBase = /* @__PURE__ */ __name((base) => { if (base === 2) { return 1024; } if (base === 10) { return 1e3; } throw new TypeError(`Unsupported base.`); }, "fromBase"); const parseBytes = /* @__PURE__ */ __name((value, options) => { const config = { base: 2, locale: "en-US", units: "metric", ...options }; if (typeof value !== "string" || value.length === 0) { throw new TypeError("Value is not a string or is empty."); } if (value.length > 100) { throw new TypeError("Value exceeds the maximum length of 100 characters."); } const match = ( // eslint-disable-next-line regexp/no-super-linear-backtracking,regexp/no-unused-capturing-group,regexp/no-misleading-capturing-group,security/detect-unsafe-regex /^(?<value>-?(?:\d+(([.,])\d+)*)?[.,]?\d+) *(?<type>bytes?|b|kb|kib|mb|mib|gb|gib|tb|tib|pb|pib|eb|eib|zb|zib|yb|yib|(kilo|kibi|mega|mebi|giga|gibi|tera|tebi|peta|pebi|exa|exbi|zetta|zebi|yotta|yobi)?bytes)?$/i.exec( value ) ); const groups = match?.groups; if (!groups) { return Number.NaN; } const localizedNumber = parseLocalizedNumber(groups.value, config.locale); const type = (groups.type ?? "Bytes").toUpperCase().replace(/^KIBI/, "KILO").replace(/^MIBI/, "MEGA").replace(/^GIBI/, "GIGA").replace(/^TEBI/, "TERA").replace(/^PEBI/, "PETA").replace(/^EXBI/, "EXA").replace(/^ZEBI/, "ZETTA").replace(/^YIBI/, "YOTTA").replace(/^(.)IB$/, "$1B"); const level = BYTE_SIZES[config.units].findIndex((unit) => unit.short[0].toUpperCase() === type[0]); const base = fromBase(config.base); return localizedNumber * base ** level; }, "parseBytes"); const formatBytes = /* @__PURE__ */ __name((bytes, options) => { if (typeof bytes !== "number" || !Number.isFinite(bytes)) { throw new TypeError("Bytesize is not a number."); } const { base: givenBase, decimals, locale, long, unit: requestedUnit, units, ...l10nOptions } = { base: 2, decimals: 0, locale: "en-US", long: false, units: "metric", ...options }; const base = fromBase(givenBase); const absoluteBytes = Math.abs(bytes); const space = options?.space ?? true ? " " : ""; const referenceTable = BYTE_SIZES[units]; const requestedUnitIndex = referenceTable.findIndex((unit2) => unit2.short === requestedUnit); if (bytes === 0) { const level2 = Math.min(0, Math.max(requestedUnitIndex, referenceTable.length - 1)); return "0" + space + referenceTable[level2][long ? "long" : "short"]; } const level = requestedUnitIndex >= 0 ? requestedUnitIndex : Math.min(Math.floor(Math.log(absoluteBytes) / Math.log(base)), referenceTable.length - 1); const unit = referenceTable[level][long ? "long" : "short"]; const value = bytes / base ** level; const fractionDigits = decimals < 0 ? void 0 : decimals; const formattedValue = new Intl.NumberFormat(locale, { // @ts-expect-error - should be overridden by the options maximumFractionDigits: fractionDigits, // @ts-expect-error - should be overridden by the options minimumFractionDigits: fractionDigits, ...l10nOptions }).format(value); return formattedValue + space + unit; }, "formatBytes"); export { formatBytes, parseBytes };