Repository Public MIT
1/** Helpers de formatage (fr-CA) utilisés par l'interface. */23export function fmtNumber(value: number | null | undefined, digits = 2): string {4 if (value == null || Number.isNaN(value)) return "—";5 return value.toLocaleString("en-US", { minimumFractionDigits: digits, maximumFractionDigits: digits });6}78export function fmtPct(value: number | null | undefined, digits = 2, signed = true): string {9 if (value == null || Number.isNaN(value)) return "—";10 const s = value.toFixed(digits);11 return `${signed && value > 0 ? "+" : ""}${s} %`;12}1314export function fmtCompact(value: number | null | undefined, prefix = ""): string {15 if (value == null || Number.isNaN(value)) return "—";16 const abs = Math.abs(value);17 const sign = value < 0 ? "-" : "";18 if (abs >= 1e12) return `${sign}${prefix}${(abs / 1e12).toFixed(2)} T`;19 if (abs >= 1e9) return `${sign}${prefix}${(abs / 1e9).toFixed(2)} G`;20 if (abs >= 1e6) return `${sign}${prefix}${(abs / 1e6).toFixed(2)} M`;21 if (abs >= 1e3) return `${sign}${prefix}${(abs / 1e3).toFixed(1)} k`;22 return `${sign}${prefix}${abs.toFixed(2)}`;23}2425export function fmtCurrency(value: number | null | undefined, currency = "USD", digits = 2): string {26 if (value == null || Number.isNaN(value)) return "—";27 return new Intl.NumberFormat("fr-CA", { style: "currency", currency, minimumFractionDigits: digits, maximumFractionDigits: digits }).format(value);28}2930export function fmtDate(value: string | number | Date, opts: Intl.DateTimeFormatOptions = { year: "numeric", month: "long", day: "numeric" }): string {31 try {32 return new Date(value).toLocaleDateString("fr-CA", opts);33 } catch {34 return String(value);35 }36}3738export function fmtDateTime(value: string | number | Date): string {39 return fmtDate(value, { year: "numeric", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit" });40}4142export function fmtDuration(ms?: number): string {43 if (ms == null) return "";44 if (ms < 1000) return `${Math.round(ms)} ms`;45 return `${(ms / 1000).toFixed(1)} s`;46}4748/** Transforme un nom d'outil snake_case en libellé lisible. */49export function humanizeTool(tool: string): string {50 return tool51 .replace(/^get_/, "")52 .replace(/^eodhd_/, "EODHD ")53 .replace(/_/g, " ")54 .replace(/\b(rsi|macd|ema|sma|adx|cci|var|garch|etf|esg|ipo|cot|sec|api|pdf|csv|otm|itm|atm)\b/gi, (m) => m.toUpperCase())55 .replace(/^\w/, (c) => c.toUpperCase());56}5758export function hostnameOf(url: string): string {59 try {60 return new URL(url).hostname.replace(/^www\./, "");61 } catch {62 return url;63 }64}6566export function pluralize(n: number, one: string, many?: string): string {67 return n > 1 ? (many ?? `${one}s`) : one;68}69