@gitlab/eslint-plugin 19.6.1 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ # [20.1.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v20.0.0...v20.1.0) (2024-08-28)
2
+
3
+
4
+ ### Features
5
+
6
+ * add rules to ensure Tailwind CSS is used properly ([c51533e](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/c51533ecfa9f20f76d0b2a3113da7213213658f6))
7
+
8
+ # [20.0.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v19.6.1...v20.0.0) (2024-08-13)
9
+
10
+
11
+ ### Features
12
+
13
+ * add max-params rule ([110cb10](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/110cb1018c8f681251f199a00a8cfda58a32bf05))
14
+
15
+
16
+ ### BREAKING CHANGES
17
+
18
+ * The max-params rule is set to error on methods using
19
+ more than 3 parameters.
20
+
1
21
  ## [19.6.1](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v19.6.0...v19.6.1) (2024-08-06)
2
22
 
3
23
 
@@ -0,0 +1,38 @@
1
+ # @gitlab/tailwind
2
+
3
+ This rule lints against string interpolation being used to build CSS utility class
4
+ names as that would prevent Tailwind from parsing those classes and adding them to the bundle.
5
+
6
+ ## Rule Details
7
+
8
+ ### Examples of **incorrect** code for this rule
9
+
10
+ ```js
11
+ // Using interpolation to build a utility in a string literal
12
+ const cssUtilsStringLiteral = 'gl-bg-red-' + variant;
13
+
14
+ // Using interpolation to build a utility in a template literal
15
+ const cssUtilsTemplateLiteral = `gl-border-top gl-bg-red-${color} gl-text-gray-400`;
16
+ ```
17
+
18
+ ### Examples of **correct** code for this rule
19
+
20
+ ```js
21
+ // Utilities declared as a string literal without interpolation
22
+ const cssUtilsStringLiteral = 'gl-bg-red-800';
23
+
24
+ // Utilities declared as a template literal without interpolation
25
+ const cssUtils = `gl-border-top gl-bg-red-800 gl-text-gray-400`;
26
+ ```
27
+
28
+ ## Options
29
+
30
+ No options.
31
+
32
+ ## Related rules
33
+
34
+ - [vue-tailwind](./vue-tailwind.md)
35
+
36
+ ## When Not To Use It
37
+
38
+ If the codebase doesn't leverage Tailwind CSS, keep this rule disabled.
@@ -0,0 +1,45 @@
1
+ # @gitlab/vue-tailwind
2
+
3
+ This rule enforces the same conventions as [tailwind](./tailwind.md) in Vue templates.
4
+
5
+ ## Rule Details
6
+
7
+ ### Examples of **incorrect** code for this rule
8
+
9
+ ```html
10
+ <!-- Using interpolation to build a utility in a string literal -->
11
+ <template>
12
+ <span :class="'gl-bg-red-' + color"></span>
13
+ </template>
14
+
15
+ <!-- Using interpolation to build a utility in a template literal -->
16
+ <template>
17
+ <span :class="`gl-border-top gl-bg-red-${color} gl-text-gray-400`"></span>
18
+ </template>
19
+ ```
20
+
21
+ ### Examples of **correct** code for this rule
22
+
23
+ ```html
24
+ <!-- Utilities declared as a string literal without interpolation -->
25
+ <template>
26
+ <span class="gl-bg-red-800"></span>
27
+ </template>
28
+
29
+ <!-- Utilities declared as a template literal without interpolation -->
30
+ <template>
31
+ <span :class="`gl-bg-red-800`"></span>
32
+ </template>
33
+ ```
34
+
35
+ ## Options
36
+
37
+ No options.
38
+
39
+ ## Related rules
40
+
41
+ - [tailwind](./tailwind.md)
42
+
43
+ ## When Not To Use It
44
+
45
+ If the codebase doesn't leverage Tailwind CSS, keep this rule disabled.
package/docs/rules.md CHANGED
@@ -8,6 +8,7 @@ Available rules:
8
8
  - [no-runtime-template-compiler](./rules/no-runtime-template-compiler.md): Disallow components which rely on a runtime template compiler.
9
9
  - [require-i18n-strings](./rules/require-i18n-strings.md): Detect a string which has been hard coded and requires externalization.
10
10
  - [require-valid-i18n-helpers](./rules/require-valid-i18n-helpers.md): Enforces valid usage of translation helpers in JavaScript.
11
+ - [tailwind](./rules/tailwind.md): Prevents undesired Tailwind CSS features from being used.
11
12
  - [vtu-no-explicit-wrapper-destroy](./rules/vtu-no-explicit-wrapper-destroy.md): Prevents redundant destroy calls and null asignment
12
13
  - [vtu-no-wrapper-vm](./rules/vtu-no-wrapper-vm.md): Prevent direct access to `vm` internals for `@vue/test-utils` wrappers.
13
14
  - [vue-no-data-toggle](./rules/vue-no-data-toggle.md): Restrict the use of `data-toggle` bootstrap behaviors within Vue templates
@@ -18,3 +19,4 @@ Available rules:
18
19
  - [vue-require-required-key](./rules/vue-require-required-key.md): Require the required key to be set
19
20
  - [vue-require-valid-i18n-helpers](./rules/vue-require-valid-i18n-helpers.md): Enforces valid usage of translation helpers in Vue templates.
20
21
  - [vue-slot-name-casing](./rules/vue-slot-name-casing.md): enforce specific casing for slot naming style in template
22
+ - [vue-tailwind](./rules/vue-tailwind.md): Prevents undesired Tailwind CSS features from being used in Vue templates.
@@ -89,5 +89,7 @@ module.exports = {
89
89
  groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
90
90
  },
91
91
  ],
92
+ // https://docs.gitlab.com/ee/development/fe_guide/style/javascript.html#limit-number-of-parameters
93
+ 'max-params': ['error', { max: 3 }]
92
94
  },
93
95
  };
@@ -37,6 +37,7 @@ const tsConfig = {
37
37
  reportUnusedDisableDirectives: true,
38
38
  rules: {
39
39
  semi: [2, 'always'],
40
+ 'max-params': 'off',
40
41
  'no-throw-literal': 'off',
41
42
  'no-shadow': 'off',
42
43
  'no-empty-function': 'off',
package/lib/index.js CHANGED
@@ -7,6 +7,7 @@ module.exports = {
7
7
  'no-runtime-template-compiler': require('./rules/no-runtime-template-compiler.js'),
8
8
  'require-i18n-strings': require('./rules/require-i18n-strings.js'),
9
9
  'require-valid-i18n-helpers': require('./rules/require-valid-i18n-helpers.js'),
10
+ tailwind: require('./rules/tailwind.js'),
10
11
  'vtu-no-explicit-wrapper-destroy': require('./rules/vtu-no-explicit-wrapper-destroy.js'),
11
12
  'vtu-no-wrapper-vm': require('./rules/vtu-no-wrapper-vm.js'),
12
13
  'vue-no-data-toggle': require('./rules/vue-no-data-toggle.js'),
@@ -17,13 +18,14 @@ module.exports = {
17
18
  'vue-require-required-key': require('./rules/vue-require-required-key.js'),
18
19
  'vue-require-valid-i18n-helpers': require('./rules/vue-require-valid-i18n-helpers.js'),
19
20
  'vue-slot-name-casing': require('./rules/vue-slot-name-casing.js'),
21
+ 'vue-tailwind': require('./rules/vue-tailwind.js'),
20
22
  },
21
23
  configs: {
22
- default: require('./configs/default.js'),
23
- typescript: require('./configs/typescript.js'),
24
24
  base: require('./configs/base.js'),
25
- vue: require('./configs/vue.js'),
25
+ default: require('./configs/default.js'),
26
26
  i18n: require('./configs/i18n.js'),
27
27
  jest: require('./configs/jest.js'),
28
+ typescript: require('./configs/typescript.js'),
29
+ vue: require('./configs/vue.js'),
28
30
  },
29
31
  };
@@ -0,0 +1,30 @@
1
+ // ------------------------------------------------------------------------------
2
+ // Requirements
3
+ // ------------------------------------------------------------------------------
4
+ const { DOCS_BASE_URL } = require('../constants');
5
+ const { validateInterpolatedUtils } = require('../utils/tailwind-utils');
6
+
7
+ // ------------------------------------------------------------------------------
8
+ // Rule Definition
9
+ // ------------------------------------------------------------------------------
10
+
11
+ module.exports = {
12
+ meta: {
13
+ type: 'error',
14
+ docs: {
15
+ description: 'Ensures Tailwind CSS is used according to our internal guidelines.',
16
+ category: 'css',
17
+ url: DOCS_BASE_URL + '/tailwind.md',
18
+ },
19
+ },
20
+ create(context) {
21
+ return {
22
+ BinaryExpression(node) {
23
+ validateInterpolatedUtils(context, node);
24
+ },
25
+ TemplateLiteral(node) {
26
+ validateInterpolatedUtils(context, node);
27
+ },
28
+ };
29
+ },
30
+ };
@@ -0,0 +1,32 @@
1
+
2
+ // ------------------------------------------------------------------------------
3
+ // Requirements
4
+ // ------------------------------------------------------------------------------
5
+ const { DOCS_BASE_URL } = require('../constants');
6
+ const { defineTemplateBodyVisitor } = require('../utils/index');
7
+ const { validateInterpolatedUtils } = require('../utils/tailwind-utils');
8
+
9
+ // ------------------------------------------------------------------------------
10
+ // Rule Definition
11
+ // ------------------------------------------------------------------------------
12
+
13
+ module.exports = {
14
+ meta: {
15
+ type: 'error',
16
+ docs: {
17
+ description: 'Ensures Tailwind CSS is used according to our internal guidelines in Vue templates.',
18
+ category: 'css',
19
+ url: DOCS_BASE_URL + '/vue-tailwind.md',
20
+ },
21
+ },
22
+ create(context) {
23
+ return defineTemplateBodyVisitor(context, {
24
+ BinaryExpression(node) {
25
+ validateInterpolatedUtils(context, node)
26
+ },
27
+ TemplateLiteral(node) {
28
+ validateInterpolatedUtils(context, node)
29
+ },
30
+ });
31
+ },
32
+ };
@@ -0,0 +1,35 @@
1
+ const INTERPOLATION_PATTERN = /gl-[a-z0-9-]*$/i;
2
+ const INTERPOLATED_UTIL_ERROR =
3
+ 'You are building a CSS utility class name using string interpolation which is forbidden because Tailwind CSS needs fully qualified names to properly generate the utilities we use.';
4
+ const INTERPOLATED_UTILS_VALIDATORS = {
5
+ BinaryExpression: binaryExpressionHasInterpolatedUtils,
6
+ TemplateLiteral: templateLiteralHasInterpolatedUtils,
7
+ };
8
+
9
+ function binaryExpressionHasInterpolatedUtils(node) {
10
+ return node.operator === '+' && INTERPOLATION_PATTERN.test(node.left.value);
11
+ }
12
+
13
+ function templateLiteralHasInterpolatedUtils(node) {
14
+ return node.quasis.some((quasi) => {
15
+ return quasi.tail === false && INTERPOLATION_PATTERN.test(quasi.value.raw);
16
+ });
17
+ }
18
+
19
+ function validateInterpolatedUtils(context, node) {
20
+ if (INTERPOLATED_UTILS_VALIDATORS[node.type] === undefined) {
21
+ return;
22
+ }
23
+
24
+ if (INTERPOLATED_UTILS_VALIDATORS[node.type](node)) {
25
+ context.report({
26
+ node,
27
+ message: INTERPOLATED_UTIL_ERROR,
28
+ });
29
+ }
30
+ }
31
+
32
+ module.exports = {
33
+ validateInterpolatedUtils,
34
+ INTERPOLATED_UTIL_ERROR,
35
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/eslint-plugin",
3
- "version": "19.6.1",
3
+ "version": "20.1.0",
4
4
  "description": "GitLab package for our custom eslint rules",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {