fix: resolve 4 bugs in termui - #3553
Conversation
📝 WalkthroughWalkthroughFour example applications update percentage rounding, hexadecimal entity parsing, tab-key parsing, and weather refresh interval setup. ChangesExample correctness fixes
Estimated code review effort: 2 (Simple) | ~10 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: 3
🤖 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: Update the percentage calculation in the label expression within the
timer display so Number.EPSILON is added to this._value before multiplying by
100, then round the scaled result as before. Preserve the existing conditional
label behavior and formatting.
In `@examples/rss-reader/src/index.tsx`:
- Around line 30-31: Update the entity decoding logic around the hexadecimal and
decimal branches to parse the complete numeric value without truncating digits,
reject hexadecimal entities with more than eight digits, and only decode values
in the valid Unicode range 0x0–0x10FFFF. Apply the same range validation before
String.fromCodePoint in the decimal branch, returning match for invalid or
out-of-range entities.
In `@examples/weather/src/index.tsx`:
- Line 204: Declare the __interval property used by the weather polling setup in
index.tsx by adding a global Window augmentation with the appropriate
timer-handle type, or replace the window attachment with a typed module-level
variable. Ensure both clearInterval and setInterval calls remain type-safe under
strict TypeScript checking.
🪄 Autofix
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: 3bdbd58b-300f-4bc4-8c5e-e8eb20da2dc4
📒 Files selected for processing (4)
examples/pomodoro-timer/src/index.tsxexamples/rss-reader/src/index.tsxexamples/showcase/src/index.tsxexamples/weather/src/index.tsx
| 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:
node <<'NODE'
const value = 29 / 200;
const current = Math.round(value * 100 + Number.EPSILON);
const corrected = Math.round((value + Number.EPSILON) * 100);
console.log({ current, corrected });
if (current === 15 || corrected !== 15) process.exit(1);
NODERepository: Karanjot786/TermUI
Length of output: 187
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate target file and class:"
fd -a 'index.tsx$' . | sed 's#^\./##' | grep 'examples/pomodoro-timer/src/index.tsx' || true
echo
echo "Relevant file context:"
sed -n '160,200p' examples/pomodoro-timer/src/index.tsx | cat -n | sed 's/^/165+/'
echo
echo "Search for GradientProgressBar setValue:"
rg -n "class GradientProgressBar|_value|setValue|Number\.EPSILON|percent|showLabel" examples/pomodoro-timer/src/index.tsxRepository: Karanjot786/TermUI
Length of output: 3046
Apply the epsilon before scaling the percentage value.
Number.EPSILON is too small after multiplying by 100. For example, this._value = 29 / 200 can produce 14.499999999999998, so the current expression displays 14% instead of 15%.
Proposed fix
- const label = this._showLabel ? ` ${Math.round(this._value * 100 + Number.EPSILON)}%` : '';
+ const label = this._showLabel ? ` ${Math.round((this._value + Number.EPSILON) * 100)}%` : '';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const label = this._showLabel ? ` ${Math.round(this._value * 100 + Number.EPSILON)}%` : ''; | |
| const label = this._showLabel ? ` ${Math.round((this._value + Number.EPSILON) * 100)}%` : ''; |
🤖 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, Update the percentage
calculation in the label expression within the timer display so Number.EPSILON
is added to this._value before multiplying by 100, then round the scaled result
as before. Preserve the existing conditional label behavior and formatting.
| const codePoint = Number.parseInt(entity.slice(2, 10), 16); | ||
| return Number.isFinite(codePoint) ? String.fromCodePoint(codePoint) : match; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
node <<'NODE'
const truncated = Number.parseInt('000000041'.slice(0, 8), 16);
console.log({ truncated });
try {
String.fromCodePoint(Number.parseInt('110000', 16));
process.exit(1);
} catch (error) {
console.log(error.name);
}
NODERepository: Karanjot786/TermUI
Length of output: 184
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Files matching index.tsx:\n'
fd -a 'index\.tsx$' . | sed 's#^\./##'
printf '\nRelevant excerpt from examples/rss-reader/src/index.tsx:\n'
if [ -f examples/rss-reader/src/index.tsx ]; then
nl -ba examples/rss-reader/src/index.tsx | sed -n '1,80p'
else
echo 'not found'
fi
printf '\nSearch for decodeEntities usages:\n'
rg -n "decodeEntities|decodeEntity|&`#x`|`#x`|String\.fromCodePoint|fromCodePoint" examples/rss-reader/src || trueRepository: Karanjot786/TermUI
Length of output: 2181
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Relevant excerpt from examples/rss-reader/src/index.tsx:\n'
awk '{printf "%6d %s\n", NR, $0}' examples/rss-reader/src/index.tsx | sed -n '1,100p'
printf '\nSearch for decodeEntities and code-point parsing usages:\n'
grep -RInE "decodeEntities|decodeEntity|&`#x`|`#x`|String\.fromCodePoint|fromCodePoint|Number\.parseInt" examples/rss-reader/src || trueRepository: Karanjot786/TermUI
Length of output: 5050
Reject invalid hexadecimal entities before decoding.
entity.slice(2, 10) drops digits after the eighth, so A decodes as U+00000004 instead of U+0041. The Number.isFinite check also allows overlong entities like � to call String.fromCodePoint, which throws RangeError. Parse the full entity value, reject more than eight hex digits, and keep valid code points only within 0x10FFFF; apply the same range check to the decimal branch.
🤖 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/rss-reader/src/index.tsx` around lines 30 - 31, Update the entity
decoding logic around the hexadecimal and decimal branches to parse the complete
numeric value without truncating digits, reject hexadecimal entities with more
than eight digits, and only decode values in the valid Unicode range
0x0–0x10FFFF. Apply the same range validation before String.fromCodePoint in the
decimal branch, returning match for invalid or out-of-range entities.
| } | ||
|
|
||
| setInterval(fetchWeather, 5000); | ||
| clearInterval(window.__interval); window.__interval = setInterval(fetchWeather, 5000); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 3 '__interval|interface Window|declare global' examples/weather --glob '*.{ts,tsx,d.ts}' || true
rg -n -C 2 '"strict"[[:space:]]*:[[:space:]]*true' --glob 'tsconfig*.json' --glob '!node_modules' || trueRepository: Karanjot786/TermUI
Length of output: 582
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)tsconfig.*\.json$|examples/weather/src/index\.tsx$|\.d\.ts$|package\.json$|pnpm-lock\.yaml$|yarn\.lock$|package-lock\.json$' || true
echo "== example index relevant section =="
sed -n '180,215p' examples/weather/src/index.tsx | cat -n -v
echo "== ts configs =="
for f in $(git ls-files '*tsconfig*.json' 'packages/**/tsconfig*.json' 'apps/**/tsconfig*.json' '**/tsconfig*.json' | rg -v node_modules || true); do
echo "--- $f"
sed -n '1,80p' "$f"
done
echo "== window declarations repo-wide =="
rg -n -C 3 '^\s*(declare )?(interface|type|namespace)\s+Window\s*|declare global|__interval|interface\s+Global.*Window|--extends|--skipLibCheck|--noImplicitAny|--strict' . --glob '*.{ts,tsx,d.ts,json,yaml,yml}' --glob '!node_modules/**' || trueRepository: Karanjot786/TermUI
Length of output: 21330
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== weather package metadata =="
cat examples/weather/package.json
echo "== root package scripts/typecheck =="
sed -n '1,160p' package.json
echo "== lockfile TS version candidates =="
for f in pnpm-lock.yaml package-lock.json yarn.lock; do
[ -f "$f" ] || continue
echo "--- $f"
rg -n 'typescript|`@types/node`|`@types/react`|`@termuijs`' "$f" | head -80 || true
done
echo "== examples/weather typecheck if TS is available =="
if command -v npx >/dev/null 2>&; then
(set -x; npx --package typescript -- tsc --version 2>&1);
npx --package typescript -- tsc --noEmit --strict --module ESNext --moduleResolution Bundler --target ES2022 examples/weather/src/index.tsx 2>&1 | sed -n '1,120p' || true
else
echo "npx not available"
fi
echo "== declare global occurrences excluding node_modules =="
rg -n -C 2 'declare global|interface Window|declare module' . --glob '!node_modules/**' || trueRepository: Karanjot786/TermUI
Length of output: 1965
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cd examples/weather
if command -v bun >/dev/null 2>&1; then
echo "== bun tsc if available =="
bun tsc --version 2>&1 || true
bun tsc --noEmit 2>&1 | sed -n '1,160p'
else
echo "bun not available"
fi
echo "== node_modules/typescript availability =="
if [ -x node_modules/.bin/tsc ]; then
./node_modules/.bin/tsc --version
./node_modules/.bin/tsc --noEmit 2>&1 | sed -n '1,160p' || true
else
echo "node_modules/.bin/tsc not available"
fiRepository: Karanjot786/TermUI
Length of output: 253
Declare window.__interval.
examples/weather runs strict: true, but window.__interval has no TypeScript declaration. Add a Window augmentation for this timer handle, or avoid attaching it directly to window.
🤖 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/weather/src/index.tsx` at line 204, Declare the __interval property
used by the weather polling setup in index.tsx by adding a global Window
augmentation with the appropriate timer-handle type, or replace the window
attachment with a typed module-level variable. Ensure both clearInterval and
setInterval calls remain type-safe under strict TypeScript checking.
Source: Coding guidelines
Description
This PR fixes real bugs found in the codebase:
Number.EPSILONtoMath.round: prevents floating-point drift (e.g.1.005 * 100rounding to 100 instead of 101).parseInt: without10, strings like'0x1F'or'08'parse in unintended bases.parseInt: without10, strings like'0x1F'or'08'parse in unintended bases.Type of Change
How Has This Been Tested?
Checklist
Related Issue
Ref: #3552
Summary by CodeRabbit