Skip to content

refactor: use Number.parseInt/Number.isNaN and lint against the globals - #645

Merged
sirmalloc merged 1 commit into
sirmalloc:mainfrom
eric-engberg:refactor/number-globals
Oct 6, 2026
Merged

sirmalloc merged 1 commit into
sirmalloc:mainfrom
eric-engberg:refactor/number-globals

Conversation

@eric-engberg

Copy link
Copy Markdown
Contributor

Summary

The codebase mixes two spellings of the same number helpers: 53 calls use the global parseInt/isNaN, the rest the Number. forms. This makes them consistent and adds a lint rule so the mix doesn't come back.

Helper Before: Number. form / global form After
parseInt 6 / 39 all Number.parseInt
isNaN 14 / 14 all Number.isNaN
isFinite 19 / 0 unchanged
parseFloat 2 / 0 unchanged

Newer code (token speed widgets, usage API) already uses the Number. forms; the older code (colors.ts, git.ts, the menus) used the globals. Skills.tsx mixed both styles in the same file.

No behavior change

  • parseInt → Number.parseInt is a pure rename: Number.parseInt === parseInt.
  • isNaN → Number.isNaN only differs for non-number arguments: the global converts its argument first (isNaN('abc') is true, Number.isNaN('abc') is false). I checked all 14 calls: each tests the result of parseInt(..., 10) on the line before, which is always a number. TypeScript also only allows number for the global isNaN.
  • Audit: with the Number. prefix stripped, the removed and added lines in the diff match exactly. Nothing else changed.

Lint rule

ESLint's built-in no-restricted-globals rejects global parseInt, parseFloat, isNaN and isFinite, with a message pointing to the Number. form:

1:18  error  Unexpected use of 'parseInt'. Use Number.parseInt instead
2:18  error  Unexpected use of 'isNaN'. Use Number.isNaN instead; it does not coerce its argument

It needs no new dependency. parseFloat and isFinite are included preemptively; the code already uses only their Number. forms.

Testing

  • With the rule added but before the rename, bun run lint flagged exactly the 53 global calls (39 parseInt, 14 isNaN).
  • After the rename, bun run lint is clean and bun test passes 2,358 tests.
  • A throwaway probe file with parseInt(...), isNaN(...) and Number.parseInt(...) gets errors on the first two only.

The codebase mixed the two spellings: 39 parseInt vs 6 Number.parseInt,
14 isNaN vs 14 Number.isNaN (Number.isFinite and Number.parseFloat were
already used exclusively).

parseInt -> Number.parseInt is a pure rename (they are the same
function). Number.isNaN differs from the global only for non-number
arguments, which it doesn't coerce; every one of the 14 calls checks the
result of parseInt(..., 10), a number, so behavior is unchanged.

ESLint's built-in no-restricted-globals now rejects global parseInt,
parseFloat, isNaN and isFinite with a message pointing at the Number.*
form, so the mix doesn't come back. No new dependency.
@sirmalloc
sirmalloc merged commit 4cd383d into sirmalloc:main Oct 6, 2026
3 checks passed
@eric-engberg
eric-engberg deleted the refactor/number-globals branch October 9, 2026 21:48
pcvelz added a commit to pcvelz/ccstatusline-usage that referenced this pull request Oct 11, 2026
Upstream: label prefixes editable with e (sirmalloc#601, sirmalloc#666), Session Cost Rate (sirmalloc#671) and Extra Usage Daily Budget (sirmalloc#672) widgets, own-lock-only usage lock clearing (sirmalloc#624), NO_PROXY and request deadlines, terminal control-sequence sanitizing, git hardening and linear-time parsing, shared searchable option editor (sirmalloc#649) and widget base classes (sirmalloc#646-sirmalloc#654), node: imports (sirmalloc#657), Number.* globals lint (sirmalloc#645), test waits on redraw instead of fixed delays (sirmalloc#652).

Hand edits outside conflicts:
- src/widgets/shared/searchable-option-editor.tsx: compat fix - ports the fork's ref-based input handling (Enter picks from what was just typed) into upstream's new shared editor
- src/utils/usage-fetch.ts: compat fix - fork's fetchFreshUsageData uses upstream's clearOwnUsageLock (sirmalloc#624) instead of the removed clearUsageLock
- src/widgets/ApiUsage.tsx, src/widgets/Battery.ts: compat fix - Number.isNaN/Number.parseInt for upstream's no-restricted-globals rule
- src/utils/__tests__/usage-prefetch.test.ts: compat fix - mock renamed to upstream's mockFetchUsage
- src/tui/components/__tests__/PowerlineSetup.test.ts, src/tui/components/__tests__/StatusLinePreview.test.ts, src/tui/components/__tests__/TerminalWidthMenu.test.ts: compat fix - drop the fork's flushInk import, unused after upstream's waitFor switch
- README.md: upstream notes linked docs/USAGE.md (deleted in the fork); inlined the proxy and workspace-trust text instead; upstream's own release-note entries not taken
- .fork-keep-deleted: src/widgets/FableWeeklyUsage.ts (upstream widget, unregistered in the fork, which ships WeeklyFableUsage.ts)
- src/widgets/WeeklyFableUsage.ts: compat fix - adopts upstream's shared getUsagePercentWidgetEditorDisplay, which carries the time-cursor modifier
- src/tui/__tests__/App.test.ts: fork deviation - one extra down-arrow for the fork's Off Hours main-menu row
- src/widgets/__tests__/CacheTimer.test.ts, src/widgets/CacheTimer.ts: compat fix - emoji toggle moved from e to o because upstream reserves e for edit-label
- src/widgets/AgentAddress.ts: split the session-title guard into its own if (same behaviour) so the .fork-invariants nameSource guard matches again
- docs/test-retirements.md: ledger for tests upstream renamed or replaced
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants