Bug 1766238 - Disallow more than one argument to ChromeUtils.import via ESLint. r=mossop

Depends on D144562

Differential Revision: https://phabricator.services.mozilla.com/D144563
This commit is contained in:
Mark Banner 2022-04-27 08:38:35 +00:00
parent 1f8462cfdd
commit 67e9352298
5 changed files with 45 additions and 120 deletions

View file

@ -1,13 +1,9 @@
reject-chromeutils-import-params
================================
``ChromeUtils.import`` can be called with two arguments, however these are now
largely deprecated.
The use of object destructuring is preferred over the second parameter being
``this`` or ``{}``.
Using explicit exports is preferred over the second parameter being ``null``.
``ChromeUtils.import`` used to be able to be called with two arguments, however
the second argument is no longer supported. Exports from modules should now be
explicit, and the imported symbols being accessed from the returned object.
Examples of incorrect code for this rule:
-----------------------------------------

View file

@ -41,58 +41,20 @@ module.exports = {
isIdentifier(callee.property, "import") &&
node.arguments.length >= 2
) {
let targetObj = node.arguments[1];
if (targetObj.type == "Literal" && targetObj.raw == "null") {
context.report(
node,
"ChromeUtils.import should not be called with (..., null) to " +
"retrieve the JSM global object. Rely on explicit exports instead."
);
} else if (targetObj.type == "ThisExpression") {
context.report({
node,
message:
"ChromeUtils.import should not be called with (..., this) to " +
"retrieve the JSM global object. Use destructuring instead.",
suggest: [
{
desc: "Use destructuring for imports.",
fix: fixer => {
let source = context.getSourceCode().getText(node);
let match = source.match(
/ChromeUtils.import\(\s*(".*\/(.*).jsm?")/m
);
return fixer.replaceText(
node,
`const { ${match[2]} } = ChromeUtils.import(${match[1]})`
);
},
context.report({
node,
message: "ChromeUtils.import only takes one argument.",
suggest: [
{
desc: "Remove the unnecessary parameters.",
fix: fixer => {
return fixer.removeRange(
getRangeAfterArgToEnd(context, 0, node.arguments)
);
},
],
});
} else if (
targetObj.type == "ObjectExpression" &&
targetObj.properties.length == 0
) {
context.report({
node,
message:
"Passing an empty object to ChromeUtils.import is unnecessary",
suggest: [
{
desc:
"Passing an empty object to ChromeUtils.import is " +
"unnecessary - remove the empty object",
fix: fixer => {
return fixer.removeRange(
getRangeAfterArgToEnd(context, 0, node.arguments)
);
},
},
],
});
}
},
],
});
}
},
};

View file

@ -1,6 +1,6 @@
{
"name": "eslint-plugin-mozilla",
"version": "2.12.0",
"version": "2.12.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "eslint-plugin-mozilla",
"version": "2.12.0",
"version": "2.12.1",
"description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla project.",
"keywords": [
"eslint",

View file

@ -16,11 +16,19 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } });
// Tests
// ------------------------------------------------------------------------------
function invalidError() {
let message =
"ChromeUtils.import should not be called with (..., null) to " +
"retrieve the JSM global object. Rely on explicit exports instead.";
return [{ message, type: "CallExpression" }];
function invalidError(suggested) {
return [
{
message: "ChromeUtils.import only takes one argument.",
type: "CallExpression",
suggestions: [
{
desc: "Remove the unnecessary parameters.",
output: suggested,
},
],
},
];
}
ruleTester.run("reject-chromeutils-import-params", rule, {
@ -28,7 +36,9 @@ ruleTester.run("reject-chromeutils-import-params", rule, {
invalid: [
{
code: 'ChromeUtils.import("resource://some/path/to/My.jsm", null)',
errors: invalidError(),
errors: invalidError(
`ChromeUtils.import("resource://some/path/to/My.jsm")`
),
},
{
code: `
@ -36,65 +46,22 @@ ChromeUtils.import(
"resource://some/path/to/My.jsm",
null
);`,
errors: invalidError(),
errors: invalidError(`
ChromeUtils.import(
"resource://some/path/to/My.jsm"
);`),
},
{
code: 'ChromeUtils.import("resource://some/path/to/My.jsm", this)',
errors: [
{
suggestions: [
{
desc: "Use destructuring for imports.",
output: `const { My } = ChromeUtils.import("resource://some/path/to/My.jsm")`,
},
],
},
],
errors: invalidError(
`ChromeUtils.import("resource://some/path/to/My.jsm")`
),
},
{
code: 'ChromeUtils.import("resource://some/path/to/My.js", this)',
errors: [
{
suggestions: [
{
desc: "Use destructuring for imports.",
output: `const { My } = ChromeUtils.import("resource://some/path/to/My.js")`,
},
],
},
],
},
{
code: `
ChromeUtils.import(
"resource://some/path/to/My.jsm",
this
);`,
errors: [
{
suggestions: [
{
desc: "Use destructuring for imports.",
output: `
const { My } = ChromeUtils.import("resource://some/path/to/My.jsm");`,
},
],
},
],
},
{
code: 'ChromeUtils.import("resource://some/path/to/My.js", {})',
errors: [
{
suggestions: [
{
desc:
"Passing an empty object to ChromeUtils.import is unnecessary - remove the empty object",
output: `ChromeUtils.import("resource://some/path/to/My.js")`,
},
],
},
],
code: 'ChromeUtils.import("resource://some/path/to/My.jsm", foo, bar)',
errors: invalidError(
`ChromeUtils.import("resource://some/path/to/My.jsm")`
),
},
],
});