Skip to content

fix: resolve 4 bugs in termui - #3693

Closed
saurabhhhcodes wants to merge 1 commit into
Karanjot786:mainfrom
saurabhhhcodes:fix/termui-53952
Closed

fix: resolve 4 bugs in termui#3693
saurabhhhcodes wants to merge 1 commit into
Karanjot786:mainfrom
saurabhhhcodes:fix/termui-53952

Conversation

@saurabhhhcodes

@saurabhhhcodes saurabhhhcodes commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes real bugs found in the codebase:

  • Added Number.EPSILON to Math.round: prevents floating-point drift (e.g. 1.005 * 100 rounding to 100 instead of 101).
  • Prevented interval leak: repeated mounts now clear the previous interval before scheduling a new one.
  • Added rejection handler to Promise.all: an unhandled rejection in any input promise previously crashed silently.
  • Fixed default sort: .sort() coerces elements to strings, so [10, 9, 2] sorts as [10, 2, 9]; numeric comparator sorts correctly.

Type of Change

  • Bug fix (non-breaking change fixing an issue)

How Has This Been Tested?

  • Local manual testing

Checklist

  • My code follows the style guidelines
  • I have performed a self-review

Related Issue

Ref: #3692

Summary by CodeRabbit

  • Bug Fixes
    • Prevented duplicate streaming timers from continuing after a new stream starts.
    • Improved Pomodoro progress percentage accuracy, avoiding display errors caused by rounding.
    • Added clearer error reporting when form-related operations fail.
  • Improvements
    • Dependency listings are now generated in a consistent, predictable order.

@github-actions github-actions Bot added type:bug +10 pts. Bug fix. area:examples Example apps. area:ui @termuijs/ui and removed type:bug +10 pts. Bug fix. labels Aug 7, 2026
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changes add interval cleanup, improve percentage rounding, log rejected form operations, and make dependency sorting use an explicit comparator.

Changes

Streaming timer cleanup

Layer / File(s) Summary
Clear the existing streaming interval
examples/ai-streaming/src/index.tsx
The streaming setup clears the existing interval before assigning a new interval handle to window.__interval.

UI and example correctness fixes

Layer / File(s) Summary
Adjust rounding and promise error handling
examples/pomodoro-timer/src/index.tsx, packages/ui/src/Form.ts
The percentage label adds Number.EPSILON before rounding. Promise.all failures are logged with console.error.

Registry dependency sorting

Layer / File(s) Summary
Use comparator-based dependency sorting
scripts/build-registry.ts
Dependency package names remain alphabetically sorted through an explicit comparator.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: type:bug

Suggested reviewers: karanjot786

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the fixes and testing, but it omits required template sections and does not use the required issue-closing syntax. Add the package list, complete the required checklist and GSSoC profile, and change Ref: #3692 to `Closes `#3692.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the four bug fixes and follows the required type: short description format.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Biome (2.5.6)
packages/ui/src/Form.ts

File contains syntax errors that prevent linting: Line 142: Expected a statement but instead found '.catch(err => console.error("Promise.all failed:", err))'.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@saurabhhhcodes saurabhhhcodes mentioned this pull request Aug 7, 2026
4 tasks
@github-actions github-actions Bot added the type:bug +10 pts. Bug fix. label Aug 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 label calculation in the timer’s
label-rendering logic so the floating-point correction is applied to the 0–1
value before multiplying by 100, or use an equivalent scale-aware adjustment.
Preserve the existing conditional label behavior and rounding.

In `@packages/ui/src/Form.ts`:
- Around line 141-142: Fix the Promise.all error-handling flow in Form by
attaching the catch to the Promise.all expression or wrapping its await in
try/catch, removing the standalone invalid .catch syntax. On validation
rejection, reset _isValidating and call markDirty(), ensuring every
state-mutating path follows the widget state-update convention.

In `@scripts/build-registry.ts`:
- Line 47: Update the sorting in collectDeps to compare dependency names with a
string comparator using localeCompare, preserving the tested alphabetical order
of package names.
🪄 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: ae664683-002b-40d9-9310-ba402e74e6c7

