From d5c8615c3c10e07123fe7edb229a11c683290941 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 07:25:30 +0000 Subject: [PATCH 1/3] Initial plan From 69d37b5ef4c717628f3a4542ef3488686bc25cff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 07:44:08 +0000 Subject: [PATCH 2/3] fix(eslint-factory): treat import bindings as local shadows in prefer-number-isnan Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- eslint-factory/src/rules/prefer-number-isnan.test.ts | 3 +++ eslint-factory/src/rules/prefer-number-isnan.ts | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/eslint-factory/src/rules/prefer-number-isnan.test.ts b/eslint-factory/src/rules/prefer-number-isnan.test.ts index 080aef770fe..269f10d03f2 100644 --- a/eslint-factory/src/rules/prefer-number-isnan.test.ts +++ b/eslint-factory/src/rules/prefer-number-isnan.test.ts @@ -34,9 +34,12 @@ describe("prefer-number-isnan", () => { valid: [ `function isNaN(value) { return false; } isNaN(value);`, `const isNaN = Number.isNaN; isNaN(value);`, + `import { isNaN } from "lodash"; isNaN(value);`, `const globalThis = { isNaN(value) { return value; } }; globalThis.isNaN(value);`, `const window = { isNaN(value) { return value; } }; window["isNaN"](value);`, `const global = { isNaN(value) { return value; } }; global.isNaN(value);`, + `import { window } from "./browser-shim"; window.isNaN(value);`, + `import { global } from "./server-shim"; global["isNaN"](value);`, // Dynamic computed access — identifier property reference, not string literal "isNaN" `globalThis[isNaN](value);`, ], diff --git a/eslint-factory/src/rules/prefer-number-isnan.ts b/eslint-factory/src/rules/prefer-number-isnan.ts index d6e55111379..0589239b1d1 100644 --- a/eslint-factory/src/rules/prefer-number-isnan.ts +++ b/eslint-factory/src/rules/prefer-number-isnan.ts @@ -34,7 +34,8 @@ export const preferNumberIsNanRule = createRule({ while (scope) { const variable = scope.set.get(name); - if (variable?.defs.some(d => d.type !== "ImportBinding")) { + // Any local definition shadows the global (including ESM ImportBinding). + if (variable && variable.defs.length > 0) { return true; } From 1e59acdc5ed9713a748206ce4953cb17fab3955b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Jul 2026 09:42:58 +0000 Subject: [PATCH 3/3] test(eslint-factory): add globalThis ESM import-shadow case and ESM invalid tests Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --- .../src/rules/prefer-number-isnan.test.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/eslint-factory/src/rules/prefer-number-isnan.test.ts b/eslint-factory/src/rules/prefer-number-isnan.test.ts index 269f10d03f2..e27bbb0fbde 100644 --- a/eslint-factory/src/rules/prefer-number-isnan.test.ts +++ b/eslint-factory/src/rules/prefer-number-isnan.test.ts @@ -38,6 +38,7 @@ describe("prefer-number-isnan", () => { `const globalThis = { isNaN(value) { return value; } }; globalThis.isNaN(value);`, `const window = { isNaN(value) { return value; } }; window["isNaN"](value);`, `const global = { isNaN(value) { return value; } }; global.isNaN(value);`, + `import { globalThis } from "./global-shim"; globalThis.isNaN(value);`, `import { window } from "./browser-shim"; window.isNaN(value);`, `import { global } from "./server-shim"; global["isNaN"](value);`, // Dynamic computed access — identifier property reference, not string literal "isNaN" @@ -102,4 +103,20 @@ describe("prefer-number-isnan", () => { ], }); }); + + it("invalid: global isNaN() is still flagged in ESM mode without a shadow", () => { + esmRuleTester.run("prefer-number-isnan", preferNumberIsNanRule, { + valid: [], + invalid: [ + { + code: `isNaN(value);`, + errors: [{ messageId: "preferNumberIsNaN", suggestions: [{ messageId: "replaceWithNumberIsNaN", output: `Number.isNaN(value);` }] }], + }, + { + code: `window.isNaN(value);`, + errors: [{ messageId: "preferNumberIsNaN", suggestions: [{ messageId: "replaceWithNumberIsNaN", output: `Number.isNaN(value);` }] }], + }, + ], + }); + }); });