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",
+ ],
+ )