feat: add rate normalization helpers

This commit is contained in:
2026-04-20 20:01:43 +08:00
parent b6b350bbf7
commit 065b6380bf
2 changed files with 117 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
type ComparableRate = {
isLessThan: boolean;
numeric: number;
};
export function normalizeRateDisplay(value: string): string {
const trimmedValue = value.trim();
const rangeMatch = trimmedValue.match(
/^([0-9]+(?:\.[0-9]+)?)\s*%?\s*-\s*([0-9]+(?:\.[0-9]+)?)\s*%$/
);
if (rangeMatch) {
const [, lowerBound, upperBound] = rangeMatch;
return `${lowerBound}% - ${upperBound}%`;
}
return trimmedValue.replace(/\s+/g, "");
}
export function parseRateLowerBound(value: string | null | undefined): number | null {
const comparableRate = toComparableRate(value);
return comparableRate?.numeric ?? null;
}
export function compareRateValues(
leftValue: string | null | undefined,
rightValue: string | null | undefined
): number {
const leftComparable = toComparableRate(leftValue);
const rightComparable = toComparableRate(rightValue);
if (!leftComparable && !rightComparable) {
return 0;
}
if (!leftComparable) {
return 1;
}
if (!rightComparable) {
return -1;
}
if (leftComparable.numeric !== rightComparable.numeric) {
return leftComparable.numeric - rightComparable.numeric;
}
if (leftComparable.isLessThan === rightComparable.isLessThan) {
return 0;
}
return leftComparable.isLessThan ? -1 : 1;
}
function toComparableRate(value: string | null | undefined): ComparableRate | null {
if (!value) {
return null;
}
const normalizedValue = normalizeRateDisplay(value);
const lessThanMatch = normalizedValue.match(/^<\s*([0-9]+(?:\.[0-9]+)?)%$/);
if (lessThanMatch) {
return {
isLessThan: true,
numeric: Number(lessThanMatch[1])
};
}
const rangeMatch = normalizedValue.match(
/^([0-9]+(?:\.[0-9]+)?)%\s*-\s*([0-9]+(?:\.[0-9]+)?)%$/
);
if (rangeMatch) {
return {
isLessThan: false,
numeric: Number(rangeMatch[1])
};
}
const exactMatch = normalizedValue.match(/^([0-9]+(?:\.[0-9]+)?)%$/);
if (exactMatch) {
return {
isLessThan: false,
numeric: Number(exactMatch[1])
};
}
return null;
}