Add eslint rule

Eslint rule is used to lint java script files.

To use eslint rule, its dependencies in "tools/js" directory
from gerrit core are needed in the current workspace, this can be
avoided by adding this rule to bazlets project.

Any plugin that need eslint rule can reuse eslint rule of bazlets
project with minimum required dependencies.

eslint rule is added to bazlets by referring following location :

https://gerrit.googlesource.com/gerrit/
    +/refs/heads/stable-3.2/tools/js/eslint.bzl

Also add "build_bazel_rules_nodejs" since this is required dependency
for eslint rule.

"build_bazel_rule_nodejs" dependency is added to bazlets from following
location :

https://gerrit.googlesource.com/bazlets/
    +/refs/heads/stable-3.3/gerrit_polymer.bzl

Change-Id: Iab68492a9e847d53377fd2eb24e22c01ec6d0142
diff --git a/gerrit_polymer.bzl b/gerrit_polymer.bzl
index 2d019d2..735d22f 100644
--- a/gerrit_polymer.bzl
+++ b/gerrit_polymer.bzl
@@ -16,3 +16,9 @@
         sha256 = "5a589bdba674e1fec7188e9251c8624ebf2d4d969beb6635f9148f420d1e08b1",
         urls = ["https://raw.githubusercontent.com/google/closure-compiler/775609aad61e14aef289ebec4bfc09ad88877f9e/contrib/externs/polymer-1.0.js"],
     )
+
+    http_archive(
+        name = "build_bazel_rules_nodejs",
+        sha256 = "1134ec9b7baee008f1d54f0483049a97e53a57cd3913ec9d6db625549c98395a",
+        urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.4.0/rules_nodejs-3.4.0.tar.gz"],
+    )
diff --git a/tools/js/eslint.bzl b/tools/js/eslint.bzl
new file mode 100644
index 0000000..33b5a69
--- /dev/null
+++ b/tools/js/eslint.bzl
@@ -0,0 +1,93 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This file contains macro to run eslint and define a eslint test rule."""
+
+load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary", "nodejs_test")
+
+def eslint(name, plugins, srcs, config, ignore, extensions = [".js"], data = []):
+    """ Macro to define eslint rules for files.
+
+    Args:
+        name: name of the rule
+        plugins: list of npm dependencies with plugins, for example "@npm//eslint-config-google"
+        srcs: list of files to be checked (ignored in {name}_bin rule)
+        config: eslint config file
+        ignore: eslint ignore file
+        extensions: list of file extensions to be checked. This is an additional filter for
+            srcs list. Each extension must start with '.' character.
+            Default: [".js"].
+        data: list of additional dependencies. For example if a config file extends an another
+            file, this other file must be added to data.
+
+    Generate: 2 rules:
+        {name}_test rule - runs eslint tests. You can run this rule with
+            'bazel test {name}_test' command. The rule tests all files from srcs with specified
+            extensions inside the package where eslint macro is called.
+        {name}_bin rule - runs eslint with specified settings; ignores srcs. To use this rule
+            you must pass a folder to check, for example:
+            bazel run {name}_test -- --fix $(pwd)/polygerrit-ui/app
+    """
+    entry_point = "@npm//:node_modules/eslint/bin/eslint.js"
+    bin_data = [
+        "@npm//eslint:eslint",
+        config,
+        ignore,
+    ] + plugins + data
+    common_templated_args = [
+        "--ext",
+        ",".join(extensions),
+        "-c",
+        # Use rlocation/rootpath instead of location.
+        # See note and example here:
+        # https://bazelbuild.github.io/rules_nodejs/Built-ins.html#nodejs_binary
+        "$$(rlocation $(rootpath {}))".format(config),
+        "--ignore-path",
+        "$$(rlocation $(rootpath {}))".format(ignore),
+    ]
+    nodejs_test(
+        name = name + "_test",
+        entry_point = entry_point,
+        data = bin_data + srcs,
+        # Bazel generates 2 .js files, where names of the files are generated from the name
+        # of the rule: {name}_test_require_patch.js and {name}_test_loader.js
+        # Ignore these 2 files, for simplicity do not use {name} in the patterns.
+        templated_args = common_templated_args + [
+            "--ignore-pattern",
+            "*_test_require_patch.js",
+            "--ignore-pattern",
+            "*_test_loader.js",
+            "./", # Relative to the config file location
+        ],
+        # Should not run sandboxed.
+        tags = [
+            "local",
+            "manual",
+        ],
+    )
+
+    nodejs_binary(
+        name = name + "_bin",
+        entry_point = "@npm//:node_modules/eslint/bin/eslint.js",
+        data = bin_data,
+        # Bazel generates 2 .js files, where names of the files are generated from the name
+        # of the rule: {name}_bin_require_patch.js and {name}_bin_loader.js
+        # Ignore these 2 files, for simplicity do not use {name} in the patterns.
+        templated_args = common_templated_args + [
+            "--ignore-pattern",
+            "*_bin_require_patch.js",
+            "--ignore-pattern",
+            "*_bin_loader.js",
+        ],
+    )