Skip to content

Commit b576a07

Browse files
committed
fix: Case-insensitive globals matching (#684)
* Use case-insensitive objectname matching only for matching browserglobals
1 parent 44f6be3 commit b576a07

File tree

2 files changed

+153
-4
lines changed

2 files changed

+153
-4
lines changed

src/helpers.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint no-nested-ternary: off */
22
import browserslist from "browserslist";
3+
import globals from "globals";
34
import { AstNodeTypes, TargetNameMappings } from "./constants";
45
import {
56
AstMetadataApiWithTargetsResolver,
@@ -165,6 +166,8 @@ function protoChainFromMemberExpression(node: ESLintNode): string[] {
165166
return [...protoChain, node.property!.name];
166167
}
167168

169+
const browserGlobals = new Set(Object.keys(globals.browser));
170+
168171
export function lintMemberExpression(
169172
context: Context,
170173
handleFailingRule: HandleFailingRule,
@@ -200,11 +203,20 @@ export function lintMemberExpression(
200203
} else {
201204
const objectName = node.object.name;
202205
const propertyName = node.property.name;
203-
const failingRule = rules.find(
204-
(rule) =>
205-
rule.object.toLowerCase() === objectName.toLowerCase() &&
206+
const isBrowserGlobal = browserGlobals.has(objectName);
207+
const objectNameLower = objectName.toLowerCase();
208+
209+
const failingRule = rules.find((rule) => {
210+
// Match case-insensitively IF the objectName was case-sentively found in browserGlobals
211+
const objectNameMatches = isBrowserGlobal
212+
? rule.object.toLowerCase() === objectNameLower
213+
: rule.object === objectName;
214+
return (
215+
objectNameMatches &&
206216
(rule.property == null || rule.property === propertyName)
207-
);
217+
);
218+
});
219+
208220
if (failingRule)
209221
checkNotInsideIfStatementAndReport(
210222
context,

test/e2e.spec.ts

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,44 @@ ruleTester.run("compat", rule, {
9393
code: "document.fonts()",
9494
settings: { browsers: ["edge 79"] },
9595
},
96+
{
97+
code: `
98+
import * as serviceWorker from './serviceWorker';
99+
serviceWorker.register(false);
100+
`,
101+
settings: { browsers: ["chrome 52", "android 145"] },
102+
},
103+
{
104+
code: `
105+
navigator.permissions
106+
.query({ name: 'local-network-access' })
107+
.then((permissionStatus) => {
108+
permissionStatus.addEventListener('change', () => {});
109+
});
110+
`,
111+
settings: { browsers: ["chrome 52", "android 145"] },
112+
},
113+
{
114+
code: `
115+
const abortController = new AbortController();
116+
abortController.abort();
117+
`,
118+
settings: { browsers: ["chrome 70"] },
119+
},
120+
{
121+
code: `
122+
const mutationObserver = new MutationObserver(() => {});
123+
mutationObserver.observe(document.body, { childList: true });
124+
`,
125+
settings: { browsers: ["chrome 52"] },
126+
},
127+
{
128+
code: `
129+
const intersectionObserver = new IntersectionObserver(() => {});
130+
intersectionObserver.observe(document.body);
131+
`,
132+
settings: { browsers: ["chrome 70"] },
133+
},
96134
// Import cases
97135
{
98136
code: `
@@ -730,5 +768,104 @@ ruleTester.run("compat", rule, {
730768
},
731769
],
732770
},
771+
{
772+
code: "[].includes()",
773+
settings: { browsers: ["ie 11"] },
774+
errors: [
775+
{
776+
message: "Array.includes() is not supported in IE 11",
777+
},
778+
],
779+
},
780+
{
781+
code: "'strsd'.includes()",
782+
settings: { browsers: ["ie 11"] },
783+
errors: [
784+
{
785+
message: "String.includes() is not supported in IE 11",
786+
},
787+
],
788+
},
789+
{
790+
code: "[1, 2, [3, 4]].flat()",
791+
settings: { browsers: ["ie 11"] },
792+
errors: [
793+
{
794+
message: "Array.flat() is not supported in IE 11",
795+
},
796+
],
797+
},
798+
{
799+
code: "[1,2,3].flatMap(x => [x, x])",
800+
settings: { browsers: ["chrome 68"] },
801+
errors: [
802+
{
803+
message: "Array.flatMap() is not supported in Chrome 68",
804+
},
805+
],
806+
},
807+
{
808+
code: "Object.fromEntries([])",
809+
settings: { browsers: ["chrome 72"] },
810+
errors: [
811+
{
812+
message: "Object.fromEntries() is not supported in Chrome 72",
813+
},
814+
],
815+
},
816+
{
817+
code: "'text'.replaceAll('x', 's')",
818+
settings: { browsers: ["chrome 84"] },
819+
errors: [
820+
{
821+
message: "String.replaceAll() is not supported in Chrome 84",
822+
},
823+
],
824+
},
825+
{
826+
code: `navigator.serviceWorker.register("/service_worker.js");`,
827+
settings: { browsers: ["chrome 39"] },
828+
errors: [
829+
{
830+
message: "navigator.serviceWorker() is not supported in Chrome 39",
831+
},
832+
],
833+
},
834+
{
835+
code: `
836+
const abortController = new AbortController();
837+
abortController.abort();
838+
`,
839+
settings: { browsers: ["chrome 65"] },
840+
errors: [
841+
{
842+
message: "AbortController is not supported in Chrome 65",
843+
},
844+
],
845+
},
846+
{
847+
code: `
848+
const mutationObserver = new MutationObserver(() => {});
849+
mutationObserver.observe(document.body, { childList: true });
850+
`,
851+
settings: { browsers: ["chrome 25"] },
852+
errors: [
853+
{
854+
message: "MutationObserver is not supported in Chrome 25",
855+
},
856+
],
857+
},
858+
{
859+
code: `
860+
const intersectionObserver = new IntersectionObserver(() => {});
861+
intersectionObserver.observe(document.body);
862+
`,
863+
settings: { browsers: ["chrome 50"] },
864+
errors: [
865+
{
866+
message: "IntersectionObserver is not supported in Chrome 50",
867+
},
868+
],
869+
},
733870
],
734871
});

0 commit comments

Comments
 (0)