From 752e56ff3600801f91aadcb67587d9229a840870 Mon Sep 17 00:00:00 2001 From: fisker Date: Tue, 24 Jun 2025 08:46:09 +0800 Subject: [PATCH] Fix `isUnresolvedVariable` --- rules/utils/is-unresolved-variable.js | 7 +- test/no-typeof-undefined.js | 27 ++++++ test/snapshots/no-typeof-undefined.js.md | 100 +++++++++++++++++++++ test/snapshots/no-typeof-undefined.js.snap | Bin 1479 -> 1672 bytes 4 files changed, 131 insertions(+), 3 deletions(-) diff --git a/rules/utils/is-unresolved-variable.js b/rules/utils/is-unresolved-variable.js index 531bad129b..b89b9c4e93 100644 --- a/rules/utils/is-unresolved-variable.js +++ b/rules/utils/is-unresolved-variable.js @@ -1,3 +1,5 @@ +import {findVariable} from '@eslint-community/eslint-utils'; + /** Checks if the given identifier node is shadowed in the given scope. @@ -7,7 +9,6 @@ Checks if the given identifier node is shadowed in the given scope. */ export default function isUnresolvedVariable(node, context) { const scope = context.sourceCode.getScope(node); - const reference = scope.references - .find(reference => reference.identifier === node); - return !reference.resolved; + const variable = findVariable(scope, node); + return !variable; } diff --git a/test/no-typeof-undefined.js b/test/no-typeof-undefined.js index 15ff01504e..6095813667 100644 --- a/test/no-typeof-undefined.js +++ b/test/no-typeof-undefined.js @@ -18,6 +18,17 @@ test.snapshot({ 'foo = 2; typeof foo === "undefined"', '/* globals foo: readonly */ typeof foo === "undefined"', '/* globals globalThis: readonly */ typeof globalThis === "undefined"', + outdent` + function parse() { + switch (typeof value === 'undefined') {} + } + `, + outdent` + /* globals value: readonly */ + function parse() { + switch (typeof value === 'undefined') {} + } + `, // Cases we are not checking '"undefined" === typeof a.b', 'const UNDEFINED = "undefined"; typeof a.b === UNDEFINED', @@ -76,6 +87,11 @@ test.snapshot({ a.b) === 'undefined'; } `, + outdent` + function parse(value) { + switch (typeof value === 'undefined') {} + } + `, ], }); @@ -86,5 +102,16 @@ test.snapshot({ invalid: [ 'typeof undefinedVariableIdentifier === "undefined"', 'typeof Array !== "undefined"', + outdent` + function parse() { + switch (typeof value === 'undefined') {} + } + `, + outdent` + /* globals value: readonly */ + function parse() { + switch (typeof value === 'undefined') {} + } + `, ].map(code => ({code, options: [{checkGlobalVariables: true}]})), }); diff --git a/test/snapshots/no-typeof-undefined.js.md b/test/snapshots/no-typeof-undefined.js.md index 3312d4fc3c..97140b4e59 100644 --- a/test/snapshots/no-typeof-undefined.js.md +++ b/test/snapshots/no-typeof-undefined.js.md @@ -511,6 +511,33 @@ Generated by [AVA](https://avajs.dev). 4 | }␊ ` +## invalid(23): function parse(value) { switch (typeof value === 'undefined') {} } + +> Input + + `␊ + 1 | function parse(value) {␊ + 2 | switch (typeof value === 'undefined') {}␊ + 3 | }␊ + ` + +> Output + + `␊ + 1 | function parse(value) {␊ + 2 | switch (value === undefined) {}␊ + 3 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | function parse(value) {␊ + > 2 | switch (typeof value === 'undefined') {}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ + 3 | }␊ + ` + ## invalid(1): typeof undefinedVariableIdentifier === "undefined" > Input @@ -568,3 +595,76 @@ Generated by [AVA](https://avajs.dev). Suggestion 1/1: Switch to \`… !== undefined\`.␊ 1 | Array !== undefined␊ ` + +## invalid(3): function parse() { switch (typeof value === 'undefined') {} } + +> Input + + `␊ + 1 | function parse() {␊ + 2 | switch (typeof value === 'undefined') {}␊ + 3 | }␊ + ` + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": true␊ + }␊ + ]␊ + ` + +> Error 1/1 + + `␊ + 1 | function parse() {␊ + > 2 | switch (typeof value === 'undefined') {}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ + 3 | }␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Switch to \`… === undefined\`.␊ + 1 | function parse() {␊ + 2 | switch (value === undefined) {}␊ + 3 | }␊ + ` + +## invalid(4): /* globals value: readonly */ function parse() { switch (typeof value === 'undefined') {} } + +> Input + + `␊ + 1 | /* globals value: readonly */␊ + 2 | function parse() {␊ + 3 | switch (typeof value === 'undefined') {}␊ + 4 | }␊ + ` + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": true␊ + }␊ + ]␊ + ` + +> Error 1/1 + + `␊ + 1 | /* globals value: readonly */␊ + 2 | function parse() {␊ + > 3 | switch (typeof value === 'undefined') {}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ + 4 | }␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Switch to \`… === undefined\`.␊ + 1 | /* globals value: readonly */␊ + 2 | function parse() {␊ + 3 | switch (value === undefined) {}␊ + 4 | }␊ + ` diff --git a/test/snapshots/no-typeof-undefined.js.snap b/test/snapshots/no-typeof-undefined.js.snap index 8dad76954cee77edd390edff0860da6e8a09c1fb..d9f56fdbe106e969d27459a15af62810bb113f65 100644 GIT binary patch literal 1672 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 hFxOFFWj;WFbx@E^q({?#`r000WS-SYqd