signal-desktop/ts/util/numbers.ts
2024-09-16 15:38:12 -04:00

79 lines
1.7 KiB
TypeScript

// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { strictAssert } from './assert';
export function safeParseNumber(value: number | string): number | null {
if (typeof value === 'number') {
return value;
}
strictAssert(typeof value === 'string', 'Expected string or number');
const trimmed = value.trim();
if (trimmed === '') {
return null;
}
const parsed = Number(value);
if (!Number.isFinite(parsed)) {
return null;
}
if (parsed < Number.MIN_SAFE_INTEGER || parsed > Number.MAX_SAFE_INTEGER) {
return null;
}
return parsed;
}
export function safeParseInteger(
value: number | string,
trunc = false
): number | null {
const parsed = safeParseNumber(value);
if (parsed == null) {
return null;
}
if (trunc) {
return Math.trunc(parsed);
}
if (!Number.isInteger(parsed)) {
return null;
}
return parsed;
}
export function safeParseBigint(
value: bigint | number | string
): bigint | null {
if (typeof value === 'bigint') {
return value;
}
if (typeof value === 'number') {
if (!Number.isInteger(value)) {
return null;
}
return BigInt(value);
}
strictAssert(typeof value === 'string', 'Expected string, number, or bigint');
const trimmed = value.trim();
if (trimmed === '') {
return null;
}
return BigInt(value);
}
export function roundFractionForProgressBar(fractionComplete: number): number {
if (fractionComplete <= 0) {
return 0;
}
if (fractionComplete >= 1) {
return 1;
}
if (fractionComplete <= 0.01) {
return 0.01;
}
if (fractionComplete >= 0.99) {
return 0.99;
}
return Math.round(fractionComplete * 100) / 100;
}