Skip to content

fix: resolve 4 bugs in termui - #3496

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

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

Conversation

@saurabhhhcodes

@saurabhhhcodes saurabhhhcodes commented Aug 4, 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).
  • 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.
  • 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: #3495

Summary by CodeRabbit

  • Bug Fixes
    • Progress-bar percentages now round more accurately at boundary values.
    • Multi-select options are consistently returned in ascending numeric order.
    • Promise failures during form operations are now logged for improved troubleshooting.
    • Dependency processing now maintains predictable numeric ordering during builds.

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

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changes update progress percentage rounding, add Form promise rejection logging, and replace lexicographic sorting with comparator-based sorting in MultiSelect and registry dependency collection.

Changes

Progress percentage rounding

Layer / File(s) Summary
Progress percentage calculation
examples/todo-app/src/index.ts
The calculation adds Number.EPSILON before rounding the scaled percentage.

Form rejection logging

Layer / File(s) Summary
Promise rejection handler
packages/ui/src/Form.ts
A .catch handler logs rejected Promise.all operations with console.error.

MultiSelect ordering

Layer / File(s) Summary
Numeric selected-option sorting
packages/ui/src/MultiSelect.ts
The selectedOptions getter sorts indices numerically instead of lexicographically.

Registry dependency ordering

Layer / File(s) Summary
Dependency sorting
scripts/build-registry.ts
collectDeps uses a subtraction-based comparator when sorting dependency strings.

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

Possibly related PRs

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 the required package section and GSSoC details and does not link the related issue with Closes #. Add the package list, complete the GSSoC section, change the issue reference to Closes #3495``, and complete the required checklist items.
✅ 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.5)
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.

@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/todo-app/src/index.ts`:
- Line 107: Update the percentage calculation at pct to add Number.EPSILON to
value before multiplying by 100, then round the scaled result. Add a regression
test covering value 0.575 and assert it produces 58.

In `@packages/ui/src/Form.ts`:
- Line 142: Fix the validation flow in the Form submit logic so the rejection
handler is syntactically attached to the Promise.all expression or handled with
try/catch. Move _isValidating = false and markDirty() into a finally block so
cleanup runs for both resolved and rejected validators, while keeping submit
callbacks only on successful validation; add a Form.test.ts case covering a
rejected validator.

In `@scripts/build-registry.ts`:
- Line 47: Update the sorting logic in collectDeps to compare package specifiers
lexicographically as strings instead of subtracting them numerically. Preserve
the existing deduplication and return behavior while ensuring the ordering
matches the registry tests when the bun script runs.
🪄 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: 1604854d-a84d-43e4-a467-e8146b38e445

📥 Commits

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

📒 Files selected for processing (4)
  • examples/todo-app/src/index.ts
  • packages/ui/src/Form.ts
  • packages/ui/src/MultiSelect.ts
  • scripts/build-registry.ts

const filled = Math.round(barWidth * value);

const pct = Math.round(value * 100);
const pct = Math.round(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 <<'EOF'
const value = 0.575;
const current = Math.round(value * 100 + Number.EPSILON);
const proposed = Math.round((value + Number.EPSILON) * 100);

console.log({ current, proposed });
if (current !== 57 || proposed !== 58) process.exit(1);
EOF

Repository: Karanjot786/TermUI

Length of output: 186


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | rg '(^|/)examples/todo-app/src/index\.ts$' || true

echo "== relevant context =="
if [ -f examples/todo-app/src/index.ts ]; then
  nl -ba examples/todo-app/src/index.ts | sed -n '80,120p'
fi

echo "== runtime boundary probe =="
node - <<'JS'
const values = [0.575, 0.015, 0.025, 0.035, 0.045, 0.055, 0.065, 0.075];
const expected = [58, 2, 2, 4, 4, 6, 6, 8];
const currentErrors = [];
const proposedErrors = [];
for (let i=0;i<values.length;i++) {
  const value = values[i];
  const current = Math.round(value * 100 + Number.EPSILON);
  const proposed = Math.round((value + Number.EPSILON) * 100);
  if (current !== expected[i]) currentErrors.push(`${value}: ${current}`);
  if (proposed !== expected[i]) proposedErrors.push(`${value}: ${proposed}`);
  console.log(`${value}: current=${current} proposed=${proposed} expected=${expected[i]}`);
}
console.log(`current_errors=${currentErrors.length} proposed_errors=${proposedErrors.length}`);
JS

Repository: Karanjot786/TermUI

Length of output: 268


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant context =="
awk '{printf "%6d\t%s\n", NR, $0}' examples/todo-app/src/index.ts | sed -n '80,120p'

echo "== runtime boundary probe =="
node - <<'JS'
const values = [0.575, 0.015, 0.025, 0.035, 0.045, 0.055, 0.065, 0.075];
const expected = [58, 2, 2, 4, 4, 6, 6, 8];
const currentErrors = [];
const proposedErrors = [];
for (let i=0;i<values.length;i++) {
  const value = values[i];
  const current = Math.round(value * 100 + Number.EPSILON);
  const proposed = Math.round((value + Number.EPSILON) * 100);
  if (current !== expected[i]) currentErrors.push(`${value}: ${current}`);
  if (proposed !== expected[i]) proposedErrors.push(`${value}: ${proposed}`);
  console.log(`${value}: current=${current} proposed=${proposed} expected=${expected[i]}`);
}
console.log(`current_errors=${currentErrors.length} proposed_errors=${proposedErrors.length}`);
JS

Repository: Karanjot786/TermUI

Length of output: 2624


Scale the epsilon before rounding.

Adding Number.EPSILON after value * 100 does not correct some floating-point rounding boundaries. For example, 0.575 * 100 can be 57.49999999999999, which still rounds to 57 instead of 58.

Add the epsilon before scaling and add a regression test for this boundary value.

Proposed fix
-            const pct = Math.round(value * 100 + Number.EPSILON);
+            const pct = Math.round((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/todo-app/src/index.ts` at line 107, Update the percentage
calculation at pct to add Number.EPSILON to value before multiplying by 100,
then round the scaled result. Add a regression test covering value 0.575 and
assert it produces 58.

