Bug 1890330 - Support new ESLint APIs in eslint-plugin-mozilla. r=frontend-codestyle-reviewers,Gijs

This gets the ESLint plugin code in a state where it can work with the old APIs or the newer ESLint v9 ones.

The testing system will be updated to ESLint v9 when we do the main upgrade. However, in the meantime, this allows
consumers to start testing out v9 implementations.

Differential Revision: https://phabricator.services.mozilla.com/D206914
This commit is contained in:
Mark Banner 2024-04-09 08:11:09 +00:00
parent 339c073aa9
commit 4618d676aa
9 changed files with 65 additions and 16 deletions

View file

@ -634,8 +634,8 @@ module.exports = {
let globalScope;
let parser = {
Program() {
globalScope = context.getScope();
Program(node) {
globalScope = helpers.getScope(context, node);
},
};
let filename = context.getFilename();
@ -651,10 +651,14 @@ module.exports = {
for (let type of Object.keys(GlobalsForNode.prototype)) {
parser[type] = function (node) {
if (type === "Program") {
globalScope = context.getScope();
globalScope = helpers.getScope(context, node);
helpers.addGlobals(extraHTMLGlobals, globalScope);
}
let globals = handler[type](node, context.getAncestors(), globalScope);
let globals = handler[type](
node,
helpers.getAncestors(context, node),
globalScope
);
helpers.addGlobals(
globals,
globalScope,

View file

@ -794,4 +794,38 @@ module.exports = {
}
return null;
},
/**
* Gets the scope for a node taking account of where the scope function
* is available (supports node versions earlier than 8.37.0).
*
* @param {object} context
* The context passed from ESLint.
* @param {object} node
* The node to get the scope for.
* returns {function}
* The getScope function object.
*/
getScope(context, node) {
return context.sourceCode?.getScope
? context.sourceCode.getScope(node)
: context.getScope();
},
/**
* Gets the ancestors for a node taking account of where the ancestors function
* is available (supports node versions earlier than 8.38.0).
*
* @param {object} context
* The context passed from ESLint.
* @param {object} node
* The node to get the scope for.
* returns {function}
* The getScope function object.
*/
getAncestors(context, node) {
return context.sourceCode?.getAncestors
? context.sourceCode.getAncestors(node)
: context.getAncestors();
},
};

View file

@ -19,16 +19,26 @@ function markArrayElementsAsUsed(context, node, expression) {
}
for (let element of expression.elements) {
context.markVariableAsUsed(element.value);
context.markVariableAsUsed
? context.markVariableAsUsed(element.value)
: context.sourceCode.markVariableAsUsed(element.value);
}
// Also mark EXPORTED_SYMBOLS as used.
context.markVariableAsUsed("EXPORTED_SYMBOLS");
context.markVariableAsUsed
? context.markVariableAsUsed("EXPORTED_SYMBOLS")
: context.sourceCode.markVariableAsUsed("EXPORTED_SYMBOLS");
}
// Ignore assignments not in the global scope, e.g. where special module
// definitions are required due to having different ways of importing files,
// e.g. osfile.
function isGlobalScope(context) {
function isGlobalScope(context, node) {
if (context.sourceCode?.getScope) {
let upper = context.sourceCode.getScope(node).upper;
// ESLint v9 uses a global scope object with type = "global". Earlier
// versions use a null upper scope.
return !upper || upper.type == "global";
}
return !context.getScope().upper;
}
@ -55,14 +65,14 @@ module.exports = {
node.left.type === "MemberExpression" &&
node.left.object.type === "ThisExpression" &&
node.left.property.name === "EXPORTED_SYMBOLS" &&
isGlobalScope(context)
isGlobalScope(context, node)
) {
markArrayElementsAsUsed(context, node, node.right);
}
},
VariableDeclaration(node) {
if (!isGlobalScope(context)) {
if (!isGlobalScope(context, node)) {
return;
}

View file

@ -29,7 +29,7 @@ module.exports = {
create(context) {
return {
ThisExpression(node) {
if (!helpers.getIsGlobalThis(context.getAncestors())) {
if (!helpers.getIsGlobalThis(helpers.getAncestors(context, node))) {
return;
}

View file

@ -71,7 +71,7 @@ module.exports = {
(callerSource === "ChromeUtils.import" ||
callerSource === "ChromeUtils.importESModule") &&
helpers.getIsTopLevelAndUnconditionallyExecuted(
context.getAncestors()
helpers.getAncestors(context, node)
)
) {
if (node.arguments.length < 1) {

View file

@ -26,7 +26,7 @@ module.exports = {
create(context) {
return {
AwaitExpression(node) {
if (!helpers.getIsTopLevelScript(context.getAncestors())) {
if (!helpers.getIsTopLevelScript(helpers.getAncestors(context, node))) {
return;
}
context.report({ node, messageId: "rejectTopLevelAwait" });
@ -34,7 +34,7 @@ module.exports = {
ForOfStatement(node) {
if (
!node.await ||
!helpers.getIsTopLevelScript(context.getAncestors())
!helpers.getIsTopLevelScript(helpers.getAncestors(context, node))
) {
return;
}

View file

@ -11,6 +11,7 @@
const fs = require("fs");
const { maybeGetMemberPropertyName } = require("../helpers");
const helpers = require("../helpers");
const privilegedGlobals = Object.keys(
require("../environments/privileged.js").globals
@ -133,7 +134,7 @@ module.exports = {
const { operator, right } = node;
if (
operator === "instanceof" &&
pointsToDOMInterface(context.getScope(), right)
pointsToDOMInterface(helpers.getScope(context, node), right)
) {
context.report({
node,

View file

@ -35,7 +35,7 @@ module.exports = {
node.init?.type != "CallExpression" ||
node.init?.callee?.type != "MemberExpression" ||
!context.getFilename().endsWith(".sys.mjs") ||
!helpers.isTopLevel(context.getAncestors())
!helpers.isTopLevel(helpers.getAncestors(context, node))
) {
return;
}

View file

@ -225,7 +225,7 @@ module.exports = {
}
if (
helpers.getIsTopLevelAndUnconditionallyExecuted(
context.getAncestors()
helpers.getAncestors(context, node)
)
) {
context.report({