@gitlab/eslint-plugin 21.5.0 → 22.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +217 -0
  2. package/README.md +16 -11
  3. package/docs/development.md +2 -1
  4. package/docs/usage.md +158 -47
  5. package/eslint9/index.js +6 -7
  6. package/lib/configs/base/best-practices.js +0 -4
  7. package/lib/configs/base/es6.js +0 -12
  8. package/lib/configs/base/imports.js +0 -9
  9. package/lib/configs/base/node.js +0 -4
  10. package/lib/confusing-browser-globals.js +68 -0
  11. package/lib/flat-configs/base.js +122 -0
  12. package/lib/flat-configs/default.js +13 -0
  13. package/lib/flat-configs/i18n.js +14 -0
  14. package/lib/flat-configs/jest.js +20 -0
  15. package/lib/flat-configs/tailwind.js +19 -0
  16. package/{eslint9/configs → lib/flat-configs}/typescript.js +47 -62
  17. package/lib/flat-configs/vue.js +16 -0
  18. package/lib/index.js +30 -39
  19. package/lib/plugin.js +32 -0
  20. package/lib/prettier-rules.js +10 -0
  21. package/lib/rules/no-runtime-template-compiler.js +5 -2
  22. package/lib/rules/vue-no-new-non-primitive-in-template.js +1 -1
  23. package/lib/rules/vue-no-undef-apollo-properties.js +1 -1
  24. package/lib/rules/vue-prefer-dollar-scopedslots.js +1 -1
  25. package/lib/rules/vue-require-required-key.js +1 -1
  26. package/lib/rules/vue-slot-name-casing.js +2 -2
  27. package/lib/vue-fragments.js +111 -0
  28. package/package.json +29 -11
  29. package/scripts/generateRuleMapFixtures.js +75 -0
  30. package/scripts/helpers/getConfigs.js +13 -6
  31. package/scripts/updateFiles.js +30 -6
  32. package/eslint9/configs/base.js +0 -140
  33. package/lib/configs/base.js +0 -115
  34. package/lib/configs/default.js +0 -17
  35. package/lib/configs/i18n.js +0 -10
  36. package/lib/configs/jest.js +0 -21
  37. package/lib/configs/tailwind.js +0 -10
  38. package/lib/configs/typescript.js +0 -95
  39. package/lib/configs/vue.js +0 -91
package/CHANGELOG.md CHANGED
@@ -1,5 +1,222 @@
1
1
  # @gitlab/eslint-plugin
2
2
 
