Recognize Number.isFinite(d.getTime()) as a valid invalid-date guard - #52968
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅
|
|
✅ 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).
|
|
✅ 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.
|
|
✅ PR Code Quality Reviewer completed the code quality review.
|
|
✅ Test Quality Sentinel completed test quality analysis.
|
Comment MemoryNote This comment is managed by comment memory.It stores persistent context for this thread in the code block at the top of this comment.
|
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
| if (isFiniteCallee) addGuardPathWithNegation(variable, node); | ||
| else addGuardPath(variable, sourceCode.getAncestors(node), node); |
🧪 Test Quality Sentinel Report✅ Test Quality Score: 85/100 — Excellent
📊 Metrics (2 tests)
Test Function Details
Verdict
|
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /diagnosing-bugs and /tdd — requesting changes on two test coverage gaps.
📋 Key Themes & Highlights
Key Themes
- Potential correctness gap:
addGuardPathWithNegationalways registers the bare call node as a valid guard path. A wrong-polarityif (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
- ✅
extractGetTimeCheckTargetis 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
addGuardPathWithNegationis a good refactor — removes the copy-paste betweenDate.parseandnew 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>|
@copilot Quick triage for maintainer-ready follow-up: Outstanding review items (newest first):
Failed checks from the compact candidate set:
Branch update was requested automatically for this run when GitHub allows it. Please run the Run context: https://github.com/github/gh-aw/actions/runs/31910845720
|
|
🎉 This pull request is included in a new release. Release: |
require-invalid-date-check-before-compareonly matchedNumber.isNaN(x.getTime())/isNaN(x.getTime())as an invalid-date guard, so code validated withNumber.isFinite(...)— this repo's established idiom for timestamp validation inactions/setup/js— was reported as unguarded.Changes
isGetTimeNaNCheckis replaced byextractGetTimeCheckTarget, which extracts the receiver of a<expr>.getTime()sole argument independent of the wrapping check function. TheCallExpressionhandler now acceptsisNaN/Number.isNaNandisFinite/Number.isFiniteoverx.getTime().isFiniteform the enclosing!negation is also registered as a guard node, soif (!Number.isFinite(d.getTime())) return;satisfiesisExitingIfGuard. This reuses the negation logic already present forDate.parseguards, factored out intoaddGuardPathWithNegation.isNaNpolarity is deliberately left unchanged, so a wrong-polarityif (!Number.isNaN(...)) return;still reports.guardDominatesComparison,isExitingIfGuard, andguardDirectlyGatesComparisonapply to the new shapes exactly as before.requireInvalidDateCheckmessage now mention!Number.isFinite(x.getTime())as an accepted check.!Number.isFinite(d.getTime())guards (includingd.getTime() < xcomparisons) and&&-gatedNumber.isFinite(...)/isFinite(...); invalid cases asserting guard-after-comparison, non-exiting, and nested-branchisFiniteguards still report.Note: five failures in
require-fs-io-try-catch.test.tsare 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 · ◷