@gitlab/eslint-plugin 22.0.0 → 24.0.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 +98 -0
- package/docs/rules.md +0 -2
- package/lib/configs/base/es6.js +1 -1
- package/lib/configs/base/imports.js +86 -97
- package/lib/flat-configs/base.js +7 -7
- package/lib/flat-configs/typescript.js +24 -7
- package/lib/plugin.js +0 -2
- package/lib/rules/no-runtime-template-compiler.js +1 -1
- package/lib/rules/require-i18n-strings.js +4 -4
- package/lib/rules/vtu-no-explicit-wrapper-destroy.js +1 -1
- package/lib/utils/hardcoded-urls.js +1 -1
- package/lib/utils/string-utils.js +6 -8
- package/lib/vue-fragments.js +5 -6
- package/package.json +3 -2
- package/scripts/benchmarking/checkAllStrings.js +1 -1
- package/scripts/helpers/getConfigs.js +4 -2
- package/scripts/publish_npm_package.mjs +0 -2
- package/docs/rules/vue-prefer-dollar-scopedslots.md +0 -62
- package/docs/rules/vue-slot-name-casing.md +0 -39
- package/lib/rules/vue-prefer-dollar-scopedslots.js +0 -64
- package/lib/rules/vue-slot-name-casing.js +0 -65
- package/scripts/generateRuleMapFixtures.js +0 -75
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,103 @@
|
|
|
1
1
|
# @gitlab/eslint-plugin
|
|
2
2
|
|
|
3
|
+
## 24.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 2defaab: Remove two Vue 2 slot rules from the `vue` config and from the plugin.
|
|
8
|
+
|
|
9
|
+
- `@gitlab/vue-prefer-dollar-scopedslots` is removed. It told authors to use `$scopedSlots`, which
|
|
10
|
+
Vue 3 does not have. Under `@vue/compat` every access is a deprecation, and eslint-plugin-vue's
|
|
11
|
+
`vue/no-deprecated-dollar-scopedslots-api` reports it. A consumer that still wants to forbid
|
|
12
|
+
`$slots` can do so with `vue/no-restricted-syntax`.
|
|
13
|
+
- `@gitlab/vue-slot-name-casing` is removed. The `vue` config now enables
|
|
14
|
+
`vue/slot-name-casing` with `kebab-case`, which checks the same `<slot name>` attribute.
|
|
15
|
+
|
|
16
|
+
Consumers that reference either rule by name, for example in an `eslint-disable` comment, must
|
|
17
|
+
drop the reference.
|
|
18
|
+
|
|
19
|
+
## 23.0.0
|
|
20
|
+
|
|
21
|
+
### Major Changes
|
|
22
|
+
|
|
23
|
+
- 8dfb811: Replace `eslint-plugin-import` with `eslint-plugin-import-x`.
|
|
24
|
+
|
|
25
|
+
`eslint-plugin-import` does not support ESLint 10. `eslint-plugin-import-x` is a maintained fork with
|
|
26
|
+
the same rules that supports ESLint 8, 9 and 10. Every config this package exports now registers
|
|
27
|
+
`eslint-plugin-import-x` under the `import-x` namespace instead of `eslint-plugin-import` under
|
|
28
|
+
`import`. The rules we enable and their options are unchanged; only their names and the settings
|
|
29
|
+
that drive them move.
|
|
30
|
+
|
|
31
|
+
## Breaking changes
|
|
32
|
+
|
|
33
|
+
1. **Every import rule is renamed from `import/<rule>` to `import-x/<rule>`.** Rule overrides in
|
|
34
|
+
your `eslint.config.js` must be renamed:
|
|
35
|
+
|
|
36
|
+
```diff
|
|
37
|
+
module.exports = [
|
|
38
|
+
...gitlab.configs.default,
|
|
39
|
+
{
|
|
40
|
+
rules: {
|
|
41
|
+
- 'import/no-cycle': 'off',
|
|
42
|
+
+ 'import-x/no-cycle': 'off',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
2. **Disable comments must be renamed too.** An `// eslint-disable-next-line import/no-cycle`
|
|
49
|
+
comment now refers to a rule ESLint cannot find, which it reports as an error. Rename them to
|
|
50
|
+
`import-x/...`. This rewrites `import/` to `import-x/` on ESLint directive lines only, leaving
|
|
51
|
+
import paths alone (review the diff before committing):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git grep -lE 'eslint-(disable|enable)|/\* *eslint ' -- '*.js' '*.mjs' '*.cjs' '*.ts' '*.vue' \
|
|
55
|
+
| xargs perl -pi -e 's#(?<=[\s,])import/(?=[a-z])#import-x/#g if m{eslint-(disable|enable)|/\*\s*eslint\s}'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
3. **Import settings are renamed from `import/*` to `import-x/*`.** `eslint-plugin-import-x` only
|
|
59
|
+
reads `import-x/`-prefixed settings and silently ignores the old names, so a leftover
|
|
60
|
+
`import/resolver`, `import/core-modules`, `import/ignore` or `import/internal-regex` stops having
|
|
61
|
+
any effect without an error. Rename each key.
|
|
62
|
+
|
|
63
|
+
4. **In the `typescript` config, custom resolvers must go in `import-x/resolver-next`.** That config
|
|
64
|
+
sets `import-x/resolver-next` so `.ts` and `.tsx` files resolve, and when that key is present
|
|
65
|
+
`eslint-plugin-import-x` ignores `import-x/resolver`. ESLint also replaces arrays in `settings`
|
|
66
|
+
rather than merging them, so your `import-x/resolver-next` replaces ours. If you need `tsconfig.json`
|
|
67
|
+
`paths` aliases, use `eslint-import-resolver-typescript`, which also resolves everything ours does:
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
const { createTypeScriptImportResolver } = require('eslint-import-resolver-typescript');
|
|
71
|
+
|
|
72
|
+
module.exports = [
|
|
73
|
+
...gitlab.configs.typescript,
|
|
74
|
+
{
|
|
75
|
+
settings: {
|
|
76
|
+
'import-x/resolver-next': [createTypeScriptImportResolver()],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The other configs set no resolver, so a custom one there only needs its key renamed (point 3).
|
|
83
|
+
|
|
84
|
+
## Other changes
|
|
85
|
+
|
|
86
|
+
- The configs other than `typescript` no longer set a resolver and rely on `eslint-plugin-import-x`'s
|
|
87
|
+
default node resolver. It resolves the same files as before, plus `.cjs` and `.node`.
|
|
88
|
+
- `import-x/core-modules` and the stylesheet/asset patterns in `import-x/ignore` are no longer set.
|
|
89
|
+
Neither had an effect: the first was the default value, and files with those extensions were
|
|
90
|
+
already skipped because they aren't listed in `import-x/extensions`. `node_modules` is still
|
|
91
|
+
ignored.
|
|
92
|
+
- `import/imports-first` is no longer configured. It was already disabled, and it is deprecated in
|
|
93
|
+
favour of `import-x/first`, which stays enabled.
|
|
94
|
+
- The `typescript` config no longer relies on `eslint-plugin-import`'s TypeScript preset. It sets the
|
|
95
|
+
equivalent settings itself: `.ts`, `.cts`, `.mts` and `.tsx` files are resolved by the node
|
|
96
|
+
resolver, `node_modules/@types` is treated as external, and `import-x/named` is disabled for
|
|
97
|
+
TypeScript files as before.
|
|
98
|
+
- If your own config also uses `eslint-plugin-import`, it can now coexist with this package: the two
|
|
99
|
+
plugins register under different names.
|
|
100
|
+
|
|
3
101
|
## 22.0.0
|
|
4
102
|
|
|
5
103
|
### Major Changes
|
package/docs/rules.md
CHANGED
|
@@ -18,11 +18,9 @@ Available rules:
|
|
|
18
18
|
- [vue-no-new-non-primitive-in-template](./rules/vue-no-new-non-primitive-in-template.md): Prevents non-primitive values from being declared in templates
|
|
19
19
|
- [vue-no-popover-target-dollar-el](./rules/vue-no-popover-target-dollar-el.md): Disallow function-form `:target` bindings ending in `.$el` on `<gl-popover>` and `<gl-tooltip>`
|
|
20
20
|
- [vue-no-undef-apollo-properties](./rules/vue-no-undef-apollo-properties.md): Require Apollo query properties to be initialized in component data.
|
|
21
|
-
- [vue-prefer-dollar-scopedslots](./rules/vue-prefer-dollar-scopedslots.md): Prefer $scopedSlots over $slots for Vue 2.x.
|
|
22
21
|
- [vue-require-i18n-attribute-strings](./rules/vue-require-i18n-attribute-strings.md): Detect non externalized strings in vue `<template>` attributes
|
|
23
22
|
- [vue-require-i18n-strings](./rules/vue-require-i18n-strings.md): enforce no bare strings in vue `<template>`
|
|
24
23
|
- [vue-require-required-key](./rules/vue-require-required-key.md): Require the required key to be set
|
|
25
24
|
- [vue-require-valid-i18n-helpers](./rules/vue-require-valid-i18n-helpers.md): Enforces valid usage of translation helpers in Vue templates.
|
|
26
|
-
- [vue-slot-name-casing](./rules/vue-slot-name-casing.md): enforce specific casing for slot naming style in template
|
|
27
25
|
- [vue-tailwind-no-interpolation](./rules/vue-tailwind-no-interpolation.md): Prevents building Tailwind CSS utility classes with string interpolation.
|
|
28
26
|
- [vue-tailwind-no-max-width-media-queries](./rules/vue-tailwind-no-max-width-media-queries.md): Prevents the usage of max-width media query Tailwind CSS utility classes.
|
package/lib/configs/base/es6.js
CHANGED
|
@@ -48,7 +48,7 @@ module.exports = {
|
|
|
48
48
|
|
|
49
49
|
// disallow importing from the same path more than once
|
|
50
50
|
// https://eslint.org/docs/rules/no-duplicate-imports
|
|
51
|
-
// replaced by https://github.com/
|
|
51
|
+
// replaced by https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-duplicates.md
|
|
52
52
|
'no-duplicate-imports': 'off',
|
|
53
53
|
|
|
54
54
|
// disallow symbol constructor
|
|
@@ -1,55 +1,49 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
settings: {
|
|
3
|
-
'import/
|
|
4
|
-
|
|
5
|
-
extensions: ['.mjs', '.js', '.json'],
|
|
6
|
-
},
|
|
7
|
-
},
|
|
8
|
-
'import/extensions': ['.js', '.mjs', '.jsx'],
|
|
9
|
-
'import/core-modules': [],
|
|
10
|
-
'import/ignore': ['node_modules', '\\.(coffee|scss|css|less|hbs|svg|json)$'],
|
|
3
|
+
'import-x/extensions': ['.js', '.mjs', '.jsx'],
|
|
4
|
+
'import-x/ignore': ['node_modules'],
|
|
11
5
|
},
|
|
12
6
|
|
|
13
7
|
rules: {
|
|
14
8
|
// Static analysis:
|
|
15
9
|
|
|
16
10
|
// ensure imports point to files/modules that can be resolved
|
|
17
|
-
// https://github.com/
|
|
18
|
-
'import/no-unresolved': ['error', { commonjs: true, caseSensitive: true }],
|
|
11
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-unresolved.md
|
|
12
|
+
'import-x/no-unresolved': ['error', { commonjs: true, caseSensitive: true }],
|
|
19
13
|
|
|
20
14
|
// ensure named imports coupled with named exports
|
|
21
|
-
// https://github.com/
|
|
22
|
-
'import/named': 'error',
|
|
15
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/named.md#when-not-to-use-it
|
|
16
|
+
'import-x/named': 'error',
|
|
23
17
|
|
|
24
18
|
// ensure default import coupled with default export
|
|
25
|
-
// https://github.com/
|
|
26
|
-
'import/default': 'off',
|
|
19
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/default.md#when-not-to-use-it
|
|
20
|
+
'import-x/default': 'off',
|
|
27
21
|
|
|
28
|
-
// https://github.com/
|
|
29
|
-
'import/namespace': 'off',
|
|
22
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/namespace.md
|
|
23
|
+
'import-x/namespace': 'off',
|
|
30
24
|
|
|
31
25
|
// Helpful warnings:
|
|
32
26
|
|
|
33
27
|
// disallow invalid exports, e.g. multiple defaults
|
|
34
|
-
// https://github.com/
|
|
35
|
-
'import/export': 'error',
|
|
28
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/export.md
|
|
29
|
+
'import-x/export': 'error',
|
|
36
30
|
|
|
37
31
|
// do not allow a default import name to match a named export
|
|
38
|
-
// https://github.com/
|
|
39
|
-
'import/no-named-as-default': 'error',
|
|
32
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-named-as-default.md
|
|
33
|
+
'import-x/no-named-as-default': 'error',
|
|
40
34
|
|
|
41
35
|
// warn on accessing default export property names that are also named exports
|
|
42
|
-
// https://github.com/
|
|
43
|
-
'import/no-named-as-default-member': 'error',
|
|
36
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-named-as-default-member.md
|
|
37
|
+
'import-x/no-named-as-default-member': 'error',
|
|
44
38
|
|
|
45
39
|
// disallow use of jsdoc-marked-deprecated imports
|
|
46
|
-
// https://github.com/
|
|
47
|
-
'import/no-deprecated': 'off',
|
|
40
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-deprecated.md
|
|
41
|
+
'import-x/no-deprecated': 'off',
|
|
48
42
|
|
|
49
43
|
// Forbid the use of extraneous packages
|
|
50
|
-
// https://github.com/
|
|
44
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-extraneous-dependencies.md
|
|
51
45
|
// paths are treated both as absolute paths, and relative to process.cwd()
|
|
52
|
-
'import/no-extraneous-dependencies': [
|
|
46
|
+
'import-x/no-extraneous-dependencies': [
|
|
53
47
|
'error',
|
|
54
48
|
{
|
|
55
49
|
devDependencies: [
|
|
@@ -81,47 +75,42 @@ module.exports = {
|
|
|
81
75
|
],
|
|
82
76
|
|
|
83
77
|
// Forbid mutable exports
|
|
84
|
-
// https://github.com/
|
|
85
|
-
'import/no-mutable-exports': 'error',
|
|
78
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-mutable-exports.md
|
|
79
|
+
'import-x/no-mutable-exports': 'error',
|
|
86
80
|
|
|
87
81
|
// Module systems:
|
|
88
82
|
|
|
89
83
|
// disallow require()
|
|
90
|
-
// https://github.com/
|
|
91
|
-
'import/no-commonjs': 'off',
|
|
84
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-commonjs.md
|
|
85
|
+
'import-x/no-commonjs': 'off',
|
|
92
86
|
|
|
93
87
|
// disallow AMD require/define
|
|
94
|
-
// https://github.com/
|
|
95
|
-
'import/no-amd': 'error',
|
|
88
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-amd.md
|
|
89
|
+
'import-x/no-amd': 'error',
|
|
96
90
|
|
|
97
91
|
// No Node.js builtin modules
|
|
98
|
-
// https://github.com/
|
|
92
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-nodejs-modules.md
|
|
99
93
|
// TODO: enable?
|
|
100
|
-
'import/no-nodejs-modules': 'off',
|
|
94
|
+
'import-x/no-nodejs-modules': 'off',
|
|
101
95
|
|
|
102
96
|
// Style guide:
|
|
103
97
|
|
|
104
98
|
// disallow non-import statements appearing before import statements
|
|
105
|
-
// https://github.com/
|
|
106
|
-
'import/first': 'error',
|
|
107
|
-
|
|
108
|
-
// disallow non-import statements appearing before import statements
|
|
109
|
-
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/imports-first.md
|
|
110
|
-
// deprecated: use `import/first`
|
|
111
|
-
'import/imports-first': 'off',
|
|
99
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/first.md
|
|
100
|
+
'import-x/first': 'error',
|
|
112
101
|
|
|
113
102
|
// disallow duplicate imports
|
|
114
|
-
// https://github.com/
|
|
115
|
-
'import/no-duplicates': 'error',
|
|
103
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-duplicates.md
|
|
104
|
+
'import-x/no-duplicates': 'error',
|
|
116
105
|
|
|
117
106
|
// disallow namespace imports
|
|
118
107
|
// TODO: enable?
|
|
119
|
-
// https://github.com/
|
|
120
|
-
'import/no-namespace': 'off',
|
|
108
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-namespace.md
|
|
109
|
+
'import-x/no-namespace': 'off',
|
|
121
110
|
|
|
122
111
|
// Ensure consistent use of file extension within the import path
|
|
123
|
-
// https://github.com/
|
|
124
|
-
'import/extensions': [
|
|
112
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/extensions.md
|
|
113
|
+
'import-x/extensions': [
|
|
125
114
|
'error',
|
|
126
115
|
'ignorePackages',
|
|
127
116
|
{
|
|
@@ -132,37 +121,37 @@ module.exports = {
|
|
|
132
121
|
],
|
|
133
122
|
|
|
134
123
|
// ensure absolute imports are above relative imports and that unassigned imports are ignored
|
|
135
|
-
// https://github.com/
|
|
124
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/order.md
|
|
136
125
|
// TODO: enforce a stricter convention in module import order?
|
|
137
|
-
'import/order': ['error', { groups: [['builtin', 'external', 'internal']] }],
|
|
126
|
+
'import-x/order': ['error', { groups: [['builtin', 'external', 'internal']] }],
|
|
138
127
|
|
|
139
128
|
// Require a newline after the last import/require in a group
|
|
140
|
-
// https://github.com/
|
|
141
|
-
'import/newline-after-import': 'error',
|
|
129
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/newline-after-import.md
|
|
130
|
+
'import-x/newline-after-import': 'error',
|
|
142
131
|
|
|
143
132
|
// Require modules with a single export to use a default export
|
|
144
|
-
// https://github.com/
|
|
145
|
-
'import/prefer-default-export': 'error',
|
|
133
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/prefer-default-export.md
|
|
134
|
+
'import-x/prefer-default-export': 'error',
|
|
146
135
|
|
|
147
136
|
// Restrict which files can be imported in a given folder
|
|
148
|
-
// https://github.com/
|
|
149
|
-
'import/no-restricted-paths': 'off',
|
|
137
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-restricted-paths.md
|
|
138
|
+
'import-x/no-restricted-paths': 'off',
|
|
150
139
|
|
|
151
140
|
// Forbid modules to have too many dependencies
|
|
152
|
-
// https://github.com/
|
|
153
|
-
'import/max-dependencies': ['off', { max: 10 }],
|
|
141
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/max-dependencies.md
|
|
142
|
+
'import-x/max-dependencies': ['off', { max: 10 }],
|
|
154
143
|
|
|
155
144
|
// Forbid import of modules using absolute paths
|
|
156
|
-
// https://github.com/
|
|
157
|
-
'import/no-absolute-path': 'error',
|
|
145
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-absolute-path.md
|
|
146
|
+
'import-x/no-absolute-path': 'error',
|
|
158
147
|
|
|
159
148
|
// Forbid require() calls with expressions
|
|
160
|
-
// https://github.com/
|
|
161
|
-
'import/no-dynamic-require': 'error',
|
|
149
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-dynamic-require.md
|
|
150
|
+
'import-x/no-dynamic-require': 'error',
|
|
162
151
|
|
|
163
152
|
// prevent importing the submodules of other modules
|
|
164
|
-
// https://github.com/
|
|
165
|
-
'import/no-internal-modules': [
|
|
153
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-internal-modules.md
|
|
154
|
+
'import-x/no-internal-modules': [
|
|
166
155
|
'off',
|
|
167
156
|
{
|
|
168
157
|
allow: [],
|
|
@@ -171,27 +160,27 @@ module.exports = {
|
|
|
171
160
|
|
|
172
161
|
// Warn if a module could be mistakenly parsed as a script by a consumer
|
|
173
162
|
// leveraging Unambiguous JavaScript Grammar
|
|
174
|
-
// https://github.com/
|
|
163
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/unambiguous.md
|
|
175
164
|
// this should not be enabled until this proposal has at least been *presented* to TC39.
|
|
176
165
|
// At the moment, it's not a thing.
|
|
177
|
-
'import/unambiguous': 'off',
|
|
166
|
+
'import-x/unambiguous': 'off',
|
|
178
167
|
|
|
179
168
|
// Forbid Webpack loader syntax in imports
|
|
180
|
-
// https://github.com/
|
|
181
|
-
'import/no-webpack-loader-syntax': 'error',
|
|
169
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-webpack-loader-syntax.md
|
|
170
|
+
'import-x/no-webpack-loader-syntax': 'error',
|
|
182
171
|
|
|
183
172
|
// Prevent unassigned imports
|
|
184
|
-
// https://github.com/
|
|
173
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-unassigned-import.md
|
|
185
174
|
// importing for side effects is perfectly acceptable, if you need side effects.
|
|
186
|
-
'import/no-unassigned-import': 'off',
|
|
175
|
+
'import-x/no-unassigned-import': 'off',
|
|
187
176
|
|
|
188
177
|
// Prevent importing the default as if it were named
|
|
189
|
-
// https://github.com/
|
|
190
|
-
'import/no-named-default': 'error',
|
|
178
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-named-default.md
|
|
179
|
+
'import-x/no-named-default': 'error',
|
|
191
180
|
|
|
192
181
|
// Reports if a module's default export is unnamed
|
|
193
|
-
// https://github.com/
|
|
194
|
-
'import/no-anonymous-default-export': [
|
|
182
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-anonymous-default-export.md
|
|
183
|
+
'import-x/no-anonymous-default-export': [
|
|
195
184
|
'off',
|
|
196
185
|
{
|
|
197
186
|
allowArray: false,
|
|
@@ -204,39 +193,39 @@ module.exports = {
|
|
|
204
193
|
],
|
|
205
194
|
|
|
206
195
|
// This rule enforces that all exports are declared at the bottom of the file.
|
|
207
|
-
// https://github.com/
|
|
196
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/exports-last.md
|
|
208
197
|
// TODO: enable?
|
|
209
|
-
'import/exports-last': 'off',
|
|
198
|
+
'import-x/exports-last': 'off',
|
|
210
199
|
|
|
211
200
|
// Reports when named exports are not grouped together in a single export declaration
|
|
212
201
|
// or when multiple assignments to CommonJS module.exports or exports object are present
|
|
213
202
|
// in a single file.
|
|
214
|
-
// https://github.com/
|
|
215
|
-
'import/group-exports': 'off',
|
|
203
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/group-exports.md
|
|
204
|
+
'import-x/group-exports': 'off',
|
|
216
205
|
|
|
217
206
|
// forbid default exports. this is a terrible rule, do not use it.
|
|
218
|
-
// https://github.com/
|
|
219
|
-
'import/no-default-export': 'off',
|
|
207
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-default-export.md
|
|
208
|
+
'import-x/no-default-export': 'off',
|
|
220
209
|
|
|
221
210
|
// Prohibit named exports. this is a terrible rule, do not use it.
|
|
222
|
-
// https://github.com/
|
|
223
|
-
'import/no-named-export': 'off',
|
|
211
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-named-export.md
|
|
212
|
+
'import-x/no-named-export': 'off',
|
|
224
213
|
|
|
225
214
|
// Forbid a module from importing itself
|
|
226
|
-
// https://github.com/
|
|
227
|
-
'import/no-self-import': 'error',
|
|
215
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-self-import.md
|
|
216
|
+
'import-x/no-self-import': 'error',
|
|
228
217
|
|
|
229
218
|
// Forbid cyclical dependencies between modules
|
|
230
|
-
// https://github.com/
|
|
231
|
-
'import/no-cycle': ['error', { maxDepth: '∞' }],
|
|
219
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-cycle.md
|
|
220
|
+
'import-x/no-cycle': ['error', { maxDepth: '∞' }],
|
|
232
221
|
|
|
233
222
|
// Ensures that there are no useless path segments
|
|
234
|
-
// https://github.com/
|
|
235
|
-
'import/no-useless-path-segments': ['error', { commonjs: true }],
|
|
223
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-useless-path-segments.md
|
|
224
|
+
'import-x/no-useless-path-segments': ['error', { commonjs: true }],
|
|
236
225
|
|
|
237
226
|
// dynamic imports require a leading comment with a webpackChunkName
|
|
238
|
-
// https://github.com/
|
|
239
|
-
'import/dynamic-import-chunkname': [
|
|
227
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/dynamic-import-chunkname.md
|
|
228
|
+
'import-x/dynamic-import-chunkname': [
|
|
240
229
|
'off',
|
|
241
230
|
{
|
|
242
231
|
importFunctions: [],
|
|
@@ -245,13 +234,13 @@ module.exports = {
|
|
|
245
234
|
],
|
|
246
235
|
|
|
247
236
|
// Use this rule to prevent imports to folders in relative parent paths.
|
|
248
|
-
// https://github.com/
|
|
249
|
-
'import/no-relative-parent-imports': 'off',
|
|
237
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-relative-parent-imports.md
|
|
238
|
+
'import-x/no-relative-parent-imports': 'off',
|
|
250
239
|
|
|
251
240
|
// Reports modules without any exports, or with unused exports
|
|
252
|
-
// https://github.com/
|
|
241
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-unused-modules.md
|
|
253
242
|
// TODO: enable once it supports CJS
|
|
254
|
-
'import/no-unused-modules': [
|
|
243
|
+
'import-x/no-unused-modules': [
|
|
255
244
|
'off',
|
|
256
245
|
{
|
|
257
246
|
ignoreExports: [],
|
|
@@ -261,8 +250,8 @@ module.exports = {
|
|
|
261
250
|
],
|
|
262
251
|
|
|
263
252
|
// Reports the use of import declarations with CommonJS exports in any module except for the main module.
|
|
264
|
-
// https://github.com/
|
|
265
|
-
'import/no-import-module-exports': [
|
|
253
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-import-module-exports.md
|
|
254
|
+
'import-x/no-import-module-exports': [
|
|
266
255
|
'error',
|
|
267
256
|
{
|
|
268
257
|
exceptions: [],
|
|
@@ -270,7 +259,7 @@ module.exports = {
|
|
|
270
259
|
],
|
|
271
260
|
|
|
272
261
|
// Use this rule to prevent importing packages through relative paths.
|
|
273
|
-
// https://github.com/
|
|
274
|
-
'import/no-relative-packages': 'error',
|
|
262
|
+
// https://github.com/un-ts/eslint-plugin-import-x/blob/master/docs/rules/no-relative-packages.md
|
|
263
|
+
'import-x/no-relative-packages': 'error',
|
|
275
264
|
},
|
|
276
265
|
};
|
package/lib/flat-configs/base.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const globals = require('globals');
|
|
2
2
|
const unicornPlugin = require('eslint-plugin-unicorn');
|
|
3
3
|
const promisePlugin = require('eslint-plugin-promise');
|
|
4
|
-
const importPlugin = require('eslint-plugin-import');
|
|
4
|
+
const importPlugin = require('eslint-plugin-import-x');
|
|
5
5
|
|
|
6
6
|
const confusingBrowserGlobals = require('../confusing-browser-globals');
|
|
7
7
|
const gitlabPlugin = require('../plugin.js');
|
|
@@ -35,7 +35,7 @@ module.exports = [
|
|
|
35
35
|
plugins: {
|
|
36
36
|
unicorn: unicornPlugin,
|
|
37
37
|
promise: promisePlugin,
|
|
38
|
-
import: importPlugin,
|
|
38
|
+
'import-x': importPlugin,
|
|
39
39
|
'@gitlab': gitlabPlugin,
|
|
40
40
|
},
|
|
41
41
|
settings: imports.settings,
|
|
@@ -63,10 +63,10 @@ module.exports = [
|
|
|
63
63
|
'arrow-body-style': 'off',
|
|
64
64
|
'unicorn/filename-case': ['error', { case: 'snakeCase' }],
|
|
65
65
|
'unicorn/no-array-callback-reference': 'error',
|
|
66
|
-
'import/prefer-default-export': 'off',
|
|
67
|
-
'import/no-default-export': 'error',
|
|
68
|
-
'import/no-deprecated': 'error',
|
|
69
|
-
'import/no-dynamic-require': ['error', { esmodule: true }],
|
|
66
|
+
'import-x/prefer-default-export': 'off',
|
|
67
|
+
'import-x/no-default-export': 'error',
|
|
68
|
+
'import-x/no-deprecated': 'error',
|
|
69
|
+
'import-x/no-dynamic-require': ['error', { esmodule: true }],
|
|
70
70
|
'no-implicit-coercion': ['error', { boolean: true, number: true, string: true }],
|
|
71
71
|
'no-param-reassign': [
|
|
72
72
|
'error',
|
|
@@ -109,7 +109,7 @@ module.exports = [
|
|
|
109
109
|
"The global `unescape` function is unsafe. Did you mean to use `decodeURI`, `decodeURIComponent` or lodash's `unescape` instead?",
|
|
110
110
|
},
|
|
111
111
|
].concat(confusingBrowserGlobals),
|
|
112
|
-
'import/order': [
|
|
112
|
+
'import-x/order': [
|
|
113
113
|
'error',
|
|
114
114
|
{
|
|
115
115
|
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const js = require('@eslint/js');
|
|
2
2
|
const tsPlugin = require('@typescript-eslint/eslint-plugin');
|
|
3
3
|
const tsParser = require('@typescript-eslint/parser');
|
|
4
|
-
const importPlugin = require('eslint-plugin-import');
|
|
4
|
+
const importPlugin = require('eslint-plugin-import-x');
|
|
5
5
|
const globals = require('globals');
|
|
6
6
|
|
|
7
7
|
const base = require('./base');
|
|
@@ -23,7 +23,24 @@ const base = require('./base');
|
|
|
23
23
|
*/
|
|
24
24
|
const tsEslintRecommended = tsPlugin.configs['flat/eslint-recommended'];
|
|
25
25
|
const tsStrict = tsPlugin.configs.strict;
|
|
26
|
-
|
|
26
|
+
/*
|
|
27
|
+
Mirrors eslint-plugin-import's `typescript` preset. import-x's own
|
|
28
|
+
`flatConfigs.typescript` isn't used because its resolver needs
|
|
29
|
+
eslint-import-resolver-typescript.
|
|
30
|
+
|
|
31
|
+
Unlike base, this sets a resolver: import-x's default one doesn't know the
|
|
32
|
+
TypeScript extensions, so `import './foo'` wouldn't find `foo.ts`. Consumers
|
|
33
|
+
who need `paths` aliases replace it with eslint-import-resolver-typescript,
|
|
34
|
+
which also resolves everything this one does.
|
|
35
|
+
*/
|
|
36
|
+
const TS_EXTENSIONS = ['.ts', '.cts', '.mts', '.tsx'];
|
|
37
|
+
const ALL_EXTENSIONS = [...TS_EXTENSIONS, '.js', '.jsx', '.mjs', '.cjs'];
|
|
38
|
+
const importTypescriptSettings = {
|
|
39
|
+
'import-x/extensions': ALL_EXTENSIONS,
|
|
40
|
+
'import-x/external-module-folders': ['node_modules', 'node_modules/@types'],
|
|
41
|
+
'import-x/parsers': { '@typescript-eslint/parser': TS_EXTENSIONS },
|
|
42
|
+
'import-x/resolver-next': [importPlugin.createNodeResolver({ extensions: ALL_EXTENSIONS })],
|
|
43
|
+
};
|
|
27
44
|
|
|
28
45
|
module.exports = [
|
|
29
46
|
...base,
|
|
@@ -36,7 +53,7 @@ module.exports = [
|
|
|
36
53
|
},
|
|
37
54
|
},
|
|
38
55
|
rules: {
|
|
39
|
-
'import/extensions': [
|
|
56
|
+
'import-x/extensions': [
|
|
40
57
|
'error',
|
|
41
58
|
'ignorePackages',
|
|
42
59
|
{ js: 'never', jsx: 'never', ts: 'never', tsx: 'never' },
|
|
@@ -54,17 +71,17 @@ module.exports = [
|
|
|
54
71
|
},
|
|
55
72
|
plugins: {
|
|
56
73
|
'@typescript-eslint': tsPlugin,
|
|
57
|
-
import: importPlugin,
|
|
74
|
+
'import-x': importPlugin,
|
|
58
75
|
},
|
|
59
76
|
linterOptions: {
|
|
60
77
|
reportUnusedDisableDirectives: true,
|
|
61
78
|
},
|
|
62
|
-
settings:
|
|
79
|
+
settings: importTypescriptSettings,
|
|
63
80
|
rules: {
|
|
64
81
|
...js.configs.recommended.rules,
|
|
65
82
|
...tsEslintRecommended.rules,
|
|
66
83
|
...tsStrict.rules,
|
|
67
|
-
|
|
84
|
+
'import-x/named': 'off',
|
|
68
85
|
semi: [2, 'always'],
|
|
69
86
|
'max-params': 'off',
|
|
70
87
|
'no-throw-literal': 'off',
|
|
@@ -79,7 +96,7 @@ module.exports = [
|
|
|
79
96
|
'@typescript-eslint/no-floating-promises': 'error',
|
|
80
97
|
'@typescript-eslint/explicit-member-accessibility': ['error', { accessibility: 'no-public' }],
|
|
81
98
|
'class-methods-use-this': 'off',
|
|
82
|
-
'import/no-cycle': 'error',
|
|
99
|
+
'import-x/no-cycle': 'error',
|
|
83
100
|
'promise/param-names': 'off',
|
|
84
101
|
'no-use-before-define': ['warn', 'nofunc'],
|
|
85
102
|
'no-restricted-syntax': [
|
package/lib/plugin.js
CHANGED
|
@@ -20,12 +20,10 @@ module.exports = {
|
|
|
20
20
|
'vue-no-new-non-primitive-in-template': require('./rules/vue-no-new-non-primitive-in-template.js'),
|
|
21
21
|
'vue-no-popover-target-dollar-el': require('./rules/vue-no-popover-target-dollar-el.js'),
|
|
22
22
|
'vue-no-undef-apollo-properties': require('./rules/vue-no-undef-apollo-properties.js'),
|
|
23
|
-
'vue-prefer-dollar-scopedslots': require('./rules/vue-prefer-dollar-scopedslots.js'),
|
|
24
23
|
'vue-require-i18n-attribute-strings': require('./rules/vue-require-i18n-attribute-strings.js'),
|
|
25
24
|
'vue-require-i18n-strings': require('./rules/vue-require-i18n-strings.js'),
|
|
26
25
|
'vue-require-required-key': require('./rules/vue-require-required-key.js'),
|
|
27
26
|
'vue-require-valid-i18n-helpers': require('./rules/vue-require-valid-i18n-helpers.js'),
|
|
28
|
-
'vue-slot-name-casing': require('./rules/vue-slot-name-casing.js'),
|
|
29
27
|
'vue-tailwind-no-interpolation': require('./rules/vue-tailwind-no-interpolation.js'),
|
|
30
28
|
'vue-tailwind-no-max-width-media-queries': require('./rules/vue-tailwind-no-max-width-media-queries.js'),
|
|
31
29
|
},
|
|
@@ -92,7 +92,7 @@ module.exports = {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function stripVariables(value) {
|
|
95
|
-
return value ? value.replace(/(
|
|
95
|
+
return value ? value.replace(/(%{[\w-]+})/g, '') : '';
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
function getCallExpressionString(node, callee) {
|
|
@@ -143,7 +143,7 @@ module.exports = {
|
|
|
143
143
|
|
|
144
144
|
function isMemberExpressionIdentifier(expression) {
|
|
145
145
|
if (expression.type !== 'MemberExpression') return false;
|
|
146
|
-
if (
|
|
146
|
+
if (expression.property.quasis) {
|
|
147
147
|
return /^\w+$/.test(getTemplateLiteralString(expression.property));
|
|
148
148
|
}
|
|
149
149
|
return /^\w+$/.test(expression.property.value);
|
|
@@ -164,14 +164,14 @@ module.exports = {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
function isObjectMethod(node) {
|
|
167
|
-
if (
|
|
167
|
+
if (node.callee.property) {
|
|
168
168
|
return objectMethods.has(node.callee.property.name);
|
|
169
169
|
}
|
|
170
170
|
return false;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
function isHtmlCall(node) {
|
|
174
|
-
if (
|
|
174
|
+
if (node.callee.property) {
|
|
175
175
|
return htmlCalls.has(node.callee.property.name);
|
|
176
176
|
}
|
|
177
177
|
return htmlCalls.has(node.callee.name);
|
|
@@ -96,7 +96,7 @@ function isHardCodedUrl(context, value) {
|
|
|
96
96
|
|
|
97
97
|
// Check for path-like patterns:
|
|
98
98
|
// Starts with / followed by word characters
|
|
99
|
-
const urlPathPattern = /^\/(?![#?])[
|
|
99
|
+
const urlPathPattern = /^\/(?![#?])[/.a-zA-Z0-9_-]+/;
|
|
100
100
|
|
|
101
101
|
return urlPathPattern.test(value);
|
|
102
102
|
}
|
|
@@ -6,13 +6,11 @@ function isFileName(value) {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
function isPath(value) {
|
|
9
|
-
return /^([\w-_]*|\.{1,2})[
|
|
9
|
+
return /^([\w-_]*|\.{1,2})[/~]+[\w-_/]*/.test(value);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function isUrl(value) {
|
|
13
|
-
return (
|
|
14
|
-
/[a-zA-Z0-9]*(:\/\/)+[a-zA-Z0-9\.]*/.test(value) || /(http){1}[s:\/a-zA-Z0-9.]*/.test(value)
|
|
15
|
-
);
|
|
13
|
+
return /[a-zA-Z0-9]*(:\/\/)+[a-zA-Z0-9.]*/.test(value) || /(http){1}[s:/a-zA-Z0-9.]*/.test(value);
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
function isMailto(str) {
|
|
@@ -39,11 +37,11 @@ function isListOfCssProperties(value) {
|
|
|
39
37
|
|
|
40
38
|
function isCssSelector(value) {
|
|
41
39
|
return (
|
|
42
|
-
/^,?\s?[
|
|
43
|
-
/^[a-zA-Z]+[a-zA-Z-]*[
|
|
40
|
+
/^,?\s?[.#*@]\w+.*/.test(value) ||
|
|
41
|
+
/^[a-zA-Z]+[a-zA-Z-]*[.#*]+[a-zA-Z]+[a-zA-Z-]*/.test(value) ||
|
|
44
42
|
/[a-zA-Z][a-zA-Z-]+[a-zA-Z]\.\w/.test(value) ||
|
|
45
43
|
/([a-zA-Z]+[a-zA-Z-]*|\*)\[.*\]/.test(value) ||
|
|
46
|
-
/^[a-zA-Z]+[a-zA-Z-]*[
|
|
44
|
+
/^[a-zA-Z]+[a-zA-Z-]*[#*]$/.test(value) ||
|
|
47
45
|
/^(?:[0-9]+[a-z]|[a-z]+[0-9])[a-z0-9]*\s[a-z0-9][a-z0-9]+-[a-z0-9-]*$/.test(value) ||
|
|
48
46
|
isListOfCssProperties(value) ||
|
|
49
47
|
isListOfHtmlElements(value)
|
|
@@ -104,7 +102,7 @@ function containsAssignment(value) {
|
|
|
104
102
|
}
|
|
105
103
|
|
|
106
104
|
function isSpecial(value) {
|
|
107
|
-
return /^[
|
|
105
|
+
return /^[:%_&#?[$].*[^.]/.test(value) || /.*[*+]+$/.test(value);
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
function isVariableName(value) {
|
package/lib/vue-fragments.js
CHANGED
|
@@ -3,7 +3,7 @@ const vueParser = require('vue-eslint-parser');
|
|
|
3
3
|
const globals = require('globals');
|
|
4
4
|
const unicornPlugin = require('eslint-plugin-unicorn');
|
|
5
5
|
const promisePlugin = require('eslint-plugin-promise');
|
|
6
|
-
const importPlugin = require('eslint-plugin-import');
|
|
6
|
+
const importPlugin = require('eslint-plugin-import-x');
|
|
7
7
|
|
|
8
8
|
const gitlabPlugin = require('./plugin.js');
|
|
9
9
|
|
|
@@ -36,7 +36,7 @@ const presetAndSetup = [
|
|
|
36
36
|
plugins: {
|
|
37
37
|
unicorn: unicornPlugin,
|
|
38
38
|
promise: promisePlugin,
|
|
39
|
-
import: importPlugin,
|
|
39
|
+
'import-x': importPlugin,
|
|
40
40
|
'@gitlab': gitlabPlugin,
|
|
41
41
|
},
|
|
42
42
|
},
|
|
@@ -63,10 +63,9 @@ const gitlabRules = [
|
|
|
63
63
|
'vue/v-slot-style': ['error', { atComponent: 'shorthand' }],
|
|
64
64
|
'@gitlab/vue-no-data-toggle': 'error',
|
|
65
65
|
'@gitlab/vue-no-popover-target-dollar-el': 'warn',
|
|
66
|
-
'
|
|
67
|
-
'@gitlab/vue-slot-name-casing': 'error',
|
|
66
|
+
'vue/slot-name-casing': ['error', 'kebab-case'],
|
|
68
67
|
'@gitlab/no-runtime-template-compiler': 'error',
|
|
69
|
-
'import/order': [
|
|
68
|
+
'import-x/order': [
|
|
70
69
|
'error',
|
|
71
70
|
{
|
|
72
71
|
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
|
@@ -103,7 +102,7 @@ const gitlabRules = [
|
|
|
103
102
|
name: '@gitlab/vue/sfc-overrides',
|
|
104
103
|
files: ['**/*.vue'],
|
|
105
104
|
rules: {
|
|
106
|
-
'import/no-default-export': 'off',
|
|
105
|
+
'import-x/no-default-export': 'off',
|
|
107
106
|
},
|
|
108
107
|
},
|
|
109
108
|
];
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gitlab/eslint-plugin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "24.0.0",
|
|
4
4
|
"description": "GitLab package for our custom eslint rules",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"createRule": "./scripts/createRule.js && yarn update",
|
|
8
8
|
"update": "./scripts/updateFiles.js && prettier --write lib/plugin.js lib/index.js",
|
|
9
9
|
"commit": "npx git-cz",
|
|
10
|
+
"lint": "eslint .",
|
|
10
11
|
"test": "mocha"
|
|
11
12
|
},
|
|
12
13
|
"repository": "https://gitlab.com/gitlab-org/frontend/eslint-plugin.git",
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
"dependencies": {
|
|
33
34
|
"@eslint/js": "^9.0.0",
|
|
34
35
|
"eslint-config-prettier": "^10.0.0",
|
|
35
|
-
"eslint-plugin-import": "^
|
|
36
|
+
"eslint-plugin-import-x": "^4.17.1",
|
|
36
37
|
"eslint-plugin-jest": "^29.0.0",
|
|
37
38
|
"eslint-plugin-promise": "^7.0.0",
|
|
38
39
|
"eslint-plugin-tailwindcss": "^3.18.3",
|
|
@@ -6,8 +6,10 @@ const configsDir = path.join(__dirname, '../../lib/flat-configs');
|
|
|
6
6
|
/*
|
|
7
7
|
lib/flat-configs/ is a closed set: this glob decides what `yarn update`
|
|
8
8
|
publishes as `plugin.configs[<basename>]`, so a shared helper dropped in that
|
|
9
|
-
directory becomes a bogus public config
|
|
10
|
-
|
|
9
|
+
directory becomes a bogus public config, which tests/lib/configs/exports.spec.js
|
|
10
|
+
fails on once `yarn update` has regenerated lib/index.js. That is why
|
|
11
|
+
lib/prettier-rules.js and lib/vue-fragments.js sit at the lib/ root instead;
|
|
12
|
+
put new shared code there.
|
|
11
13
|
|
|
12
14
|
No `.meta` spread, unlike getRules.js: a flat config exports an array.
|
|
13
15
|
*/
|
|
@@ -170,7 +170,6 @@ async function createReleases({ changesets, releases }) {
|
|
|
170
170
|
|
|
171
171
|
if (type) {
|
|
172
172
|
releaseDescriptionObject[type].push(
|
|
173
|
-
// eslint-disable-next-line no-await-in-loop
|
|
174
173
|
await defaultChangelogFunctions.getReleaseLine(changeset, type),
|
|
175
174
|
);
|
|
176
175
|
}
|
|
@@ -181,7 +180,6 @@ async function createReleases({ changesets, releases }) {
|
|
|
181
180
|
.map(([type, lines]) => releaseSection(type, lines))
|
|
182
181
|
.join('\n\n');
|
|
183
182
|
|
|
184
|
-
// eslint-disable-next-line no-await-in-loop
|
|
185
183
|
await createRelease({ tag: `v${release.newVersion}`, description });
|
|
186
184
|
}
|
|
187
185
|
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# @gitlab/vue-prefer-dollar-scopedslots
|
|
2
|
-
|
|
3
|
-
Prefer $scopedSlots over $slots when using Vue 2.x.
|
|
4
|
-
|
|
5
|
-
Scoped slots are more flexible and powerful, ease migration to Vue 3.x, and
|
|
6
|
-
also work around https://github.com/vuejs/vue/issues/11084.
|
|
7
|
-
|
|
8
|
-
This rule should _not_ be used with Vue 3.x, since `$scopedSlots` was
|
|
9
|
-
[removed](https://v3-migration.vuejs.org/breaking-changes/slots-unification.html).
|
|
10
|
-
Instead, use
|
|
11
|
-
[`vue/no-deprecated-dollar-scopedslots-api`](https://eslint.vuejs.org/rules/no-deprecated-dollar-scopedslots-api.html).
|
|
12
|
-
It includes a fixer that will migrate `$scopedSlots` usage _back_ to `$slots`,
|
|
13
|
-
which is trivial since the API for Vue 2.x's `$scopedSlots` is identical to Vue
|
|
14
|
-
3.x's `$slots`.
|
|
15
|
-
|
|
16
|
-
## Rule Details
|
|
17
|
-
|
|
18
|
-
### Examples of **incorrect** code for this rule
|
|
19
|
-
|
|
20
|
-
```html
|
|
21
|
-
<div v-if="$slots.default">
|
|
22
|
-
<slot></slot>
|
|
23
|
-
</div>
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
```javascript
|
|
27
|
-
export default {
|
|
28
|
-
render(h) {
|
|
29
|
-
return this.$slots.foo ? this.$slots.foo : null;
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Examples of **correct** code for this rule
|
|
35
|
-
|
|
36
|
-
```html
|
|
37
|
-
<div v-if="$scopedSlots.default">
|
|
38
|
-
<slot></slot>
|
|
39
|
-
</div>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
```javascript
|
|
43
|
-
export default {
|
|
44
|
-
render(h) {
|
|
45
|
-
return this.$scopedSlots.foo
|
|
46
|
-
? this.$scopedSlots.foo() // Note the function call!
|
|
47
|
-
: null;
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Options
|
|
53
|
-
|
|
54
|
-
Nothing
|
|
55
|
-
|
|
56
|
-
## Related rules
|
|
57
|
-
|
|
58
|
-
- [`vue/no-deprecated-dollar-scopedslots-api`](https://eslint.vuejs.org/rules/no-deprecated-dollar-scopedslots-api.html) (for Vue 3.x)
|
|
59
|
-
|
|
60
|
-
## When Not To Use It
|
|
61
|
-
|
|
62
|
-
When using Vue 3.x.
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# @gitlab/vue-slot-name-casing
|
|
2
|
-
|
|
3
|
-
Ensures that slot names are kebab-cased
|
|
4
|
-
|
|
5
|
-
## Rule Details
|
|
6
|
-
|
|
7
|
-
### Examples of **incorrect** code for this rule
|
|
8
|
-
|
|
9
|
-
```html
|
|
10
|
-
<slot name="filepathPrepend"></slot>
|
|
11
|
-
<slot name="filepathPrepend"></slot>
|
|
12
|
-
<slot name="filepathPrepend"></slot>
|
|
13
|
-
<div>
|
|
14
|
-
<template #filepathPrepend
|
|
15
|
-
>example</template
|
|
16
|
-
>
|
|
17
|
-
</div>
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
### Examples of **correct** code for this rule
|
|
21
|
-
|
|
22
|
-
```html
|
|
23
|
-
<slot name="filepath-prepend"></slot>
|
|
24
|
-
<slot name="filepath-prepend"></slot>
|
|
25
|
-
<slot name="filepath-prepend"></slot>
|
|
26
|
-
<div>
|
|
27
|
-
<template #filepath-prepend
|
|
28
|
-
>example</template
|
|
29
|
-
>
|
|
30
|
-
</div>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Options
|
|
34
|
-
|
|
35
|
-
No options
|
|
36
|
-
|
|
37
|
-
## Related rules
|
|
38
|
-
|
|
39
|
-
- TBA
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
// ------------------------------------------------------------------------------
|
|
2
|
-
// Requirements
|
|
3
|
-
// ------------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
const { DOCS_BASE_URL } = require('../constants');
|
|
6
|
-
const { defineTemplateBodyVisitor } = require('../utils/index');
|
|
7
|
-
const utils = require('eslint-plugin-vue/dist/utils').default;
|
|
8
|
-
|
|
9
|
-
// ------------------------------------------------------------------------------
|
|
10
|
-
// Helpers
|
|
11
|
-
// ------------------------------------------------------------------------------
|
|
12
|
-
|
|
13
|
-
const DOLLAR_SLOTS = '$slots';
|
|
14
|
-
|
|
15
|
-
// ------------------------------------------------------------------------------
|
|
16
|
-
// Rule Definition
|
|
17
|
-
// ------------------------------------------------------------------------------
|
|
18
|
-
|
|
19
|
-
module.exports = {
|
|
20
|
-
meta: {
|
|
21
|
-
type: 'error',
|
|
22
|
-
docs: {
|
|
23
|
-
description: 'Prefer $scopedSlots over $slots for Vue 2.x.',
|
|
24
|
-
category: undefined,
|
|
25
|
-
url: DOCS_BASE_URL + '/vue-prefer-dollar-scopedslots.md',
|
|
26
|
-
},
|
|
27
|
-
messages: {
|
|
28
|
-
preferDollarScopedSlots:
|
|
29
|
-
'Prefer $scopedSlots over $slots for Vue 2.x. Scoped slots are more flexible and powerful, ease migration to Vue 3.x, and also work around https://github.com/vuejs/vue/issues/11084.',
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
create(context) {
|
|
33
|
-
const templateVisitor = {
|
|
34
|
-
VExpressionContainer(node) {
|
|
35
|
-
for (const ref of node.references) {
|
|
36
|
-
if (ref.id.name === DOLLAR_SLOTS) {
|
|
37
|
-
context.report({
|
|
38
|
-
node,
|
|
39
|
-
loc: ref.id.loc,
|
|
40
|
-
messageId: 'preferDollarScopedSlots',
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const scriptVisitor = utils.defineVueVisitor(context, {
|
|
48
|
-
MemberExpression(node) {
|
|
49
|
-
if (node.computed) return;
|
|
50
|
-
|
|
51
|
-
const { property } = node;
|
|
52
|
-
if (property.name === DOLLAR_SLOTS) {
|
|
53
|
-
context.report({
|
|
54
|
-
node: property,
|
|
55
|
-
loc: property.loc,
|
|
56
|
-
messageId: 'preferDollarScopedSlots',
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
return defineTemplateBodyVisitor(context, templateVisitor, scriptVisitor);
|
|
63
|
-
},
|
|
64
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// ------------------------------------------------------------------------------
|
|
4
|
-
// Requirements
|
|
5
|
-
// ------------------------------------------------------------------------------
|
|
6
|
-
|
|
7
|
-
const utils = require('eslint-plugin-vue/dist/utils').default;
|
|
8
|
-
const casing = require('eslint-plugin-vue/dist/utils/casing');
|
|
9
|
-
const { DOCS_BASE_URL } = require('../constants');
|
|
10
|
-
|
|
11
|
-
// ------------------------------------------------------------------------------
|
|
12
|
-
// Rule Definition
|
|
13
|
-
// ------------------------------------------------------------------------------
|
|
14
|
-
|
|
15
|
-
module.exports = {
|
|
16
|
-
meta: {
|
|
17
|
-
type: 'suggestion',
|
|
18
|
-
docs: {
|
|
19
|
-
description: 'enforce specific casing for slot naming style in template',
|
|
20
|
-
category: undefined,
|
|
21
|
-
url: DOCS_BASE_URL + '/vue-slot-name-casing.md',
|
|
22
|
-
},
|
|
23
|
-
schema: [],
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
create(context) {
|
|
27
|
-
const sourceCode = context.getSourceCode();
|
|
28
|
-
const caseType = 'kebab-case';
|
|
29
|
-
|
|
30
|
-
let hasInvalidEOF = false;
|
|
31
|
-
|
|
32
|
-
return utils.defineTemplateBodyVisitor(
|
|
33
|
-
context,
|
|
34
|
-
{
|
|
35
|
-
"VElement[name='slot'] > VStartTag > VAttribute[key.name='name']"(node) {
|
|
36
|
-
if (hasInvalidEOF) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const name = node.value.value;
|
|
41
|
-
const casingName = casing.getConverter(caseType)(name);
|
|
42
|
-
if (casingName !== name) {
|
|
43
|
-
context.report({
|
|
44
|
-
node,
|
|
45
|
-
loc: node.loc,
|
|
46
|
-
message: 'Slot name "{{name}}" is not {{caseType}}.',
|
|
47
|
-
data: {
|
|
48
|
-
name,
|
|
49
|
-
caseType,
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
Object.assign(
|
|
56
|
-
{
|
|
57
|
-
Program(node) {
|
|
58
|
-
hasInvalidEOF = utils.hasInvalidEOF(node);
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
{},
|
|
62
|
-
),
|
|
63
|
-
);
|
|
64
|
-
},
|
|
65
|
-
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* ONE-SHOT generator. Resolves each eslintrc config in lib/configs/ into a
|
|
4
|
-
* flat map of rule -> [severity, ...options] and writes it to
|
|
5
|
-
* tests/fixtures/rule-maps/. Run once, on ESLint 8, BEFORE the flat-config
|
|
6
|
-
* migration. Committed for reviewability; not wired into CI.
|
|
7
|
-
*
|
|
8
|
-
* Its inputs are gone and it no longer runs. Kept only as the provenance of
|
|
9
|
-
* the frozen fixtures; deleted at the end of this stack.
|
|
10
|
-
*/
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const { ESLint } = require('eslint');
|
|
14
|
-
|
|
15
|
-
const CONFIG_DIR = path.join(__dirname, '../lib/configs');
|
|
16
|
-
const OUT_DIR = path.join(__dirname, '../tests/fixtures/rule-maps');
|
|
17
|
-
|
|
18
|
-
// Top level only: lib/configs/base/ holds rule fragments, not configs.
|
|
19
|
-
const CONFIGS = fs
|
|
20
|
-
.readdirSync(CONFIG_DIR)
|
|
21
|
-
.filter((file) => file.endsWith('.js'))
|
|
22
|
-
.map((file) => path.basename(file, '.js'));
|
|
23
|
-
const SAMPLES = ['sample.js', 'sample.vue', 'sample.ts', 'sample.test.ts'];
|
|
24
|
-
|
|
25
|
-
const SEVERITIES = ['off', 'warn', 'error'];
|
|
26
|
-
|
|
27
|
-
/** Normalise [2, opts] / 'error' / ['error', opts] into 'error' or ['error', ...opts]. */
|
|
28
|
-
function normalizeEntry(entry) {
|
|
29
|
-
const value = Array.isArray(entry) ? entry : [entry];
|
|
30
|
-
const [severity, ...options] = value;
|
|
31
|
-
const name = typeof severity === 'number' ? SEVERITIES[severity] : severity;
|
|
32
|
-
return options.length > 0 ? [name, ...options] : name;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function normalizeRules(rules) {
|
|
36
|
-
return Object.fromEntries(
|
|
37
|
-
Object.keys(rules)
|
|
38
|
-
.sort()
|
|
39
|
-
.map((name) => [name, normalizeEntry(rules[name])]),
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function mapForConfig(configName) {
|
|
44
|
-
const configPath = require.resolve(`../lib/configs/${configName}.js`);
|
|
45
|
-
const eslint = new ESLint({
|
|
46
|
-
useEslintrc: false,
|
|
47
|
-
// The plugin cannot resolve itself by name from inside its own repo.
|
|
48
|
-
plugins: { '@gitlab': require('../lib/index.js') },
|
|
49
|
-
baseConfig: { extends: [configPath] },
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const resolved = await Promise.all(
|
|
53
|
-
SAMPLES.map((sample) => eslint.calculateConfigForFile(path.join(process.cwd(), sample))),
|
|
54
|
-
);
|
|
55
|
-
return Object.fromEntries(
|
|
56
|
-
SAMPLES.map((sample, index) => [sample, normalizeRules(resolved[index].rules || {})]),
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function main() {
|
|
61
|
-
fs.mkdirSync(OUT_DIR, { recursive: true });
|
|
62
|
-
for (const name of CONFIGS) {
|
|
63
|
-
// eslint-disable-next-line no-await-in-loop
|
|
64
|
-
const map = await mapForConfig(name);
|
|
65
|
-
const file = path.join(OUT_DIR, `${name}.json`);
|
|
66
|
-
fs.writeFileSync(file, `${JSON.stringify(map, null, 2)}\n`);
|
|
67
|
-
const counts = SAMPLES.map((sample) => `${sample} ${Object.keys(map[sample]).length}`);
|
|
68
|
-
console.log(`Wrote ${path.relative(process.cwd(), file)} (${counts.join(', ')})`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
main().catch((error) => {
|
|
73
|
-
console.error(error);
|
|
74
|
-
process.exit(1);
|
|
75
|
-
});
|