1+ import { isStringLiteral } from './ast/index.js' ;
2+
13const MESSAGE_ID_ERROR = 'prefer-global-this/error' ;
24const messages = {
35 [ MESSAGE_ID_ERROR ] : 'Prefer `{{replacement}}` over `{{value}}`.' ,
@@ -37,7 +39,7 @@ Some constructors are occasionally related to window (like Element !== iframe.co
3739
3840Please use these criteria to decide whether an API should be added here. Context: https://github.com/sindresorhus/eslint-plugin-unicorn/pull/2410#discussion_r1695312427
3941*/
40- const windowSpecificAPIs = new Set ( [
42+ const windowSpecificApis = new Set ( [
4143 // Properties and methods
4244 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-window-object
4345 'name' ,
@@ -103,7 +105,7 @@ const windowSpecificAPIs = new Set([
103105 'devicePixelRatio' ,
104106] ) ;
105107
106- const webWorkerSpecificAPIs = new Set ( [
108+ const webWorkerSpecificApis = new Set ( [
107109 // https://html.spec.whatwg.org/multipage/workers.html#the-workerglobalscope-common-interface
108110 'addEventListener' ,
109111 'removeEventListener' ,
@@ -125,13 +127,18 @@ const webWorkerSpecificAPIs = new Set([
125127 'onconnect' ,
126128] ) ;
127129
130+ const environmentSpecificApisByGlobalIdentifier = new Map ( [
131+ [ 'window' , windowSpecificApis ] ,
132+ [ 'self' , webWorkerSpecificApis ] ,
133+ ] ) ;
134+
128135/**
129136Check if the node is a window-specific API.
130137
131138@param {import('estree').MemberExpression } node
132139@returns {boolean }
133140*/
134- const isWindowSpecificAPI = node => {
141+ const isWindowSpecificApi = node => {
135142 if ( node . type !== 'MemberExpression' ) {
136143 return false ;
137144 }
@@ -140,7 +147,7 @@ const isWindowSpecificAPI = node => {
140147 return false ;
141148 }
142149
143- if ( windowSpecificAPIs . has ( node . property . name ) ) {
150+ if ( windowSpecificApis . has ( node . property . name ) ) {
144151 if ( [ 'addEventListener' , 'removeEventListener' , 'dispatchEvent' ] . includes ( node . property . name ) && node . parent . type === 'CallExpression' && node . parent . callee === node ) {
145152 const argument = node . parent . arguments [ 0 ] ;
146153 return argument && argument . type === 'Literal' && windowSpecificEvents . has ( argument . value ) ;
@@ -160,13 +167,37 @@ function isComputedMemberExpressionObject(identifier) {
160167 return identifier . parent . type === 'MemberExpression' && identifier . parent . computed && identifier . parent . object === identifier ;
161168}
162169
170+ /**
171+ Check if the identifier is used in an existence check for a known environment-specific API.
172+
173+ @param {import('estree').Identifier } identifier
174+ @returns {boolean }
175+ */
176+ function isKnownSpecificApiExistenceCheck ( identifier ) {
177+ const specificApis = environmentSpecificApisByGlobalIdentifier . get ( identifier . name ) ;
178+ if ( ! specificApis ) {
179+ return false ;
180+ }
181+
182+ const { parent} = identifier ;
183+ if ( parent . type !== 'BinaryExpression' || parent . operator !== 'in' || parent . right !== identifier ) {
184+ return false ;
185+ }
186+
187+ if ( ! isStringLiteral ( parent . left ) ) {
188+ return false ;
189+ }
190+
191+ return specificApis . has ( parent . left . value ) ;
192+ }
193+
163194/**
164195Check if the node is a web worker specific API.
165196
166197@param {import('estree').MemberExpression } node
167198@returns {boolean }
168199*/
169- const isWebWorkerSpecificAPI = node => node . type === 'MemberExpression' && node . object . name === 'self' && node . property . type === 'Identifier' && webWorkerSpecificAPIs . has ( node . property . name ) ;
200+ const isWebWorkerSpecificApi = node => node . type === 'MemberExpression' && node . object . name === 'self' && node . property . type === 'Identifier' && webWorkerSpecificApis . has ( node . property . name ) ;
170201
171202/** @param {import('eslint').Rule.RuleContext } context */
172203const create = context => {
@@ -183,8 +214,9 @@ const create = context => {
183214 for ( const { identifier} of references ) {
184215 if (
185216 isComputedMemberExpressionObject ( identifier )
186- || isWindowSpecificAPI ( identifier . parent )
187- || isWebWorkerSpecificAPI ( identifier . parent )
217+ || isKnownSpecificApiExistenceCheck ( identifier )
218+ || isWindowSpecificApi ( identifier . parent )
219+ || isWebWorkerSpecificApi ( identifier . parent )
188220 ) {
189221 continue ;
190222 }
0 commit comments