Skip to content

Recognize Number.isFinite(d.getTime()) as a valid invalid-date guard - #52968

Merged
pelikhan merged 3 commits into
mainfrom
copilot/require-invalid-date-check-before-compare
Aug 15, 2026
Merged

Recognize Number.isFinite(d.getTime()) as a valid invalid-date guard#52968
pelikhan merged 3 commits into
mainfrom
copilot/require-invalid-date-check-before-compare

Conversation

Copilot AI commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

require-invalid-date-check-before-compare only matched Number.isNaN(x.getTime()) / isNaN(x.getTime()) as an invalid-date guard, so code validated with Number.isFinite(...) — this repo's established idiom for timestamp validation in actions/setup/js — was reported as unguarded.

// previously reported as unguarded; now recognized
const d = new Date(input);
if (!Number.isFinite(d.getTime())) return;
if (d > threshold) doIt();

Changes

  • Guard matcher generalized: isGetTimeNaNCheck is replaced by extractGetTimeCheckTarget, which extracts the receiver of a <expr>.getTime() sole argument independent of the wrapping check function. The CallExpression handler now accepts isNaN/Number.isNaN and isFinite/Number.isFinite over x.getTime().
  • Polarity handling: for the isFinite form the enclosing ! negation is also registered as a guard node, so if (!Number.isFinite(d.getTime())) return; satisfies isExitingIfGuard. This reuses the negation logic already present for Date.parse guards, factored out into addGuardPathWithNegation. isNaN polarity is deliberately left unchanged, so a wrong-polarity if (!Number.isNaN(...)) return; still reports.
  • Unchanged reachability semantics: guardDominatesComparison, isExitingIfGuard, and guardDirectlyGatesComparison apply to the new shapes exactly as before.
  • Docs/messages: rule description and the requireInvalidDateCheck message now mention !Number.isFinite(x.getTime()) as an accepted check.
  • Tests: valid cases for exiting !Number.isFinite(d.getTime()) guards (including d.getTime() < x comparisons) and &&-gated Number.isFinite(...) / isFinite(...); invalid cases asserting guard-after-comparison, non-exiting, and nested-branch isFinite guards still report.

Note: five failures in require-fs-io-try-catch.test.ts are pre-existing on this branch and untouched by these changes.


Run context: https://github.com/github/gh-aw/actions/runs/31910845720> Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.7 AIC · ⌖ 6.91 AIC · ⊞ 8.7K ·

Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix guard recognition for finite date checks Recognize Number.isFinite(d.getTime()) as a valid invalid-date guard Aug 15, 2026
Copilot AI requested a review from pelikhan August 15, 2026 21:24
@pelikhan
pelikhan marked this pull request as ready for review August 15, 2026 21:38
Copilot AI balanced review requested due to automatic review settings August 15, 2026 21:38
@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR does not have the 'implementation' label and has 0 new lines of code in business logic directories (threshold: 100).

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Ponytail review: no over-engineering found. The refactor (isGetTimeNaNCheck -> extractGetTimeCheckTarget, addGuardPathWithNegation extraction) actually reduces duplication by unifying negation-handling logic that previously existed separately for isFinite guards. No dead code, no speculative abstractions, no unnecessary dependencies. Lean already. Ship.

Generated by Ponytail Reviewer for #52968

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-08-15T21:40:00Z
review_event: COMMENT
top_themes:
  - no actionable blocking issues in changed lines
  - added coverage for Number.isFinite(getTime()) guards
files_reviewed:
  - eslint-factory/src/rules/require-invalid-date-check-before-compare.ts
  - eslint-factory/src/rules/require-invalid-date-check-before-compare.test.ts
comment_count: 0

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 4.39 AIC · ⌖ 5.32 AIC · ⊞ 4.5K ·
Comment /review to run again

@github-actions github-actions Bot 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.

Verdict

COMMENT — I don't see a blocking defect in the changed lines.

Review notes

The rule change is internally consistent: it broadens getTime() guard recognition to isFinite/Number.isFinite, preserves the existing control-flow gating rules, and adds regression coverage for the newly accepted guard shapes plus a few non-dominating counterexamples.

The background grumpy-coder helper was unavailable in this environment, so the review relied on a direct pass over the diff.

🔎 Code quality review by PR Code Quality Reviewer · gpt54 · 4.39 AIC · ⌖ 5.32 AIC · ⊞ 4.5K
Comment /review to run again

@github-actions github-actions Bot 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.

The implementation is correct and well-tested. extractGetTimeCheckTarget cleanly generalizes the old boolean check to return the receiver node, addGuardPathWithNegation removes the duplicated negation-registration logic, and the CallExpression fall-through to the Date.parse path is preserved. Test coverage is thorough, including both positive (guarded) and negative (guard-after-comparison, non-exiting guard) cases.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 17.9 AIC · ⌖ 7.01 AIC · ⊞ 5.6K

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

Extends invalid-date validation recognition to support Number.isFinite(d.getTime()) patterns.

Changes:

  • Generalizes .getTime() guard extraction.
  • Adds finite-check polarity handling, documentation, and tests.
  • Preserves existing reachability checks.
Show a summary per file
File Description
eslint-factory/src/rules/require-invalid-date-check-before-compare.ts Adds finite-check guard recognition.
eslint-factory/src/rules/require-invalid-date-check-before-compare.test.ts Tests valid and ineffective finite guards.

