@visulima/humanizer
Version:
Humanizer is a library for humanizing data in a human-readable form.
244 lines (242 loc) • 6.01 kB
JavaScript
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 };