@allthings/eslint-config 3.7.0 → 3.7.1-alpha.1

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 (5) hide show
  1. package/README.md +2 -2
  2. package/base.js +309 -0
  3. package/index.js +25 -302
  4. package/node.js +19 -300
  5. package/package.json +3 -2
package/README.md CHANGED
@@ -57,7 +57,7 @@ Run `yarn link @allthings/eslint-config` in the project that you want to test it
57
57
  After you finish run in your project `yarn unlink @allthings/eslint-config` and then `yarn install --force`
58
58
  to restore the initial state of dependencies
59
59
 
60
- Or you could release a dev npm version with `yarn deploy:dev`. Remember to update the version in package.json
60
+ If `yarn link` isn't enough and you need a real published artifact, see [Development release](#development-release) below.
61
61
 
62
62
  ### Testing the config
63
63
 
@@ -95,7 +95,7 @@ See semantic-releases [docs](https://github.com/semantic-release/semantic-releas
95
95
  git push --force origin HEAD:beta # or alpha / next
96
96
  ```
97
97
 
98
- The pipeline will automatically run `semantic-release`, which detects the branch name, bumps the version with the appropriate pre-release tag, and publishes it to npm under the matching dist-tag. Check [Actions page](https://github.com/allthings/eslint-config/actions) for the release logs.
98
+ The pipeline will automatically run `semantic-release`, which detects the branch name, bumps the version with the appropriate pre-release tag, and publishes it to npm under the matching dist-tag. Check [Actions page](https://github.com/allthings/eslint-config-allthings/actions) for the release logs.
99
99
 
100
100
  3. **Install the pre-release** in another project:
101
101
 
package/base.js ADDED
@@ -0,0 +1,309 @@
1
+ import stylisticPlugin from '@stylistic/eslint-plugin'
2
+ import jestPlugin from 'eslint-plugin-jest'
3
+ import perfectionistPlugin from 'eslint-plugin-perfectionist'
4
+ import preferArrowPlugin from 'eslint-plugin-prefer-arrow'
5
+ import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort'
6
+ import globals from 'globals'
7
+
8
+ export const baseGlobals = {
9
+ ...globals.node,
10
+ ...jestPlugin.environments.globals.globals,
11
+ }
12
+
13
+ export const baseParserOptions = {
14
+ ecmaVersion: 2021,
15
+ project: 'tsconfig.json',
16
+ sourceType: 'module',
17
+ warnOnUnsupportedTypeScriptVersion: false,
18
+ }
19
+
20
+ export const baseSettings = {
21
+ 'import/parsers': {
22
+ '@typescript-eslint/parser': ['.ts', '.mts', '.cts', '.tsx', '.d.ts'],
23
+ },
24
+ 'import/resolver': {
25
+ node: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
26
+ typescript: { alwaysTryTypes: true },
27
+ },
28
+ }
29
+
30
+ export const basePlugins = {
31
+ '@stylistic': stylisticPlugin,
32
+ jest: jestPlugin,
33
+ perfectionist: perfectionistPlugin,
34
+ 'prefer-arrow': preferArrowPlugin,
35
+ 'simple-import-sort': simpleImportSortPlugin,
36
+ }
37
+
38
+ export const baseRules = {
39
+ '@stylistic/padding-line-between-statements': [
40
+ 'error',
41
+ {
42
+ blankLine: 'always',
43
+ next: 'return',
44
+ prev: '*',
45
+ },
46
+ ],
47
+ '@stylistic/spaced-comment': [
48
+ 'error',
49
+ 'always',
50
+ {
51
+ markers: ['/'],
52
+ },
53
+ ],
54
+ '@typescript-eslint/adjacent-overload-signatures': 'error',
55
+ '@typescript-eslint/array-type': [
56
+ 'error',
57
+ {
58
+ default: 'array',
59
+ },
60
+ ],
61
+ '@typescript-eslint/consistent-type-assertions': 'error',
62
+ '@typescript-eslint/consistent-type-definitions': 'off',
63
+ '@typescript-eslint/explicit-function-return-type': 'off',
64
+ '@typescript-eslint/explicit-module-boundary-types': [
65
+ 'warn', // TODO: strict later
66
+ {
67
+ allowArgumentsExplicitlyTypedAsAny: true,
68
+ allowDirectConstAssertionInArrowFunctions: true,
69
+ allowHigherOrderFunctions: false,
70
+ allowTypedFunctionExpressions: false,
71
+ },
72
+ ],
73
+ '@typescript-eslint/naming-convention': [
74
+ 'error',
75
+ {
76
+ custom: {
77
+ match: true,
78
+ regex: '^I[A-Z]',
79
+ },
80
+ format: ['PascalCase'],
81
+ selector: 'interface',
82
+ },
83
+ ],
84
+ '@typescript-eslint/no-base-to-string': 'warn',
85
+ '@typescript-eslint/no-dynamic-delete': 'error',
86
+ // need for tests' mockups
87
+ '@typescript-eslint/no-empty-function': 'warn',
88
+ '@typescript-eslint/no-empty-object-type': 'error',
89
+ '@typescript-eslint/no-explicit-any': 'warn',
90
+ // turn on later
91
+ '@typescript-eslint/no-floating-promises': 'warn',
92
+ '@typescript-eslint/no-for-in-array': 'error',
93
+ '@typescript-eslint/no-inferrable-types': 'error',
94
+ '@typescript-eslint/no-misused-new': 'error',
95
+ '@typescript-eslint/no-namespace': 'error',
96
+ '@typescript-eslint/no-redundant-type-constituents': 'warn',
97
+ '@typescript-eslint/no-require-imports': 'error',
98
+ '@typescript-eslint/no-shadow': [
99
+ 'error',
100
+ {
101
+ hoist: 'all',
102
+ },
103
+ ],
104
+ '@typescript-eslint/no-this-alias': 'error',
105
+ '@typescript-eslint/no-unsafe-argument': 'warn',
106
+ '@typescript-eslint/no-unsafe-assignment': 'warn',
107
+ '@typescript-eslint/no-unsafe-call': 'warn',
108
+ '@typescript-eslint/no-unsafe-enum-comparison': 'off',
109
+ '@typescript-eslint/no-unsafe-member-access': 'off',
110
+ '@typescript-eslint/no-unsafe-return': 'warn',
111
+ '@typescript-eslint/no-unused-expressions': 'error',
112
+ '@typescript-eslint/no-use-before-define': 'error',
113
+ '@typescript-eslint/prefer-for-of': 'error',
114
+ '@typescript-eslint/prefer-function-type': 'error',
115
+ '@typescript-eslint/prefer-namespace-keyword': 'error',
116
+ '@typescript-eslint/prefer-nullish-coalescing': 'off',
117
+ '@typescript-eslint/prefer-promise-reject-errors': 'warn',
118
+ '@typescript-eslint/restrict-template-expressions': 'warn',
119
+ '@typescript-eslint/triple-slash-reference': [
120
+ 'error',
121
+ {
122
+ lib: 'always',
123
+ path: 'always',
124
+ types: 'prefer-import',
125
+ },
126
+ ],
127
+ '@typescript-eslint/unified-signatures': 'error',
128
+ 'arrow-body-style': ['error', 'as-needed'],
129
+ complexity: [
130
+ 'error',
131
+ {
132
+ max: 15,
133
+ },
134
+ ],
135
+ 'constructor-super': 'error',
136
+ eqeqeq: ['error', 'smart'],
137
+ 'guard-for-in': 'error',
138
+ 'id-denylist': [
139
+ 'error',
140
+ 'any',
141
+ 'Number',
142
+ 'number',
143
+ 'String',
144
+ 'string',
145
+ 'Boolean',
146
+ 'boolean',
147
+ 'Undefined',
148
+ 'undefined',
149
+ ],
150
+ 'id-match': 'error',
151
+ 'import/no-anonymous-default-export': [
152
+ 'error',
153
+ {
154
+ allowAnonymousClass: false,
155
+ allowAnonymousFunction: false,
156
+ allowArray: false,
157
+ allowArrowFunction: true,
158
+ allowCallExpression: true,
159
+ // The true value here is for backward compatibility
160
+ allowLiteral: false,
161
+ allowObject: true,
162
+ },
163
+ ],
164
+ 'import/no-extraneous-dependencies': [
165
+ 'error',
166
+ {
167
+ devDependencies: true,
168
+ },
169
+ ],
170
+ 'jest/no-disabled-tests': 'warn',
171
+ 'jest/no-focused-tests': 'error',
172
+ 'jest/no-identical-title': 'error',
173
+ 'jest/valid-expect': 'error',
174
+ 'max-classes-per-file': ['error', 1],
175
+ 'no-bitwise': 'error',
176
+ 'no-caller': 'error',
177
+ 'no-cond-assign': 'error',
178
+ 'no-console': 'error',
179
+ 'no-debugger': 'error',
180
+ 'no-duplicate-case': 'error',
181
+ 'no-duplicate-imports': 'error',
182
+ 'no-empty': 'error',
183
+ 'no-eval': 'error',
184
+ 'no-extra-bind': 'error',
185
+ 'no-multiple-empty-lines': 'error',
186
+ 'no-new-func': 'error',
187
+ 'no-new-wrappers': 'error',
188
+ 'no-param-reassign': 'error',
189
+ 'no-redeclare': 'error',
190
+ 'no-sequences': 'error',
191
+ 'no-sparse-arrays': 'error',
192
+ 'no-template-curly-in-string': 'error',
193
+ 'no-throw-literal': 'error',
194
+ 'no-trailing-spaces': 'error',
195
+ 'no-undef-init': 'error',
196
+ 'no-unsafe-finally': 'error',
197
+ 'no-unused-labels': 'error',
198
+ 'no-var': 'error',
199
+ 'object-shorthand': 'error',
200
+ 'one-var': ['error', 'never'],
201
+ // perfectionist — replaces eslint-plugin-typescript-sort-keys
202
+ // (string-enum equivalent: sort-enums with default sortByValue: 'ifNumericEnum')
203
+ 'perfectionist/sort-enums': 'error',
204
+ 'perfectionist/sort-heritage-clauses': 'error',
205
+ 'perfectionist/sort-interfaces': 'error',
206
+ 'perfectionist/sort-object-types': 'error',
207
+ 'prefer-arrow/prefer-arrow-functions': 'warn',
208
+ 'prefer-const': 'error',
209
+ 'prefer-object-spread': 'error',
210
+ 'prefer-template': 'error',
211
+ radix: 'error',
212
+ 'simple-import-sort/exports': 'error',
213
+ 'simple-import-sort/imports': 'error',
214
+ 'sort-keys': 'error',
215
+ 'unicorn/better-regex': 'off',
216
+ 'unicorn/consistent-existence-index-check': 'off',
217
+ 'unicorn/expiring-todo-comments': 'off',
218
+ 'unicorn/filename-case': [
219
+ 'warn',
220
+ {
221
+ cases: {
222
+ camelCase: true,
223
+ pascalCase: true,
224
+ },
225
+ },
226
+ ],
227
+ 'unicorn/import-style': 'warn',
228
+ 'unicorn/no-anonymous-default-export': 'off',
229
+ 'unicorn/no-array-reduce': 'off',
230
+ // .reverse() mutates in place — semantic + perf cost to force .toReversed()
231
+ 'unicorn/no-array-reverse': 'off',
232
+ // .sort() mutates in place — same story as no-array-reverse
233
+ 'unicorn/no-array-sort': 'off',
234
+ 'unicorn/no-await-expression-member': 'warn',
235
+ 'unicorn/no-console-spaces': 'off',
236
+ 'unicorn/no-document-cookie': 'warn',
237
+ 'unicorn/no-empty-file': 'off',
238
+ 'unicorn/no-hex-escape': 'warn',
239
+ 'unicorn/no-invalid-remove-event-listener': 'warn',
240
+ 'unicorn/no-named-default': 'warn',
241
+ 'unicorn/no-nested-ternary': 'off',
242
+ // because we have a lot of logic depends on null
243
+ 'unicorn/no-null': 'warn',
244
+ 'unicorn/no-object-as-default-parameter': 'warn',
245
+ 'unicorn/no-single-promise-in-promise-methods': 'warn',
246
+ 'unicorn/no-unreadable-array-destructuring': 'off',
247
+ 'unicorn/no-unused-properties': 'warn',
248
+ 'unicorn/no-zero-fractions': 'off',
249
+ 'unicorn/prefer-class-fields': 'warn',
250
+ 'unicorn/prefer-export-from': 'off',
251
+ 'unicorn/prefer-global-this': 'warn',
252
+ 'unicorn/prefer-includes': 'off',
253
+ 'unicorn/prefer-math-min-max': 'warn',
254
+ 'unicorn/prefer-module': 'warn',
255
+ 'unicorn/prefer-node-protocol': 'off',
256
+ 'unicorn/prefer-optional-catch-binding': 'off',
257
+ 'unicorn/prefer-prototype-methods': 'off',
258
+ 'unicorn/prefer-query-selector': 'off',
259
+ 'unicorn/prefer-regexp-test': 'off',
260
+ 'unicorn/prefer-set-has': 'off',
261
+ 'unicorn/prefer-set-size': 'off',
262
+ // opinionated condition ordering — too noisy
263
+ 'unicorn/prefer-simple-condition-first': 'off',
264
+ 'unicorn/prefer-string-raw': 'off',
265
+ 'unicorn/prefer-string-replace-all': 'off',
266
+ 'unicorn/prefer-structured-clone': 'warn',
267
+ 'unicorn/prevent-abbreviations': [
268
+ 'error',
269
+ {
270
+ allowList: {
271
+ params: true,
272
+ props: true,
273
+ utils: true,
274
+ },
275
+ replacements: {
276
+ params: {
277
+ properties: false,
278
+ },
279
+ props: {
280
+ properties: false,
281
+ },
282
+ utils: {
283
+ utilities: false,
284
+ },
285
+ },
286
+ },
287
+ ],
288
+ 'unicorn/relative-url-style': 'off',
289
+ 'unicorn/require-module-attributes': 'warn',
290
+ 'unicorn/switch-case-braces': 'off',
291
+ 'unicorn/template-indent': 'off',
292
+ 'use-isnan': 'error',
293
+ }
294
+
295
+ export const baseTestOverrides = {
296
+ // because of jest
297
+ files: ['**/*.test.ts'],
298
+ rules: {
299
+ '@typescript-eslint/explicit-function-return-type': 'off',
300
+ '@typescript-eslint/no-empty-function': 'off',
301
+ '@typescript-eslint/no-explicit-any': 'off',
302
+ '@typescript-eslint/no-misused-promises': 'off',
303
+ '@typescript-eslint/no-unsafe-assignment': 'off',
304
+ '@typescript-eslint/no-unsafe-return': 'off',
305
+ '@typescript-eslint/require-await': 'off',
306
+ 'unicorn/no-array-callback-reference': 'off',
307
+ 'unicorn/no-await-expression-member': 'off',
308
+ },
309
+ }
package/index.js CHANGED
@@ -1,19 +1,23 @@
1
- import stylisticPlugin from '@stylistic/eslint-plugin'
2
1
  import tsPlugin from '@typescript-eslint/eslint-plugin'
3
- import globals from 'globals'
4
- import jsxA11yPlugin from 'eslint-plugin-jsx-a11y'
2
+ import vitestPlugin from '@vitest/eslint-plugin'
5
3
  import importPlugin from 'eslint-plugin-import'
6
- import jestPlugin from 'eslint-plugin-jest'
7
- import perfectionistPlugin from 'eslint-plugin-perfectionist'
8
- import preferArrowPlugin from 'eslint-plugin-prefer-arrow'
4
+ import jsxA11yPlugin from 'eslint-plugin-jsx-a11y'
9
5
  import prettierConfig from 'eslint-plugin-prettier/recommended'
10
6
  import reactPlugin from 'eslint-plugin-react'
11
7
  import reactHooksPlugin from 'eslint-plugin-react-hooks'
12
- import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort'
13
8
  import unicornPlugin from 'eslint-plugin-unicorn'
14
- import vitestPlugin from '@vitest/eslint-plugin'
9
+ import globals from 'globals'
10
+
11
+ import {
12
+ baseGlobals,
13
+ baseParserOptions,
14
+ basePlugins,
15
+ baseRules,
16
+ baseSettings,
17
+ baseTestOverrides,
18
+ } from './base.js'
15
19
 
16
- export default [
20
+ const config = [
17
21
  ...tsPlugin.configs['flat/recommended-type-checked'],
18
22
  ...tsPlugin.configs['flat/stylistic-type-checked'],
19
23
  unicornPlugin.configs['flat/recommended'],
@@ -28,217 +32,25 @@ export default [
28
32
  languageOptions: {
29
33
  globals: {
30
34
  ...globals.browser,
31
- ...globals.node,
32
- ...jestPlugin.environments.globals.globals,
35
+ ...baseGlobals,
33
36
  },
34
37
  parserOptions: {
38
+ ...baseParserOptions,
35
39
  ecmaFeatures: {
36
40
  jsx: true,
37
41
  },
38
- ecmaVersion: 2021,
39
- project: 'tsconfig.json',
40
- sourceType: 'module',
41
- warnOnUnsupportedTypeScriptVersion: false,
42
- },
43
- },
44
- plugins: {
45
- '@stylistic': stylisticPlugin,
46
- jest: jestPlugin,
47
- perfectionist: perfectionistPlugin,
48
- 'prefer-arrow': preferArrowPlugin,
49
- 'simple-import-sort': simpleImportSortPlugin,
50
- },
51
- settings: {
52
- react: { version: 'detect' },
53
- 'import/parsers': {
54
- '@typescript-eslint/parser': ['.ts', '.mts', '.cts', '.tsx', '.d.ts'],
55
- },
56
- 'import/resolver': {
57
- node: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
58
- typescript: { alwaysTryTypes: true },
59
42
  },
60
43
  },
44
+ plugins: basePlugins,
61
45
  rules: {
62
- // perfectionist — replaces eslint-plugin-typescript-sort-keys
63
- // (string-enum equivalent: sort-enums with default sortByValue: 'ifNumericEnum')
64
- 'perfectionist/sort-enums': 'error',
65
- 'perfectionist/sort-heritage-clauses': 'error',
66
- 'perfectionist/sort-interfaces': 'error',
67
- 'perfectionist/sort-object-types': 'error',
68
- // react-hooks override (recommended-latest has exhaustive-deps as 'warn')
69
- 'react-hooks/exhaustive-deps': 'error',
70
- '@stylistic/padding-line-between-statements': [
71
- 'error',
72
- {
73
- blankLine: 'always',
74
- prev: '*',
75
- next: 'return',
76
- },
77
- ],
78
- '@stylistic/spaced-comment': [
79
- 'error',
80
- 'always',
81
- {
82
- markers: ['/'],
83
- },
84
- ],
85
- '@typescript-eslint/adjacent-overload-signatures': 'error',
86
- '@typescript-eslint/array-type': [
87
- 'error',
88
- {
89
- default: 'array',
90
- },
91
- ],
92
- '@typescript-eslint/consistent-type-assertions': 'error',
93
- '@typescript-eslint/consistent-type-definitions': 'off',
94
- '@typescript-eslint/explicit-function-return-type': 'off',
95
- '@typescript-eslint/explicit-module-boundary-types': [
96
- 'warn', // TODO: strict later
97
- {
98
- allowArgumentsExplicitlyTypedAsAny: true,
99
- allowDirectConstAssertionInArrowFunctions: true,
100
- allowHigherOrderFunctions: false,
101
- allowTypedFunctionExpressions: false,
102
- },
103
- ],
104
- '@typescript-eslint/naming-convention': [
105
- 'error',
106
- {
107
- custom: {
108
- match: true,
109
- regex: '^I[A-Z]',
110
- },
111
- format: ['PascalCase'],
112
- selector: 'interface',
113
- },
114
- ],
115
- '@typescript-eslint/no-base-to-string': 'warn',
116
- '@typescript-eslint/no-dynamic-delete': 'error',
117
- // need for tests' mockups
118
- '@typescript-eslint/no-empty-function': 'warn',
119
- '@typescript-eslint/no-empty-object-type': 'error',
120
- '@typescript-eslint/no-explicit-any': 'warn',
121
- // turn on later
122
- '@typescript-eslint/no-floating-promises': 'warn',
123
- '@typescript-eslint/no-for-in-array': 'error',
124
- '@typescript-eslint/no-inferrable-types': 'error',
125
- '@typescript-eslint/no-misused-new': 'error',
126
- '@typescript-eslint/no-namespace': 'error',
127
- '@typescript-eslint/no-redundant-type-constituents': 'warn',
128
- '@typescript-eslint/no-require-imports': 'error',
129
- '@typescript-eslint/no-shadow': [
130
- 'error',
131
- {
132
- hoist: 'all',
133
- },
134
- ],
135
- '@typescript-eslint/no-this-alias': 'error',
46
+ ...baseRules,
136
47
  '@typescript-eslint/no-unnecessary-type-assertion': 'warn',
137
- '@typescript-eslint/no-unsafe-argument': 'warn',
138
- '@typescript-eslint/no-unsafe-assignment': 'warn',
139
- '@typescript-eslint/no-unsafe-call': 'warn',
140
- '@typescript-eslint/no-unsafe-enum-comparison': 'off',
141
- '@typescript-eslint/no-unsafe-member-access': 'off',
142
- '@typescript-eslint/no-unsafe-return': 'warn',
143
- '@typescript-eslint/no-unused-expressions': 'error',
144
48
  '@typescript-eslint/no-unused-vars': [
145
49
  'error',
146
50
  { varsIgnorePattern: '^jsx$' },
147
51
  ],
148
- '@typescript-eslint/no-use-before-define': 'error',
149
- '@typescript-eslint/prefer-for-of': 'error',
150
- '@typescript-eslint/prefer-function-type': 'error',
151
- '@typescript-eslint/prefer-namespace-keyword': 'error',
152
- '@typescript-eslint/prefer-nullish-coalescing': 'off',
153
- '@typescript-eslint/prefer-promise-reject-errors': 'warn',
154
- '@typescript-eslint/restrict-template-expressions': 'warn',
155
- '@typescript-eslint/triple-slash-reference': [
156
- 'error',
157
- {
158
- path: 'always',
159
- types: 'prefer-import',
160
- lib: 'always',
161
- },
162
- ],
163
- '@typescript-eslint/unified-signatures': 'error',
164
- 'arrow-body-style': ['error', 'as-needed'],
165
- complexity: [
166
- 'error',
167
- {
168
- max: 15,
169
- },
170
- ],
171
- 'constructor-super': 'error',
172
- eqeqeq: ['error', 'smart'],
173
- 'guard-for-in': 'error',
174
- 'id-denylist': [
175
- 'error',
176
- 'any',
177
- 'Number',
178
- 'number',
179
- 'String',
180
- 'string',
181
- 'Boolean',
182
- 'boolean',
183
- 'Undefined',
184
- 'undefined',
185
- ],
186
- 'id-match': 'error',
187
- 'import/no-anonymous-default-export': [
188
- 'error',
189
- {
190
- allowAnonymousClass: false,
191
- allowAnonymousFunction: false,
192
- allowArray: false,
193
- allowArrowFunction: true,
194
- allowCallExpression: true,
195
- // The true value here is for backward compatibility
196
- allowLiteral: false,
197
- allowObject: true,
198
- },
199
- ],
200
- 'import/no-extraneous-dependencies': [
201
- 'error',
202
- {
203
- devDependencies: true,
204
- },
205
- ],
206
- 'jest/no-disabled-tests': 'warn',
207
- 'jest/no-focused-tests': 'error',
208
- 'jest/no-identical-title': 'error',
209
- 'jest/valid-expect': 'error',
210
- 'max-classes-per-file': ['error', 1],
211
- 'no-bitwise': 'error',
212
- 'no-caller': 'error',
213
- 'no-cond-assign': 'error',
214
- 'no-console': 'error',
215
- 'no-debugger': 'error',
216
- 'no-duplicate-case': 'error',
217
- 'no-duplicate-imports': 'error',
218
- 'no-empty': 'error',
219
- 'no-eval': 'error',
220
- 'no-extra-bind': 'error',
221
- 'no-multiple-empty-lines': 'error',
222
- 'no-new-func': 'error',
223
- 'no-new-wrappers': 'error',
224
- 'no-param-reassign': 'error',
225
- 'no-redeclare': 'error',
226
- 'no-sequences': 'error',
227
- 'no-sparse-arrays': 'error',
228
- 'no-template-curly-in-string': 'error',
229
- 'no-throw-literal': 'error',
230
- 'no-trailing-spaces': 'error',
231
- 'no-undef-init': 'error',
232
- 'no-unsafe-finally': 'error',
233
- 'no-unused-labels': 'error',
234
- 'no-var': 'error',
235
- 'object-shorthand': 'error',
236
- 'one-var': ['error', 'never'],
237
- 'prefer-arrow/prefer-arrow-functions': 'warn',
238
- 'prefer-const': 'error',
239
- 'prefer-object-spread': 'error',
240
- 'prefer-template': 'error',
241
- radix: 'error',
52
+ // react-hooks override (recommended-latest has exhaustive-deps as 'warn')
53
+ 'react-hooks/exhaustive-deps': 'error',
242
54
  'react/jsx-curly-brace-presence': [
243
55
  'error',
244
56
  {
@@ -257,103 +69,14 @@ export default [
257
69
  'react/no-unknown-property': ['error', { ignore: ['css'] }],
258
70
  'react/prop-types': 'off',
259
71
  'react/react-in-jsx-scope': 'off',
260
- 'simple-import-sort/exports': 'error',
261
- 'simple-import-sort/imports': 'error',
262
- 'sort-keys': 'error',
263
- 'unicorn/better-regex': 'off',
264
- 'unicorn/consistent-existence-index-check': 'off',
265
- 'unicorn/expiring-todo-comments': 'off',
266
- 'unicorn/filename-case': [
267
- 'warn',
268
- {
269
- cases: {
270
- camelCase: true,
271
- pascalCase: true,
272
- },
273
- },
274
- ],
275
- 'unicorn/import-style': 'warn',
276
- 'unicorn/no-anonymous-default-export': 'off',
277
- 'unicorn/no-array-reduce': 'off',
278
- // .reverse() mutates in place — semantic + perf cost to force .toReversed()
279
- 'unicorn/no-array-reverse': 'off',
280
- // .sort() mutates in place — same story as no-array-reverse
281
- 'unicorn/no-array-sort': 'off',
282
- 'unicorn/no-await-expression-member': 'warn',
283
- 'unicorn/no-console-spaces': 'off',
284
- 'unicorn/no-document-cookie': 'warn',
285
- 'unicorn/no-empty-file': 'off',
286
- 'unicorn/no-hex-escape': 'warn',
287
- 'unicorn/no-invalid-remove-event-listener': 'warn',
288
- 'unicorn/no-named-default': 'warn',
289
- 'unicorn/no-nested-ternary': 'off',
290
- // because we have a lot of logic depends on null
291
- 'unicorn/no-null': 'warn',
292
- 'unicorn/no-object-as-default-parameter': 'warn',
293
- 'unicorn/no-single-promise-in-promise-methods': 'warn',
294
- 'unicorn/no-unreadable-array-destructuring': 'off',
295
- 'unicorn/no-unused-properties': 'warn',
296
- 'unicorn/no-zero-fractions': 'off',
297
- 'unicorn/prefer-class-fields': 'warn',
298
- 'unicorn/prefer-export-from': 'off',
299
- 'unicorn/prefer-global-this': 'warn',
300
- 'unicorn/prefer-includes': 'off',
301
- 'unicorn/prefer-math-min-max': 'warn',
302
- 'unicorn/prefer-module': 'warn',
303
- 'unicorn/prefer-node-protocol': 'off',
304
- 'unicorn/prefer-optional-catch-binding': 'off',
305
- 'unicorn/prefer-prototype-methods': 'off',
306
- 'unicorn/prefer-query-selector': 'off',
307
- 'unicorn/prefer-regexp-test': 'off',
308
- 'unicorn/prefer-set-has': 'off',
309
- 'unicorn/prefer-set-size': 'off',
310
- // opinionated condition ordering — too noisy
311
- 'unicorn/prefer-simple-condition-first': 'off',
312
- 'unicorn/prefer-string-raw': 'off',
313
- 'unicorn/prefer-string-replace-all': 'off',
314
- 'unicorn/prefer-structured-clone': 'warn',
315
- 'unicorn/prevent-abbreviations': [
316
- 'error',
317
- {
318
- allowList: {
319
- params: true,
320
- props: true,
321
- utils: true,
322
- },
323
- replacements: {
324
- params: {
325
- properties: false,
326
- },
327
- props: {
328
- properties: false,
329
- },
330
- utils: {
331
- utilities: false,
332
- },
333
- },
334
- },
335
- ],
336
- 'unicorn/relative-url-style': 'off',
337
- 'unicorn/require-module-attributes': 'warn',
338
- 'unicorn/switch-case-braces': 'off',
339
- 'unicorn/template-indent': 'off',
340
- 'use-isnan': 'error',
341
72
  },
342
- },
343
- {
344
- // because of jest
345
- files: ['**/*.test.ts'],
346
- rules: {
347
- '@typescript-eslint/explicit-function-return-type': 'off',
348
- '@typescript-eslint/no-empty-function': 'off',
349
- '@typescript-eslint/no-explicit-any': 'off',
350
- '@typescript-eslint/no-misused-promises': 'off',
351
- '@typescript-eslint/no-unsafe-assignment': 'off',
352
- '@typescript-eslint/no-unsafe-return': 'off',
353
- '@typescript-eslint/require-await': 'off',
354
- 'unicorn/no-array-callback-reference': 'off',
355
- 'unicorn/no-await-expression-member': 'off',
73
+ settings: {
74
+ ...baseSettings,
75
+ react: { version: 'detect' },
356
76
  },
357
77
  },
78
+ baseTestOverrides,
358
79
  prettierConfig,
359
80
  ]
81
+
82
+ export default config
package/node.js CHANGED
@@ -1,16 +1,19 @@
1
- import stylisticPlugin from '@stylistic/eslint-plugin'
2
1
  import tsPlugin from '@typescript-eslint/eslint-plugin'
3
- import globals from 'globals'
2
+ import vitestPlugin from '@vitest/eslint-plugin'
4
3
  import importPlugin from 'eslint-plugin-import'
5
- import jestPlugin from 'eslint-plugin-jest'
6
- import perfectionistPlugin from 'eslint-plugin-perfectionist'
7
- import preferArrowPlugin from 'eslint-plugin-prefer-arrow'
8
4
  import prettierConfig from 'eslint-plugin-prettier/recommended'
9
- import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort'
10
5
  import unicornPlugin from 'eslint-plugin-unicorn'
11
- import vitestPlugin from '@vitest/eslint-plugin'
12
6
 
13
- export default [
7
+ import {
8
+ baseGlobals,
9
+ baseParserOptions,
10
+ basePlugins,
11
+ baseRules,
12
+ baseSettings,
13
+ baseTestOverrides,
14
+ } from './base.js'
15
+
16
+ const config = [
14
17
  ...tsPlugin.configs['flat/recommended-type-checked'],
15
18
  ...tsPlugin.configs['flat/stylistic-type-checked'],
16
19
  unicornPlugin.configs['flat/recommended'],
@@ -19,303 +22,19 @@ export default [
19
22
  vitestPlugin.configs.recommended,
20
23
  {
21
24
  languageOptions: {
22
- globals: {
23
- ...globals.node,
24
- ...jestPlugin.environments.globals.globals,
25
- },
26
- parserOptions: {
27
- ecmaVersion: 2021,
28
- project: 'tsconfig.json',
29
- sourceType: 'module',
30
- warnOnUnsupportedTypeScriptVersion: false,
31
- },
32
- },
33
- plugins: {
34
- '@stylistic': stylisticPlugin,
35
- jest: jestPlugin,
36
- perfectionist: perfectionistPlugin,
37
- 'prefer-arrow': preferArrowPlugin,
38
- 'simple-import-sort': simpleImportSortPlugin,
39
- },
40
- settings: {
41
- 'import/parsers': {
42
- '@typescript-eslint/parser': ['.ts', '.mts', '.cts', '.tsx', '.d.ts'],
43
- },
44
- 'import/resolver': {
45
- node: { extensions: ['.js', '.jsx', '.ts', '.tsx'] },
46
- typescript: { alwaysTryTypes: true },
47
- },
25
+ globals: baseGlobals,
26
+ parserOptions: baseParserOptions,
48
27
  },
28
+ plugins: basePlugins,
49
29
  rules: {
50
- // perfectionist — replaces eslint-plugin-typescript-sort-keys
51
- // (string-enum equivalent: sort-enums with default sortByValue: 'ifNumericEnum')
52
- 'perfectionist/sort-enums': 'error',
53
- 'perfectionist/sort-heritage-clauses': 'error',
54
- 'perfectionist/sort-interfaces': 'error',
55
- 'perfectionist/sort-object-types': 'error',
56
- '@stylistic/padding-line-between-statements': [
57
- 'error',
58
- {
59
- blankLine: 'always',
60
- prev: '*',
61
- next: 'return',
62
- },
63
- ],
64
- '@stylistic/spaced-comment': [
65
- 'error',
66
- 'always',
67
- {
68
- markers: ['/'],
69
- },
70
- ],
71
- '@typescript-eslint/adjacent-overload-signatures': 'error',
72
- '@typescript-eslint/array-type': [
73
- 'error',
74
- {
75
- default: 'array',
76
- },
77
- ],
78
- '@typescript-eslint/consistent-type-assertions': 'error',
79
- '@typescript-eslint/consistent-type-definitions': 'off',
30
+ ...baseRules,
80
31
  '@typescript-eslint/dot-notation': 'error',
81
- '@typescript-eslint/explicit-function-return-type': 'off',
82
- '@typescript-eslint/explicit-module-boundary-types': [
83
- 'warn', // TODO: strict later
84
- {
85
- allowArgumentsExplicitlyTypedAsAny: true,
86
- allowDirectConstAssertionInArrowFunctions: true,
87
- allowHigherOrderFunctions: false,
88
- allowTypedFunctionExpressions: false,
89
- },
90
- ],
91
- '@typescript-eslint/naming-convention': [
92
- 'error',
93
- {
94
- custom: {
95
- match: true,
96
- regex: '^I[A-Z]',
97
- },
98
- format: ['PascalCase'],
99
- selector: 'interface',
100
- },
101
- ],
102
- '@typescript-eslint/no-base-to-string': 'warn',
103
- '@typescript-eslint/no-dynamic-delete': 'error',
104
- // need for tests' mockups
105
- '@typescript-eslint/no-empty-function': 'warn',
106
- '@typescript-eslint/no-empty-object-type': 'error',
107
- '@typescript-eslint/no-explicit-any': 'warn',
108
- // turn on later
109
- '@typescript-eslint/no-floating-promises': 'warn',
110
- '@typescript-eslint/no-for-in-array': 'error',
111
- '@typescript-eslint/no-inferrable-types': 'error',
112
- '@typescript-eslint/no-misused-new': 'error',
113
- '@typescript-eslint/no-namespace': 'error',
114
- '@typescript-eslint/no-redundant-type-constituents': 'warn',
115
- '@typescript-eslint/no-require-imports': 'error',
116
- '@typescript-eslint/no-shadow': [
117
- 'error',
118
- {
119
- hoist: 'all',
120
- },
121
- ],
122
- '@typescript-eslint/no-this-alias': 'error',
123
- '@typescript-eslint/no-unsafe-argument': 'warn',
124
- '@typescript-eslint/no-unsafe-assignment': 'warn',
125
- '@typescript-eslint/no-unsafe-call': 'warn',
126
- '@typescript-eslint/no-unsafe-enum-comparison': 'off',
127
- '@typescript-eslint/no-unsafe-member-access': 'off',
128
- '@typescript-eslint/no-unsafe-return': 'warn',
129
- '@typescript-eslint/no-unused-expressions': 'error',
130
32
  '@typescript-eslint/no-unused-vars': 'error',
131
- '@typescript-eslint/no-use-before-define': 'error',
132
- '@typescript-eslint/prefer-for-of': 'error',
133
- '@typescript-eslint/prefer-function-type': 'error',
134
- '@typescript-eslint/prefer-namespace-keyword': 'error',
135
- '@typescript-eslint/prefer-nullish-coalescing': 'off',
136
- '@typescript-eslint/prefer-promise-reject-errors': 'warn',
137
- '@typescript-eslint/restrict-template-expressions': 'warn',
138
- '@typescript-eslint/triple-slash-reference': [
139
- 'error',
140
- {
141
- path: 'always',
142
- types: 'prefer-import',
143
- lib: 'always',
144
- },
145
- ],
146
- '@typescript-eslint/unified-signatures': 'error',
147
- 'arrow-body-style': ['error', 'as-needed'],
148
- complexity: [
149
- 'error',
150
- {
151
- max: 15,
152
- },
153
- ],
154
- 'constructor-super': 'error',
155
- eqeqeq: ['error', 'smart'],
156
- 'guard-for-in': 'error',
157
- 'id-denylist': [
158
- 'error',
159
- 'any',
160
- 'Number',
161
- 'number',
162
- 'String',
163
- 'string',
164
- 'Boolean',
165
- 'boolean',
166
- 'Undefined',
167
- 'undefined',
168
- ],
169
- 'id-match': 'error',
170
- 'import/no-anonymous-default-export': [
171
- 'error',
172
- {
173
- allowAnonymousClass: false,
174
- allowAnonymousFunction: false,
175
- allowArray: false,
176
- allowArrowFunction: true,
177
- allowCallExpression: true,
178
- // The true value here is for backward compatibility
179
- allowLiteral: false,
180
- allowObject: true,
181
- },
182
- ],
183
- 'import/no-extraneous-dependencies': [
184
- 'error',
185
- {
186
- devDependencies: true,
187
- },
188
- ],
189
- 'jest/no-disabled-tests': 'warn',
190
- 'jest/no-focused-tests': 'error',
191
- 'jest/no-identical-title': 'error',
192
- 'jest/valid-expect': 'error',
193
- 'max-classes-per-file': ['error', 1],
194
- 'no-bitwise': 'error',
195
- 'no-caller': 'error',
196
- 'no-cond-assign': 'error',
197
- 'no-console': 'error',
198
- 'no-debugger': 'error',
199
- 'no-duplicate-case': 'error',
200
- 'no-duplicate-imports': 'error',
201
- 'no-empty': 'error',
202
- 'no-eval': 'error',
203
- 'no-extra-bind': 'error',
204
- 'no-multiple-empty-lines': 'error',
205
- 'no-new-func': 'error',
206
- 'no-new-wrappers': 'error',
207
- 'no-param-reassign': 'error',
208
- 'no-redeclare': 'error',
209
- 'no-sequences': 'error',
210
- 'no-sparse-arrays': 'error',
211
- 'no-template-curly-in-string': 'error',
212
- 'no-throw-literal': 'error',
213
- 'no-trailing-spaces': 'error',
214
- 'no-undef-init': 'error',
215
- 'no-unsafe-finally': 'error',
216
- 'no-unused-labels': 'error',
217
- 'no-var': 'error',
218
- 'object-shorthand': 'error',
219
- 'one-var': ['error', 'never'],
220
- 'prefer-arrow/prefer-arrow-functions': 'warn',
221
- 'prefer-const': 'error',
222
- 'prefer-object-spread': 'error',
223
- 'prefer-template': 'error',
224
- radix: 'error',
225
- 'simple-import-sort/exports': 'error',
226
- 'simple-import-sort/imports': 'error',
227
- 'sort-keys': 'error',
228
- 'unicorn/better-regex': 'off',
229
- 'unicorn/consistent-existence-index-check': 'off',
230
- 'unicorn/expiring-todo-comments': 'off',
231
- 'unicorn/filename-case': [
232
- 'warn',
233
- {
234
- cases: {
235
- camelCase: true,
236
- pascalCase: true,
237
- },
238
- },
239
- ],
240
- 'unicorn/import-style': 'warn',
241
- 'unicorn/no-anonymous-default-export': 'off',
242
- 'unicorn/no-array-reduce': 'off',
243
- 'unicorn/no-array-reverse': 'off',
244
- 'unicorn/no-array-sort': 'off',
245
- 'unicorn/no-await-expression-member': 'warn',
246
- 'unicorn/no-console-spaces': 'off',
247
- 'unicorn/no-document-cookie': 'warn',
248
- 'unicorn/no-empty-file': 'off',
249
- 'unicorn/no-hex-escape': 'warn',
250
- 'unicorn/no-invalid-remove-event-listener': 'warn',
251
- 'unicorn/no-named-default': 'warn',
252
- 'unicorn/no-nested-ternary': 'off',
253
- // because we have a lot of logic depends on null
254
- 'unicorn/no-null': 'warn',
255
- 'unicorn/no-object-as-default-parameter': 'warn',
256
- 'unicorn/no-single-promise-in-promise-methods': 'warn',
257
- 'unicorn/no-unreadable-array-destructuring': 'off',
258
- 'unicorn/no-unused-properties': 'warn',
259
- 'unicorn/no-zero-fractions': 'off',
260
- 'unicorn/prefer-class-fields': 'warn',
261
- 'unicorn/prefer-export-from': 'off',
262
- 'unicorn/prefer-global-this': 'warn',
263
- 'unicorn/prefer-includes': 'off',
264
- 'unicorn/prefer-math-min-max': 'warn',
265
- 'unicorn/prefer-module': 'warn',
266
- 'unicorn/prefer-node-protocol': 'off',
267
- 'unicorn/prefer-optional-catch-binding': 'off',
268
- 'unicorn/prefer-prototype-methods': 'off',
269
- 'unicorn/prefer-query-selector': 'off',
270
- 'unicorn/prefer-regexp-test': 'off',
271
- 'unicorn/prefer-set-has': 'off',
272
- 'unicorn/prefer-set-size': 'off',
273
- 'unicorn/prefer-simple-condition-first': 'off',
274
- 'unicorn/prefer-string-raw': 'off',
275
- 'unicorn/prefer-string-replace-all': 'off',
276
- 'unicorn/prefer-structured-clone': 'warn',
277
- 'unicorn/prevent-abbreviations': [
278
- 'error',
279
- {
280
- allowList: {
281
- params: true,
282
- props: true,
283
- utils: true,
284
- },
285
- replacements: {
286
- params: {
287
- properties: false,
288
- },
289
- props: {
290
- properties: false,
291
- },
292
- utils: {
293
- utilities: false,
294
- },
295
- },
296
- },
297
- ],
298
- 'unicorn/relative-url-style': 'off',
299
- 'unicorn/require-module-attributes': 'warn',
300
- 'unicorn/switch-case-braces': 'off',
301
- 'unicorn/template-indent': 'off',
302
- 'use-isnan': 'error',
303
- },
304
- },
305
- {
306
- // because of jest
307
- files: ['**/*.test.ts'],
308
- rules: {
309
- '@typescript-eslint/explicit-function-return-type': 'off',
310
- '@typescript-eslint/no-empty-function': 'off',
311
- '@typescript-eslint/no-explicit-any': 'off',
312
- '@typescript-eslint/no-misused-promises': 'off',
313
- '@typescript-eslint/no-unsafe-assignment': 'off',
314
- '@typescript-eslint/no-unsafe-return': 'off',
315
- '@typescript-eslint/require-await': 'off',
316
- 'unicorn/no-array-callback-reference': 'off',
317
- 'unicorn/no-await-expression-member': 'off',
318
33
  },
34
+ settings: baseSettings,
319
35
  },
36
+ baseTestOverrides,
320
37
  prettierConfig,
321
38
  ]
39
+
40
+ export default config
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allthings/eslint-config",
3
- "version": "3.7.0",
3
+ "version": "3.7.1-alpha.1",
4
4
  "type": "module",
5
5
  "description": "ESlint shareable config for Allthings style",
6
6
  "main": "index.js",
@@ -13,12 +13,13 @@
13
13
  "./node": "./node.js"
14
14
  },
15
15
  "files": [
16
+ "base.js",
16
17
  "index.js",
17
18
  "node.js"
18
19
  ],
19
20
  "packageManager": "yarn@4.14.1",
20
21
  "scripts": {
21
- "lint": "prettier --check .",
22
+ "lint": "prettier --check . && eslint .",
22
23
  "semantic-release": "semantic-release",
23
24
  "test": "yarn test:audit && yarn test:behavioral",
24
25
  "test:audit": "node test/audit.js",