📥 Commits

Reviewing files that changed from the base of the PR and between 6c7584e and 9333313.

📒 Files selected for processing (4)
  • examples/ai-streaming/src/index.tsx
  • examples/pomodoro-timer/src/index.tsx
  • packages/ui/src/Form.ts
  • scripts/build-registry.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)}%` : '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

node <<'NODE'
const value = 0.145;
const current = Math.round(value * 100 + Number.EPSILON);
const corrected = Math.round((value + Number.EPSILON) * 100);

console.log({ current, corrected });

if (current !== 14 || corrected !== 15) process.exit(1);
NODE

Repository: Karanjot786/TermUI

Length of output: 187


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '--- candidate file ---\n'
wc -l examples/pomodoro-timer/src/index.tsx
printf '\n--- relevant lines ---\n'
sed -n '1,230p' examples/pomodoro-timer/src/index.tsx
printf '\n--- _value references ---\n'
rg -n "_value|set(Value|Interval)" examples/pomodoro-timer/src/index.tsx

Repository: Karanjot786/TermUI

Length of output: 247


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '%s\n' '--- candidate file ---'
wc -l examples/pomodoro-timer/src/index.tsx || true
printf '%s\n' ''
printf '%s\n' '--- relevant lines ---'
sed -n '1,230p' examples/pomodoro-timer/src/index.tsx || true
printf '%s\n' ''
printf '%s\n' '--- _value and setValue references ---'
rg -n '_value|setValue|setInterval|setInterval' examples/pomodoro-timer/src/index.tsx || true

Repository: Karanjot786/TermUI

Length of output: 7114


Apply Number.EPSILON before converting to percentage.

setValue() stores values in the 0–1 range, but Number.EPSILON is added after _value * 100. The added value is too small to affect rounding for inputs just below half-integer percentage boundaries. Add it to _value before multiplication, or use a scale-aware correction.

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.

Suggested change
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
label calculation in the timer’s label-rendering logic so the floating-point
correction is applied to the 0–1 value before multiplying by 100, or use an
equivalent scale-aware adjustment. Preserve the existing conditional label
behavior and rounding.

Comment thread packages/ui/src/Form.ts
Comment on lines +141 to +142

.catch(err => console.error("Promise.all failed:", err)); No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Fix the invalid .catch placement before merging.

Line 142 starts a standalone .catch expression, so packages/ui/src/Form.ts does not parse. Attach the handler to the Promise.all(...) expression at Line 83, or use try/catch around await Promise.all(...).

When validation rejects, also reset _isValidating and call markDirty(). The cleanup at Lines 92 and97 runs only after a successful await. Logging the error alone leaves the form in the validating state.

As per coding guidelines, every state-mutating method on a widget calls this.markDirty().

🧰 Tools
🪛 Biome (2.5.6)

[error] 142-142: Expected a statement but instead found '.catch(err => console.error("Promise.all failed:", err))'.

(parse)

🪛 GitHub Actions: CI / 0_build-and-test.txt

[error] 142-142: Build failed during 'tsup' due to a syntax error: Unexpected '.' at '.catch(err => console.error("Promise.all failed:", err));'. TypeScript also reported TS1128, TS1005, and TS2304.

🪛 GitHub Actions: CI / build-and-test

[error] 142-142: tsup/esbuild build failed: Unexpected '.' at the standalone '.catch(err => console.error("Promise.all failed:", err));'. TypeScript also reports TS1128, TS1005, and TS2304 syntax errors. The failing command was 'bun run build'.

🤖 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 `@packages/ui/src/Form.ts` around lines 141 - 142, Fix the Promise.all
error-handling flow in Form by attaching the catch to the Promise.all expression
or wrapping its await in try/catch, removing the standalone invalid .catch
syntax. On validation rejection, reset _isValidating and call markDirty(),
ensuring every state-mutating path follows the widget state-update convention.

Sources: Coding guidelines, Linters/SAST tools

Comment thread scripts/build-registry.ts
let m: RegExpExecArray | null;
while ((m = re.exec(content)) !== null) deps.add(m[1]!);
return [...deps].sort();
return [...deps].sort((a, b) => a - b);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)scripts/(build-registry|build-registry\.test)\.(ts|tsx)$|(^|/)tsconfig.*\.json$|(^|/)package\.json$' || true

echo "== build-registry outline =="
ast-grep outline scripts/build-registry.ts 2>/dev/null || true

echo "== relevant build-registry lines =="
sed -n '1,140p' scripts/build-registry.ts

echo "== relevant build-registry test lines =="
sed -n '110,155p' scripts/build-registry.test.ts

echo "== tsconfig strict settings =="
for f in $(git ls-files | rg '(^|/)tsconfig.*\.json$'); do
  echo "-- $f"
  sed -n '1,220p' "$f"
done

Repository: Karanjot786/TermUI

Length of output: 28868


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
deps = ['`@termuijs/core`', '`@termuijs/motion`', '`@termuijs/widgets`']
print("numeric comparator returns:", [(a, b, a < b or a > b or a == b, a == b or a > b) for a, b in zip(deps, deps[1:])])
print("NaN comparison behavior:", (float('nan') < 0), (float('nan') > 0), (float('nan') == float('nan')))
print("local compare:", sorted(deps, key=None))
PY

Repository: Karanjot786/TermUI

Length of output: 412


🌐 Web query:

TypeScript string subtraction compile error strict comparison operators

💡 Result:

In TypeScript, attempting to perform subtraction on strings (e.g., "10" - "5") results in a compilation error because the language restricts arithmetic operations to specific types [1][2][3]. Why TypeScript Prevents String Subtraction The TypeScript compiler enforces strict type checking for arithmetic operators, including subtraction (-). To prevent common programming errors and unintended implicit type coercion—which is a common source of bugs in JavaScript—TypeScript requires that both the left-hand side and right-hand side of an arithmetic operation be of type number, bigint, any, or a numeric enum [1][2][3]. When you attempt to subtract strings, the compiler throws error TS2362 or TS2363, stating that the operand must be of one of these permitted types [1][4][2]. If you need to perform numeric subtraction with string data, you must explicitly convert the strings to a numeric type using functions like Number, parseFloat, parseInt, or the unary plus (+) operator [4][2][5]. Strict Comparison Operators Regarding comparison, TypeScript distinguishes between strict (===) and loose (==) operators, and leverages them for type narrowing [6][7]. 1. Strict Equality (===): This operator checks both value and type without performing implicit coercion [8][9]. In TypeScript, if the compiler can statically determine that the types of the two operands have no overlap (e.g., comparing a string literal to a number), it will issue a compile-time error (ts(2367)) [8]. 2. Loose Equality (==): This operator performs type coercion before comparison [6][9]. While this can sometimes be useful (e.g., the common null-check idiom value == null), it is generally discouraged in TypeScript because it can mask type-related bugs [6][10]. Best Practices - Arithmetic: Always ensure operands are explicitly numeric before performing subtraction [2][3]. - Comparisons: Default to using strict equality (===) throughout your code to avoid the pitfalls of implicit type coercion [10][9]. If you need to safely handle data of varying types, utilize Type Guards (e.g., typeof, instanceof) to narrow types before performing operations [6][7].

Citations:


Use a string comparator for dependency names.

collectDeps returns string package names, so a - b is invalid in strict TypeScript and can produce NaN at runtime. Array.sort needs a comparator returning a negative value, zero, or a positive value; use a.localeCompare(b) so @termuijs/core, @termuijs/motion, and @termuijs/widgets stay in tested alphabetical order.

🤖 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 `@scripts/build-registry.ts` at line 47, Update the sorting in collectDeps to
compare dependency names with a string comparator using localeCompare,
preserving the tested alphabetical order of package names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:examples Example apps. area:ui @termuijs/ui type:bug +10 pts. Bug fix.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant