@gitlab/eslint-plugin 19.4.0 → 19.6.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/.tool-versions +1 -1
- package/CHANGELOG.md +14 -0
- package/docs/rules/require-valid-i18n-helpers.md +7 -0
- package/docs/rules/vue-require-valid-i18n-helpers.md +5 -0
- package/lib/configs/base.js +92 -0
- package/lib/configs/default.js +8 -140
- package/lib/configs/typescript.js +88 -0
- package/lib/configs/vue.js +81 -0
- package/lib/index.js +3 -0
- package/lib/utils/i18n-utils.js +28 -3
- package/package.json +3 -2
package/.tool-versions
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
nodejs
|
|
1
|
+
nodejs 20.13.1
|
|
2
2
|
yarn 1.22.19
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [19.6.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v19.5.0...v19.6.0) (2024-07-15)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **config:** add TypeScript configuration ([5f7c042](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/5f7c0427f60c9778bdf799c2a883d083e5ec08de))
|
|
7
|
+
|
|
8
|
+
# [19.5.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v19.4.0...v19.5.0) (2024-03-27)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **require-valid-i18n-helpers:** lint against string interpolation ([268d858](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/268d858f8bd02cab06ea74f2c6844166489d0d89))
|
|
14
|
+
|
|
1
15
|
# [19.4.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v19.3.0...v19.4.0) (2024-01-10)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -5,6 +5,8 @@ following:
|
|
|
5
5
|
|
|
6
6
|
- All helpers should be called with string-literal arguments to ensure the strings are properly
|
|
7
7
|
collected by the `gettext:regenerate` script.
|
|
8
|
+
- The helpers' arguments should not use string interpolation as this also prevents the strings from
|
|
9
|
+
being collected.
|
|
8
10
|
- `__` should not be called with a namespace.
|
|
9
11
|
- `s__` requires a translation namespace to be provided.
|
|
10
12
|
- `n__` should use the same namespace, or no namespace at all, for both the singular and plural forms.
|
|
@@ -21,6 +23,11 @@ const description = __(getDescription());
|
|
|
21
23
|
// Extraneous namespace
|
|
22
24
|
const globalTranslation = __('Global|Translation');
|
|
23
25
|
|
|
26
|
+
// String interpolation
|
|
27
|
+
const withStringInterpolation1 = __(`String ${interpolation}`);
|
|
28
|
+
const withStringInterpolation2 = s__("SomeContext", `String ${interpolation}`);
|
|
29
|
+
const withStringInterpolation3 = n__("%d apple", `%d ${apples}`, appleCount);
|
|
30
|
+
|
|
24
31
|
// Missing translation namespace
|
|
25
32
|
const namespacedTranslation = s__('NamespacedTranslation');
|
|
26
33
|
|
|
@@ -13,6 +13,11 @@ This rule is like [require-valid-i18n-helpers](./require-valid-i18n-helpers.md)
|
|
|
13
13
|
{{ __(LABEL) }}
|
|
14
14
|
{{ __(getDescription()) }}
|
|
15
15
|
|
|
16
|
+
<!-- String interpolation -->
|
|
17
|
+
{{ __(`String ${interpolation}`) }}
|
|
18
|
+
{{ s__("SomeContext", `String ${interpolation}`) }}
|
|
19
|
+
{{ n__("%d apple", `%d ${apples}`, appleCount) }}
|
|
20
|
+
|
|
16
21
|
<!-- Missing translation namespace -->
|
|
17
22
|
{{ s__('NamespacedTranslation') }}
|
|
18
23
|
</div>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const [, ...restrictedGlobals] = require('eslint-config-airbnb-base/rules/variables').rules[
|
|
2
|
+
'no-restricted-globals'
|
|
3
|
+
];
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
This plugin contains rules related to GitLab JavaScript style guide
|
|
7
|
+
Vue specific rules are in lib/configs/vue.js
|
|
8
|
+
*/
|
|
9
|
+
module.exports = {
|
|
10
|
+
env: {
|
|
11
|
+
browser: true,
|
|
12
|
+
es2020: true,
|
|
13
|
+
},
|
|
14
|
+
extends: ['airbnb-base', 'prettier', 'plugin:promise/recommended'],
|
|
15
|
+
parserOptions: {
|
|
16
|
+
parser: 'espree',
|
|
17
|
+
ecmaVersion: 'latest',
|
|
18
|
+
},
|
|
19
|
+
plugins: ['unicorn', 'promise', 'import', '@gitlab'],
|
|
20
|
+
rules: {
|
|
21
|
+
camelcase: [
|
|
22
|
+
'error',
|
|
23
|
+
{
|
|
24
|
+
properties: 'never',
|
|
25
|
+
ignoreDestructuring: true,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
'default-param-last': 'off',
|
|
29
|
+
'unicorn/filename-case': ['error', { case: 'snakeCase' }],
|
|
30
|
+
'unicorn/no-array-callback-reference': 'error',
|
|
31
|
+
'import/prefer-default-export': 'off',
|
|
32
|
+
'import/no-default-export': 'error',
|
|
33
|
+
'import/no-deprecated': 'error',
|
|
34
|
+
'import/no-dynamic-require': ['error', { esmodule: true }],
|
|
35
|
+
'no-implicit-coercion': [
|
|
36
|
+
'error',
|
|
37
|
+
{
|
|
38
|
+
boolean: true,
|
|
39
|
+
number: true,
|
|
40
|
+
string: true,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
'no-param-reassign': [
|
|
44
|
+
'error',
|
|
45
|
+
{
|
|
46
|
+
props: true,
|
|
47
|
+
ignorePropertyModificationsFor: ['acc', 'accumulator', 'el', 'element', 'state'],
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
'no-restricted-exports': [
|
|
51
|
+
'error',
|
|
52
|
+
{
|
|
53
|
+
restrictedNamedExports: [
|
|
54
|
+
'then', // avoid confusion when used with dynamic `import()` promise
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
'no-restricted-syntax': 'off',
|
|
59
|
+
'no-sequences': [
|
|
60
|
+
'error',
|
|
61
|
+
{
|
|
62
|
+
allowInParentheses: false,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
'promise/catch-or-return': [
|
|
66
|
+
'error',
|
|
67
|
+
{
|
|
68
|
+
allowFinally: true,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
'no-restricted-globals': [
|
|
72
|
+
'error',
|
|
73
|
+
...restrictedGlobals,
|
|
74
|
+
{
|
|
75
|
+
name: 'escape',
|
|
76
|
+
message:
|
|
77
|
+
"The global `escape` function is unsafe. Did you mean to use `encodeURI`, `encodeURIComponent` or lodash's `escape` instead?",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'unescape',
|
|
81
|
+
message:
|
|
82
|
+
"The global `unescape` function is unsafe. Did you mean to use `decodeURI`, `decodeURIComponent` or lodash's `unescape` instead?",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
'import/order': [
|
|
86
|
+
'error',
|
|
87
|
+
{
|
|
88
|
+
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
};
|
package/lib/configs/default.js
CHANGED
|
@@ -1,150 +1,18 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
];
|
|
1
|
+
const baseConfig = require('./base');
|
|
2
|
+
const vueConfig = require('./vue');
|
|
4
3
|
|
|
5
4
|
module.exports = {
|
|
6
|
-
|
|
7
|
-
browser: true,
|
|
8
|
-
es2020: true,
|
|
9
|
-
},
|
|
5
|
+
...baseConfig,
|
|
10
6
|
extends: [
|
|
11
7
|
'airbnb-base',
|
|
12
|
-
'plugin:vue/recommended',
|
|
13
8
|
'prettier',
|
|
14
|
-
'prettier/vue',
|
|
15
9
|
'plugin:promise/recommended',
|
|
10
|
+
'plugin:vue/recommended',
|
|
11
|
+
'prettier/vue',
|
|
16
12
|
],
|
|
17
|
-
parserOptions: {
|
|
18
|
-
parser: 'espree',
|
|
19
|
-
ecmaVersion: 'latest',
|
|
20
|
-
},
|
|
21
|
-
plugins: ['unicorn', 'promise', 'import', '@gitlab'],
|
|
22
13
|
rules: {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
properties: 'never',
|
|
27
|
-
ignoreDestructuring: true,
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
'default-param-last': 'off',
|
|
31
|
-
'unicorn/filename-case': ['error', { case: 'snakeCase' }],
|
|
32
|
-
'unicorn/no-array-callback-reference': 'error',
|
|
33
|
-
'import/prefer-default-export': 'off',
|
|
34
|
-
'import/no-default-export': 'error',
|
|
35
|
-
'import/no-deprecated': 'error',
|
|
36
|
-
'import/no-dynamic-require': ['error', { esmodule: true }],
|
|
37
|
-
'no-implicit-coercion': [
|
|
38
|
-
'error',
|
|
39
|
-
{
|
|
40
|
-
boolean: true,
|
|
41
|
-
number: true,
|
|
42
|
-
string: true,
|
|
43
|
-
},
|
|
44
|
-
],
|
|
45
|
-
'no-param-reassign': [
|
|
46
|
-
'error',
|
|
47
|
-
{
|
|
48
|
-
props: true,
|
|
49
|
-
ignorePropertyModificationsFor: ['acc', 'accumulator', 'el', 'element', 'state'],
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
'no-restricted-exports': [
|
|
53
|
-
'error',
|
|
54
|
-
{
|
|
55
|
-
restrictedNamedExports: [
|
|
56
|
-
'then', // avoid confusion when used with dynamic `import()` promise
|
|
57
|
-
],
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
'no-restricted-syntax': 'off',
|
|
61
|
-
'no-sequences': [
|
|
62
|
-
'error',
|
|
63
|
-
{
|
|
64
|
-
allowInParentheses: false,
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
'promise/catch-or-return': [
|
|
68
|
-
'error',
|
|
69
|
-
{
|
|
70
|
-
allowFinally: true,
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
'vue/html-self-closing': [
|
|
74
|
-
'error',
|
|
75
|
-
{
|
|
76
|
-
html: {
|
|
77
|
-
void: 'any',
|
|
78
|
-
normal: 'never',
|
|
79
|
-
component: 'always',
|
|
80
|
-
},
|
|
81
|
-
svg: 'always',
|
|
82
|
-
math: 'always',
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
'vue/component-tags-order': [
|
|
86
|
-
'error',
|
|
87
|
-
{
|
|
88
|
-
order: ['script', 'template', 'style'],
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
'vue/component-options-name-casing': ['error', 'PascalCase'],
|
|
92
|
-
'vue/component-name-in-template-casing': ['error', 'kebab-case'],
|
|
93
|
-
'@gitlab/vue-require-required-key': 'error',
|
|
94
|
-
'no-restricted-globals': [
|
|
95
|
-
'error',
|
|
96
|
-
...restrictedGlobals,
|
|
97
|
-
{
|
|
98
|
-
name: 'escape',
|
|
99
|
-
message:
|
|
100
|
-
"The global `escape` function is unsafe. Did you mean to use `encodeURI`, `encodeURIComponent` or lodash's `escape` instead?",
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: 'unescape',
|
|
104
|
-
message:
|
|
105
|
-
"The global `unescape` function is unsafe. Did you mean to use `decodeURI`, `decodeURIComponent` or lodash's `unescape` instead?",
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
'vue/v-slot-style': [
|
|
109
|
-
'error',
|
|
110
|
-
{
|
|
111
|
-
atComponent: 'shorthand',
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
'@gitlab/vue-no-data-toggle': 'error',
|
|
115
|
-
'@gitlab/vue-prefer-dollar-scopedslots': 'error',
|
|
116
|
-
'@gitlab/vue-slot-name-casing': 'error',
|
|
117
|
-
'@gitlab/no-runtime-template-compiler': 'error',
|
|
118
|
-
'import/order': [
|
|
119
|
-
'error',
|
|
120
|
-
{
|
|
121
|
-
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
// See https://gitlab.com/gitlab-org/frontend/eslint-plugin/-/issues/52.
|
|
125
|
-
'vue/component-api-style': ['error', ['options']],
|
|
126
|
-
// BEGIN rules to aid migration from Vue 2.x to 3.x.
|
|
127
|
-
// See https://gitlab.com/groups/gitlab-org/-/epics/3174 for more details.
|
|
128
|
-
'vue/no-deprecated-data-object-declaration': 'error',
|
|
129
|
-
'vue/no-deprecated-events-api': 'error',
|
|
130
|
-
'vue/no-deprecated-filter': 'error',
|
|
131
|
-
'vue/no-deprecated-functional-template': 'error',
|
|
132
|
-
'vue/no-deprecated-html-element-is': 'error',
|
|
133
|
-
'vue/no-deprecated-inline-template': 'error',
|
|
134
|
-
'vue/no-deprecated-props-default-this': 'error',
|
|
135
|
-
'vue/no-deprecated-scope-attribute': 'error',
|
|
136
|
-
'vue/no-deprecated-slot-attribute': 'error',
|
|
137
|
-
'vue/no-deprecated-slot-scope-attribute': 'error',
|
|
138
|
-
'vue/no-deprecated-v-on-number-modifiers': 'error',
|
|
139
|
-
'vue/no-deprecated-vue-config-keycodes': 'error',
|
|
140
|
-
// END rules to aid migration from Vue 2.x to 3.x.
|
|
14
|
+
...baseConfig.rules,
|
|
15
|
+
...vueConfig.rules,
|
|
141
16
|
},
|
|
142
|
-
overrides:
|
|
143
|
-
{
|
|
144
|
-
files: ['**/*.vue'],
|
|
145
|
-
rules: {
|
|
146
|
-
'import/no-default-export': 'off',
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
],
|
|
17
|
+
overrides: vueConfig.overrides,
|
|
150
18
|
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const baseConfig = require('./base');
|
|
2
|
+
|
|
3
|
+
const tsConfig = {
|
|
4
|
+
env: {
|
|
5
|
+
mocha: true,
|
|
6
|
+
jest: true,
|
|
7
|
+
},
|
|
8
|
+
parserOptions: baseConfig.parserOptions,
|
|
9
|
+
extends: [...baseConfig.extends],
|
|
10
|
+
plugins: [...baseConfig.plugins],
|
|
11
|
+
rules: {
|
|
12
|
+
...baseConfig.rules,
|
|
13
|
+
'import/extensions': [
|
|
14
|
+
'error',
|
|
15
|
+
'ignorePackages',
|
|
16
|
+
{
|
|
17
|
+
js: 'never',
|
|
18
|
+
jsx: 'never',
|
|
19
|
+
ts: 'never',
|
|
20
|
+
tsx: 'never',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
overrides: [
|
|
25
|
+
{
|
|
26
|
+
files: ['**/*.ts'],
|
|
27
|
+
parserOptions: {
|
|
28
|
+
parser: '@typescript-eslint/parser',
|
|
29
|
+
project: ['./tsconfig.json'],
|
|
30
|
+
},
|
|
31
|
+
plugins: ['@typescript-eslint', 'import'],
|
|
32
|
+
extends: [
|
|
33
|
+
'eslint:recommended',
|
|
34
|
+
'plugin:@typescript-eslint/strict',
|
|
35
|
+
'plugin:import/typescript',
|
|
36
|
+
],
|
|
37
|
+
reportUnusedDisableDirectives: true,
|
|
38
|
+
rules: {
|
|
39
|
+
semi: [2, 'always'],
|
|
40
|
+
'no-throw-literal': 'off',
|
|
41
|
+
'no-shadow': 'off',
|
|
42
|
+
'no-empty-function': 'off',
|
|
43
|
+
'no-plusplus': 'off',
|
|
44
|
+
'unicorn/no-array-callback-reference': 'off',
|
|
45
|
+
'@typescript-eslint/no-throw-literal': 'error',
|
|
46
|
+
'@typescript-eslint/no-unused-vars': 'error',
|
|
47
|
+
'@typescript-eslint/no-shadow': 'error',
|
|
48
|
+
'@typescript-eslint/return-await': 'error',
|
|
49
|
+
'@typescript-eslint/no-floating-promises': 'error',
|
|
50
|
+
'class-methods-use-this': 'off',
|
|
51
|
+
'import/no-cycle': 'error',
|
|
52
|
+
'promise/param-names': 'off',
|
|
53
|
+
'no-use-before-define': ['warn', 'nofunc'],
|
|
54
|
+
'no-restricted-syntax': [
|
|
55
|
+
'error',
|
|
56
|
+
{
|
|
57
|
+
selector: ':matches(PropertyDefinition, MethodDefinition)[accessibility="private"]',
|
|
58
|
+
message: 'Use # prefix instead of `private` to indicate private class members.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
selector: 'ForInStatement',
|
|
62
|
+
message:
|
|
63
|
+
'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
selector: 'LabeledStatement',
|
|
67
|
+
message:
|
|
68
|
+
'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
selector: 'WithStatement',
|
|
72
|
+
message:
|
|
73
|
+
'`with` is disallowed in strict mode because it makes code impossible to predict and optimize.',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
files: ['*.test.ts', '*.test.js'],
|
|
80
|
+
rules: {
|
|
81
|
+
'max-classes-per-file': 'off',
|
|
82
|
+
'@typescript-eslint/no-non-null-assertion': 'off',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
module.exports = tsConfig;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This plugin contains rules related to GitLab Vue style guide
|
|
3
|
+
base JavaScript rules are in lib/configs/base.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
env: {
|
|
8
|
+
browser: true,
|
|
9
|
+
es2020: true,
|
|
10
|
+
},
|
|
11
|
+
extends: ['plugin:vue/recommended', 'prettier/vue'],
|
|
12
|
+
parserOptions: {
|
|
13
|
+
parser: 'espree',
|
|
14
|
+
ecmaVersion: 'latest',
|
|
15
|
+
},
|
|
16
|
+
plugins: ['unicorn', 'promise', 'import', '@gitlab'],
|
|
17
|
+
rules: {
|
|
18
|
+
'vue/html-self-closing': [
|
|
19
|
+
'error',
|
|
20
|
+
{
|
|
21
|
+
html: {
|
|
22
|
+
void: 'any',
|
|
23
|
+
normal: 'never',
|
|
24
|
+
component: 'always',
|
|
25
|
+
},
|
|
26
|
+
svg: 'always',
|
|
27
|
+
math: 'always',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
'vue/component-tags-order': [
|
|
31
|
+
'error',
|
|
32
|
+
{
|
|
33
|
+
order: ['script', 'template', 'style'],
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
'vue/component-options-name-casing': ['error', 'PascalCase'],
|
|
37
|
+
'vue/component-name-in-template-casing': ['error', 'kebab-case'],
|
|
38
|
+
'@gitlab/vue-require-required-key': 'error',
|
|
39
|
+
'vue/v-slot-style': [
|
|
40
|
+
'error',
|
|
41
|
+
{
|
|
42
|
+
atComponent: 'shorthand',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
'@gitlab/vue-no-data-toggle': 'error',
|
|
46
|
+
'@gitlab/vue-prefer-dollar-scopedslots': 'error',
|
|
47
|
+
'@gitlab/vue-slot-name-casing': 'error',
|
|
48
|
+
'@gitlab/no-runtime-template-compiler': 'error',
|
|
49
|
+
'import/order': [
|
|
50
|
+
'error',
|
|
51
|
+
{
|
|
52
|
+
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
// See https://gitlab.com/gitlab-org/frontend/eslint-plugin/-/issues/52.
|
|
56
|
+
'vue/component-api-style': ['error', ['options']],
|
|
57
|
+
// BEGIN rules to aid migration from Vue 2.x to 3.x.
|
|
58
|
+
// See https://gitlab.com/groups/gitlab-org/-/epics/3174 for more details.
|
|
59
|
+
'vue/no-deprecated-data-object-declaration': 'error',
|
|
60
|
+
'vue/no-deprecated-events-api': 'error',
|
|
61
|
+
'vue/no-deprecated-filter': 'error',
|
|
62
|
+
'vue/no-deprecated-functional-template': 'error',
|
|
63
|
+
'vue/no-deprecated-html-element-is': 'error',
|
|
64
|
+
'vue/no-deprecated-inline-template': 'error',
|
|
65
|
+
'vue/no-deprecated-props-default-this': 'error',
|
|
66
|
+
'vue/no-deprecated-scope-attribute': 'error',
|
|
67
|
+
'vue/no-deprecated-slot-attribute': 'error',
|
|
68
|
+
'vue/no-deprecated-slot-scope-attribute': 'error',
|
|
69
|
+
'vue/no-deprecated-v-on-number-modifiers': 'error',
|
|
70
|
+
'vue/no-deprecated-vue-config-keycodes': 'error',
|
|
71
|
+
// END rules to aid migration from Vue 2.x to 3.x.
|
|
72
|
+
},
|
|
73
|
+
overrides: [
|
|
74
|
+
{
|
|
75
|
+
files: ['**/*.vue'],
|
|
76
|
+
rules: {
|
|
77
|
+
'import/no-default-export': 'off',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -20,6 +20,9 @@ module.exports = {
|
|
|
20
20
|
},
|
|
21
21
|
configs: {
|
|
22
22
|
default: require('./configs/default.js'),
|
|
23
|
+
typescript: require('./configs/typescript.js'),
|
|
24
|
+
base: require('./configs/base.js'),
|
|
25
|
+
vue: require('./configs/vue.js'),
|
|
23
26
|
i18n: require('./configs/i18n.js'),
|
|
24
27
|
jest: require('./configs/jest.js'),
|
|
25
28
|
},
|
package/lib/utils/i18n-utils.js
CHANGED
|
@@ -10,6 +10,8 @@ const P_GETTEXT = 's__';
|
|
|
10
10
|
const N_GETTEXT = 'n__';
|
|
11
11
|
|
|
12
12
|
const ERROR_MESSAGE_STRING_LITERAL = 'Translation helpers must be called with a string literal.';
|
|
13
|
+
const ERROR_MESSAGE_STRING_INTERPOLATION =
|
|
14
|
+
'Translation helpers should not use string interpolation.';
|
|
13
15
|
const ERROR_MESSAGE_EXTRANEOUS_NAMESPACE =
|
|
14
16
|
'__ should not be used with a translation namespace, consider using s__ instead.';
|
|
15
17
|
const ERROR_MESSAGE_MISSING_NAMESPACE = 's__ requires a translation namespace to be provided.';
|
|
@@ -38,6 +40,16 @@ const mustBeCalledWithStringLiteralArguments = (context, node) => {
|
|
|
38
40
|
}
|
|
39
41
|
};
|
|
40
42
|
|
|
43
|
+
const mustNotHaveStringInterpolation = (context, node) => {
|
|
44
|
+
const [arg1, arg2] = node.arguments;
|
|
45
|
+
if ([arg1, arg2].some((arg) => arg?.expressions?.length)) {
|
|
46
|
+
context.report({
|
|
47
|
+
node,
|
|
48
|
+
message: ERROR_MESSAGE_STRING_INTERPOLATION,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
41
53
|
const mustHaveNamespace = (context, node) => {
|
|
42
54
|
if (node.arguments.length === 2) {
|
|
43
55
|
return;
|
|
@@ -94,9 +106,21 @@ const namespacesMustMatch = (context, node) => {
|
|
|
94
106
|
};
|
|
95
107
|
|
|
96
108
|
const VALIDATORS = {
|
|
97
|
-
[GETTEXT]: [
|
|
98
|
-
|
|
99
|
-
|
|
109
|
+
[GETTEXT]: [
|
|
110
|
+
mustBeCalledWithStringLiteralArguments,
|
|
111
|
+
mustNotHaveStringInterpolation,
|
|
112
|
+
mustNotHaveNamespace,
|
|
113
|
+
],
|
|
114
|
+
[P_GETTEXT]: [
|
|
115
|
+
mustBeCalledWithStringLiteralArguments,
|
|
116
|
+
mustNotHaveStringInterpolation,
|
|
117
|
+
mustHaveNamespace,
|
|
118
|
+
],
|
|
119
|
+
[N_GETTEXT]: [
|
|
120
|
+
mustBeCalledWithStringLiteralArguments,
|
|
121
|
+
mustNotHaveStringInterpolation,
|
|
122
|
+
namespacesMustMatch,
|
|
123
|
+
],
|
|
100
124
|
};
|
|
101
125
|
|
|
102
126
|
const validateI18nHelperCallFactory = (context) => (node) => {
|
|
@@ -113,6 +137,7 @@ const validateI18nHelperCallFactory = (context) => (node) => {
|
|
|
113
137
|
module.exports = {
|
|
114
138
|
validateI18nHelperCallFactory,
|
|
115
139
|
ERROR_MESSAGE_STRING_LITERAL,
|
|
140
|
+
ERROR_MESSAGE_STRING_INTERPOLATION,
|
|
116
141
|
ERROR_MESSAGE_EXTRANEOUS_NAMESPACE,
|
|
117
142
|
ERROR_MESSAGE_MISSING_NAMESPACE,
|
|
118
143
|
ERROR_MESSAGE_NAMESPACES_MISMATCH,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/eslint-plugin",
|
|
3
|
-
"version": "19.
|
|
3
|
+
"version": "19.6.0",
|
|
4
4
|
"description": "GitLab package for our custom eslint rules",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"node": ">=14"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@typescript-eslint/eslint-plugin": "^7.14.1",
|
|
33
34
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
34
35
|
"eslint-config-prettier": "^6.10.0",
|
|
35
36
|
"eslint-plugin-import": "^2.28.0",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"eslint-plugin-promise": "^6.0.1",
|
|
38
39
|
"eslint-plugin-unicorn": "^40.1.0",
|
|
39
40
|
"eslint-plugin-vue": "^9.17.0",
|
|
41
|
+
"vue-eslint-parser": "^9.3.1",
|
|
40
42
|
"lodash": "^4.17.21"
|
|
41
43
|
},
|
|
42
44
|
"peerDependencies": {
|
|
@@ -48,7 +50,6 @@
|
|
|
48
50
|
"jest": "^27.5.1",
|
|
49
51
|
"prettier": "^2.6.1",
|
|
50
52
|
"pretty-quick": "^3.1.3",
|
|
51
|
-
"vue-eslint-parser": "^9.3.1",
|
|
52
53
|
"yarn-deduplicate": "^6.0.2"
|
|
53
54
|
},
|
|
54
55
|
"release": {
|