79 lines
1.7 KiB
TypeScript
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;
|
|
}
|