UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

114 lines (113 loc) 4.68 kB
import { isArray } from "./array.js"; import { NNBSP } from "./constants.js"; import { isDate, requireDate } from "./date.js"; import { getPercent } from "./number.js"; import { isObject } from "./object.js"; import { requireTime } from "./time.js"; import { requireURL } from "./url.js"; /** Format a number range (based on the user's browser language settings). */ export function formatRange(min, max, options) { return `${formatNumber(min, options)}${NNBSP}${NNBSP}${formatNumber(max, options)}`; } /** Format a number with a short suffix, e.g. `1,000 kg` */ export function formatQuantity(num, suffix, options) { const o = { unitDisplay: "short", ...options, style: "decimal" }; const str = formatNumber(num, o); const sep = o.unitDisplay === "narrow" ? "" : NNBSP; return `${str}${sep}${suffix}`; } /** Format a number (based on the user's browser language settings). */ export function formatNumber(num, options) { if (!Number.isFinite(num)) return Number.isNaN(num) ? "-" : "∞"; return new Intl.NumberFormat(undefined, options).format(num).replace(/ /, NNBSP); } /** Format a number with a longer full-word suffix. */ export function pluralizeQuantity(num, singular, plural, options) { const o = { ...options, style: "decimal" }; const qty = formatNumber(num, o); return `${qty}${NNBSP}${num === 1 ? singular : plural}`; } /** * Format a percentage (combines `getPercent()` and `formatQuantity()` for convenience). * - Defaults to showing no decimal places. * - Defaults to rounding closer to zero (so that 99.99% is shown as 99%). * * @param numerator Number representing the amount of progress. * @param denumerator The number representing the whole amount. */ export function formatPercent(numerator, denumerator, options) { const fullOptions = { style: "percent", maximumFractionDigits: 0, roundingMode: "trunc", ...options }; return formatNumber(getPercent(numerator, denumerator), fullOptions); } /** * Format an unknown object as a string. * - Use the custom `.toString()` function if it exists (don't use built in `Object.prototype.toString` because it's useless. * - Use `.title` or `.name` or `.id` if they exist and are strings. * - Use `Object` otherwise. */ export function formatObject(obj) { if (typeof obj.toString === "function" && obj.toString !== Object.prototype.toString) return obj.toString(); const name = obj.name; if (typeof name === "string") return name; const title = obj.title; if (typeof title === "string") return title; const id = obj.id; if (typeof id === "string") return id; return "Object"; } /** Format an unknown array as a string. */ export function formatArray(arr, separator = ", ") { return arr.map(formatValue).join(separator); } /** Format a date in the browser locale. */ export function formatDate(date) { return requireDate(date, formatDate).toLocaleDateString(); } /** Format a time as a string based on the browser locale settings. */ export function formatTime(time, precision = 2) { return requireTime(time, formatTime).format(precision); } /** Format a URL as a user-friendly string, e.g. `http://shax.com/test?uid=129483` → `shax.com/test` */ export function formatURL(possible, base) { const { host, pathname } = requireURL(possible, base, formatURL); return `${host}${pathname.length > 1 ? pathname : ""}`; } /** * Convert any unknown value into a friendly string for user-facing use. * - Strings return the string. * - Booleans return `"Yes"` or `"No"` * - Numbers return formatted number with commas etc (e.g. `formatNumber()`). * - Dates return formatted date (e.g. `formatDate()`). * - Arrays return the array items converted to string (with `toTitle()`), and joined with a comma. * - Objects return... * 1. `object.name` if it exists, or * 2. `object.title` if it exists. * - Falsy values like `null` and `undefined` return `"None"` * - Everything else returns `"Unknown"` */ export function formatValue(value) { if (value === null || value === undefined) return "None"; if (typeof value === "boolean") return value ? "Yes" : "No"; if (typeof value === "string") return value || "None"; if (typeof value === "number") return formatNumber(value); if (typeof value === "symbol") return value.description || "Symbol"; if (typeof value === "function") return "Function"; if (isDate(value)) return formatDate(value); if (isArray(value)) return formatArray(value); if (isObject(value)) return formatObject(value); return "Unknown"; }