Skip to content

fix: resolve 4 bugs in termui - #3582

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

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

Conversation

@saurabhhhcodes

@saurabhhhcodes saurabhhhcodes commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

This PR fixes real bugs found in the codebase:

  • Added explicit radix to parseInt: without 10, strings like '0x1F' or '08' parse in unintended bases.
  • Removed redundant boolean comparison: x === true is equivalent to x (and x === false to !x), and shorter to read.
  • Replaced global isNaN with Number.isNaN: the global version coerces its argument, so isNaN('1') returns false while Number.isNaN is strict.
  • 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: #3581

Summary by CodeRabbit

  • Bug Fixes
    • Improved RSS reader handling of hexadecimal HTML entities, including entities with longer numeric values.
    • Corrected multi-select ordering so selected options appear in their intended numeric order.
    • Improved prompt validation to accurately reject invalid selection values.

@github-actions github-actions Bot added the type:bug +10 pts. Bug fix. label Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changes correct hexadecimal entity length handling, numeric sorting of selected options, and NaN validation for prompt choices.

Changes

RSS entity parsing

Layer / File(s) Summary
Limit hexadecimal entity parsing
examples/rss-reader/src/index.tsx
Hexadecimal entities use at most eight digits before conversion.

MultiSelect ordering

Layer / File(s) Summary
Sort checked indexes numerically
packages/ui/src/MultiSelect.ts
Checked option indexes use ascending numeric order.

Prompt choice validation

Layer / File(s) Summary
Use strict NaN validation
packages/ui/src/prompts.ts
Choice validation uses Number.isNaN(n) and preserves existing range and retry handling.

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 bug fix but omits the required package section, GSSoC section, and most template checklist fields. Complete every required template section, identify affected packages, use Closes #3581``, and mark all checklist items accurately.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies this as a bug-fix change and summarizes the main objective.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added area:examples Example apps. area:ui @termuijs/ui labels Aug 6, 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: 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/rss-reader/src/index.tsx`:
- Around line 30-31: Update the entity decoding logic around codePoint to parse
the complete hexadecimal payload rather than truncating it with entity.slice(2,
10). Reject payloads exceeding the supported Unicode hexadecimal length or
values outside the valid code point range before calling String.fromCodePoint,
and return match for invalid entities while preserving valid decoding.
🪄 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: d59f8d2f-dd99-4cb6-8e93-eafd78987eb8

📥 Commits

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

📒 Files selected for processing (3)
  • examples/rss-reader/src/index.tsx
  • packages/ui/src/MultiSelect.ts
  • packages/ui/src/prompts.ts

Comment on lines +30 to 31
const codePoint = Number.parseInt(entity.slice(2, 10), 16);
return Number.isFinite(codePoint) ? String.fromCodePoint(codePoint) : match;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file outline =="
ast-grep outline examples/rss-reader/src/index.tsx --view compact || true

echo "== relevant decodeEntities code =="
rg -n "decodeEntities|String.fromCodePoint|Number.parseInt|number;hex" examples/rss-reader/src/index.tsx -C 8

echo "== read file 1-80 =="
sed -n '1,80p' examples/rss-reader/src/index.tsx

echo "== deterministic JS probe =="
node - <<'JS'
const samples = [
  ['&`#x00001F600`;', 8],
  ['&`#xFFF`;', 3],
  ['&`#xFFFFFFFF`;', 8],
  ['&`#x110000`;', 5],
  ['&`#x999999999`;', 9],
];
for (const [input, sliceParam] of samples) {
  const entity = input;
  const truncatedCodePoint = Number.parseInt(entity.slice(2, 10), 16);
  const fullHex = entity.slice(2);
  const fullCodePoint = Number.parseInt(fullHex, 16);
  let out = null;
  let err = null;
  try {
    const result = Number.isFinite(truncatedCodePoint) ? String.fromCodePoint(truncatedCodePoint) : input;
    out = result;
  } catch (e) {
    err = e.toString();
  }
  console.log(JSON.stringify({ input, sliceParam, truncated: truncatedCodePoint, fullHex, fullCodePoint, out, err }));
}
JS

Repository: Karanjot786/TermUI

Length of output: 5281


🌐 Web query:

MDN String.fromCodePoint RangeError values outside the Unicode code point range 0x0000 to 0x10FFFF

💡 Result:

The JavaScript static method String.fromCodePoint throws a RangeError if any provided argument is not a valid Unicode code point [1][2]. According to the ECMAScript specification and MDN documentation, a valid code point must be an integral number within the inclusive range of 0x0000 to 0x10FFFF [1][3][2]. A RangeError is triggered if the provided argument: - Is a non-integer (e.g., 3.14) [1][2] - Is less than 0 [1][2] - Is greater than 0x10FFFF (1114111) [1][2] - Is NaN [1][4] Values outside the 0x0000 to 0x10FFFF range are considered invalid because they fall outside the defined Unicode codespace [1][2]. While UTF-16 encoding, which JavaScript uses for strings, represents higher code points using surrogate pairs, the method itself strictly validates that the input corresponds to a valid, representable Unicode code point [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

node - <<'JS'
function decodeEntities(value) {
  const entities = {
    amp: '&',
    lt: '<',
    gt: '>',
    quot: '"',
    apos: "'",
    nbsp: ' ',
  };
  return value.replace(/&(`#x`?[0-9a-fA-F]+|[a-zA-Z]+);/g, (match, entity) => {
    if (entity.startsWith('`#x`')) {
      const codePoint = Number.parseInt(entity.slice(2, 10), 16);
      return Number.isFinite(codePoint) ? String.fromCodePoint(codePoint) : match;
    }
    if (entity.startsWith('#')) {
      const codePoint = Number.parseInt(entity.slice(1), 10);
      return Number.isFinite(codePoint) ? String.fromCodePoint(codePoint) : match;
    }
    return entities[entity.toLowerCase()] ?? match;
  });
}

const samples = [
  '&`#x00001F600`;',
  '&`#xFFF`;',
  '&`#xFFFFFFFF`;',
  '&`#x110000`;',
  '&`#x999999999`;',
  '&`#99`;',
];

for (const input of samples) {
  let result;
  try {
    result = decodeEntities(input);
  } catch (e) {
    console.log(JSON.stringify({ input, result: null, error: e.name + ': ' + e.message }));
    continue;
  }
  console.log(JSON.stringify({ input, result }));
}
JS

Repository: Karanjot786/TermUI

Length of output: 528


Denial of Service (CWE-20): Improper Input Validation

Exploitability: Theoretical

Reject oversized hexadecimal entities instead of truncating them.

entity.slice(2, 10) keeps only the first eight digits, so &#x00001F600; decodes to U+1F60 instead of completing the entity. Values such as &#xFFFFFFFF; pass Number.isFinite, then String.fromCodePoint throws RangeError. Validate the full payload length and the Unicode range before decoding.

🤖 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 codePoint to parse the complete hexadecimal payload rather
than truncating it with entity.slice(2, 10). Reject payloads exceeding the
supported Unicode hexadecimal length or values outside the valid code point
range before calling String.fromCodePoint, and return match for invalid entities
while preserving valid decoding.

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