Review details

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment on lines +303 to +304
if (isFiniteCallee) addGuardPathWithNegation(variable, node);
else addGuardPath(variable, sourceCode.getAncestors(node), node);
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 85/100 — Excellent

Analyzed 2 test(s): 2 design, 0 implementation, 0 violation(s).

Note: The changed test file is *.test.ts (TypeScript/vitest), which was not detected by the pre-fetch scanner (configured for *.test.cjs/*.test.js). Tests were analyzed directly from the PR diff.

📊 Metrics (2 tests)
Metric Value
Analyzed 2 (Go: 0, JS/TS: 2)
✅ Design 2 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 1 (50%)
Duplicate clusters 0
Inflation No (test +32 lines / prod +50 additions = 0.64 ratio)
🚨 Violations 0
Test File Classification Issues
valid: Number.isFinite(d.getTime()) before comparison require-invalid-date-check-before-compare.test.ts design_test / behavioral_contract / high_value None
invalid: guards that do not protect the comparison still report require-invalid-date-check-before-compare.test.ts design_test / behavioral_contract / high_value None

Test Function Details

valid: Number.isFinite(d.getTime()) before comparison — Verifies the new guard patterns are accepted: early-return !Number.isFinite(...), throw form, and &&-gated isFinite/Number.isFinite. Covers 4 valid code shapes that the rule must not flag. Happy-path only (as expected for valid-case table).

invalid: guards that do not protect the comparison still report — Verifies that guard-after-comparison, non-exiting guard (core.warning), and nested-branch guard still produce errors. Each case asserts exact messageId (requireInvalidDateCheck) and data (subject, operator, getTimeTarget), giving strong regression protection against over-eager guard acceptance.

Verdict

Passed. 0% implementation tests (threshold: 30%). Both new tests verify behavioral contracts — valid and invalid guard shapes for the new Number.isFinite(d.getTime()) rule extension. No violations detected.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 44.6 AIC · ⌖ 8.65 AIC · ⊞ 7.9K ·
Comment /review to run again

@github-actions github-actions Bot 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.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — requesting changes on two test coverage gaps.

📋 Key Themes & Highlights

Key Themes

  • Potential correctness gap: addGuardPathWithNegation always registers the bare call node as a valid guard path. A wrong-polarity if (Number.isFinite(d.getTime())) return; guard (exits on the valid date) may silently pass the rule — this needs a test to confirm it fires or a code fix if it doesn't.
  • Undocumented invariant: The PR description states !Number.isNaN(d.getTime()) (wrong-polarity isNaN) still reports, but no test asserts it.

Positive Highlights

  • extractGetTimeCheckTarget is a clean, well-named generalization — returns the receiver directly instead of a boolean, avoiding the double traversal from the old code.
  • ✅ Factoring negation-registration logic into addGuardPathWithNegation is a good refactor — removes the copy-paste between Date.parse and new Date(x) paths.
  • ✅ Invalid test cases cover guard-after-comparison, non-exiting guards, and nested-branch guards — good breadth.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 50.2 AIC · ⌖ 8.6 AIC · ⊞ 7.7K
Comment /matt to run again

Comments that could not be inline-anchored

eslint-factory/src/rules/require-invalid-date-check-before-compare.ts:303

[/tdd] Wrong-polarity isFinite guard may be silently accepted as valid.

addGuardPathWithNegation always registers the bare CallExpression node as one of the guard paths (line 263). When the code reads if (Number.isFinite(d.getTime())) return; (exits on a valid date — wrong polarity), isExitingIfGuard would match this bare call node as the if test and treat it as a satisfied guard, suppressing the error for a subsequent comparison that is still unprotected.

<details>
<summary…

eslint-factory/src/rules/require-invalid-date-check-before-compare.test.ts:215

[/tdd] The PR description says if (!Number.isNaN(d.getTime())) return; (wrong-polarity isNaN) still reports, but no test covers this.

The isNaN path uses the plain addGuardPath (not addGuardPathWithNegation), so a negated isNaN call would not be registered as a guard — the rule should correctly fire. Adding an explicit test case makes this a documented, regression-protected invariant rather than an undocumented assumption.

<details>
<summary>💡 Suggested test</summary>

it…

</details>

@github-actions github-actions Bot 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.

✅ Test Quality Sentinel: 85/100 — Excellent. 0% implementation tests (threshold: 30%). Both new tests are design tests covering valid and invalid guard shapes for the Number.isFinite(d.getTime()) extension. No violations.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Quick triage for maintainer-ready follow-up:

Outstanding review items (newest first):

Failed checks from the compact candidate set:

  • None listed.

Branch update was requested automatically for this run when GitHub allows it. Please run the pr-finisher skill before handing this PR back to maintainers.

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

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.7 AIC · ⌖ 6.91 AIC · ⊞ 8.7K ·
Comment /souschef to run again

@pelikhan
pelikhan merged commit 042383a into main Aug 15, 2026
1 check failed
@pelikhan
pelikhan deleted the copilot/require-invalid-date-check-before-compare branch August 15, 2026 22:03
Copilot stopped work on behalf of gh-aw-bot due to an error August 15, 2026 22:03
Copilot AI requested a review from gh-aw-bot August 15, 2026 22:03
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.87.0

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

Labels

None yet

Projects

None yet

4 participants