Merge branch 'stable-3.2' into stable-3.3

* stable-3.2:
  Add eslint rule

in this branch eslint rule is added to bazlets by referring following
location :

https://gerrit.googlesource.com/gerrit/
    +/refs/heads/stable-3.3/tools/js

Change-Id: I1d7715727f468545ee2f9a3953dc763acb26dc7f
diff --git a/tools/js/eslint-rules/BUILD b/tools/js/eslint-rules/BUILD
new file mode 100644
index 0000000..476c4ff
--- /dev/null
+++ b/tools/js/eslint-rules/BUILD
@@ -0,0 +1,11 @@
+package(default_visibility = ["//visibility:public"])
+
+# To load eslint rules from a directory, we must pass a directory
+# name to it. We can't get the directory name in bazel, but we can calculate
+# use a file from this directory. We are using README.md for it.
+exports_files(["README.md"])
+
+filegroup(
+    name = "eslint-rules-srcs",
+    srcs = glob(["**/*.js"]),
+)
diff --git a/tools/js/eslint-rules/README.md b/tools/js/eslint-rules/README.md
new file mode 100644
index 0000000..b425d74
--- /dev/null
+++ b/tools/js/eslint-rules/README.md
@@ -0,0 +1,74 @@
+# Eslint rules for polygerrit
+This directory contains custom eslint rules for polygerrit.
+
+## ts-imports-js
+This rule must be used only for `.ts` files.
+The rule ensures that:
+* All import paths either a relative paths or module imports.
+```typescript
+// Correct imports
+import './file1'; // relative path
+import '../abc/file2'; // relative path
+import 'module_name/xyz'; // import from the module_name
+
+// Incorrect imports
+import '/usr/home/file3'; // absolute path
+```
+* All *relative* import paths has a short form (i.e. don't include extension):
+```typescript
+// Correct imports
+import './file1'; // relative path without extension
+import data from 'module_name/file2.json'; // file in a module, can be anything
+
+// Incorrect imports
+import './file1.js'; // relative path with extension
+```
+
+* Imported `.js` and `.d.ts` files both exists (only for a relative import path):
+
+Example:
+```
+polygerrit-ui/app
+ |- ex.ts
+ |- abc
+     |- correct_ts.ts
+     |- correct_js.js
+     |- correct_js.d.ts
+     |- incorrect_1.js
+     |- incorrect_2.d.ts
+```
+```typescript
+// The ex.ts file:
+// Correct imports
+import {x} from './abc/correct_js'; // correct_js.js and correct_js.d.ts exist
+import {x} from './abc/correct_ts'; // import from .ts - d.ts is not required
+
+// Incorrect imports
+import {x} from './abc/incorrect_1'; // incorrect_1.d.ts doesn't exist
+import {x} from './abc/incorrect_2'; // incorrect_2.js doesn't exist
+```
+
+To fix the last two imports 2 files must be added: `incorrect_1.d.ts` and
+`incorrect_2.js`.
+
+## goog-module-id
+Enforce correct usage of goog.declareModuleId:
+* The goog.declareModuleId must be used only in `.js` files which have
+associated `.d.ts` files.
+* The module name is correct. The correct module name is constructed from the
+file path using the folowing rules
+rules:
+  1. Get part of the path after the '/polygerrit-ui/app/':
+    `/usr/home/gerrit/polygerrit-ui/app/elements/shared/x/y.js` ->
+    `elements/shared/x/y.js`
+  2. Discard `.js` extension and replace all `/` with `.`:
+    `elements/shared/x/y.js` -> `elements.shared.x.y`
+  3. Add `polygerrit.` prefix:
+    `elements.shared.x.y` -> `polygerrit.elements.shared.x.y`
+    The last string is a module name.
+
+Example:
+```javascript
+// polygerrit-ui/app/elements/shared/x/y.js
+goog.declareModuleId('polygerrit.elements.shared.x.y');
+```
diff --git a/tools/js/eslint.bzl b/tools/js/eslint.bzl
new file mode 100644
index 0000000..9633dd7
--- /dev/null
+++ b/tools/js/eslint.bzl
@@ -0,0 +1,110 @@
+# 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"
+
+    # There are custom eslint rules in eslint-rules directory. Eslint loads
+    # custom rules from a directory specified with the --rulesdir argument.
+    # When bazel runs eslint, it places the eslint-rules directory into
+    # some location in the filesystem, and the location is not known in advance.
+    # It is not possible to get the directory location in bazel directly.
+    # Instead, we can use dirname to get a directory for a file in the
+    # eslint-rules directory.
+    # README.md is the most "stable" file in the eslint-rules directory
+    # (i.e. it is unlikely will be removed), and we are using it to calculate
+    # exact directory path in bazel.
+    eslint_rules_toplevel_file = "@com_googlesource_gerrit_bazlets//tools/js/eslint-rules:README.md"
+    bin_data = [
+        "@npm//eslint:eslint",
+        config,
+        ignore,
+         "@com_googlesource_gerrit_bazlets//tools/js/eslint-rules:eslint-rules-srcs",
+        eslint_rules_toplevel_file,
+    ] + 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),
+        # Load custom rules from eslint-rules directory
+        "--rulesdir",
+        "$$(dirname $$(rlocation $(rootpath {})))".format(eslint_rules_toplevel_file),
+    ]
+    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",
+        ],
+    )