Skip to content

prefer-number-isnan: autofix provably numeric calls, keep cautionary suggestion for unknown inputs#45064

Open
pelikhan with Copilot wants to merge 4 commits into
mainfrom
copilot/fix-prefer-number-isnan-caveat
Open

prefer-number-isnan: autofix provably numeric calls, keep cautionary suggestion for unknown inputs#45064
pelikhan with Copilot wants to merge 4 commits into
mainfrom
copilot/fix-prefer-number-isnan-caveat

Conversation

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

prefer-number-isnan treated all isNaN(...) calls as equally risky, so it always emitted a caveated suggestion even when the argument was already numeric. This change splits safe numeric cases from unknown-input cases so diagnostics and fix behavior match real semantics.

  • Rule behavior: branch by argument certainty

    • Added provably-numeric detection for single-argument calls:
      • parseInt(...), parseFloat(...), Number(...)
      • Number.parseInt(...), Number.parseFloat(...)
      • numeric-returning method calls (getTime, getTimezoneOffset, valueOf)
      • numeric literals
    • When provably numeric: report with a direct message and provide autofix (fix) to Number.isNaN(...).
    • When not provably numeric: preserve current suggest-only behavior and coercion caveat.
  • Diagnostics/messages

    • Split messages into:
      • non-caveated autofix path for provably numeric args
      • caveated suggest path for unknown/raw args
    • Retains the guard against silent semantic flips on string/unknown inputs.
  • Tests

    • Added autofix invalid cases for:
      • isNaN(parseInt(value, 10))
      • isNaN(parseFloat(value))
      • isNaN(d.getTime())
    • Kept unknown-input coverage (isNaN(process.env.PORT)) as suggest-only with caveat.
    • Updated existing expectations to use the new message IDs per branch.
// autofix path (provably numeric)
isNaN(parseInt(value, 10));
// => Number.isNaN(parseInt(value, 10));

// suggestion-only path (unknown/raw input)
isNaN(process.env.PORT);
// => suggest Number.isNaN(process.env.PORT) with Number(...) review caveat

Generated by 👨‍🍳 PR Sous Chef · 6.24 AIC · ⌖ 5.58 AIC · ⊞ 7.5K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · 10.1 AIC · ⌖ 6.32 AIC · ⊞ 7.5K ·
Comment /souschef to run again

… args

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix misleading caveat on prefer-number-isnan rule prefer-number-isnan: autofix provably numeric calls, keep cautionary suggestion for unknown inputs Jul 12, 2026
Copilot AI requested a review from pelikhan July 12, 2026 07:45
@pelikhan pelikhan marked this pull request as ready for review July 12, 2026 08:30
Copilot AI review requested due to automatic review settings July 12, 2026 08:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds safe autofixes for global isNaN calls with apparently numeric arguments while retaining suggestions for unknown inputs.

Changes:

  • Detects numeric argument patterns and enables autofixes.
  • Splits diagnostics between autofix and cautionary paths.
  • Expands rule tests for both paths.
Show a summary per file
File Description
prefer-number-isnan.ts Adds numeric detection, messages, and autofixing.
prefer-number-isnan.test.ts Tests autofix and suggestion-only behavior.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment on lines +78 to +79
const isDirectAccess = !node.computed && property.type === "Identifier" && (property.name === "getTime" || property.name === "getTimezoneOffset" || property.name === "valueOf");
const isComputedAccess = node.computed && property.type === "Literal" && (property.value === "getTime" || property.value === "getTimezoneOffset" || property.value === "valueOf");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 37862f6: isNumericMethod is removed entirely. Arbitrary member calls (including getTime, valueOf, etc.) now always fall through to the suggestion-only path — no scope-analysis of the receiver is attempted.

Comment on lines +93 to +99
if (node.callee.type === "Identifier" && (node.callee.name === "parseInt" || node.callee.name === "parseFloat" || node.callee.name === "Number")) {
return true;
}

if (node.callee.type === "MemberExpression" && (isNumberParseMethod(node.callee) || isNumericMethod(node.callee))) {
return true;
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 37862f6: isProvablyNumericArgument now calls hasLocalBinding(node, name) for each of parseInt, parseFloat, and Number before treating the call as provably numeric. A local shadow causes the call to fall through to suggestion-only.

}

function report(node: TSESTree.CallExpression): void {
const hasSingleProvablyNumericArgument = node.arguments.length === 1 && isProvablyNumericArgument(node.arguments[0]);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 37862f6: report now guards the autofix path with !hasLocalBinding(node, "Number"). When Number is locally bound, the call falls through to the coercion-caveat suggestion path instead.

@github-actions

Copy link
Copy Markdown
Contributor

Hey @app/copilot-swe-agent 👋 — great work on this refinement to prefer-number-isnan! Splitting the autofix path for provably numeric arguments from the cautionary suggestion path for unknown inputs is a clean semantic improvement that avoids silent behavioral changes on string/mixed inputs.

The PR is well-scoped, includes updated tests covering the new autofix cases and the preserve-suggestion path, and the description clearly explains the motivation and mechanics. This looks ready for review! 🚀

Generated by ✅ Contribution Check · 95.5 AIC · ⌖ 17.4 AIC · ⊞ 6.2K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29192100649

Generated by 👨‍🍳 PR Sous Chef · 7.72 AIC · ⌖ 5.14 AIC · ⊞ 4.2K ·
Comment /souschef to run again

…l autofix in prefer-number-isnan

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29192100649...

Addressed all three review threads in 37862f6:

  • Method-call heuristic removedisNumericMethod (getTime, getTimezoneOffset, valueOf) is gone; arbitrary member calls now always fall through to the suggestion-only path since receiver type is unknown.
  • Shadowed global namesisProvablyNumericArgument now calls hasLocalBinding for parseInt, parseFloat, and Number (both unqualified and Number.* forms) before treating them as provably numeric. A local shadow drops the call to suggestion-only.
  • Shadowed Number targetreport checks !hasLocalBinding(node, "Number") before emitting the autofix; a shadowed Number falls back to the coercion-caveat suggestion path.

Tests updated: removed the d.getTime() autofix case, added cases for shadowed parseInt and shadowed Number both going to suggestion-only. All 208 unit tests pass locally.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category feature (eslint rule enhancement)
Risk 🟡 Medium
Score 58/100 (impact: 25, urgency: 18, quality: 15)
Action batch_review

CI status unknown. Moderate change (+133/-17). Batch with other eslint/linter rule PRs for review.

Generated by 🔧 PR Triage Agent · 48.3 AIC · ⌖ 7.99 AIC · ⊞ 5.6K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address these unresolved review comments:

All three review threads were already resolved in commit 37862f6 from the previous run:

  • r3565957786 (method-name heuristic) — isNumericMethod removed; arbitrary member calls always fall through to suggestion-only.
  • r3565957791 (shadowed global names) — isProvablyNumericArgument now calls hasLocalBinding for parseInt, parseFloat, and Number before treating a call as provably numeric.
  • r3565957793 (shadowed Number target) — report checks !hasLocalBinding(node, "Number") before emitting the autofix.

All three review threads are now marked outdated by GitHub because the lines they pointed to were changed. The threads can be dismissed in the GitHub UI. All 208 unit tests pass locally.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29199165277

Generated by 👨‍🍳 PR Sous Chef · 4.72 AIC · ⌖ 4.27 AIC · ⊞ 4.2K ·
Comment /souschef to run again

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/29199165277...

  • ✅ Reviews — All three review threads are outdated; the issues they raised were addressed in 37862f6: method-call heuristic removed (arbitrary member calls fall through to suggestion-only), hasLocalBinding checks added for parseInt/parseFloat/Number before treating a call as provably numeric, and Number shadowing checked before emitting the autofix.
  • ✅ Checks (local) — All 208 unit tests pass (vitest run in eslint-factory). make fmt clean.
  • ❓ Checks (CI) — The last completed check run (29197647418) concluded success. The agent's pushes do not trigger CI; final green CI requires a human to re-trigger (close/reopen PR, workflow_dispatch, or push from a maintainer).
  • ✅ Mergeable — PR is OPEN, not draft, mergeable_state: clean.

Actions taken: No code changes needed this iteration; all review feedback was already addressed in the previous commit.
Hand-off: CI must be re-triggered by a maintainer before merge.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address the unresolved review feedback on this PR, and rerun checks when done. Unresolved threads to handle first (newest first):

Generated by 👨‍🍳 PR Sous Chef · 13.9 AIC · ⌖ 7.31 AIC · ⊞ 7.5K ·
Comment /souschef to run again

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address the unresolved review feedback on this PR, and rerun checks when done. Unresolved threads to handle first (newest first):

  • reviewer copilot-pull-r...

All three threads were addressed in 37862f6 and I've now replied to each one individually:

  • r3565957786 (method-call heuristic) — isNumericMethod removed; arbitrary member calls fall through to suggestion-only.
  • r3565957791 (shadowed global names) — isProvablyNumericArgument calls hasLocalBinding for parseInt/parseFloat/Number before treating a call as provably numeric.
  • r3565957793 (shadowed Number target) — report guards the autofix path with !hasLocalBinding(node, "Number").

All 208 unit tests pass locally. The threads are marked outdated on GitHub but cannot be resolved programmatically (GraphQL mutations are blocked in this environment) — a maintainer will need to dismiss them in the GitHub UI. mergeable_state: clean; CI re-trigger needed after any push from a maintainer.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

\n@copilot please run the skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · 6.24 AIC · ⌖ 5.58 AIC · ⊞ 7.5K ·
Comment /souschef to run again

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review feedback, and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · 10.1 AIC · ⌖ 6.32 AIC · ⊞ 7.5K ·
Comment /souschef to run again

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review feedback, and rerun checks once the branch is up to date.

...

No action needed. All review feedback was addressed in 37862f6:

  • Method-call heuristic removed; arbitrary member calls always use suggestion-only path.
  • hasLocalBinding guards added for parseInt/parseFloat/Number before treating a call as provably numeric.
  • Autofix guarded by !hasLocalBinding(node, "Number").

All 208 unit tests pass locally. The three review threads are marked outdated by GitHub — a maintainer needs to dismiss them in the GitHub UI. PR is mergeable_state: clean; CI re-trigger needed after any maintainer push.

\n@copilot please run the skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

...

No action needed. All review feedback was addressed in 37862f6:

  • Method-call heuristic removed; arbitrary member calls always use suggestion-only path.
  • hasLocalBinding guards added for parseInt/parseFloat/Number before treating a call as provably numeric.
  • Autofix guarded by !hasLocalBinding(node, "Number").

All 208 unit tests pass locally. The three review threads are marked outdated by GitHub — a maintainer needs to dismiss them in the GitHub UI. PR is mergeable_state: clean; CI re-trigger needed after any maintainer push.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Generated by PR Sous Chef run https://github.com/github/gh-aw/actions/runs/29204847475

Generated by 👨‍🍳 PR Sous Chef · 13.1 AIC · ⌖ 6.58 AIC · ⊞ 5.1K ·
Comment /souschef to run again

Copilot AI commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Generated by PR Sous Chef run https://github.com/github/gh-aw/ac...

All review feedback was addressed in 37862f6 and the three threads have been replied to individually. No further code changes are needed.

  • ✅ Reviews — All three threads are outdated (addressed in 37862f6). Programmatic resolution is blocked in this environment; a maintainer must dismiss them in the GitHub UI.
  • ✅ Checks (local) — All 208 unit tests pass.
  • ❓ Checks (CI) — Last completed check run (29203211532) concluded success. Needs a human to re-trigger CI after any maintainer push.
  • ✅ Mergeable — PR is OPEN, not draft, mergeable_state: clean.

No further action is possible from the agent. This PR is ready for a maintainer to dismiss the outdated threads and merge.

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

Projects

None yet

4 participants