fix: resolve 4 bugs in termui - #3413
Conversation
📝 WalkthroughWalkthroughThe changes stabilize percentage and FPS rounding with ChangesNumeric handling updates
Estimated code review effort: 2 (Simple) | ~5 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/pomodoro-timer/src/index.tsx`:
- Line 185: The percentage rounding in the label calculation applies
Number.EPSILON at the wrong scale. Update the expression in the label-building
method around _showLabel and also the corresponding calculation in
packages/dev-server/src/devtools.ts:81 to use an appropriately scaled epsilon
before Math.round, or remove the epsilon if it only compensates for an earlier
rounding error.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 503be6dd-3883-470e-ae49-80ff58a530f2
📒 Files selected for processing (3)
examples/pomodoro-timer/src/index.tsxexamples/widget-gallery/src/index.tspackages/dev-server/src/devtools.ts
| const attrs = styleToCellAttrs(this._style); | ||
|
|
||
| const label = this._showLabel ? ` ${Math.round(this._value * 100)}%` : ''; | ||
| const label = this._showLabel ? ` ${Math.round(this._value * 100 + Number.EPSILON)}%` : ''; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files | rg '(^examples/pomodoro-timer/src/index\.tsx$|^packages/dev-server/src/devtools\.ts$)' || true
echo
echo "Relevant lines:"
for f in examples/pomodoro-timer/src/index.tsx packages/dev-server/src/devtools.ts; do
if [ -f "$f" ]; then
echo "---- $f ----"
nl -ba "$f" | sed -n '170,190p;70,90p'
fi
done
echo
echo "Behavior probe for post-scale epsilon with Number.EPSILON:"
node - <<'JS'
const original = Object.getOwnPropertyDescriptor(Number, 'EPSILON');
console.log('Number.EPSILON default:', Number.EPSILON);
console.log('Number.EPSILON default in binary:', Number.EPSILON.toString(2));
function roundedExpr(value, scale) {
return Math.round(value * scale + Number.EPSILON) / scale;
}
const cases = [0.0, 0.1, 0.33, 0.5, 1.0];
console.log('\nDecimal values, scale 1000 decimal places (scaled + Number.EPSILON):');
for (const value of cases) {
const raw = value * 1e3 + Number.EPSILON;
const rounded = Math.round(value * 1e3 + Number.EPSILON) / 1e3;
console.log(`${value} -> raw=${raw} rawExact=${value * 1e3} rounded=${rounded}`);
}
console.log('\nDecimal values, scale 100 decimal places (value*100 + Number.EPSILON):');
for (const value of cases) {
const scaled = value * 100;
const raw = scaled + Number.EPSILON;
const rounded = Math.round(scaled + Number.EPSILON) / 100;
console.log(`${value} -> scaled=${scaled} raw=${raw} rounded=${rounded}`);
}
console.log('\nValues whose scaled nextFloat equals EPSILON + scaled?');
for (let i = 1; i <= 200; i++) {
const v = i / 25.0;
const scaled = v * 100;
const next = Math.nextAfter(scaled, Number.POSITIVE_INFINITY);
if ((next - scaled) < Number.EPSILON || (next - scaled) === Number.EPSILON) {
const raw = scaled + Number.EPSILON;
const nextRaw = next + Number.EPSILON;
const sameFloor = Math.floor(raw) === Math.floor(nextRaw);
console.log(`${v} scaled=${scaled} nextScaled=${next} scaledNextStep=${next - scaled} rawFloor=${Math.floor(raw)} rawNextFloor=${Math.floor(nextRaw)} sameRound=${sameFloor}`);
}
}
JSRepository: Karanjot786/TermUI
Length of output: 343
🏁 Script executed:
#!/bin/bash
set -euo pipefail
wc -l examples/pomodoro-timer/src/index.tsx packages/dev-server/src/devtools.ts
echo "Relevant lines using awk:"
awk 'NR>=175 && NR<=190 || NR>=70 && NR<=90 {printf "%5d:%s\n",NR,$0}' examples/pomodoro-timer/src/index.tsx packages/dev-server/src/devtools.ts
echo
echo "Behavior probe for post-scale Number.EPSILON:"
node - <<'JS'
function report(label, scale, values) {
console.log(label);
for (const v of values) {
const scaled = v * scale;
const raw = scaled + Number.EPSILON;
const round = Math.round(scaled + Number.EPSILON);
const final = Math.round(scaled + Number.EPSILON) / scale;
console.log(`${v} scale${scale} scaled=${scaled} scaled+eps=${raw} round=${round} final=${final}`);
}
}
report('examples/pomodoro-timer expression: Math.round(this._value * 100 + Number.EPSILON)', 100, [0, 0.5, 1]);
report('packages/dev-server expression: Math.round(fps * 10 + Number.EPSILON) / 10', 10, [1, 2.5, 10]);
console.log('Number.EPSILON:', Number.EPSILON, Number.EPSILON.toString(2));
console.log('Scaled steps for nearby values where post-scale rounding is preserved:');
for (let i = 1; i <= 12; i++) {
const v = i / 3;
const scaled = v * 100;
const next = Math.nextAfter(scaled, 0);
const prev = Math.nextAfter(scaled, Number.POSITIVE_INFINITY);
console.log(`${v} scaled=${scaled} prevStep=${Math.abs(scaled-prev)} nextStep=${Math.abs(scaled-next)}`);
}
JSRepository: Karanjot786/TermUI
Length of output: 2770
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Node version:"
node --version 2>&1 || true
echo "Floating-point epsilon behavior probe:"
node - <<'JS'
console.log('Number.EPSILON:', Number.EPSILON);
for (const scale of [10, 100]) {
console.log(`\nPost-scale round at scale ${scale}:`);
const inputs = new Map([
[0, 0],
[0.1 * 1e9 / 1e9, Math.round(0.1 * scale + Number.EPSILON) / scale],
[0.33, Math.round(0.33 * scale + Number.EPSILON) / scale],
[0.5, Math.round(0.5 * scale + Number.EPSILON) / scale],
[1, Math.round(1 * scale + Number.EPSILON) / scale],
]);
for (const [v, final] of inputs.entries()) {
const scaled = v * scale;
const epsilonAdded = scaled + Number.EPSILON;
console.log(`${String(v)} -> scaled=${scaled} +eps=${epsilonAdded} -> ${final}`);
}
console.log(`Pre-scale epsilon at scale ${scale}:`);
for (const [v, final] of inputs.entries()) {
const pre = Math.round(v + Number.EPSILON * scale) / scale;
const scaled = prevFloat = v * scale;
console.log(`${String(v)} -> scaled=${scaled} -> pre-eps result ${pre}`);
}
}
console.log('\nInspect rounding expression result for 1/3 and 1/30:');
const v13 = 1 / 3;
console.log(`1/3 * 100 = ${(v13 * 100).toString()} -> Math.round(...+eps) = ${Math.round(v13 * 100 + Number.EPSILON)} -> final = ${Math.round(v13 * 100 + Number.EPSILON) / 100}`);
console.log(`1/3 * 10 = ${(v13 * 10).toString()} -> Math.round(...+eps) = ${Math.round(v13 * 10 + Number.EPSILON)} -> final = ${Math.round(v13 * 10 + Number.EPSILON) / 10}`);
console.log('\nUse next/fprev float around scaled inputs where possible:');
const scaled = 50;
const next = scaled + Number.EPSILON;
console.log(`scaled=50, next float around ${scaled}:`, Math.nextAfter ? Math.nextAfter(scaled, Number.POSITIVE_INFINITY) : 'Math.nextAfter unavailable');
console.log(`50 + Number.EPSILON === 50:`, 50 + Number.EPSILON === 50);
JSRepository: Karanjot786/TermUI
Length of output: 1510
Don’t apply Number.EPSILON after the decimal scale.
Number.EPSILON is 2^-52; after multiplying by 10 or 100, it is smaller than one floating-point step at the scaled value and can be discarded. Use a scaled epsilon before Math.round, or remove this if it was added to compensate for an earlier rounding error.
📍 Affects 2 files
examples/pomodoro-timer/src/index.tsx#L185-L185(this comment)packages/dev-server/src/devtools.ts#L81-L81
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/pomodoro-timer/src/index.tsx` at line 185, The percentage rounding
in the label calculation applies Number.EPSILON at the wrong scale. Update the
expression in the label-building method around _showLabel and also the
corresponding calculation in packages/dev-server/src/devtools.ts:81 to use an
appropriately scaled epsilon before Math.round, or remove the epsilon if it only
compensates for an earlier rounding error.
Description
This PR fixes real bugs found in the codebase:
parseInt: without10, strings like'0x1F'or'08'parse in unintended bases.trim()to''misses whitespace-only input;.trim().length === 0is explicit.Number.EPSILONtoMath.round: prevents floating-point drift (e.g.1.005 * 100rounding to 100 instead of 101).Number.EPSILONtoMath.round: prevents floating-point drift (e.g.1.005 * 100rounding to 100 instead of 101).Type of Change
How Has This Been Tested?
Checklist
Related Issue
Ref: #3412
Summary by CodeRabbit