Normalize conversion factor formatting
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { solve } from '$lib/engine';
|
import { solve } from '$lib/engine';
|
||||||
import type { CalculatorDef } from '$lib/data/calculators';
|
import type { CalculatorDef } from '$lib/data/calculators';
|
||||||
|
import { formatConversionValue } from '$lib/utils/formatConversionValue';
|
||||||
|
|
||||||
export let config: CalculatorDef;
|
export let config: CalculatorDef;
|
||||||
|
|
||||||
@@ -17,40 +18,29 @@
|
|||||||
? solve(config, 1, exampleInput.toString(), '', '')
|
? solve(config, 1, exampleInput.toString(), '', '')
|
||||||
: null;
|
: null;
|
||||||
$: offset = config.offset ?? 0;
|
$: offset = config.offset ?? 0;
|
||||||
$: formulaExpression = supportsExample
|
$: hasOffset = Boolean(offset);
|
||||||
? `${exampleInput} × ${config.factor}${offset ? ` + ${offset}` : ''}`
|
$: formattedFactorValue = supportsExample
|
||||||
|
? formatConversionValue(config.factor)
|
||||||
|
: '';
|
||||||
|
$: formattedOffsetValue = hasOffset
|
||||||
|
? formatConversionValue(offset)
|
||||||
|
: '';
|
||||||
|
$: formulaExpression = supportsExample
|
||||||
|
? `${exampleInput} × ${formattedFactorValue}${hasOffset ? ` + ${formattedOffsetValue}` : ''}`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
const formatExampleValue = (value: number | null): string => {
|
|
||||||
if (value === null || Number.isNaN(value)) {
|
|
||||||
return '—';
|
|
||||||
}
|
|
||||||
if (!Number.isFinite(value)) {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
if (value === 0) {
|
|
||||||
return '0';
|
|
||||||
}
|
|
||||||
const rounded = parseFloat(value.toFixed(6));
|
|
||||||
if (rounded !== 0) {
|
|
||||||
return rounded.toString();
|
|
||||||
}
|
|
||||||
const precise = value.toFixed(12).replace(/\.?0+$/, '');
|
|
||||||
return precise || '0';
|
|
||||||
};
|
|
||||||
|
|
||||||
$: reverseExampleValue =
|
$: reverseExampleValue =
|
||||||
supportsExample && config.factor !== 0
|
supportsExample && config.factor !== 0
|
||||||
? (1 - offset) / config.factor
|
? (1 - offset) / config.factor
|
||||||
: null;
|
: null;
|
||||||
$: formattedReverseValue = formatExampleValue(reverseExampleValue);
|
$: formattedReverseValue = formatConversionValue(reverseExampleValue);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if supportsExample && result}
|
{#if supportsExample && result}
|
||||||
<section class="example-card">
|
<section class="example-card">
|
||||||
<h3>How to convert {config.labels.in1} to {config.labels.in2}</h3>
|
<h3>How to convert {config.labels.in1} to {config.labels.in2}</h3>
|
||||||
<p class="example-note">
|
<p class="example-note">
|
||||||
1 {config.labels.in1} = {config.factor}{config.offset ? ` + ${config.offset}` : ''} {config.labels.in2}
|
1 {config.labels.in1} = {formattedFactorValue}{hasOffset ? ` + ${formattedOffsetValue}` : ''} {config.labels.in2}
|
||||||
</p>
|
</p>
|
||||||
<p class="example-note">
|
<p class="example-note">
|
||||||
1 {config.labels.in2} = {formattedReverseValue} {config.labels.in1}
|
1 {config.labels.in2} = {formattedReverseValue} {config.labels.in1}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { CalculatorDef } from '$lib/data/calculators';
|
import type { CalculatorDef } from '$lib/data/calculators';
|
||||||
|
import { formatConversionValue } from '$lib/utils/formatConversionValue';
|
||||||
|
|
||||||
type RateConfig = Pick<CalculatorDef, 'type' | 'factor' | 'offset' | 'labels'>;
|
type RateConfig = Pick<CalculatorDef, 'type' | 'factor' | 'offset' | 'labels'>;
|
||||||
|
|
||||||
@@ -12,5 +13,9 @@ export const getConversionRateText = (config: RateConfig): string | null => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `1 ${in1} = ${config.factor}${config.offset ? ` + ${config.offset}` : ''} ${in2}`;
|
const formattedFactor = formatConversionValue(config.factor);
|
||||||
|
const hasOffset = Boolean(config.offset);
|
||||||
|
const formattedOffset = formatConversionValue(config.offset ?? 0);
|
||||||
|
|
||||||
|
return `1 ${in1} = ${formattedFactor}${hasOffset ? ` + ${formattedOffset}` : ''} ${in2}`;
|
||||||
};
|
};
|
||||||
|
|||||||
17
hdyc-svelte/src/lib/utils/formatConversionValue.ts
Normal file
17
hdyc-svelte/src/lib/utils/formatConversionValue.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export function formatConversionValue(value: number | null | undefined): string {
|
||||||
|
if (value === null || value === undefined || Number.isNaN(value)) {
|
||||||
|
return '—';
|
||||||
|
}
|
||||||
|
if (!Number.isFinite(value)) {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
if (value === 0) {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
const rounded = parseFloat(value.toFixed(6));
|
||||||
|
if (rounded !== 0) {
|
||||||
|
return rounded.toString();
|
||||||
|
}
|
||||||
|
const precise = value.toFixed(12).replace(/\.?0+$/, '');
|
||||||
|
return precise || '0';
|
||||||
|
}
|
||||||
27
tests/test_conversion_rate_tooltip.py
Normal file
27
tests/test_conversion_rate_tooltip.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
CONVERSION_RATE = (
|
||||||
|
ROOT / "hdyc-svelte" / "src" / "lib" / "utils" / "conversionRate.ts"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ConversionRateTooltipFormattingTests(unittest.TestCase):
|
||||||
|
def test_conversion_rate_text_uses_formatter(self) -> None:
|
||||||
|
text = CONVERSION_RATE.read_text(encoding="utf-8")
|
||||||
|
normalized = " ".join(text.split())
|
||||||
|
self.assertIn(
|
||||||
|
"formatConversionValue(config.factor)",
|
||||||
|
normalized,
|
||||||
|
"Conversion rate helper must format the factor before inserting it into the tooltip text",
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
"formatConversionValue(config.offset ?? 0)",
|
||||||
|
normalized,
|
||||||
|
"Conversion rate tooltip must format any offset before rendering",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
26
tests/test_quick_conversion_formatting.py
Normal file
26
tests/test_quick_conversion_formatting.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
QUICK_CONVERSION_EXAMPLE = (
|
||||||
|
ROOT / "hdyc-svelte" / "src" / "lib" / "components" / "QuickConversionExample.svelte"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class QuickConversionExampleFormattingTests(unittest.TestCase):
|
||||||
|
def test_formula_uses_formatted_factor_and_offset(self) -> None:
|
||||||
|
text = QUICK_CONVERSION_EXAMPLE.read_text(encoding="utf-8")
|
||||||
|
normalized = " ".join(text.split())
|
||||||
|
snippet = (
|
||||||
|
"1 {config.labels.in1} = {formattedFactorValue}{hasOffset ? ` + ${formattedOffsetValue}` : ''} "
|
||||||
|
"{config.labels.in2}"
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
snippet,
|
||||||
|
normalized,
|
||||||
|
"The formula snippet should render formatted factor/offset values instead of raw floats",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user