Comment thread packages/ui/src/Form.ts
}
}

.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

Attach the rejection handler correctly and preserve submit cleanup.

Line 142 is a standalone .catch(...) expression, so TypeScript cannot parse this file. Attach the handler to the Promise.all(...) expression or wrap the await in try/catch.

When validation rejects, execution also bypasses Lines 92 and 97. Move _isValidating = false and markDirty() into finally; keep submit callbacks on the successful validation path. Add a test in packages/ui/src/Form.test.ts for a rejected validator.

🧰 Tools
🪛 Biome (2.5.5)

[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: The @termuijs/ui build (tsup/esbuild) failed due to an unexpected '.' at the start of '.catch(err => console.error("Promise.all failed:", err));'. TypeScript also reported declaration and syntax errors on this line.

🪛 GitHub Actions: CI / build-and-test

[error] 142-142: The @termuijs/ui build command (tsup) failed because of an unexpected '.' in .catch(err => console.error("Promise.all failed:", err));. TypeScript also reported syntax errors including missing try, ), and ;.

🤖 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` at line 142, Fix the validation flow in the Form
submit logic so the rejection handler is syntactically attached to the
Promise.all expression or handled with try/catch. Move _isValidating = false and
markDirty() into a finally block so cleanup runs for both resolved and rejected
validators, while keeping submit callbacks only on successful validation; add a
Form.test.ts case covering a rejected validator.

Source: 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:

#!/usr/bin/env bash
set -euo pipefail

npx tsc --noEmit --pretty false
npx vitest run scripts/build-registry.test.ts

Repository: Karanjot786/TermUI

Length of output: 5708


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

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

printf '\n== build-registry outline ==\n'
ast-grep outline scripts/build-registry.ts --view expanded || true

printf '\n== relevant build-registry lines ==\n'
sed -n '1,100p' scripts/build-registry.ts

printf '\n== relevant tests around dependency order ==\n'
sed -n '100,160p' scripts/build-registry.test.ts

printf '\n== tsconfig files ==\n'
for f in $(git ls-files 'tsconfig*.json'); do
  echo "--- $f"
  cat -n "$f"
done

printf '\n== runtime comparator behavior probe ==\n'
node - <<'JS'
const deps = ['foo', 'bar', 'baz'];
console.log([...deps].sort((a, b) => a - b));
console.log('comparator returns NaN:', Number.isNaN((a, b) => a - b) ? true : ((a,b)=>a-b)('foo','bar'));
JS

Repository: Karanjot786/TermUI

Length of output: 13309


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '== package scripts/typecheck fields ==\n'
node - <<'JS'
const { readFileSync } = require('node:fs');
const pkg = JSON.parse(readFileSync('package.json', 'utf-8'));
console.log(JSON.stringify({ scripts: pkg.scripts, dependencies: pkg.dependencies }, null, 2));
JS

printf '\n== lockfile snippets around bun/tsc packages if present ==\n'
git ls-files | rg '(^|/)(bun\.lockb|bun\.lock|pnpm-lock\.yaml|package-lock\.json|yarn\.lock)$' || true

Repository: Karanjot786/TermUI

Length of output: 816


Use a string comparator for package specifiers.

collectDeps handles string specifiers, so a - b makes the compiled script compare by NaN instead of lexicographically when the bun script is run. Use a string comparator to match the registry collectDeps test expectations.

🤖 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 logic in
collectDeps to compare package specifiers lexicographically as strings instead
of subtracting them numerically. Preserve the existing deduplication and return
behavior while ensuring the ordering matches the registry tests when the bun
script runs.

Source: Coding guidelines

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