3
+ ## 22.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 5c9ebc5: Migrate to ESLint 9 flat config.
8
+
9
+ Every config this package exports is now an array of flat config objects, meant to be spread into
10
+ an `eslint.config.js`. The eslintrc configs have been removed. `docs/usage.md` has the new examples
11
+ and a table mapping each old `extends` entry to its replacement.
12
+
13
+ ```js
14
+ const gitlab = require('@gitlab/eslint-plugin');
15
+
16
+ module.exports = [...gitlab.configs.default];
17
+ ```
18
+
19
+ ## If you use the `typescript` config, read this first
20
+
21
+ **Your `.ts` files were not being parsed as TypeScript before this release, and now they are.**
22
+ `lib/configs/typescript.js` set `parserOptions.parser: '@typescript-eslint/parser'` inside an
23
+ `overrides` block, and eslintrc ignores that key — only a `parser` key selects a parser. The flat
24
+ config sets `languageOptions.parser`, correctly. So `.ts` files are now genuinely parsed as
25
+ TypeScript, the type-aware rules in the config (`@typescript-eslint/no-floating-promises`,
26
+ `@typescript-eslint/return-await`, the `strict` preset) start doing real work for the first time,
27
+ and you should expect a wave of new findings on code that has not changed. Budget for that before
28
+ you upgrade. Nothing in the rule configuration changed to cause it; the rules were always listed,
29
+ they just had nothing to analyse.
30
+
31
+ Relatedly, the `typescript` config could not be installed from a clean install: it needs
32
+ `typescript` and `@typescript-eslint/parser` to load `@typescript-eslint/eslint-plugin`, and neither
33
+ was declared, so it only worked because the README told you to install them yourself. All three are
34
+ now declared optional peer dependencies. Install them in your own project and your package manager
35
+ will resolve them:
36
+
37
+ ```bash
38
+ yarn add --dev typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin
39
+ ```
40
+
41
+ The `overrides` block the README used to ask for is no longer needed and can be deleted.
42
+
43
+ ## Breaking changes
44
+
45
+ ### Config format and surface
46
+
47
+ 1. **The seven eslintrc configs are gone.** Every `extends: ['plugin:@gitlab/*']` in an `.eslintrc`
48
+ stops resolving. Move to `eslint.config.js` and spread the array of the same name:
49
+ `...gitlab.configs.default`, `...gitlab.configs.vue`, and so on.
50
+ 2. **The eight `base` fragments are no longer exported as configs** — `best-practices`, `errors`,
51
+ `es6`, `imports`, `node`, `strict`, `style` and `variables`. This is separate from the point
52
+ above: it hits anyone who extended a fragment directly rather than extending `base`. The files
53
+ are still in the package; only the public config surface shrinks. Use `base`.
54
+ 3. **Config values changed shape.** Each config is now an array of flat config objects, not a single
55
+ eslintrc object. Code that read `configs.base.rules` or merged a config into another object needs
56
+ to work with the array instead.
57
+ 4. **`configs` entries are lazy getters.** This keeps `require('@gitlab/eslint-plugin')` from
58
+ loading the optional TypeScript packages for consumers who do not use them. `Object.keys` and
59
+ `for...in` still list all seven names, but anything that _reads_ every entry at once —
60
+ `{ ...plugin.configs }`, a deep clone, `JSON.stringify` — invokes all seven getters and throws if
61
+ the TypeScript packages are absent. `Object.getOwnPropertyDescriptor(configs, name).value` is now
62
+ `undefined` where it used to be the config. Read configs by name.
63
+ 5. **Deep subpath imports no longer resolve.** The package has no `exports` map, so every path in
64
+ the tarball used to be importable. The files behind those paths were deleted, so
65
+ `@gitlab/eslint-plugin/lib/configs/vue` and `@gitlab/eslint-plugin/eslint9/configs/base` now
66
+ throw `MODULE_NOT_FOUND`. Import from the package root. The `/eslint9` subpath itself still
67
+ resolves.
68
+ 6. **`@gitlab/eslint-plugin/eslint9` is now the full package root**, not
69
+ `{ configs: { base, typescript } }`. It re-exports everything the root does, so existing imports
70
+ keep working, and it is deprecated — switch to `@gitlab/eslint-plugin`. It is scheduled for
71
+ removal in a future major release.
72
+ 7. **`plugin.meta` now exists** (`{ name, version }`). Additive, and it is what makes the plugin
73
+ registerable in a flat config; ESLint uses it for cache keys and error attribution.
74
+
75
+ ### Requirements and dependencies
76
+
77
+ - **`eslint` is now a `^9.0.0` peer dependency.** ESLint 8 is no longer supported.
78
+ - **`engines.node` is now `^20.12.0 || ^22.0.0 || >=24.0.0`.** This drops Node 18 and the
79
+ odd-numbered lines. It is the intersection of every runtime dependency's own `engines`,
80
+ and is set by `eslint-plugin-jest` 29 rather than by ESLint 9, which is more permissive
81
+ (`^18.18.0 || ^20.9.0 || >=21.1.0`).
82
+ - **`@typescript-eslint/eslint-plugin`, `@typescript-eslint/parser` and `typescript` moved from
83
+ dependencies to optional peer dependencies.** Only consumers of the `typescript` config need them,
84
+ and those consumers now control the versions. See the section above.
85
+ - **`eslint-plugin-vue` is bumped to `^10.0.0`.** `vue/component-tags-order` was removed upstream
86
+ and is configured here as `vue/block-order` with the same options. If your project overrides
87
+ `vue/component-tags-order`, rename it: configuring a rule a plugin no longer defines is a hard
88
+ error in flat config, so ESLint refuses to run rather than ignoring it.
89
+ - **`vue-eslint-parser` is bumped to `^10.3.0`, `eslint-plugin-jest` to `^29.0.0`, and
90
+ `eslint-config-prettier` to `^10.0.0`.** Each brings its own upstream preset changes.
91
+ - **`@typescript-eslint/no-throw-literal` is configured as `@typescript-eslint/only-throw-error`**,
92
+ following the rename in `@typescript-eslint` v8.
93
+
94
+ ### ESLint 9 defaults
95
+
96
+ Two core rules report less than they did under ESLint 8:
97
+
98
+ - `no-constant-condition` no longer reports `while (true)`.
99
+ - `no-inner-declarations` no longer reports block-scoped function declarations.
100
+
101
+ `no-fallthrough`, `no-useless-escape` and `no-unused-expressions` gained new options in ESLint 9,
102
+ but their defaults preserve ESLint 8 behaviour, so nothing changes for them unless you opt in.
103
+
104
+ One flat-config default reports **more**. ESLint 9 defaults
105
+ `linterOptions.reportUnusedDisableDirectives` to `warn`, where eslintrc left unused directives
106
+ unreported unless you passed `--report-unused-disable-directives`. Every stale
107
+ `// eslint-disable` comment in your project — including ones made stale by the rule changes listed
108
+ below — now produces a warning. This is ESLint's default and not something this package sets, but
109
+ it is a new source of warnings on unchanged code, and it will fail a build that runs
110
+ `eslint --max-warnings 0`. `eslint --fix` removes the directives; alternatively set
111
+ `linterOptions: { reportUnusedDisableDirectives: 'off' }` in a config object of your own.
112
+
113
+ ### What stops being caught
114
+
115
+ Most of the churn below is substitution: a rule is renamed, split or superseded, and the same code
116
+ is still reported by its replacement. These are the reductions where nothing in this package takes
117
+ over.
118
+
119
+ | No longer reported | Configs | Picked up by |
120
+ | ------------------------------------------------ | ------- | ------------ |
121
+ | `while (true)` | all | nothing |
122
+ | a function declaration inside a block | all | nothing |
123
+ | assigning to a class binding (`no-class-assign`) | `.ts` | `tsc` |
124
+ | `with (obj) {}` (`no-with`) | `.ts` | `tsc` |
125
+ | stray semicolons, mixed spaces and tabs | `.ts` | prettier |
126
+
127
+ The first two are the ESLint 9 default changes described above; they apply to every config. The
128
+ other three are only switched off for TypeScript files, by `@typescript-eslint` v8 and by ESLint 9
129
+ dropping two deprecated formatting rules from `eslint:recommended`.
130
+
131
+ Separately, and in the other direction: `vue/jsx-uses-vars` no longer applies outside `.vue` files.
132
+ It suppresses `no-unused-vars` for identifiers used only in JSX, so if you enable JSX in your own
133
+ config you may see new false `no-unused-vars` reports. Re-enable the rule yourself if so. These
134
+ configs never enabled JSX, so nothing changes unless you did.
135
+
136
+ ### Rules whose severity changes
137
+
138
+ 25 rules change in a severity-visible way: they turn on, turn off, or are replaced by a differently
139
+ named rule. Everything else resolves to the same severity it did before. The causes are the
140
+ dependency majors listed above — none of these are a change of intent by this package.
141
+
142
+ **`vue` and `default` — 5 rules.** These hit the widest audience:
143
+
144
+ - `vue/component-tags-order` (`error`) is **gone**, replaced by `vue/block-order` (`error`) with
145
+ the same `{ order }` option. Rename any override you have; see the note above on why a stale
146
+ override is a hard error rather than a no-op.
147
+ - `vue/no-required-prop-with-default` is **newly on at `warn`**. eslint-plugin-vue v10 added it to
148
+ the recommended presets. It fires on ordinary, unchanged Vue 2 code, and because it is a warning
149
+ rather than an error it will **fail any build running `eslint --max-warnings 0`** while passing a
150
+ plain `eslint` run. If that describes your CI, expect this one to break it. Either fix the props
151
+ it flags or set `'vue/no-required-prop-with-default': 'off'` in your own config.
152
+ - `vue/comment-directive` and `vue/jsx-uses-vars` **no longer apply outside `.vue` files**.
153
+ eslint-plugin-vue v10 scopes both to `**/*.vue`, where v9 declared them for every linted file. No
154
+ coverage is lost: `vue/comment-directive` only ever acts on single-file-component output, and
155
+ `vue/jsx-uses-vars` needs `parserOptions.ecmaFeatures.jsx`, which these configs never enabled.
156
+
157
+ **`typescript`, on `.ts` and `.test.ts` files — 20 rules.** These arrive from ESLint 9's
158
+ `eslint:recommended` and from `@typescript-eslint` v8's `strict` preset, which only this config
159
+ extends. Note that they land on top of the parsing change described at the top of this changeset,
160
+ so a `typescript` consumer should expect new findings from both at once.
161
+
162
+ Newly reporting at `error`:
163
+
164
+ - From ESLint 9's `eslint:recommended`: `no-constant-binary-expression`, `no-empty-static-block`,
165
+ `no-unused-private-class-members`.
166
+ - From `@typescript-eslint` v8 dropping the extension-rule pair, so the core rule takes over:
167
+ `no-loss-of-precision`.
168
+ - From the `ban-types` split: `@typescript-eslint/no-empty-object-type`,
169
+ `@typescript-eslint/no-unsafe-function-type`, `@typescript-eslint/no-wrapper-object-types`.
170
+ - Replacing a dropped or renamed rule: `@typescript-eslint/no-require-imports` (for
171
+ `no-var-requires`), `@typescript-eslint/only-throw-error` (for `no-throw-literal`),
172
+ `@typescript-eslint/no-unused-expressions` (for the core rule).
173
+ - Moved into `recommended`, and so into `strict`, by `@typescript-eslint` v8:
174
+ `@typescript-eslint/prefer-namespace-keyword`.
175
+
176
+ No longer reporting — switched off, or removed from the rule set entirely:
177
+
178
+ - Dropped from `eslint:recommended` in ESLint 9, and already switched off by
179
+ `eslint-config-prettier` earlier in the chain, so they stay off: `no-extra-semi`,
180
+ `no-mixed-spaces-and-tabs`. Both are deprecated formatting rules that prettier enforces anyway.
181
+ - Added to `@typescript-eslint` v8's `eslint-recommended` layer, on the grounds that the TypeScript
182
+ compiler already reports them: `no-class-assign`, `no-with`.
183
+ - Superseded by the TypeScript-aware rule named above: `no-unused-expressions`.
184
+ - Removed from the `@typescript-eslint` v8 rule set or dropped from its `strict` preset:
185
+ `@typescript-eslint/ban-types`, `@typescript-eslint/no-var-requires`,
186
+ `@typescript-eslint/no-loss-of-precision`, `@typescript-eslint/no-throw-literal`.
187
+
188
+ The `base`, `jest`, `i18n` and `tailwind` configs have no severity changes at all.
189
+
190
+ ### `@stylistic` rules are not disabled for you
191
+
192
+ `eslint-config-prettier` v10 added 180 `@stylistic/*` entries to the formatting rules it switches
193
+ off. This package strips them before shipping, because it does not register the `@stylistic`
194
+ plugin and configuring a rule for an unregistered plugin is a hard error in flat config. So if you
195
+ register `@stylistic` yourself, **you do not get prettier's `@stylistic` disables from this
196
+ package** and its formatting rules may conflict with prettier. Apply `eslint-config-prettier` in
197
+ your own config, after the GitLab configs, to switch them off.
198
+
199
+ ## What has not changed
200
+
201
+ **The Vue rules still target Vue 2.** `eslint-plugin-vue` v9's `configs.recommended` resolved to the
202
+ Vue 2 preset, and this release deliberately maps it to v10's `flat/vue2-recommended` rather than
203
+ v10's `flat/recommended`, which is Vue 3. Retargeting would have added 33 rules and removed 6, which
204
+ is a product decision rather than something to fold into a config-format migration. Vue rule
205
+ coverage is unchanged in this release; a deliberate Vue 3 retarget is planned for a later one.
206
+
207
+ **No rule set was changed on purpose.** The migration is gated on frozen rule-map fixtures captured
208
+ from the eslintrc configs before any of this work started, and every difference between those
209
+ fixtures and what the flat configs resolve to is recorded and justified in the repository. The 25
210
+ rules listed under "Rules whose severity changes" above are the complete set of severity-visible
211
+ differences; the rest are ESLint 9 rendering the same configured options differently, which changes
212
+ no behaviour.
213
+
214
+ ## New
215
+
216
+ - Flat configs for all seven config names: `base`, `default`, `vue`, `jest`, `i18n`, `tailwind` and
217
+ `typescript`. Previously only `base` and `typescript` had flat equivalents, under
218
+ `@gitlab/eslint-plugin/eslint9`.
219
+
3
220
  ## 21.5.0
4
221
 
5
222
  ### Minor Changes
package/README.md CHANGED
@@ -21,22 +21,27 @@ upstream later.
21
21
  - [Installation and Usage](./docs/usage.md)
22
22
  - [Creation & Development of rules](./docs/development.md)
23
23
 
24
- ## Eslint 9 migration
24
+ ## Requirements
25
25
 
26
- The TS portion of this plugin has been migrated to eslint v9 and can be used as `const gitlabPlugin = require('@gitlab/eslint-plugin/eslint9');`. You still add the `@gitlab/eslint-plugin` as a dependency.
26
+ - ESLint 9 (`^9.0.0`), configured with [flat config](https://eslint.org/docs/latest/use/configure/configuration-files) (`eslint.config.js`)
27
+ - Node.js `^18.18.0 || ^20.9.0 || >=21.1.0`
27
28
 
28
- Add these overrides to your project's package.json:
29
+ Every config this package exports is a flat config array:
29
30
 
30
- ```json
31
- "overrides": {
32
- "@gitlab/eslint-plugin": {
33
- "@typescript-eslint/eslint-plugin": "^8.38.0",
34
- "@typescript-eslint/parser": "^8.38.0"
35
- }
36
- }
31
+ ```js
32
+ const gitlab = require('@gitlab/eslint-plugin');
33
+
34
+ module.exports = [...gitlab.configs.default];
37
35
  ```
38
36
 
39
- (replace the versions with what your main project uses)
37
+ The eslintrc configs (`extends: ['plugin:@gitlab/default']`) were removed in this major release.
38
+ See [Installation and Usage](./docs/usage.md#migrating-from-the-eslintrc-configs) for the
39
+ migration.
40
+
41
+ Using the `typescript` config additionally requires `@typescript-eslint/parser`,
42
+ `@typescript-eslint/eslint-plugin` and `typescript` in your own project. They are optional peer
43
+ dependencies, so your project controls their versions — the `overrides` workaround this README used
44
+ to document is no longer needed.
40
45
 
41
46
  ## Contribution guidelines
42
47
 
@@ -8,7 +8,8 @@ Always `yarn install` before doing things.
8
8
  a [lefthook](https://github.com/Arkweid/lefthook) `pre-commit` hook.
9
9
  2. This project adheres to semantic commits,
10
10
  use a tool like [git-cz](https://www.npmjs.com/package/git-cz) to write commit messages
11
- 3. There is a script `yarn update` which updates `docs/rules.md` and `lib/index.js`,
11
+ 3. There is a script `yarn update` which regenerates `lib/plugin.js` (the rule map),
12
+ `lib/index.js` (the config getters) and `docs/rules.md` (the rule index),
12
13
  please run it after creating or updating rules.
13
14
 
14
15
  ## Creating rules
package/docs/usage.md CHANGED
@@ -1,9 +1,10 @@
1
1
  ## Installation
2
2
 
3
- You'll first need to install [ESLint](http://eslint.org):
3
+ You'll first need to install [ESLint](http://eslint.org) 9. The peer dependency is `^9.0.0`:
4
+ ESLint 8 and below are not supported, and ESLint 10 is not supported either.
4
5
 
5
6
  ```bash
6
- yarn add --dev eslint
7
+ yarn add --dev eslint@^9.0.0
7
8
  ```
8
9
 
9
10
  Next, install `@gitlab/eslint-plugin`:
@@ -16,80 +17,190 @@ yarn add --dev @gitlab/eslint-plugin
16
17
 
17
18
  ## Usage (configs)
18
19
 
19
- ### `plugin:@gitlab/default`
20
+ All configs are [flat configs](https://eslint.org/docs/latest/use/configure/configuration-files),
21
+ so they belong in an `eslint.config.js` (or `.mjs`/`.cjs`) file. Each one is an **array** of flat
22
+ config objects, which you spread into your own array:
20
23
 
21
- Add `plugin:@gitlab/default` to the extends section of your `.eslintrc` configuration file.
22
- This config is for our common javascript and Vue rules.
24
+ ```js
25
+ const gitlab = require('@gitlab/eslint-plugin');
23
26
 
24
- ```yaml
25
- extends:
26
- - 'plugin:@gitlab/default'
27
+ module.exports = [...gitlab.configs.default];
27
28
  ```
28
29
 
29
- `plugin:@gitlab/default` uses the `espree` parser, shipped with `eslint` under the hood.
30
+ ESM works the same way:
30
31
 
31
- The configured JS version is `latest`, so eslint should be able to parse even the newest JS syntax.
32
- You can adjust this behavior as [described here][ecma-version]. For example:
32
+ ```js
33
+ import gitlab from '@gitlab/eslint-plugin';
33
34
 
34
- ```yaml
35
- parserOptions:
36
- ecmaVersion: 2020
35
+ export default [...gitlab.configs.default];
37
36
  ```
38
37
 
39
- That being said, when it comes to globals, we still assume a `ES2015` environment, which brought us `Set`, `Map`.
40
- If you need newer globals, you can define newer env as [described here][globals]. For example:
38
+ ### Available configs
41
39
 
42
- ```yaml
43
- env:
44
- es2022: true
40
+ | Config | Contents |
41
+ | ------------ | ---------------------------------------------------------------------------------------------------------------------- |
42
+ | `default` | The GitLab JavaScript and Vue rules together. What most projects want. |
43
+ | `base` | GitLab JavaScript style guide rules only, with no Vue rules. |
44
+ | `vue` | GitLab Vue style guide rules on top of `eslint-plugin-vue`'s recommended set. Vue rules only — combine it with `base`. |
45
+ | `typescript` | `base` plus the TypeScript layer. Requires extra dependencies, see [TypeScript](#typescript). |
46
+ | `jest` | Jest rules, on top of `eslint-plugin-jest`'s recommended set. Requires `jest` in your project. |
47
+ | `i18n` | i18n linting for the GitLab project. |
48
+ | `tailwind` | Tailwind utility-class rules. |
49
+
50
+ `default` is not simply `base` followed by `vue`: the two configs place
51
+ [`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier) differently relative
52
+ to the Vue preset, which is deliberate and matches what these configs have always resolved to. Use
53
+ `default` if you want both; use `base` and `vue` separately only if you need to interleave something
54
+ between them.
55
+
56
+ ### Composing configs
57
+
58
+ Because every config is an array, you can spread several of them:
59
+
60
+ ```js
61
+ const gitlab = require('@gitlab/eslint-plugin');
62
+
63
+ module.exports = [...gitlab.configs.default, ...gitlab.configs.i18n];
64
+ ```
65
+
66
+ The configs are not restricted to particular files, so they apply to everything ESLint lints. To
67
+ scope one to a subset of your project, add a `files` pattern to each of its entries:
68
+
69
+ ```js
70
+ const gitlab = require('@gitlab/eslint-plugin');
71
+
72
+ module.exports = [
73
+ ...gitlab.configs.default,
74
+ ...gitlab.configs.jest.map((config) => ({ ...config, files: ['**/*.spec.js'] })),
75
+ ];
76
+ ```
77
+
78
+ **Do not do this to `vue`, `default` or `typescript`.** Those three already set `files` on some of
79
+ their entries, and `{ ...config, files: [...] }` overwrites that key rather than narrowing it. On
80
+ `vue` and `default` you would drop the scope from the two `**/*.vue` entries, so Vue
81
+ single-file-component rules would start applying to plain `.js` files. On `typescript` you would
82
+ drop the scope from its `**/*.ts` and `**/*.test.ts` entries, so the TypeScript parser and the
83
+ type-aware rules would be applied to every file the pattern matches — including `.spec.js`, which
84
+ they cannot parse. Scope those configs by narrowing the patterns they
85
+ already declare, or by adding your own config object after them, not by replacing `files` wholesale.
86
+ `jest`, `i18n`, `tailwind` and `base` declare no `files` key and are safe to map this way.
87
+
88
+ ### Parsers and language options
89
+
90
+ `base` and `default` use `espree`, shipped with `eslint`, at `ecmaVersion: 'latest'`, so even the
91
+ newest JavaScript syntax parses. `vue` (and therefore `default`) uses
92
+ [`vue-eslint-parser`](https://github.com/vuejs/vue-eslint-parser) with `espree` for `<script>`
93
+ blocks.
94
+
95
+ To change a language option, add a config object of your own after the GitLab configs — later
96
+ entries win:
97
+
98
+ ```js
99
+ const gitlab = require('@gitlab/eslint-plugin');
100
+
101
+ module.exports = [
102
+ ...gitlab.configs.default,
103
+ {
104
+ languageOptions: {
105
+ ecmaVersion: 2020,
106
+ globals: {
107
+ gon: 'readonly',
108
+ },
109
+ },
110
+ },
111
+ ];
45
112
  ```
46
113
 
47
- If you want to completely swap out the parser (e.g. using a typescript or babel parser), please follow
48
- the [`eslint` docs][eslint-parser-config] if you only lint JS files,
49
- and the [`vue-eslint-parser` docs][vue-eslint-parser-config] if you lint VUE files as well.
114
+ See the ESLint docs on [language options][language-options] and
115
+ [configuring a parser][eslint-parser-config] for the full set of keys.
50
116
 
51
- [ecma-version]: https://eslint.org/docs/latest/use/configure/language-options#specifying-parser-options
52
- [globals]: https://eslint.org/docs/latest/use/configure/language-options#specifying-environments
117
+ [language-options]: https://eslint.org/docs/latest/use/configure/language-options
53
118
  [eslint-parser-config]: https://eslint.org/docs/latest/use/configure/parser
54
- [vue-eslint-parser-config]: https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser
55
119
 
56
- ### `plugin:@gitlab/i18n`
120
+ ### TypeScript
57
121
 
58
- Add `plugin:@gitlab/i18n` to the extends section of your `.eslintrc` configuration file.
59
- This config is for i18n linting on the GitLab project.
122
+ The `typescript` config needs `@typescript-eslint/parser`, `@typescript-eslint/eslint-plugin` and
123
+ `typescript` in your own project. They are optional peer dependencies of this package, so your
124
+ project controls their versions:
60
125
 
61
- ```yaml
62
- extends:
63
- - 'plugin:@gitlab/i18n'
126
+ ```bash
127
+ yarn add --dev typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin
64
128
  ```
65
129
 
66
- ### `plugin:@gitlab/jest`
130
+ ```js
131
+ const gitlab = require('@gitlab/eslint-plugin');
67
132
 
68
- Add `plugin:@gitlab/jest` to the extends section of your `.eslintrc` configuration file.
69
- This config is for Jest rules.
133
+ module.exports = [...gitlab.configs.typescript];
134
+ ```
70
135
 
71
- ```yaml
72
- extends:
73
- - 'plugin:@gitlab/jest'
136
+ The `**/*.ts` layer is type-aware: it sets `parserOptions.project` to `./tsconfig.json`, so a
137
+ `tsconfig.json` must exist at the directory ESLint runs from and must include the files you lint.
138
+ If your `tsconfig.json` lives elsewhere, override it after spreading the config:
139
+
140
+ ```js
141
+ const gitlab = require('@gitlab/eslint-plugin');
142
+
143
+ module.exports = [
144
+ ...gitlab.configs.typescript,
145
+ {
146
+ files: ['**/*.ts'],
147
+ languageOptions: {
148
+ parserOptions: { project: ['./config/tsconfig.eslint.json'] },
149
+ },
150
+ },
151
+ ];
74
152
  ```
75
153
 
154
+ Requiring `@gitlab/eslint-plugin` does **not** load the TypeScript packages unless you actually read
155
+ `configs.typescript`; each config is exposed through a getter. One consequence: spreading the whole
156
+ `configs` object (`{ ...gitlab.configs }`), deep-cloning it or passing it to `JSON.stringify` reads
157
+ every config at once and throws if the TypeScript packages are not installed. Read the configs you
158
+ need by name instead.
159
+
76
160
  ## Usage (rules)
77
161
 
78
- Add `@gitlab` to the plugins section of your `.eslintrc` configuration file:
162
+ To use individual rules without one of the configs, register the plugin yourself and enable the
163
+ rules you want:
164
+
165
+ ```js
166
+ const gitlab = require('@gitlab/eslint-plugin');
79
167
 
80
- ```yaml
81
- plugins:
82
- - @gitlab
168
+ module.exports = [
169
+ {
170
+ plugins: { '@gitlab': gitlab },
171
+ rules: {
172
+ '@gitlab/require-i18n-strings': 'error',
173
+ },
174
+ },
175
+ ];
83
176
  ```
84
177
 
85
- Then configure the rules you want to use under the rules section, for example:
178
+ See [Available rules](./rules.md) for the full list.
86
179
 
87
- YAML:
180
+ ## Migrating from the eslintrc configs
88
181
 
89
- ```yaml
90
- rules:
91
- '@gitlab/vue-require-i18n-attribute-strings': error
92
- ```
182
+ Up to and including v21, this package shipped eslintrc configs used through `extends`. Those are
183
+ gone. The replacement is a spread of the same-named config:
184
+
185
+ | Before (`.eslintrc.yml`) | After (`eslint.config.js`) |
186
+ | ---------------------------------------- | ------------------------------ |
187
+ | `extends: ['plugin:@gitlab/default']` | `...gitlab.configs.default` |
188
+ | `extends: ['plugin:@gitlab/base']` | `...gitlab.configs.base` |
189
+ | `extends: ['plugin:@gitlab/vue']` | `...gitlab.configs.vue` |
190
+ | `extends: ['plugin:@gitlab/typescript']` | `...gitlab.configs.typescript` |
191
+ | `extends: ['plugin:@gitlab/jest']` | `...gitlab.configs.jest` |
192
+ | `extends: ['plugin:@gitlab/i18n']` | `...gitlab.configs.i18n` |
193
+ | `extends: ['plugin:@gitlab/tailwind']` | `...gitlab.configs.tailwind` |
194
+
195
+ The eight fragments that `base` is assembled from — `plugin:@gitlab/best-practices`,
196
+ `plugin:@gitlab/errors`, `plugin:@gitlab/es6`, `plugin:@gitlab/imports`, `plugin:@gitlab/node`,
197
+ `plugin:@gitlab/strict`, `plugin:@gitlab/style` and `plugin:@gitlab/variables` — were also exported
198
+ as configs. They are no longer part of the public surface; extend `base` instead.
199
+
200
+ ESLint's own [configuration migration guide][eslint-migration] covers the rest of the move, and
201
+ `npx @eslint/migrate-config .eslintrc` can convert the parts of your config that are not GitLab's.
202
+
203
+ [eslint-migration]: https://eslint.org/docs/latest/use/configure/migration-guide
93
204
 
94
205
  ## VueJS (.vue files)
95
206
 
package/eslint9/index.js CHANGED
@@ -1,9 +1,8 @@
1
1
  /**
2
- * This file is GENERATED, please run `yarn update` after adding or renaming a rule
2
+ * @deprecated Use the package root instead:
3
+ * const gitlab = require('@gitlab/eslint-plugin');
4
+ *
5
+ * Kept so existing `@gitlab/eslint-plugin/eslint9` imports keep resolving.
6
+ * Scheduled for removal in the ESLint 10 major.
3
7
  */
4
- module.exports = {
5
- configs: {
6
- base: require('./configs/base.js'),
7
- typescript: require('./configs/typescript.js'),
8
- },
9
- };
8
+ module.exports = require('../lib/index.js');
@@ -1,8 +1,4 @@
1
1
  module.exports = {
2
- parserOptions: {
3
- ecmaVersion: 2018,
4
- sourceType: 'module',
5
- },
6
2
  rules: {
7
3
  // enforces getter/setter pairs in objects
8
4
  // https://eslint.org/docs/rules/accessor-pairs
@@ -1,16 +1,4 @@
1
1
  module.exports = {
2
- env: {
3
- es6: true,
4
- },
5
- parserOptions: {
6
- ecmaVersion: 6,
7
- sourceType: 'module',
8
- ecmaFeatures: {
9
- generators: false,
10
- objectLiteralDuplicateProperties: false,
11
- },
12
- },
13
-
14
2
  rules: {
15
3
  // enforces no braces where they can be omitted
16
4
  // https://eslint.org/docs/rules/arrow-body-style
@@ -1,13 +1,4 @@
1
1
  module.exports = {
2
- env: {
3
- es6: true,
4
- },
5
- parserOptions: {
6
- ecmaVersion: 6,
7
- sourceType: 'module',
8
- },
9
- plugins: ['import'],
10
-
11
2
  settings: {
12
3
  'import/resolver': {
13
4
  node: {
@@ -1,8 +1,4 @@
1
1
  module.exports = {
2
- env: {
3
- node: true,
4
- },
5
-
6
2
  rules: {
7
3
  // enforce return after a callback
8
4
  'callback-return': 'off',
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Inlined from the `confusing-browser-globals` package.
3
+ * Copyright (c) 2015-present, Facebook, Inc.
4
+ * Licensed under the MIT License.
5
+ * See: https://www.npmjs.com/package/confusing-browser-globals
6
+ */
7
+ const confusingBrowserGlobals = [
8
+ 'addEventListener',
9
+ 'blur',
10
+ 'close',
11
+ 'closed',
12
+ 'confirm',
13
+ 'defaultStatus',
14
+ 'defaultstatus',
15
+ 'event',
16
+ 'external',
17
+ 'find',
18
+ 'focus',
19
+ 'frameElement',
20
+ 'frames',
21
+ 'history',
22
+ 'innerHeight',
23
+ 'innerWidth',
24
+ 'length',
25
+ 'location',
26
+ 'locationbar',
27
+ 'menubar',
28
+ 'moveBy',
29
+ 'moveTo',
30
+ 'name',
31
+ 'onblur',
32
+ 'onerror',
33
+ 'onfocus',
34
+ 'onload',
35
+ 'onresize',
36
+ 'onunload',
37
+ 'open',
38
+ 'opener',
39
+ 'opera',
40
+ 'outerHeight',
41
+ 'outerWidth',
42
+ 'pageXOffset',
43
+ 'pageYOffset',
44
+ 'parent',
45
+ 'print',
46
+ 'removeEventListener',
47
+ 'resizeBy',
48
+ 'resizeTo',
49
+ 'screen',
50
+ 'screenLeft',
51
+ 'screenTop',
52
+ 'screenX',
53
+ 'screenY',
54
+ 'scroll',
55
+ 'scrollbars',
56
+ 'scrollBy',
57
+ 'scrollTo',
58
+ 'scrollX',
59
+ 'scrollY',
60
+ 'self',
61
+ 'status',
62
+ 'statusbar',
63
+ 'stop',
64
+ 'toolbar',
65
+ 'top',
66
+ ];
67
+
68
+ module.exports = confusingBrowserGlobals;