1
1
const jsRules = {
2
2
'no-empty-pattern' : 1 ,
3
3
'arrow-body-style' : [ 1 , 'as-needed' , { requireReturnForObjectLiteral : true } ] ,
4
- 'arrow-parens' : [ 1 , 'always' ] ,
5
- 'arrow-spacing' : 1 ,
6
- 'block-spacing' : [ 1 , 'never' ] ,
7
- 'brace-style' : [ 1 , '1tbs' , { allowSingleLine : true } ] ,
8
- 'comma-dangle' : [ 1 , 'always-multiline' ] ,
9
- 'comma-spacing' : [ 1 , { before : false , after : true } ] ,
10
4
curly : 1 ,
11
- 'eol-last' : [ 1 , 'always' ] ,
12
5
eqeqeq : 1 ,
13
- 'func-call-spacing' : 1 ,
14
- 'jsx-quotes' : [ 'warn' , 'prefer-single' ] ,
15
- 'key-spacing' : [ 1 , { beforeColon : false , afterColon : true , mode : 'strict' } ] ,
16
6
'max-nested-callbacks' : [ 1 , 6 ] ,
17
7
'no-case-declarations' : 1 ,
18
- 'no-confusing-arrow' : 1 ,
19
8
'no-console' : [ 1 , { allow : [ 'info' , 'warn' , 'error' ] } ] ,
20
9
'no-control-regex' : 0 ,
21
10
'no-debugger' : 1 ,
22
11
'no-duplicate-imports' : 1 ,
23
12
'no-extend-native' : 1 ,
24
13
'no-extra-bind' : 1 ,
25
14
'no-extra-boolean-cast' : 1 ,
26
- 'no-extra-semi' : 1 ,
27
15
'no-fallthrough' : 1 ,
28
16
'no-inner-declarations' : 1 ,
29
17
'no-irregular-whitespace' : 1 ,
30
18
'no-lonely-if' : 1 ,
31
- 'no-mixed-spaces-and-tabs' : 1 ,
32
- 'no-multi-spaces' : 1 ,
33
- 'no-multiple-empty-lines' : [ 1 , { max : 2 , maxEOF : 1 } ] ,
34
19
'no-nonoctal-decimal-escape' : 1 ,
35
20
'no-prototype-builtins' : 1 ,
36
- 'no-trailing-spaces' : 1 ,
37
21
'no-undef-init' : 1 ,
38
22
'no-undef' : 1 ,
39
23
'no-unexpected-multiline' : 1 ,
@@ -44,12 +28,10 @@ const jsRules = {
44
28
'no-useless-escape' : 1 ,
45
29
'no-useless-rename' : 1 ,
46
30
'no-var' : 1 ,
47
- 'no-whitespace-before-property' : 1 ,
48
31
'one-var' : [ 'warn' , 'never' ] ,
49
32
'prefer-const' : 1 ,
50
33
'prefer-rest-params' : 1 ,
51
34
'prefer-spread' : 1 ,
52
- quotes : [ 'warn' , 'single' , { avoidEscape : true } ] ,
53
35
'react/jsx-boolean-value' : 1 ,
54
36
'react/jsx-no-undef' : 2 ,
55
37
'react/jsx-sort-prop-types' : 0 ,
@@ -64,13 +46,87 @@ const jsRules = {
64
46
'react/react-in-jsx-scope' : 2 ,
65
47
'react/self-closing-comp' : 2 ,
66
48
'react/wrap-multilines' : 0 ,
49
+ strict : 1 ,
50
+
51
+ // Formatting (stylistic) rules.
52
+ //
53
+ // 'Deprecated' in ESLint 8.53.0, see announcement
54
+ // - Announcement: https://eslint.org/blog/2023/10/deprecating-formatting-rules/
55
+ // - Rules deprecated: (https://github.com/eslint/eslint/commit/528e1c00dc2a)
56
+ //
57
+ // Successor: ESLint Stylistic, community project
58
+ // - Rules: https://eslint.style/packages/default#rules
59
+ //
60
+ // It'll be useful to keep a variant of these rules around as an alternative
61
+ // "auto-fixer" (versus Prettier), since Prettier modifies line wrappings in
62
+ // a way that can harm code readability at times.
63
+ //
64
+ // Idea:
65
+ // * Create a 'stylistic-only' ESLint config with these rules
66
+ // * Use the stylistic config for 'auto-fix' (lightweight formatting) in editor
67
+ // (normalize quotes, commas, semicolons, etc. without touching linebreaks)
68
+ // * Remove 'stylistic' rules from the main config, to reduce diagnostic
69
+ // clutter in code or in the 'Problems' pane
70
+ // * Keep an optional well-configured 'Prettier' tooling, able to run on
71
+ // modified lines or current/selected paragraph, around for convenience
72
+ 'arrow-parens' : [ 1 , 'always' ] ,
73
+ 'arrow-spacing' : 1 ,
74
+ 'block-spacing' : [ 1 , 'never' ] ,
75
+ 'brace-style' : [ 1 , '1tbs' , { allowSingleLine : true } ] ,
76
+ 'comma-dangle' : [ 1 , 'always-multiline' ] ,
77
+ 'comma-spacing' : [ 1 , { before : false , after : true } ] ,
78
+ 'eol-last' : [ 1 , 'always' ] ,
79
+ 'func-call-spacing' : 1 ,
80
+ 'jsx-quotes' : [ 'warn' , 'prefer-single' ] ,
81
+ 'key-spacing' : [ 1 , { beforeColon : false , afterColon : true , mode : 'strict' } ] ,
82
+ 'no-confusing-arrow' : 1 ,
83
+ 'no-extra-semi' : 1 ,
84
+ 'no-mixed-spaces-and-tabs' : 1 ,
85
+ 'no-multi-spaces' : 1 , // Comment out to permit columnar formatting
86
+ 'no-multiple-empty-lines' : [ 1 , { max : 2 , maxEOF : 1 } ] ,
87
+ 'no-trailing-spaces' : 1 ,
88
+ 'no-whitespace-before-property' : 1 ,
89
+ 'quotes' : [ 'warn' , 'single' , { avoidEscape : true } ] ,
67
90
'semi-spacing' : [ 1 , { before : false , after : true } ] ,
68
91
'semi-style' : [ 1 , 'last' ] ,
69
- semi : 1 ,
92
+ ' semi' : 1 ,
70
93
'space-before-function-paren' : 'off' ,
71
94
'space-in-parens' : [ 1 , 'never' ] ,
72
95
'space-infix-ops' : 1 ,
73
- strict : 1 ,
96
+
97
+ // React Plugin - Default to plugin:react/recommended.
98
+ // https://github.com/jsx-eslint/eslint-plugin-react
99
+
100
+ // TODO: Set these rules back to 'error' severity and fix the affected code
101
+ // (1) comment these out (2) run npx eslint (...) with --quiet to list only errors
102
+ // ===============================================================================
103
+ // Deprecated API
104
+ 'react/no-deprecated' : 1 , // e.g. componentWillReceiveProps
105
+ 'react/no-find-dom-node' : 1 , // Do not use findDOMNode
106
+ 'react/no-string-refs' : 1 , // Using string literals in ref attributes is deprecated
107
+ // Misuse
108
+ 'react/jsx-key' : 1 , // Missing "key" prop for element in iterator
109
+ 'react/no-direct-mutation-state' : 1 , // Do not mutate state directly. Use setState()
110
+ // Other
111
+ 'react/display-name' : 1 , // "Component definition is missing display name"
112
+ 'react/no-unescaped-entities' : 1 , // e.g. `"` can be escaped with `"`…
113
+
114
+ // OK
115
+ // ==
116
+ 'react/jsx-no-target-blank' : 0 , // Using target="_blank" without rel="noreferrer"
117
+ // …not a problem for modern browsers; see 2021 update
118
+ // (https://mathiasbynens.github.io/rel-noopener/#recommendations)
119
+
120
+
121
+ // React Hooks - Default to plugin:react-hooks/recommended
122
+ // https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks
123
+
124
+ // TODO: Fix these! They should be errors, too.
125
+ 'react-hooks/rules-of-hooks' : 1 , // TODO: make this an error, not warning
126
+
127
+ // React Query - Default to plugin:@tanstack/eslint-plugin-query/recommended
128
+ // https://tanstack.com/query/latest/docs/eslint/eslint-plugin-query
129
+
74
130
} ;
75
131
76
132
// TypeScript rules override some of JavaScript rules plus add a few more.
@@ -79,19 +135,8 @@ const tsRules = Object.assign({}, jsRules, {
79
135
// Would be good to enable in future, when most of codebase is TS.
80
136
'@typescript-eslint/ban-types' : 'off' ,
81
137
'@typescript-eslint/ban-ts-comment' : 1 ,
82
- '@typescript-eslint/comma-dangle' : [ 1 , 'always-multiline' ] ,
83
- '@typescript-eslint/comma-spacing' : [ 1 , { before : false , after : true } ] ,
84
138
'@typescript-eslint/consistent-type-definitions' : [ 1 , 'interface' ] ,
85
139
'@typescript-eslint/consistent-type-imports' : [ 1 , { prefer : 'type-imports' } ] ,
86
- '@typescript-eslint/func-call-spacing' : [ 1 , 'never' ] ,
87
- '@typescript-eslint/keyword-spacing' : [ 1 , { before : true , after : true } ] ,
88
- '@typescript-eslint/member-delimiter-style' : [
89
- 1 ,
90
- {
91
- multiline : { delimiter : 'semi' } ,
92
- singleline : { delimiter : 'semi' } ,
93
- } ,
94
- ] ,
95
140
'@typescript-eslint/method-signature-style' : [ 1 , 'property' ] ,
96
141
'@typescript-eslint/naming-convention' : [
97
142
1 ,
@@ -127,8 +172,6 @@ const tsRules = Object.assign({}, jsRules, {
127
172
'@typescript-eslint/no-empty-function' : 1 ,
128
173
'@typescript-eslint/no-empty-interface' : 1 ,
129
174
'@typescript-eslint/no-explicit-any' : 1 ,
130
- '@typescript-eslint/no-extra-parens' : 'off' ,
131
- '@typescript-eslint/no-extra-semi' : 1 ,
132
175
'@typescript-eslint/no-inferrable-types' : 1 ,
133
176
'@typescript-eslint/no-invalid-void-type' : 1 ,
134
177
'@typescript-eslint/no-loop-func' : 1 ,
@@ -139,38 +182,11 @@ const tsRules = Object.assign({}, jsRules, {
139
182
'@typescript-eslint/no-use-before-define' : 1 ,
140
183
'@typescript-eslint/no-useless-constructor' : 1 ,
141
184
'@typescript-eslint/no-var-requires' : 'off' ,
142
- '@typescript-eslint/object-curly-spacing' : 1 ,
143
185
'@typescript-eslint/parameter-properties' : 1 ,
144
186
'@typescript-eslint/prefer-enum-initializers' : 1 ,
145
187
'@typescript-eslint/prefer-optional-chain' : 1 ,
146
- '@typescript-eslint/quotes' : [ 'warn' , 'single' , { avoidEscape : true } ] ,
147
- '@typescript-eslint/semi' : 1 ,
148
188
'@typescript-eslint/sort-type-union-intersection-members' : 'off' ,
149
- '@typescript-eslint/space-before-function-paren' : [
150
- 1 ,
151
- {
152
- anonymous : 'always' ,
153
- named : 'never' ,
154
- asyncArrow : 'always' , // TODO: Defer all formatting rules to Prettier
155
- } ,
156
- ] ,
157
- '@typescript-eslint/type-annotation-spacing' : [
158
- 1 ,
159
- {
160
- before : false ,
161
- after : true ,
162
- overrides : {
163
- arrow : {
164
- before : true ,
165
- after : true ,
166
- } ,
167
- } ,
168
- } ,
169
- ] ,
170
189
'@typescript-eslint/unified-signatures' : 1 ,
171
- 'comma-dangle' : 'off' ,
172
- 'comma-spacing' : 'off' ,
173
- 'func-call-spacing' : 'off' ,
174
190
// The 'import' plugin supports separately importing types
175
191
// (@typescript-eslint/no-duplicate-imports is deprecated)
176
192
'import/no-duplicates' : 1 ,
@@ -185,8 +201,47 @@ const tsRules = Object.assign({}, jsRules, {
185
201
'no-unused-vars' : 'off' ,
186
202
'no-useless-backreference' : 'off' ,
187
203
'no-var' : 1 ,
188
- quotes : 'off' ,
189
- semi : 'off' ,
204
+
205
+ // Formatting (stylistic) rules, for TypeScript.
206
+ // 'Deprecated' in @typescript-eslint v6.16.0 (https://typescript-eslint.io/blog/deprecating-formatting-rules/),
207
+ // Still useful for us in some form, particularly with auto-fix.
208
+ // See "Formatting (stylistic) rules" comment, above.
209
+ '@typescript-eslint/comma-dangle' : [ 1 , 'always-multiline' ] ,
210
+ '@typescript-eslint/comma-spacing' : [ 1 , { before : false , after : true } ] ,
211
+ '@typescript-eslint/func-call-spacing' : [ 1 , 'never' ] ,
212
+ '@typescript-eslint/keyword-spacing' : [ 1 , { before : true , after : true } ] ,
213
+ '@typescript-eslint/no-extra-parens' : 'off' ,
214
+ '@typescript-eslint/no-extra-semi' : 1 ,
215
+ '@typescript-eslint/object-curly-spacing' : 1 ,
216
+ '@typescript-eslint/member-delimiter-style' : [ 1 , {
217
+ multiline : { delimiter : 'semi' } ,
218
+ singleline : { delimiter : 'semi' } ,
219
+ } ] ,
220
+ '@typescript-eslint/quotes' : [ 'warn' , 'single' , { avoidEscape : true } ] ,
221
+ '@typescript-eslint/semi' : 1 ,
222
+ '@typescript-eslint/type-annotation-spacing' : [ 1 , {
223
+ before : false ,
224
+ after : true ,
225
+ overrides : {
226
+ arrow : {
227
+ before : true ,
228
+ after : true ,
229
+ } ,
230
+ } ,
231
+ } ] ,
232
+ '@typescript-eslint/space-before-function-paren' : [ 1 , {
233
+ anonymous : 'always' ,
234
+ named : 'never' ,
235
+ asyncArrow : 'always' ,
236
+ } ] ,
237
+ // Turn off equivalent ESLint rules
238
+ 'comma-dangle' : 'off' ,
239
+ 'comma-spacing' : 'off' ,
240
+ 'func-call-spacing' : 'off' ,
241
+ 'no-extra-semi' : 'off' ,
242
+ 'quotes' : 'off' ,
243
+ 'semi' : 'off' ,
244
+
190
245
} ) ;
191
246
192
247
module . exports = {
@@ -206,12 +261,27 @@ module.exports = {
206
261
} ,
207
262
ignorePatterns : [ '**/*.scss' ] ,
208
263
plugins : [ 'react' ] ,
209
- extends : [ 'eslint:recommended' , 'prettier' , 'plugin:storybook/recommended' ] ,
264
+ extends : [
265
+ 'eslint:recommended' ,
266
+ 'plugin:react/recommended' , // Use recommended rules: https://github.com/jsx-eslint/eslint-plugin-react#list-of-supported-rules
267
+ 'plugin:react/jsx-runtime' , // Use the new JSX transform
268
+ 'plugin:react-hooks/recommended' , // Rules of Hooks (https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks)
269
+ 'plugin:@tanstack/eslint-plugin-query/recommended' , // For Tanstack Query (aka react-query)
270
+ 'prettier' ,
271
+ 'plugin:storybook/recommended' ] ,
210
272
rules : jsRules ,
211
273
settings : {
212
274
react : {
213
275
version : 'detect' ,
214
276
} ,
277
+ // https://github.com/jsx-eslint/eslint-plugin-react#configuration-legacy-eslintrc-
278
+ // Try to include all the component wrapper functions we use here
279
+ componentWrapperFunctions : [
280
+ 'observer' , // MobX observer
281
+ ] ,
282
+ linkComponenets : [
283
+ { name : 'Link' , linkAttribute : 'to' } , // React Router Link
284
+ ] ,
215
285
} ,
216
286
overrides : [
217
287
{
0 commit comments