Bug 1339461 - Implement new eslint rule to prefer array.includes over array.indexOf comparison with -1. r?florian
MozReview-Commit-ID: GnVqoYsC2BL
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -6,16 +6,17 @@ module.exports = {
"mozilla"
],
"rules": {
"mozilla/avoid-removeChild": "error",
"mozilla/import-globals": "warn",
"mozilla/no-import-into-var-and-global": "error",
"mozilla/no-useless-parameters": "error",
"mozilla/no-useless-removeEventListener": "error",
+ "mozilla/prefer-array-includes": "error",
// No (!foo in bar) or (!object instanceof Class)
"no-unsafe-negation": "error",
},
"env": {
"es6": true
},
"parserOptions": {
--- a/tools/lint/docs/linters/eslint-plugin-mozilla.rst
+++ b/tools/lint/docs/linters/eslint-plugin-mozilla.rst
@@ -137,16 +137,22 @@ Reject common XPCOM methods called with
``Services.io.newURI(url, null, null)``, or non-existent parameters (eg.
``Services.obs.removeObserver(name, observer, false)``).
no-useless-removeEventListener
------------------------------
Reject calls to removeEventListener where {once: true} could be used instead.
+prefer-array-includes
+-----------------------------
+
+Rejects calls to array.indexOf which compares the result to -1. array.includes
+should be used instead.
+
reject-importGlobalProperties
-----------------------------
Rejects calls to ``Cu.importGlobalProperties``. Use of this function is
undesirable in some parts of the tree.
reject-some-requires
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
@@ -25,16 +25,17 @@ module.exports = {
"import-test-globals": require("../lib/rules/import-test-globals"),
"mark-test-function-used": require("../lib/rules/mark-test-function-used"),
"no-aArgs": require("../lib/rules/no-aArgs"),
"no-cpows-in-tests": require("../lib/rules/no-cpows-in-tests"),
"no-single-arg-cu-import": require("../lib/rules/no-single-arg-cu-import"),
"no-import-into-var-and-global": require("../lib/rules/no-import-into-var-and-global.js"),
"no-useless-parameters": require("../lib/rules/no-useless-parameters"),
"no-useless-removeEventListener": require("../lib/rules/no-useless-removeEventListener"),
+ "prefer-array-includes": require("../lib/rules/prefer-array-includes"),
"reject-importGlobalProperties": require("../lib/rules/reject-importGlobalProperties"),
"reject-some-requires": require("../lib/rules/reject-some-requires"),
"var-only-at-top-level": require("../lib/rules/var-only-at-top-level")
},
rulesConfig: {
"avoid-removeChild": 0,
"balanced-listeners": 0,
"import-browserjs-globals": 0,
@@ -43,13 +44,14 @@ module.exports = {
"import-test-globals": 0,
"mark-test-function-used": 0,
"no-aArgs": 0,
"no-cpows-in-tests": 0,
"no-single-arg-cu-import": 0,
"no-import-into-var-and-global": 0,
"no-useless-parameters": 0,
"no-useless-removeEventListener": 0,
+ "prefer-array-includes": 0,
"reject-importGlobalProperties": 0,
"reject-some-requires": 0,
"var-only-at-top-level": 0
}
};
new file mode 100644
--- /dev/null
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/prefer-array-includes.js
@@ -0,0 +1,41 @@
+/**
+ * @fileoverview Prefer using Array.includes() instead of comparing
+ Array.indexOf() to -1.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+"use strict";
+
+// -----------------------------------------------------------------------------
+// Rule Definition
+// -----------------------------------------------------------------------------
+
+module.exports = function(context) {
+
+ // ---------------------------------------------------------------------------
+ // Public
+ // --------------------------------------------------------------------------
+
+ return {
+ BinaryExpression(node) {
+ if (node.type !== "BinaryExpression" ||
+ node.left.type !== "CallExpression" ||
+ node.left.callee.type !== "MemberExpression" ||
+ node.left.callee.property.type !== "Identifier" ||
+ node.left.callee.property.name !== "indexOf" ||
+ node.right.type !== "UnaryExpression" ||
+ node.right.operator !== "-" ||
+ node.right.argument.type !== "Literal" ||
+ node.right.argument.value !== 1) {
+ return;
+ }
+
+ let operator = node.operator;
+ context.report(node, "use array.includes() instead of " +
+ `array.indexOf() ${operator} -1`);
+ }
+ };
+};
--- a/tools/lint/eslint/eslint-plugin-mozilla/package.json
+++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json
@@ -1,11 +1,11 @@
{
"name": "eslint-plugin-mozilla",
- "version": "0.2.18",
+ "version": "0.2.19",
"description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla project.",
"keywords": [
"eslint",
"eslintplugin",
"eslint-plugin",
"mozilla",
"firefox"
],
new file mode 100644
--- /dev/null
+++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-array-includes.js
@@ -0,0 +1,32 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+var rule = require("../lib/rules/prefer-array-includes");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+function invalidCode(code, operator) {
+ let message = "use array.includes() instead of " +
+ `array.indexOf() ${operator} -1`;
+ return {code: code, errors: [{message: message, type: "BinaryExpression"}]};
+}
+
+exports.runTest = function(ruleTester) {
+ ruleTester.run("prefer-array-includes", rule, {
+ valid: [
+ "array.indexOf('foo') == 3;",
+ "array.indexOf('foo') > 0"
+ ],
+ invalid: [
+ invalidCode("function a() { if(array.indexOf('foo') == -1) return; }", "=="),
+ ]
+ });
+};