eslint-plugin-code-style 1.0.10 → 1.0.16

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 (3) hide show
  1. package/README.md +1046 -156
  2. package/index.js +344 -10
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![License](https://img.shields.io/npm/l/eslint-plugin-code-style?style=for-the-badge&color=blue)](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/blob/main/LICENSE)
8
8
 
9
9
  [![ESLint](https://img.shields.io/badge/ESLint-%3E%3D9.0.0-4B32C3?style=for-the-badge&logo=eslint&logoColor=white)](https://eslint.org/)
10
- [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D24.0.0-339933?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org/)
10
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18.0.0-339933?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org/)
11
11
  [![React](https://img.shields.io/badge/React-JSX%20Support-61DAFB?style=for-the-badge&logo=react&logoColor=black)](https://react.dev/)
12
12
 
13
13
  [![GitHub stars](https://img.shields.io/github/stars/Mohamed-Elhawary/eslint-plugin-code-style?style=for-the-badge&logo=github&color=yellow)](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/stargazers)
@@ -17,20 +17,69 @@
17
17
 
18
18
  **A powerful ESLint plugin for enforcing consistent code formatting and style rules in React/JSX projects.**
19
19
 
20
- *45+ auto-fixable rules to keep your codebase clean and consistent*
20
+ *47 auto-fixable rules to keep your codebase clean and consistent*
21
+
22
+ </div>
23
+
24
+ <br />
25
+
26
+ ## 🎯 Why This Plugin?
27
+
28
+ This plugin provides **rules that don't exist in ESLint's built-in rule set** and are **not available in popular third-party ESLint packages**. These are the style requirements that teams often check manually, making them easy to miss and hard to enforce consistently.
29
+
30
+ **Key Benefits:**
31
+ - **Fills the gaps** — Covers formatting rules that ESLint and other plugins miss
32
+ - **Works alongside existing tools** — Complements ESLint's built-in rules and packages like `eslint-plugin-react`, `eslint-plugin-import`, etc.
33
+ - **Consistency at scale** — Reduces code-style differences between team members by enforcing uniform formatting across your projects
34
+ - **Fully automated** — All 47 rules support auto-fix, eliminating manual style reviews
35
+
36
+ When combined with ESLint's native rules and other popular plugins, this package helps create a **complete code style solution** that keeps your codebase clean and consistent.
37
+
38
+ <div align="center">
21
39
 
22
40
  <br />
23
41
 
24
42
  [Installation](#-installation) •
25
43
  [Quick Start](#-quick-start) •
44
+ [Recommended Configs](#-recommended-configurations) •
26
45
  [Rules](#-rules-reference) •
27
- [Examples](#-examples) •
28
46
  [Contributing](#-contributing)
29
47
 
30
48
  </div>
31
49
 
32
50
  <br />
33
51
 
52
+ ## 📁 Recommended Configurations
53
+
54
+ We provide **ready-to-use ESLint flat configuration files** that combine `eslint-plugin-code-style` with carefully selected third-party plugins and ESLint built-in rules. These configurations represent our battle-tested setup that reduces code-style differences by ~95%.
55
+
56
+ ### 💡 Why Use These Configs?
57
+
58
+ - **Complete Coverage** — Combines ESLint built-in rules, third-party plugins, and all 47 code-style rules
59
+ - **Ready-to-Use** — Copy the config file and start linting immediately
60
+ - **Battle-Tested** — These configurations have been refined through real-world usage
61
+ - **Fully Documented** — Each config includes detailed instructions and explanations
62
+
63
+ ### 📋 Available Configurations
64
+
65
+ | Configuration | Description | Link |
66
+ |---------------|-------------|------|
67
+ | **React** | React.js projects (JavaScript, JSX) | [View Config](./recommended-configs/react/) |
68
+ | **React + TS + Tailwind** | React + TypeScript + Tailwind CSS | *Coming Soon* |
69
+ | **Next.js + TS + Tailwind** | Next.js + TypeScript + Tailwind CSS | *Coming Soon* |
70
+
71
+ ### ⚡ Quick Start with Recommended Config
72
+
73
+ 1. Navigate to the [recommended-configs](./recommended-configs/) folder
74
+ 2. Choose the configuration for your project type
75
+ 3. Follow the installation instructions in the README
76
+ 4. Copy the `eslint.config.js` to your project root
77
+ 5. Run `eslint src/ --fix`
78
+
79
+ > **Note:** Each configuration includes a detailed README with installation commands, plugin explanations, and rule documentation.
80
+
81
+ <br />
82
+
34
83
  ---
35
84
 
36
85
  <br />
@@ -41,13 +90,13 @@
41
90
  <tr>
42
91
  <td width="50%">
43
92
 
44
- ### Auto-Fixable Rules
45
- All **45+ rules** support automatic fixing with `eslint --fix`. No manual code changes needed.
93
+ ### 🔧 Auto-Fixable Rules
94
+ All **47 rules** support automatic fixing with `eslint --fix`. No manual code changes needed.
46
95
 
47
96
  </td>
48
97
  <td width="50%">
49
98
 
50
- ### React & JSX Support
99
+ ### ⚛️ React & JSX Support
51
100
  Built specifically for React projects with comprehensive JSX formatting rules.
52
101
 
53
102
  </td>
@@ -55,13 +104,13 @@ Built specifically for React projects with comprehensive JSX formatting rules.
55
104
  <tr>
56
105
  <td width="50%">
57
106
 
58
- ### ESLint v9+ Ready
107
+ ### ESLint v9+ Ready
59
108
  Designed for ESLint's new flat config system. Modern and future-proof.
60
109
 
61
110
  </td>
62
111
  <td width="50%">
63
112
 
64
- ### Zero Dependencies
113
+ ### 📭 Zero Dependencies
65
114
  Lightweight plugin with no external dependencies. Fast and efficient.
66
115
 
67
116
  </td>
@@ -83,12 +132,12 @@ pnpm add eslint-plugin-code-style -D
83
132
  yarn add eslint-plugin-code-style -D
84
133
  ```
85
134
 
86
- ### Requirements
135
+ ### 📋 Requirements
87
136
 
88
137
  | Dependency | Version |
89
138
  |------------|---------|
90
139
  | **ESLint** | `>= 9.0.0` |
91
- | **Node.js** | `>= 24.0.0` |
140
+ | **Node.js** | `>= 18.0.0` |
92
141
 
93
142
  <br />
94
143
 
@@ -126,25 +175,28 @@ eslint src/ --fix
126
175
 
127
176
  ```javascript
128
177
  rules: {
129
- "code-style/absolute-imports-only": "error",
130
178
  "code-style/array-items-per-line": "error",
131
179
  "code-style/array-objects-on-new-lines": "error",
132
180
  "code-style/arrow-function-block-body": "error",
133
181
  "code-style/arrow-function-simple-jsx": "error",
134
182
  "code-style/arrow-function-simplify": "error",
183
+ "code-style/curried-arrow-same-line": "error",
135
184
  "code-style/assignment-value-same-line": "error",
136
185
  "code-style/block-statement-newlines": "error",
137
186
  "code-style/comment-spacing": "error",
138
- "code-style/curried-arrow-same-line": "error",
139
- "code-style/export-format": "error",
140
187
  "code-style/function-call-spacing": "error",
141
188
  "code-style/function-naming-convention": "error",
142
189
  "code-style/function-params-per-line": "error",
143
190
  "code-style/hook-callback-format": "error",
144
191
  "code-style/hook-deps-per-line": "error",
145
192
  "code-style/if-statement-format": "error",
193
+ "code-style/multiline-if-conditions": "error",
194
+ "code-style/absolute-imports-only": "error",
195
+ "code-style/export-format": "error",
146
196
  "code-style/import-format": "error",
147
197
  "code-style/import-source-spacing": "error",
198
+ "code-style/index-export-style": "error",
199
+ "code-style/module-index-exports": "error",
148
200
  "code-style/jsx-children-on-new-line": "error",
149
201
  "code-style/jsx-closing-bracket-spacing": "error",
150
202
  "code-style/jsx-element-child-new-line": "error",
@@ -155,9 +207,7 @@ rules: {
155
207
  "code-style/jsx-string-value-trim": "error",
156
208
  "code-style/jsx-ternary-format": "error",
157
209
  "code-style/member-expression-bracket-spacing": "error",
158
- "code-style/module-index-exports": "error",
159
210
  "code-style/multiline-argument-newline": "error",
160
- "code-style/multiline-if-conditions": "error",
161
211
  "code-style/multiple-arguments-per-line": "error",
162
212
  "code-style/nested-call-closing-brackets": "error",
163
213
  "code-style/no-empty-lines-in-function-calls": "error",
@@ -178,237 +228,1077 @@ rules: {
178
228
 
179
229
  <br />
180
230
 
181
- ## 📖 Rules Reference
182
-
183
- > All rules are **auto-fixable** using `eslint --fix`
231
+ ---
184
232
 
185
- <br />
233
+ ## 📖 Rules Summary
186
234
 
187
- ### 📥 Import/Export Rules
235
+ > All **47 rules** are auto-fixable. See detailed examples for each rule in the [Rules Reference](#-rules-reference) section below.
236
+ >
237
+ > Rules marked with ⚙️ support customization options (e.g., extending default folder lists).
188
238
 
189
239
  | Rule | Description |
190
240
  |------|-------------|
191
- | `absolute-imports-only` | Enforce absolute imports using `@/` alias instead of relative paths |
192
- | `import-format` | Format imports: `import {` on same line, `} from` on same line, collapse 1-3 specifiers |
241
+ | `array-items-per-line` | Enforce array formatting: 3 or less items on one line, more than 3 each on new line |
242
+ | `array-objects-on-new-lines` | Enforce array of objects to have each object on a new line |
243
+ | `arrow-function-block-body` | Enforce parentheses for arrow functions with multiline expressions |
244
+ | `arrow-function-simple-jsx` | Simplify arrow functions returning simple JSX to single line |
245
+ | `arrow-function-simplify` | Simplify arrow functions in JSX props with single statement block body |
246
+ | `curried-arrow-same-line` | Enforce curried arrow function to start on same line as `=>` |
247
+ | `assignment-value-same-line` | Enforce assignment value on same line as equals sign |
248
+ | `block-statement-newlines` | Enforce newlines after opening brace and before closing brace |
249
+ | `comment-spacing` | Enforce comment spacing and formatting |
250
+ | `function-call-spacing` | Enforce no space between function name and opening parenthesis |
251
+ | `function-naming-convention` | Enforce function naming conventions (camelCase, verb prefix) |
252
+ | `function-params-per-line` | Enforce function parameters on separate lines when multiline |
253
+ | `hook-callback-format` | Enforce consistent formatting for React hooks callbacks |
254
+ | `hook-deps-per-line` | Enforce each hook dependency on its own line when more than 2 |
255
+ | `if-statement-format` | Ensure if statement has proper formatting |
256
+ | `multiline-if-conditions` | Enforce multiline if conditions when there are multiple operands |
257
+ | `absolute-imports-only` | Enforce absolute imports using `@/` alias instead of relative paths ⚙️ |
258
+ | `export-format` | Format exports: collapse 1-3 specifiers, multiline for 4+ |
259
+ | `import-format` | Format imports: collapse 1-3 specifiers, multiline for 4+ |
193
260
  | `import-source-spacing` | Enforce no extra spaces inside import path quotes |
194
- | `export-format` | Format exports: `export {` on same line, collapse 1-3 specifiers, multiline for 4+ |
195
- | `module-index-exports` | Enforce proper exports in index files |
261
+ | `index-export-style` | Enforce consistent export style in index files (shorthand or import-then-export) ⚙️ |
262
+ | `module-index-exports` | Enforce proper exports in index files ⚙️ |
263
+ | `jsx-children-on-new-line` | Enforce JSX children on separate lines from parent tags |
264
+ | `jsx-closing-bracket-spacing` | No space before `>` or `/>` in JSX tags |
265
+ | `jsx-element-child-new-line` | JSX element children must be on new lines |
266
+ | `jsx-logical-expression-simplify` | Simplify logical expressions in JSX |
267
+ | `jsx-parentheses-position` | Enforce opening parenthesis position for JSX in arrow functions |
268
+ | `jsx-prop-naming-convention` | Enforce JSX prop naming conventions (camelCase) |
269
+ | `jsx-simple-element-one-line` | Simple JSX elements with single child on one line |
270
+ | `jsx-string-value-trim` | Disallow leading/trailing whitespace in JSX string values |
271
+ | `jsx-ternary-format` | Enforce consistent formatting for JSX ternary expressions |
272
+ | `member-expression-bracket-spacing` | Enforce no spaces inside brackets for member expressions |
273
+ | `multiline-argument-newline` | Enforce newlines for function calls with multiline arguments |
274
+ | `multiple-arguments-per-line` | Enforce multiple arguments to each be on their own line |
275
+ | `nested-call-closing-brackets` | Enforce nested function call closing brackets on same line |
276
+ | `no-empty-lines-in-function-calls` | Disallow empty lines in function calls |
277
+ | `no-empty-lines-in-function-params` | Disallow empty lines in function parameters |
278
+ | `no-empty-lines-in-jsx` | Disallow empty lines inside JSX elements |
279
+ | `no-empty-lines-in-objects` | Disallow empty lines inside objects |
280
+ | `no-empty-lines-in-switch-cases` | Prevent empty lines at the beginning of switch case logic |
281
+ | `object-property-per-line` | Enforce each property on its own line when object has 2+ properties |
282
+ | `object-property-value-brace` | Enforce opening brace on same line as colon for object values |
283
+ | `object-property-value-format` | Enforce property value on same line as colon |
284
+ | `opening-brackets-same-line` | Enforce opening brackets on same line for function calls |
285
+ | `simple-call-single-line` | Simplify simple function calls with arrow function to single line |
286
+ | `single-argument-on-one-line` | Enforce single simple argument calls to be on one line |
287
+ | `string-property-spacing` | Enforce no extra spaces inside string property keys |
288
+ | `variable-naming-convention` | Enforce variable naming conventions (camelCase, UPPER_CASE, PascalCase) |
196
289
 
197
290
  <br />
198
291
 
199
- ### ⚡ Function Rules
292
+ ---
200
293
 
201
- | Rule | Description |
202
- |------|-------------|
203
- | `arrow-function-block-body` | Enforce parentheses for arrow functions with multiline expressions |
204
- | `arrow-function-simplify` | Simplify arrow functions returning simple JSX to single line |
205
- | `arrow-function-simple-jsx` | Simplify arrow functions in JSX props with single statement block body |
206
- | `function-call-spacing` | Enforce no space between function name and opening parenthesis |
207
- | `function-naming-convention` | Enforce function naming conventions (camelCase) |
208
- | `function-params-per-line` | Enforce function parameters on separate lines when more than 2 |
209
- | `curried-arrow-same-line` | Enforce curried arrow function to start on same line as `=>` |
294
+ ## 📖 Rules Reference
295
+
296
+ > All rules are **auto-fixable** using `eslint --fix`
210
297
 
211
298
  <br />
212
299
 
213
- ### 📦 Object Rules
300
+ ## 📚 Array Rules
214
301
 
215
- | Rule | Description |
216
- |------|-------------|
217
- | `object-property-per-line` | Enforce each property on its own line when object has 2+ properties |
218
- | `object-property-value-format` | Enforce property value on same line as colon with proper spacing |
219
- | `object-property-value-brace` | Enforce opening brace on same line as colon for object property values |
220
- | `no-empty-lines-in-objects` | Disallow empty lines inside objects |
221
- | `string-property-spacing` | Enforce no extra spaces inside string property keys |
302
+ ### `array-items-per-line`
222
303
 
223
- <br />
304
+ Enforce array formatting based on item count. 3 or less items on one line, more than 3 items each on its own line.
224
305
 
225
- ### 📚 Array Rules
306
+ ```javascript
307
+ // Good
308
+ const arr = [1, 2, 3];
309
+ const arr = [
310
+ item1,
311
+ item2,
312
+ item3,
313
+ item4,
314
+ ];
226
315
 
227
- | Rule | Description |
228
- |------|-------------|
229
- | `array-items-per-line` | Enforce array formatting: 3 or less items on one line, more than 3 each on new line |
230
- | `array-objects-on-new-lines` | Enforce array of objects to have each object on a new line |
316
+ // Bad
317
+ const arr = [1, 2, 3, 4, 5];
318
+ const arr = [item1,
319
+ item2, item3];
320
+ ```
321
+
322
+ ---
323
+
324
+ ### `array-objects-on-new-lines`
325
+
326
+ In arrays of objects, each object should start on a new line for better readability.
327
+
328
+ ```javascript
329
+ // Good
330
+ const items = [
331
+ { id: 1, name: "first" },
332
+ { id: 2, name: "second" },
333
+ ];
334
+
335
+ // Bad
336
+ const items = [{ id: 1, name: "first" },
337
+ { id: 2, name: "second" }];
338
+ ```
231
339
 
232
340
  <br />
233
341
 
234
- ### ⚛️ JSX Rules
342
+ ## ➡️ Arrow Function Rules
235
343
 
236
- | Rule | Description |
237
- |------|-------------|
238
- | `jsx-children-on-new-line` | Enforce JSX children on separate lines from parent tags |
239
- | `jsx-closing-bracket-spacing` | No space before `>` or `/>` in JSX tags |
240
- | `jsx-element-child-new-line` | JSX children that are JSX elements must be on new lines |
241
- | `jsx-logical-expression-simplify` | Simplify logical expressions in JSX when right side is single-line |
242
- | `jsx-parentheses-position` | Enforce opening parenthesis position for JSX in arrow functions |
243
- | `jsx-prop-naming-convention` | Enforce JSX prop naming conventions (camelCase) |
244
- | `jsx-simple-element-one-line` | Simple JSX elements with only text/expression children on one line |
245
- | `jsx-string-value-trim` | Disallow leading/trailing whitespace in JSX string values |
246
- | `jsx-ternary-format` | Enforce consistent formatting for JSX ternary expressions |
247
- | `no-empty-lines-in-jsx` | Disallow empty lines inside JSX elements |
344
+ ### `arrow-function-block-body`
345
+
346
+ Arrow functions with complex logic should use block body. Ensures consistent formatting when function body needs multiple statements or complex expressions.
347
+
348
+ ```javascript
349
+ // Good
350
+ () => {
351
+ doSomething();
352
+ return value;
353
+ }
354
+
355
+ // Bad
356
+ () => (doSomething(), value)
357
+ ```
358
+
359
+ ---
360
+
361
+ ### `arrow-function-simple-jsx`
362
+
363
+ Simplify arrow functions returning simple JSX to single line by removing unnecessary parentheses and line breaks.
364
+
365
+ ```javascript
366
+ // Good
367
+ export const X = ({ children }) => <Sidebar>{children}</Sidebar>;
368
+
369
+ // Bad
370
+ export const X = ({ children }) => (
371
+ <Sidebar>{children}</Sidebar>
372
+ );
373
+ ```
374
+
375
+ ---
376
+
377
+ ### `arrow-function-simplify`
378
+
379
+ Simplify arrow functions that have a single return statement by using implicit return instead of block body.
380
+
381
+ ```javascript
382
+ // Good
383
+ () => value
384
+ (x) => x * 2
385
+ items.map(item => item.name)
386
+
387
+ // Bad
388
+ () => { return value; }
389
+ (x) => { return x * 2; }
390
+ items.map(item => { return item.name; })
391
+ ```
392
+
393
+ ---
394
+
395
+ ### `curried-arrow-same-line`
396
+
397
+ Curried arrow function body must start on the same line as the arrow (=>), not on a new line.
398
+
399
+ ```javascript
400
+ // Good
401
+ const fn = () => async (dispatch) => {
402
+ dispatch(action);
403
+ };
404
+
405
+ // Bad
406
+ const fn = () =>
407
+ async (dispatch) => {
408
+ dispatch(action);
409
+ };
410
+ ```
248
411
 
249
412
  <br />
250
413
 
251
- ### 📞 Call Expression Rules
414
+ ## 📐 Spacing & Formatting Rules
252
415
 
253
- | Rule | Description |
254
- |------|-------------|
255
- | `simple-call-single-line` | Simplify simple function calls with arrow function to single line |
256
- | `single-argument-on-line` | Enforce single simple argument calls to be on one line |
257
- | `multiple-arguments-per-line` | Enforce multiple arguments to each be on their own line |
258
- | `multiline-argument-newline` | Enforce newlines for function calls with multiline arguments |
259
- | `nested-call-closing-brackets` | Enforce nested function call closing brackets on same line |
260
- | `no-empty-lines-in-function-calls` | Disallow empty lines in function calls |
261
- | `opening-brackets-same-line` | Enforce opening brackets on same line for function calls |
416
+ ### `assignment-value-same-line`
417
+
418
+ The value in an assignment should start on the same line as the equals sign, not on a new line.
419
+
420
+ ```javascript
421
+ // Good
422
+ const name = "John";
423
+ const data = {
424
+ key: "value",
425
+ };
426
+
427
+ // Bad
428
+ const name =
429
+ "John";
430
+ const data =
431
+ {
432
+ key: "value",
433
+ };
434
+ ```
435
+
436
+ ---
437
+
438
+ ### `block-statement-newlines`
439
+
440
+ Block statements should have proper newlines after the opening brace and before the closing brace.
441
+
442
+ ```javascript
443
+ // Good
444
+ if (condition) {
445
+ doSomething();
446
+ }
447
+
448
+ // Bad
449
+ if (condition) { doSomething(); }
450
+ if (condition) {doSomething();}
451
+ ```
452
+
453
+ ---
454
+
455
+ ### `comment-spacing`
456
+
457
+ Comments should have proper spacing: a space after the opening delimiter (// or block comment opener), and proper blank lines around comment blocks.
458
+
459
+ ```javascript
460
+ // Good
461
+ // This is a comment
462
+ /* This is a block comment */
463
+
464
+ // Bad
465
+ //This is a comment (missing space)
466
+ /*No space after opener*/
467
+ ```
468
+
469
+ ---
470
+
471
+ ### `member-expression-bracket-spacing`
472
+
473
+ No spaces inside brackets in computed member expressions. The property name should touch both brackets.
474
+
475
+ ```javascript
476
+ // Good
477
+ arr[value]
478
+ obj[key]
479
+
480
+ // Bad
481
+ arr[ value ]
482
+ obj[ key ]
483
+ ```
484
+
485
+ ---
486
+
487
+ ### `no-empty-lines-in-function-params`
488
+
489
+ Function parameter lists should not contain empty lines between parameters or after opening/before closing parens.
490
+
491
+ ```javascript
492
+ // Good
493
+ function test(
494
+ param1,
495
+ param2,
496
+ ) {}
497
+
498
+ // Bad
499
+ function test(
500
+ param1,
501
+
502
+ param2,
503
+ ) {}
504
+ ```
505
+
506
+ ---
507
+
508
+ ### `variable-naming-convention`
509
+
510
+ Variable names should follow naming conventions: camelCase for regular variables, UPPER_CASE for constants, and PascalCase for React components.
511
+
512
+ ```javascript
513
+ // Good
514
+ const userName = "John";
515
+ const MAX_RETRIES = 3;
516
+ const UserProfile = () => <div />;
517
+ const useCustomHook = () => {};
518
+
519
+ // Bad
520
+ const user_name = "John";
521
+ const maxretries = 3;
522
+ const userProfile = () => <div />;
523
+ ```
262
524
 
263
525
  <br />
264
526
 
265
- ### 🪝 React Hooks Rules
527
+ ## Function Rules
266
528
 
267
- | Rule | Description |
268
- |------|-------------|
269
- | `hook-callback-format` | Enforce consistent formatting for React hooks (useEffect, useCallback, etc.) |
270
- | `hook-deps-per-line` | Enforce each hook dependency on its own line when more than 2 dependencies |
529
+ ### `function-call-spacing`
530
+
531
+ No space between function name and opening parenthesis.
532
+
533
+ ```javascript
534
+ // Good
535
+ useDispatch()
536
+ myFunction(arg)
537
+
538
+ // Bad
539
+ useDispatch ()
540
+ myFunction (arg)
541
+ ```
542
+
543
+ ---
544
+
545
+ ### `function-naming-convention`
546
+
547
+ Function names should follow naming conventions: camelCase, starting with a verb, and handlers ending with "Handler".
548
+
549
+ ```javascript
550
+ // Good
551
+ function getUserData() {}
552
+ function handleClick() {}
553
+ function isValidEmail() {}
554
+ const submitHandler = () => {}
555
+
556
+ // Bad
557
+ function GetUserData() {}
558
+ function user_data() {}
559
+ function click() {}
560
+ ```
561
+
562
+ ---
563
+
564
+ ### `function-params-per-line`
565
+
566
+ When function parameters span multiple lines, each parameter should be on its own line with consistent indentation.
567
+
568
+ ```javascript
569
+ // Good
570
+ function test(
571
+ param1,
572
+ param2,
573
+ param3,
574
+ ) {}
575
+
576
+ // Bad
577
+ function test(param1,
578
+ param2, param3) {}
579
+ ```
271
580
 
272
581
  <br />
273
582
 
274
- ### 🔀 Control Flow Rules
583
+ ## 🪝 React Hooks Rules
275
584
 
276
- | Rule | Description |
277
- |------|-------------|
278
- | `if-statement-format` | Ensure if statement has proper formatting |
279
- | `multiline-if-conditions` | Enforce multiline if conditions when there are more than 3 operands |
280
- | `no-empty-lines-in-switch-cases` | Prevent empty lines at the beginning of switch case logic |
585
+ ### `hook-callback-format`
586
+
587
+ Enforce consistent formatting for React hooks like useEffect, useCallback, useMemo with callback and dependency array.
588
+
589
+ ```javascript
590
+ // Good
591
+ useEffect(
592
+ () => { doSomething(); },
593
+ [dep1, dep2],
594
+ );
595
+
596
+ // Bad
597
+ useEffect(() => { doSomething(); }, [dep1, dep2]);
598
+ ```
599
+
600
+ ---
601
+
602
+ ### `hook-deps-per-line`
603
+
604
+ React hook dependency arrays with more than 2 dependencies should have each dependency on its own line.
605
+
606
+ ```javascript
607
+ // Good
608
+ useEffect(() => {}, [dep1, dep2])
609
+ useEffect(() => {}, [
610
+ dep1,
611
+ dep2,
612
+ dep3,
613
+ ])
614
+
615
+ // Bad
616
+ useEffect(() => {}, [dep1, dep2, dep3, dep4])
617
+ ```
281
618
 
282
619
  <br />
283
620
 
284
- ### 📐 Spacing & Formatting Rules
621
+ ## 🔀 Control Flow Rules
285
622
 
286
- | Rule | Description |
287
- |------|-------------|
288
- | `assignment-value-same-line` | Enforce assignment value on same line as equals sign |
289
- | `block-statement-newlines` | Enforce newlines after opening brace and before closing brace |
290
- | `comment-spacing` | Enforce comment spacing and formatting |
291
- | `member-expression-bracket-spacing` | Enforce no spaces inside brackets for member expressions |
292
- | `no-empty-lines-in-function-params` | Disallow empty lines in function parameters |
293
- | `variable-naming-convention` | Enforce variable naming conventions (camelCase) |
623
+ ### `if-statement-format`
624
+
625
+ If statements should have consistent formatting with the opening brace on the same line as the condition and else on the same line as the closing brace.
626
+
627
+ ```javascript
628
+ // Good
629
+ if (condition) {
630
+ doSomething();
631
+ } else {
632
+ doOther();
633
+ }
634
+
635
+ // Bad
636
+ if (condition)
637
+ {
638
+ doSomething();
639
+ }
640
+ else
641
+ {
642
+ doOther();
643
+ }
644
+ ```
645
+
646
+ ---
647
+
648
+ ### `multiline-if-conditions`
649
+
650
+ When an if statement has multiple conditions that span multiple lines, each condition should be on its own line.
651
+
652
+ ```javascript
653
+ // Good
654
+ if (
655
+ conditionA &&
656
+ conditionB &&
657
+ conditionC
658
+ ) {}
659
+
660
+ // Bad
661
+ if (conditionA &&
662
+ conditionB && conditionC) {}
663
+ ```
664
+
665
+ ---
666
+
667
+ ### `no-empty-lines-in-switch-cases`
668
+
669
+ Switch case blocks should not have empty lines at the beginning of the case logic or between consecutive cases.
670
+
671
+ ```javascript
672
+ // Good
673
+ switch (value) {
674
+ case 1:
675
+ return "one";
676
+ case 2:
677
+ return "two";
678
+ }
679
+
680
+ // Bad
681
+ switch (value) {
682
+ case 1:
683
+
684
+ return "one";
685
+
686
+ case 2:
687
+ return "two";
688
+ }
689
+ ```
294
690
 
295
691
  <br />
296
692
 
297
- ## 💡 Examples
693
+ ## 📥 Import/Export Rules
298
694
 
299
- ### Import Formatting
695
+ ### `absolute-imports-only`
696
+
697
+ Enforce absolute imports from index files only for local paths. Local paths (starting with @/) should only import from folder-level index files.
300
698
 
301
699
  ```javascript
302
- // Good - 3 or fewer specifiers on one line
303
- import { Box, Button, Grid } from "@mui/material";
700
+ // Good
701
+ import { Button } from "@/components";
702
+ import { useAuth } from "@/hooks";
703
+
704
+ // Bad
705
+ import { Button } from "@/components/buttons/primary-button";
706
+ import { useAuth } from "@/hooks/auth/useAuth";
707
+ ```
708
+
709
+ **Default Allowed Folders:**
710
+ `actions`, `apis`, `assets`, `atoms`, `components`, `constants`, `contexts`, `data`, `hooks`, `layouts`, `middlewares`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `utils`, `views`
711
+
712
+ **Customization Options:**
713
+
714
+ | Option | Type | Description |
715
+ |--------|------|-------------|
716
+ | `extraAllowedFolders` | `string[]` | Add extra folders to the default list |
717
+ | `extraReduxSubfolders` | `string[]` | Add extra redux subfolders (default: `actions`, `reducers`, `store`, `thunks`, `types`) |
718
+ | `extraDeepImportFolders` | `string[]` | Add extra folders that allow deep imports (default: `assets`) |
719
+ | `aliasPrefix` | `string` | Change the import alias prefix (default: `@/`) |
720
+ | `allowedFolders` | `string[]` | Replace default folders entirely |
721
+ | `reduxSubfolders` | `string[]` | Replace default redux subfolders entirely |
722
+ | `deepImportFolders` | `string[]` | Replace default deep import folders entirely |
304
723
 
305
- // ✅ Good - 4+ specifiers on multiple lines
724
+ ```javascript
725
+ // Example: Add custom folders to the defaults
726
+ "code-style/absolute-imports-only": ["error", {
727
+ extraAllowedFolders: ["features", "modules", "lib"],
728
+ extraDeepImportFolders: ["images", "fonts"]
729
+ }]
730
+ ```
731
+
732
+ ---
733
+
734
+ ### `export-format`
735
+
736
+ Export statements should have consistent formatting with proper spacing. Collapse 1-3 specifiers on one line, use multiline for 4+ specifiers.
737
+
738
+ ```javascript
739
+ // Good
740
+ export { a, b, c };
741
+ export {
742
+ a,
743
+ b,
744
+ c,
745
+ d,
746
+ };
747
+
748
+ // Bad
749
+ export {a,b,c};
750
+ export { a, b, c, d, e };
751
+ ```
752
+
753
+ ---
754
+
755
+ ### `import-format`
756
+
757
+ Import statements should have consistent formatting with proper spacing. Collapse 1-3 specifiers on one line, use multiline for 4+ specifiers.
758
+
759
+ ```javascript
760
+ // Good
761
+ import { a, b, c } from "module";
306
762
  import {
307
- Box,
763
+ a,
764
+ b,
765
+ c,
766
+ d,
767
+ } from "module";
768
+
769
+ // Bad
770
+ import {a,b,c} from "module";
771
+ import { a, b, c, d, e } from "module";
772
+ ```
773
+
774
+ ---
775
+
776
+ ### `import-source-spacing`
777
+
778
+ No spaces inside import path quotes. The module path should not have leading or trailing whitespace.
779
+
780
+ ```javascript
781
+ // Good
782
+ import { Button } from "@mui/material";
783
+
784
+ // Bad
785
+ import { Button } from " @mui/material ";
786
+ ```
787
+
788
+ ---
789
+
790
+ ### `index-export-style`
791
+
792
+ Enforce consistent export style in index files. Choose between shorthand re-exports or import-then-export pattern.
793
+
794
+ **Style: "shorthand" (default)**
795
+ ```javascript
796
+ // Good - shorthand re-exports
797
+ export { Button } from "./button";
798
+ export { Input, Select } from "./form";
799
+ export { StyledCard, StyledCardWithActions } from "./card";
800
+ ```
801
+
802
+ **Style: "import-export"**
803
+ ```javascript
804
+ // Good - import then export
805
+ import { Button } from "./button";
806
+ import { Input, Select } from "./form";
807
+ import { StyledCard, StyledCardWithActions } from "./card";
808
+
809
+ export {
308
810
  Button,
309
- Grid,
310
- Typography,
311
- } from "@mui/material";
811
+ Input,
812
+ Select,
813
+ StyledCard,
814
+ StyledCardWithActions,
815
+ };
816
+ ```
312
817
 
313
- // Bad
314
- import {
315
- Box, Button, Grid } from "@mui/material";
818
+ **Bad - mixing styles**
819
+ ```javascript
820
+ // Bad - don't mix shorthand with import-then-export
821
+ export { Button } from "./button";
822
+ import { Input } from "./input";
823
+ export { Input };
316
824
  ```
317
825
 
318
- <br />
826
+ **Customization Options:**
319
827
 
320
- ### Function Parameters
828
+ | Option | Type | Default | Description |
829
+ |--------|------|---------|-------------|
830
+ | `style` | `"shorthand"` \| `"import-export"` | `"shorthand"` | The export style to enforce |
321
831
 
322
832
  ```javascript
323
- // Good - 2 or fewer params on one line
324
- const fn = (a, b) => {};
833
+ // Example: Use shorthand style (default)
834
+ "code-style/index-export-style": "error"
325
835
 
326
- // Good - 3+ params on separate lines
327
- const fn = (
328
- param1,
329
- param2,
330
- param3,
331
- ) => {};
836
+ // Example: Use import-then-export style
837
+ "code-style/index-export-style": ["error", { style: "import-export" }]
838
+ ```
839
+
840
+ ---
841
+
842
+ ### `module-index-exports`
843
+
844
+ Ensure module folders have index files that export all contents. Each module folder must have an index file that exports all subfolders and files in the module.
845
+
846
+ ```javascript
847
+ // Good
848
+ // index.js
849
+ export { Button } from "./Button";
850
+ export { Input } from "./Input";
851
+
852
+ // Bad
853
+ // Missing exports in index.js
854
+ ```
855
+
856
+ **Default Module Folders:**
857
+ `apis`, `assets`, `atoms`, `components`, `constants`, `contexts`, `data`, `hooks`, `layouts`, `middlewares`, `providers`, `redux`, `requests`, `routes`, `schemas`, `services`, `styles`, `theme`, `utils`, `views`
332
858
 
333
- // ❌ Bad
334
- const fn = (param1, param2, param3) => {};
859
+ **Customization Options:**
860
+
861
+ | Option | Type | Description |
862
+ |--------|------|-------------|
863
+ | `extraModuleFolders` | `string[]` | Add extra module folders to the default list |
864
+ | `extraLazyLoadFolders` | `string[]` | Add extra lazy load folders (default: `views`) |
865
+ | `extraIgnorePatterns` | `string[]` | Add extra ignore patterns (supports wildcards like `*.stories.js`) |
866
+ | `moduleFolders` | `string[]` | Replace default module folders entirely |
867
+ | `lazyLoadFolders` | `string[]` | Replace default lazy load folders entirely |
868
+ | `ignorePatterns` | `string[]` | Replace default ignore patterns entirely |
869
+
870
+ **Default Ignore Patterns:**
871
+ `index.js`, `index.jsx`, `index.ts`, `index.tsx`, `.DS_Store`, `__tests__`, `__mocks__`, `*.test.js`, `*.test.jsx`, `*.spec.js`, `*.spec.jsx`
872
+
873
+ ```javascript
874
+ // Example: Add custom folders and patterns to the defaults
875
+ "code-style/module-index-exports": ["error", {
876
+ extraModuleFolders: ["features", "modules", "lib"],
877
+ extraLazyLoadFolders: ["pages"],
878
+ extraIgnorePatterns: ["*.stories.js", "*.mock.js"]
879
+ }]
335
880
  ```
336
881
 
337
882
  <br />
338
883
 
339
- ### JSX Ternary
884
+ ## ⚛️ JSX Rules
885
+
886
+ ### `jsx-children-on-new-line`
887
+
888
+ When a JSX element has multiple children, each child should be on its own line with proper indentation.
340
889
 
341
890
  ```javascript
342
- // Good - Simple ternary on one line
343
- {condition ? <Simple /> : <Other />}
891
+ // Good
892
+ <Container>
893
+ <Header />
894
+ <Content />
895
+ <Footer />
896
+ </Container>
897
+
898
+ // Bad
899
+ <Container><Header /><Content />
900
+ <Footer /></Container>
901
+ ```
902
+
903
+ ---
904
+
905
+ ### `jsx-closing-bracket-spacing`
906
+
907
+ No space before > or /> in JSX tags. The closing bracket should be directly after the last attribute or tag name.
344
908
 
345
- // ✅ Good - Complex ternary with proper formatting
346
- {condition ? (
909
+ ```javascript
910
+ // Good
911
+ <Button />
912
+ <Button className="primary">
913
+
914
+ // Bad
915
+ <Button / >
916
+ <Button className="primary" >
917
+ ```
918
+
919
+ ---
920
+
921
+ ### `jsx-element-child-new-line`
922
+
923
+ JSX element children (nested JSX elements) must be on their own line, not on the same line as the opening tag.
924
+
925
+ ```javascript
926
+ // Good
927
+ <Button>
928
+ <Icon />
929
+ </Button>
930
+
931
+ // Bad
932
+ <Button><Icon /></Button>
933
+ ```
934
+
935
+ ---
936
+
937
+ ### `jsx-logical-expression-simplify`
938
+
939
+ Simplify JSX logical expressions by removing unnecessary parentheses around conditions and JSX elements.
940
+
941
+ ```javascript
942
+ // Good
943
+ {condition && <Component />}
944
+ {isVisible && <Modal />}
945
+
946
+ // Bad
947
+ {(condition) && (<Component />)}
948
+ {(isVisible) && (<Modal />)}
949
+ ```
950
+
951
+ ---
952
+
953
+ ### `jsx-parentheses-position`
954
+
955
+ JSX return parentheses should be on the same line as the arrow or return keyword, not on a new line.
956
+
957
+ ```javascript
958
+ // Good
959
+ const Component = () => (
960
+ <div>content</div>
961
+ );
962
+ return (
963
+ <div>content</div>
964
+ );
965
+
966
+ // Bad
967
+ const Component = () =>
968
+ (
969
+ <div>content</div>
970
+ );
971
+ return
972
+ (
973
+ <div>content</div>
974
+ );
975
+ ```
976
+
977
+ ---
978
+
979
+ ### `jsx-prop-naming-convention`
980
+
981
+ Enforce camelCase naming for JSX props. Allows PascalCase for component reference props, and kebab-case for data-* and aria-*.
982
+
983
+ ```javascript
984
+ // Good
985
+ <Button onClick={handler} />
986
+ <Input data-testid="input" />
987
+ <Modal ContentComponent={Panel} />
988
+
989
+ // Bad
990
+ <Button on_click={handler} />
991
+ <Input test_id="input" />
992
+ ```
993
+
994
+ ---
995
+
996
+ ### `jsx-simple-element-one-line`
997
+
998
+ Simple JSX elements with only a single text or expression child should be collapsed onto a single line.
999
+
1000
+ ```javascript
1001
+ // Good
1002
+ <Button>{buttonLinkText}</Button>
1003
+ <Title>Hello</Title>
1004
+
1005
+ // Bad
1006
+ <Button>
1007
+ {buttonLinkText}
1008
+ </Button>
1009
+ ```
1010
+
1011
+ ---
1012
+
1013
+ ### `jsx-string-value-trim`
1014
+
1015
+ JSX string attribute values should not have leading or trailing whitespace inside the quotes.
1016
+
1017
+ ```javascript
1018
+ // Good
1019
+ className="button"
1020
+ title="Hello World"
1021
+
1022
+ // Bad
1023
+ className=" button "
1024
+ title=" Hello World "
1025
+ ```
1026
+
1027
+ ---
1028
+
1029
+ ### `jsx-ternary-format`
1030
+
1031
+ Format ternary expressions in JSX with proper structure. Simple branches stay on one line, complex branches get parentheses with proper indentation.
1032
+
1033
+ ```javascript
1034
+ // Good
1035
+ {condition ? <Simple /> : <Other />}
1036
+ {condition ? <Simple /> : (
347
1037
  <Complex>
348
- <Children />
1038
+ <Child />
349
1039
  </Complex>
350
- ) : (
351
- <Alternative>
352
- <Content />
353
- </Alternative>
354
1040
  )}
355
1041
 
356
- // Bad - Empty lines inside ternary
357
- {condition ? (
1042
+ // Bad
1043
+ {condition
1044
+ ? <Simple />
1045
+ : <Other />}
1046
+ ```
358
1047
 
359
- <Button />
1048
+ ---
360
1049
 
361
- ) : (
1050
+ ### `no-empty-lines-in-jsx`
362
1051
 
363
- <Link />
1052
+ JSX elements should not contain empty lines between children or after opening/before closing tags.
364
1053
 
365
- )}
1054
+ ```javascript
1055
+ // Good
1056
+ <div>
1057
+ <span>text</span>
1058
+ <span>more</span>
1059
+ </div>
1060
+
1061
+ // Bad
1062
+ <div>
1063
+
1064
+ <span>text</span>
1065
+
1066
+ <span>more</span>
1067
+
1068
+ </div>
366
1069
  ```
367
1070
 
368
1071
  <br />
369
1072
 
370
- ### React Hooks
1073
+ ## 📞 Call Expression Rules
1074
+
1075
+ ### `multiline-argument-newline`
1076
+
1077
+ When function arguments span multiple lines, each argument should start on its own line with consistent indentation.
371
1078
 
372
1079
  ```javascript
373
- // Good
374
- useEffect(
375
- () => {
376
- doSomething();
377
- },
378
- [dependency],
1080
+ // Good
1081
+ fn(
1082
+ arg1,
1083
+ arg2,
1084
+ )
1085
+
1086
+ // Bad
1087
+ fn(arg1,
1088
+ arg2)
1089
+ ```
1090
+
1091
+ ---
1092
+
1093
+ ### `multiple-arguments-per-line`
1094
+
1095
+ When a function call has 2+ arguments, each argument should be on its own line with proper indentation.
1096
+
1097
+ ```javascript
1098
+ // Good
1099
+ setValue(
1100
+ "numberOfCopies",
1101
+ null,
1102
+ )
1103
+
1104
+ // Bad
1105
+ setValue("numberOfCopies", null)
1106
+ ```
1107
+
1108
+ ---
1109
+
1110
+ ### `nested-call-closing-brackets`
1111
+
1112
+ Nested function calls (like styled-components) should have closing brackets on the same line: }));
1113
+
1114
+ ```javascript
1115
+ // Good
1116
+ styled(Card)(({ theme }) => ({
1117
+ color: theme.color,
1118
+ }));
1119
+
1120
+ // Bad
1121
+ styled(Card)(({ theme }) => ({
1122
+ color: theme.color,
1123
+ })
379
1124
  );
1125
+ ```
380
1126
 
381
- // ✅ Good - Simple callback
382
- useEffect(() => doSomething(), []);
1127
+ ---
383
1128
 
384
- // ❌ Bad
385
- useEffect(() => {
386
- doSomething();
387
- }, [dependency]);
1129
+ ### `no-empty-lines-in-function-calls`
1130
+
1131
+ Function call arguments should not have empty lines between them or after opening/before closing parentheses.
1132
+
1133
+ ```javascript
1134
+ // Good
1135
+ fn(
1136
+ arg1,
1137
+ arg2,
1138
+ )
1139
+
1140
+ // Bad
1141
+ fn(
1142
+ arg1,
1143
+
1144
+ arg2,
1145
+ )
1146
+ ```
1147
+
1148
+ ---
1149
+
1150
+ ### `opening-brackets-same-line`
1151
+
1152
+ Opening brackets should be on the same line as function/method calls. This applies to objects, arrays, and arrow function parameters.
1153
+
1154
+ ```javascript
1155
+ // Good
1156
+ fn({ prop: value })
1157
+ .map(({ x }) => x)
1158
+ fn([1, 2, 3])
1159
+
1160
+ // Bad
1161
+ fn(
1162
+ { prop: value }
1163
+ )
1164
+ .map(
1165
+ ({ x }) => x
1166
+ )
1167
+ ```
1168
+
1169
+ ---
1170
+
1171
+ ### `simple-call-single-line`
1172
+
1173
+ Simple function calls with an arrow function containing a simple call expression should be on a single line.
1174
+
1175
+ ```javascript
1176
+ // Good
1177
+ fn(() => call(arg))
1178
+ lazy(() => import("./module"))
1179
+
1180
+ // Bad
1181
+ fn(
1182
+ () => call(arg),
1183
+ )
1184
+ ```
1185
+
1186
+ ---
1187
+
1188
+ ### `single-argument-on-one-line`
1189
+
1190
+ Function calls with a single simple argument (literal, identifier, member expression) should be on one line.
1191
+
1192
+ ```javascript
1193
+ // Good
1194
+ fn(arg)
1195
+ getValue("key")
1196
+ obj.method(value)
1197
+
1198
+ // Bad
1199
+ fn(
1200
+ arg,
1201
+ )
388
1202
  ```
389
1203
 
390
1204
  <br />
391
1205
 
392
- ### Multiline Conditions
1206
+ ## 📦 Object Rules
1207
+
1208
+ ### `no-empty-lines-in-objects`
1209
+
1210
+ Object literals should not contain empty lines between properties or after opening/before closing braces.
393
1211
 
394
1212
  ```javascript
395
- // Good - 3 or fewer operands on one line
396
- if (a && b && c) {}
1213
+ // Good
1214
+ {
1215
+ a: 1,
1216
+ b: 2,
1217
+ }
397
1218
 
398
- // ✅ Good - 4+ operands on multiple lines
399
- if (
400
- condition1
401
- && condition2
402
- && condition3
403
- && condition4
404
- ) {}
1219
+ // Bad
1220
+ {
1221
+ a: 1,
1222
+
1223
+ b: 2,
1224
+ }
1225
+ ```
1226
+
1227
+ ---
1228
+
1229
+ ### `object-property-per-line`
1230
+
1231
+ When an object has 2 or more properties and spans multiple lines, each property should be on its own line.
405
1232
 
406
- // ❌ Bad
407
- if (condition1 && condition2 && condition3 && condition4) {}
1233
+ ```javascript
1234
+ // Good
1235
+ {
1236
+ name: "John",
1237
+ age: 30,
1238
+ }
1239
+
1240
+ // Bad
1241
+ { name: "John",
1242
+ age: 30 }
1243
+ ```
1244
+
1245
+ ---
1246
+
1247
+ ### `object-property-value-brace`
1248
+
1249
+ Opening brace of an object value should be on the same line as the colon, not on a new line.
1250
+
1251
+ ```javascript
1252
+ // Good
1253
+ "& a": { color: "red" }
1254
+
1255
+ // Bad
1256
+ "& a":
1257
+ { color: "red" }
1258
+ ```
1259
+
1260
+ ---
1261
+
1262
+ ### `object-property-value-format`
1263
+
1264
+ Object property values should be on the same line as the colon with proper spacing for simple values.
1265
+
1266
+ ```javascript
1267
+ // Good
1268
+ {
1269
+ name: "John",
1270
+ age: 30,
1271
+ }
1272
+
1273
+ // Bad
1274
+ {
1275
+ name:
1276
+ "John",
1277
+ age:
1278
+ 30,
1279
+ }
1280
+ ```
1281
+
1282
+ ---
1283
+
1284
+ ### `string-property-spacing`
1285
+
1286
+ String property keys should not have extra leading or trailing spaces inside the quotes.
1287
+
1288
+ ```javascript
1289
+ // Good
1290
+ { "& a": value }
1291
+ { "selector": value }
1292
+
1293
+ // Bad
1294
+ { " & a ": value }
1295
+ { " selector ": value }
408
1296
  ```
409
1297
 
410
1298
  <br />
411
1299
 
1300
+ ---
1301
+
412
1302
  ## 🔧 Auto-fixing
413
1303
 
414
1304
  All rules support auto-fixing. Run ESLint with the `--fix` flag: