Bug 1334831 - add an eslint rule to report usage of .parentNode.removeChild when .remove() could be used instead, r=jaws.
authorFlorian Quèze <florian@queze.net>
Mon, 30 Jan 2017 08:10:18 +0100
changeset 331624 cbe16a8a26150a0469177a50e08f090146d2afbe
parent 331623 5d95649edd01cee9bf502db4a7b07de0f965f49f
child 331625 a9d172aa441447396884068a7d01561843cdf596
push id86308
push userflorian@queze.net
push dateMon, 30 Jan 2017 07:14:53 +0000
treeherdermozilla-inbound@a9d172aa4414 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1334831
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1334831 - add an eslint rule to report usage of .parentNode.removeChild when .remove() could be used instead, r=jaws.
.eslintrc.js
tools/lint/docs/linters/eslint-plugin-mozilla.rst
tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-removeChild.js
tools/lint/eslint/eslint-plugin-mozilla/package.json
tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,16 +1,17 @@
 "use strict";
 
 module.exports = {
   // When adding items to this file please check for effects on sub-directories.
   "plugins": [
     "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",
 
     // No (!foo in bar) or (!object instanceof Class)
     "no-unsafe-negation": "error",
   },
--- a/tools/lint/docs/linters/eslint-plugin-mozilla.rst
+++ b/tools/lint/docs/linters/eslint-plugin-mozilla.rst
@@ -1,12 +1,17 @@
 =====================
 Mozilla ESLint Plugin
 =====================
 
+avoid-removeChild
+-----------------
+
+Rejects using element.parentNode.removeChild(element) when element.remove()
+can be used instead.
 
 balanced-listeners
 ------------------
 
 Checks that for every occurence of 'addEventListener' or 'on' there is an
 occurence of 'removeEventListener' or 'off' with the same event name.
 
 
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
@@ -12,16 +12,17 @@
 // Plugin Definition
 //------------------------------------------------------------------------------
 
 module.exports = {
   processors: {
     ".xml": require("../lib/processors/xbl-bindings"),
   },
   rules: {
+    "avoid-removeChild": require("../lib/rules/avoid-removeChild"),
     "balanced-listeners": require("../lib/rules/balanced-listeners"),
     "import-browserjs-globals": require("../lib/rules/import-browserjs-globals"),
     "import-globals": require("../lib/rules/import-globals"),
     "import-headjs-globals": require("../lib/rules/import-headjs-globals"),
     "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"),
@@ -29,16 +30,17 @@ module.exports = {
     "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"),
     "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,
     "import-globals": 0,
     "import-headjs-globals": 0,
     "import-test-globals": 0,
     "mark-test-function-used": 0,
     "no-aArgs": 0,
     "no-cpows-in-tests": 0,
new file mode 100644
--- /dev/null
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/rules/avoid-removeChild.js
@@ -0,0 +1,43 @@
+/**
+ * @fileoverview Reject using element.parentNode.removeChild(element) when
+ *               element.remove() can be used instead.
+ *
+ * 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
+// -----------------------------------------------------------------------------
+
+var helpers = require("../helpers");
+
+module.exports = function(context) {
+
+  // ---------------------------------------------------------------------------
+  // Public
+  //  --------------------------------------------------------------------------
+
+  return {
+    "CallExpression": function(node) {
+      let callee = node.callee;
+      if (callee.type !== "MemberExpression" ||
+          callee.property.type !== "Identifier" ||
+          callee.property.name != "removeChild" ||
+          callee.object.type != "MemberExpression" ||
+          callee.object.property.type != "Identifier" ||
+          callee.object.property.name != "parentNode" ||
+          helpers.getASTSource(callee.object.object) !=
+            helpers.getASTSource(node.arguments[0]) ||
+          node.arguments.length != 1) {
+        return;
+      }
+
+      context.report(node, "use element.remove() instead of " +
+                           "element.parentNode.removeChild(element)");
+    }
+  };
+};
--- 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.15",
+  "version": "0.2.16",
   "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/avoid-removeChild.js
@@ -0,0 +1,37 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+var rule = require("../lib/rules/avoid-removeChild");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+function invalidCode(code) {
+  let message = "use element.remove() instead of " +
+                "element.parentNode.removeChild(element)";
+  return {code: code, errors: [{message: message, type: "CallExpression"}]};
+}
+
+exports.runTest = function(ruleTester) {
+  ruleTester.run("no-useless-removeEventListener", rule, {
+    valid: [
+      "elt.remove();",
+      "elt.parentNode.parentNode.removeChild(elt2.parentNode);",
+      "elt.parentNode.removeChild(elt2);",
+      "elt.removeChild(elt2);"
+    ],
+    invalid: [
+      invalidCode("elt.parentNode.removeChild(elt);"),
+      invalidCode("elt.parentNode.parentNode.removeChild(elt.parentNode);"),
+      invalidCode("$(e).parentNode.removeChild($(e));"),
+      invalidCode("$('e').parentNode.removeChild($('e'));"),
+    ]
+  });
+};