eslint-plugin-code-style 1.11.7 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +122 -0
- package/README.md +320 -7
- package/index.d.ts +5 -0
- package/index.js +1440 -204
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,122 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.14.0] - 2026-02-05
|
|
11
|
+
|
|
12
|
+
**New Rule: useState Naming Convention**
|
|
13
|
+
|
|
14
|
+
**Version Range:** v1.13.0 → v1.14.0
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
**New Rules (1)**
|
|
19
|
+
- `use-state-naming-convention` - Enforce boolean useState variables to start with valid prefixes 🔧
|
|
20
|
+
- Boolean state must start with: `is`, `has`, `with`, `without` (configurable)
|
|
21
|
+
- Auto-fixes both state variable and setter function names, plus all usages
|
|
22
|
+
- Detects boolean literals (`useState(false)`) and type annotations (`useState<boolean>()`)
|
|
23
|
+
- Options: `booleanPrefixes`, `extendBooleanPrefixes`, `allowPastVerbBoolean`, `allowContinuousVerbBoolean`
|
|
24
|
+
|
|
25
|
+
### Enhanced
|
|
26
|
+
|
|
27
|
+
- **`folder-component-suffix`** - Add auto-fix to rename component and all references in the file
|
|
28
|
+
- **`function-naming-convention`** - Detect useCallback-wrapped functions in custom hooks
|
|
29
|
+
- **`prop-naming-convention`** - Auto-fix now renames both type annotation AND destructured parameter with all usages
|
|
30
|
+
|
|
31
|
+
### Stats
|
|
32
|
+
|
|
33
|
+
- Total Rules: 76 (was 75)
|
|
34
|
+
- Auto-fixable: 67 rules 🔧
|
|
35
|
+
- Configurable: 17 rules ⚙️
|
|
36
|
+
- Report-only: 9 rules
|
|
37
|
+
|
|
38
|
+
**Full Changelog:** [v1.13.0...v1.14.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.13.0...v1.14.0)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## [1.13.0] - 2026-02-05
|
|
43
|
+
|
|
44
|
+
**New Rule: Prop Naming Convention & Auto-Fix Enhancements**
|
|
45
|
+
|
|
46
|
+
**Version Range:** v1.12.1 → v1.13.0
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
**New Rules (1)**
|
|
51
|
+
- `prop-naming-convention` - Enforce naming conventions for boolean and callback props 🔧
|
|
52
|
+
- Boolean props must start with: `is`, `has`, `with`, `without` (configurable)
|
|
53
|
+
- Callback props must start with: `on` (configurable)
|
|
54
|
+
- Detects React event handler types (`MouseEventHandler`, `ChangeEventHandler`, `FormEventHandler`, etc.)
|
|
55
|
+
- Supports nested types at any depth
|
|
56
|
+
- Applies to interfaces, type aliases, and inline types (NOT JSX attributes)
|
|
57
|
+
- Options: `booleanPrefixes`, `extendBooleanPrefixes`, `allowPastVerbBoolean`, `allowContinuousVerbBoolean`, `callbackPrefix`, `allowActionSuffix`
|
|
58
|
+
|
|
59
|
+
### Enhanced
|
|
60
|
+
|
|
61
|
+
- **`enum-format`** - Add auto-fix for member names (convert to UPPER_SNAKE_CASE)
|
|
62
|
+
- **`interface-format`** - Add auto-fix for property names (convert to camelCase); collapse single-member nested object types to one line
|
|
63
|
+
- **`type-format`** - Add auto-fix for property names (convert to camelCase); collapse single-member nested object types to one line; union type formatting with configurable threshold (`minUnionMembersForMultiline` option, default 5)
|
|
64
|
+
|
|
65
|
+
### Stats
|
|
66
|
+
|
|
67
|
+
- Total Rules: 75 (was 74)
|
|
68
|
+
- Auto-fixable: 66 rules 🔧
|
|
69
|
+
- Configurable: 17 rules ⚙️
|
|
70
|
+
- Report-only: 9 rules
|
|
71
|
+
|
|
72
|
+
**Full Changelog:** [v1.12.1...v1.13.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.12.1...v1.13.0)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## [1.12.1] - 2026-02-04
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- **`function-object-destructure`** - Skip when param is used in spread operations, exclude object property keys from reference counting
|
|
81
|
+
- **`no-empty-lines-in-function-params`** - Only check parens within function's own range (fix for `.map(config => ...)` false positives)
|
|
82
|
+
- **`jsx-children-on-new-line`** - Remove blank line check after opening tag (handled by `no-empty-lines-in-jsx` rule)
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## [1.12.0] - 2026-02-04
|
|
87
|
+
|
|
88
|
+
**New Rule: Folder Component Suffix**
|
|
89
|
+
|
|
90
|
+
**Version Range:** v1.11.1 → v1.12.0
|
|
91
|
+
|
|
92
|
+
### Added
|
|
93
|
+
|
|
94
|
+
**New Rules (1)**
|
|
95
|
+
- `folder-component-suffix` - Enforce naming conventions based on folder location:
|
|
96
|
+
- Components in `views/` folder must end with `View` suffix
|
|
97
|
+
- Components in `pages/` folder must end with `Page` suffix
|
|
98
|
+
|
|
99
|
+
### Stats
|
|
100
|
+
|
|
101
|
+
- Total Rules: 74 (was 73)
|
|
102
|
+
- Auto-fixable: 65 rules 🔧
|
|
103
|
+
- Report-only: 9 rules
|
|
104
|
+
|
|
105
|
+
**Full Changelog:** [v1.11.1...v1.12.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.1...v1.12.0)
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## [1.11.9] - 2026-02-04
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
|
|
113
|
+
- **`variable-naming-convention`** - Enforce camelCase for object property keys (no longer allows SCREAMING_SNAKE_CASE like `APP_NAME`)
|
|
114
|
+
- **`variable-naming-convention`** - Add auto-fix to convert property names to camelCase (e.g., `APP_NAME` → `appName`)
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## [1.11.8] - 2026-02-04
|
|
119
|
+
|
|
120
|
+
### Fixed
|
|
121
|
+
|
|
122
|
+
- **`comment-format`** - Allow `/* */` syntax for ESLint directive comments (`/* eslint-disable ... */`, `/* eslint-enable ... */`, etc.) since these must use block comment syntax
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
10
126
|
## [1.11.7] - 2026-02-04
|
|
11
127
|
|
|
12
128
|
### Changed
|
|
@@ -1538,6 +1654,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1538
1654
|
|
|
1539
1655
|
---
|
|
1540
1656
|
|
|
1657
|
+
[1.14.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.13.0...v1.14.0
|
|
1658
|
+
[1.13.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.12.1...v1.13.0
|
|
1659
|
+
[1.12.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.12.0...v1.12.1
|
|
1660
|
+
[1.12.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.9...v1.12.0
|
|
1661
|
+
[1.11.9]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.8...v1.11.9
|
|
1662
|
+
[1.11.8]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.7...v1.11.8
|
|
1541
1663
|
[1.11.7]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.6...v1.11.7
|
|
1542
1664
|
[1.11.6]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.5...v1.11.6
|
|
1543
1665
|
[1.11.5]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.4...v1.11.5
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
**A powerful ESLint plugin for enforcing consistent code formatting and style rules in React/JSX projects.**
|
|
21
21
|
|
|
22
|
-
*
|
|
22
|
+
*76 rules (67 auto-fixable, 17 configurable) to keep your codebase clean and consistent*
|
|
23
23
|
|
|
24
24
|
</div>
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
## 🎯 Why This Plugin?
|
|
29
29
|
|
|
30
|
-
This plugin provides **
|
|
30
|
+
This plugin provides **75 custom rules** (66 auto-fixable, 17 configurable) for code formatting. Built for **ESLint v9 flat configs**.
|
|
31
31
|
|
|
32
32
|
> **Note:** ESLint [deprecated 79 formatting rules](https://eslint.org/blog/2023/10/deprecating-formatting-rules/) in v8.53.0. Our recommended configs use `@stylistic/eslint-plugin` as the replacement for these deprecated rules.
|
|
33
33
|
|
|
@@ -36,7 +36,7 @@ This plugin provides **73 custom rules** (65 auto-fixable) for code formatting.
|
|
|
36
36
|
- **Works alongside existing tools** — Complements ESLint's built-in rules and packages like eslint-plugin-react, eslint-plugin-import, etc
|
|
37
37
|
- **Self-sufficient rules** — Each rule handles complete formatting independently
|
|
38
38
|
- **Consistency at scale** — Reduces code-style differences between team members by enforcing uniform formatting across your projects
|
|
39
|
-
- **Highly automated** —
|
|
39
|
+
- **Highly automated** — 67 of 76 rules support auto-fix with `eslint --fix`
|
|
40
40
|
|
|
41
41
|
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.
|
|
42
42
|
|
|
@@ -97,7 +97,7 @@ We provide **ready-to-use ESLint flat configuration files** that combine `eslint
|
|
|
97
97
|
<td width="50%">
|
|
98
98
|
|
|
99
99
|
### 🔧 Auto-Fixable Rules
|
|
100
|
-
**
|
|
100
|
+
**67 rules** support automatic fixing with `eslint --fix`. **17 rules** have configurable options. 9 rules are report-only (require manual changes).
|
|
101
101
|
|
|
102
102
|
</td>
|
|
103
103
|
<td width="50%">
|
|
@@ -205,6 +205,7 @@ rules: {
|
|
|
205
205
|
"code-style/enum-format": "error",
|
|
206
206
|
"code-style/enum-type-enforcement": "error",
|
|
207
207
|
"code-style/export-format": "error",
|
|
208
|
+
"code-style/folder-component-suffix": "error",
|
|
208
209
|
"code-style/function-arguments-format": "error",
|
|
209
210
|
"code-style/function-call-spacing": "error",
|
|
210
211
|
"code-style/function-declaration-style": "error",
|
|
@@ -213,6 +214,7 @@ rules: {
|
|
|
213
214
|
"code-style/function-params-per-line": "error",
|
|
214
215
|
"code-style/hook-callback-format": "error",
|
|
215
216
|
"code-style/hook-deps-per-line": "error",
|
|
217
|
+
"code-style/use-state-naming-convention": "error",
|
|
216
218
|
"code-style/if-else-spacing": "error",
|
|
217
219
|
"code-style/if-statement-format": "error",
|
|
218
220
|
"code-style/import-format": "error",
|
|
@@ -229,6 +231,7 @@ rules: {
|
|
|
229
231
|
"code-style/jsx-simple-element-one-line": "error",
|
|
230
232
|
"code-style/jsx-string-value-trim": "error",
|
|
231
233
|
"code-style/jsx-ternary-format": "error",
|
|
234
|
+
"code-style/logical-expression-multiline": "error",
|
|
232
235
|
"code-style/member-expression-bracket-spacing": "error",
|
|
233
236
|
"code-style/module-index-exports": "error",
|
|
234
237
|
"code-style/multiline-if-conditions": "error",
|
|
@@ -244,6 +247,7 @@ rules: {
|
|
|
244
247
|
"code-style/object-property-value-brace": "error",
|
|
245
248
|
"code-style/object-property-value-format": "error",
|
|
246
249
|
"code-style/opening-brackets-same-line": "error",
|
|
250
|
+
"code-style/prop-naming-convention": "error",
|
|
247
251
|
"code-style/react-code-order": "error",
|
|
248
252
|
"code-style/simple-call-single-line": "error",
|
|
249
253
|
"code-style/single-argument-on-one-line": "error",
|
|
@@ -262,7 +266,7 @@ rules: {
|
|
|
262
266
|
|
|
263
267
|
## 📖 Rules Categories
|
|
264
268
|
|
|
265
|
-
> **
|
|
269
|
+
> **76 rules total** — 67 with auto-fix 🔧, 17 configurable ⚙️, 9 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
|
|
266
270
|
>
|
|
267
271
|
> **Legend:** 🔧 Auto-fixable with `eslint --fix` • ⚙️ Customizable options
|
|
268
272
|
|
|
@@ -289,6 +293,7 @@ rules: {
|
|
|
289
293
|
| **Component Rules** | |
|
|
290
294
|
| `component-props-destructure` | Component props must be destructured `({ prop })` not received as `(props)` 🔧 |
|
|
291
295
|
| `component-props-inline-type` | Inline type annotation `} : {` with matching props, proper spacing, commas, no interface reference 🔧 |
|
|
296
|
+
| `folder-component-suffix` | Components in `views/` folder must end with "View", components in `pages/` folder must end with "Page" |
|
|
292
297
|
| `svg-component-icon-naming` | SVG components must end with "Icon" suffix; "Icon" suffix components must return SVG |
|
|
293
298
|
| **Class Rules** | |
|
|
294
299
|
| `class-method-definition-format` | Consistent spacing in class/method definitions: space before `{`, no space before `(` 🔧 |
|
|
@@ -298,6 +303,7 @@ rules: {
|
|
|
298
303
|
| `empty-line-after-block` | Empty line required between closing `}` of block and next statement 🔧 |
|
|
299
304
|
| `if-else-spacing` | Empty line between consecutive if blocks, no empty line between single-line if/else 🔧 |
|
|
300
305
|
| `if-statement-format` | `{` on same line as `if`/`else if`, `else` on same line as `}`, proper spacing 🔧 |
|
|
306
|
+
| `logical-expression-multiline` | Logical expressions (&&, \|\|) with >maxOperands get one operand per line (default: >3) 🔧 ⚙️ |
|
|
301
307
|
| `multiline-if-conditions` | Conditions exceeding threshold get one operand per line with proper indentation (default: >3) 🔧 ⚙️ |
|
|
302
308
|
| `no-empty-lines-in-switch-cases` | No empty line after `case X:` before code, no empty lines between cases 🔧 |
|
|
303
309
|
| `ternary-condition-multiline` | ≤maxOperands always single line; >maxOperands multiline (based on operand count, not line length) 🔧 ⚙️ |
|
|
@@ -311,6 +317,7 @@ rules: {
|
|
|
311
317
|
| **Hook Rules** | |
|
|
312
318
|
| `hook-callback-format` | React hooks: callback on new line, deps array on separate line, proper indentation 🔧 |
|
|
313
319
|
| `hook-deps-per-line` | Collapse deps ≤ threshold to one line; expand larger arrays with each dep on own line (default: >2) 🔧 ⚙️ |
|
|
320
|
+
| `use-state-naming-convention` | Boolean useState variables must start with is/has/with/without prefix 🔧 ⚙️ |
|
|
314
321
|
| **Import/Export Rules** | |
|
|
315
322
|
| `absolute-imports-only` | Use alias imports from index files only (not deep paths), no relative imports (default: `@/`) ⚙️ |
|
|
316
323
|
| `export-format` | `export {` on same line; collapse ≤ threshold to one line; expand larger with each specifier on own line (default: ≤3) 🔧 ⚙️ |
|
|
@@ -348,8 +355,9 @@ rules: {
|
|
|
348
355
|
| `enum-type-enforcement` | Enforce using enum values instead of string literals for variables typed with `*Type` (e.g., use `ButtonVariantEnum.PRIMARY` not `"primary"`) 🔧 |
|
|
349
356
|
| `interface-format` | Enforce interface naming (PascalCase + Interface suffix), camelCase properties, no empty lines, and trailing commas 🔧 |
|
|
350
357
|
| `no-inline-type-definitions` | Inline union types in function params should be extracted to named types ⚙️ |
|
|
358
|
+
| `prop-naming-convention` | Enforce boolean props start with is/has/with/without, callback props start with on 🔧 ⚙️ |
|
|
351
359
|
| `type-annotation-spacing` | Enforce consistent spacing in type annotations: no space before colon/generic/array brackets, one space after colon 🔧 |
|
|
352
|
-
| `type-format` | Enforce type naming (PascalCase + Type suffix), camelCase properties,
|
|
360
|
+
| `type-format` | Enforce type naming (PascalCase + Type suffix), camelCase properties, union type formatting, and trailing commas 🔧 ⚙️ |
|
|
353
361
|
| `typescript-definition-location` | Enforce TypeScript definitions (interfaces, types, enums) to be in designated folders ⚙️ |
|
|
354
362
|
| **React Rules** | |
|
|
355
363
|
| `react-code-order` | Enforce consistent ordering in components and hooks: props destructure → refs → state → redux → router → context → custom hooks → derived → memo → callback → handlers → effects → return 🔧 |
|
|
@@ -1166,6 +1174,45 @@ else
|
|
|
1166
1174
|
|
|
1167
1175
|
---
|
|
1168
1176
|
|
|
1177
|
+
### `logical-expression-multiline`
|
|
1178
|
+
|
|
1179
|
+
**What it does:** When a logical expression (`&&`, `||`) has more operands than the threshold (default: 3), each operand goes on its own line with the operator at the start.
|
|
1180
|
+
|
|
1181
|
+
**Why use it:** Long logical expressions are hard to read on one line. One operand per line makes each part clear and easy to modify.
|
|
1182
|
+
|
|
1183
|
+
```javascript
|
|
1184
|
+
// ✅ Good — 3 or fewer operands stay inline
|
|
1185
|
+
const isValid = a && b && c;
|
|
1186
|
+
const result = x || y;
|
|
1187
|
+
|
|
1188
|
+
// ✅ Good — 4+ operands get one per line
|
|
1189
|
+
const err = data.error
|
|
1190
|
+
|| data.message
|
|
1191
|
+
|| data.status
|
|
1192
|
+
|| data.fallback;
|
|
1193
|
+
|
|
1194
|
+
const isComplete = hasName
|
|
1195
|
+
&& hasEmail
|
|
1196
|
+
&& hasPhone
|
|
1197
|
+
&& hasAddress;
|
|
1198
|
+
|
|
1199
|
+
// ❌ Bad — 4+ operands on single line
|
|
1200
|
+
const err = data.error || data.message || data.status || data.fallback;
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
**Options:**
|
|
1204
|
+
|
|
1205
|
+
| Option | Type | Default | Description |
|
|
1206
|
+
|--------|------|---------|-------------|
|
|
1207
|
+
| `maxOperands` | `integer` | `3` | Maximum operands allowed on a single line |
|
|
1208
|
+
|
|
1209
|
+
```javascript
|
|
1210
|
+
// Configuration example - allow up to 4 operands on single line
|
|
1211
|
+
"code-style/logical-expression-multiline": ["error", { maxOperands: 4 }]
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
---
|
|
1215
|
+
|
|
1169
1216
|
### `multiline-if-conditions`
|
|
1170
1217
|
|
|
1171
1218
|
**What it does:** When an if statement has more conditions than the threshold (default: 3), each condition goes on its own line with proper indentation.
|
|
@@ -1716,6 +1763,49 @@ useEffect(() => {}, [
|
|
|
1716
1763
|
|
|
1717
1764
|
<br />
|
|
1718
1765
|
|
|
1766
|
+
### `use-state-naming-convention`
|
|
1767
|
+
|
|
1768
|
+
**What it does:** Enforces boolean useState variables to start with valid prefixes (is, has, with, without).
|
|
1769
|
+
|
|
1770
|
+
**Why use it:** Consistent boolean state naming makes code more predictable and self-documenting. When you see `isLoading`, you immediately know it's a boolean state.
|
|
1771
|
+
|
|
1772
|
+
```typescript
|
|
1773
|
+
// ✅ Good — boolean state with proper prefix
|
|
1774
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
1775
|
+
const [hasError, setHasError] = useState<boolean>(false);
|
|
1776
|
+
const [isAuthenticated, setIsAuthenticated] = useState(true);
|
|
1777
|
+
const [withBorder, setWithBorder] = useState(false);
|
|
1778
|
+
|
|
1779
|
+
// ❌ Bad — boolean state without prefix
|
|
1780
|
+
const [loading, setLoading] = useState(false);
|
|
1781
|
+
const [authenticated, setAuthenticated] = useState<boolean>(true);
|
|
1782
|
+
const [error, setError] = useState<boolean>(false);
|
|
1783
|
+
```
|
|
1784
|
+
|
|
1785
|
+
**Customization Options:**
|
|
1786
|
+
|
|
1787
|
+
| Option | Type | Default | Description |
|
|
1788
|
+
|--------|------|---------|-------------|
|
|
1789
|
+
| `booleanPrefixes` | `string[]` | `["is", "has", "with", "without"]` | Replace default prefixes entirely |
|
|
1790
|
+
| `extendBooleanPrefixes` | `string[]` | `[]` | Add additional prefixes to defaults |
|
|
1791
|
+
| `allowPastVerbBoolean` | `boolean` | `false` | Allow past verb names without prefix (disabled, selected) |
|
|
1792
|
+
| `allowContinuousVerbBoolean` | `boolean` | `false` | Allow continuous verb names without prefix (loading, saving) |
|
|
1793
|
+
|
|
1794
|
+
```javascript
|
|
1795
|
+
// Example: Allow "loading" and "disabled" without prefix
|
|
1796
|
+
"code-style/use-state-naming-convention": ["error", {
|
|
1797
|
+
allowPastVerbBoolean: true,
|
|
1798
|
+
allowContinuousVerbBoolean: true
|
|
1799
|
+
}]
|
|
1800
|
+
|
|
1801
|
+
// Example: Add "should" prefix
|
|
1802
|
+
"code-style/use-state-naming-convention": ["error", {
|
|
1803
|
+
extendBooleanPrefixes: ["should"]
|
|
1804
|
+
}]
|
|
1805
|
+
```
|
|
1806
|
+
|
|
1807
|
+
<br />
|
|
1808
|
+
|
|
1719
1809
|
## 📥 Import/Export Rules
|
|
1720
1810
|
|
|
1721
1811
|
### `absolute-imports-only`
|
|
@@ -2969,6 +3059,30 @@ export const Card = ({ a, b } : { a: string, b: string }) => (
|
|
|
2969
3059
|
|
|
2970
3060
|
---
|
|
2971
3061
|
|
|
3062
|
+
### `folder-component-suffix`
|
|
3063
|
+
|
|
3064
|
+
**What it does:** Enforces naming conventions for components based on folder location:
|
|
3065
|
+
- Components in `views/` folder must end with "View" suffix
|
|
3066
|
+
- Components in `pages/` folder must end with "Page" suffix
|
|
3067
|
+
|
|
3068
|
+
**Why use it:** Consistent naming based on folder structure makes component purpose immediately clear. View components and page components have different responsibilities, and the suffix reflects this.
|
|
3069
|
+
|
|
3070
|
+
```tsx
|
|
3071
|
+
// ✅ Good — in views/dashboard-view.tsx
|
|
3072
|
+
export const DashboardView = () => <div>Dashboard</div>;
|
|
3073
|
+
|
|
3074
|
+
// ✅ Good — in pages/home-page.tsx
|
|
3075
|
+
export const HomePage = () => <div>Home</div>;
|
|
3076
|
+
|
|
3077
|
+
// ❌ Bad — in views/dashboard.tsx (missing "View" suffix)
|
|
3078
|
+
export const Dashboard = () => <div>Dashboard</div>;
|
|
3079
|
+
|
|
3080
|
+
// ❌ Bad — in pages/home.tsx (missing "Page" suffix)
|
|
3081
|
+
export const Home = () => <div>Home</div>;
|
|
3082
|
+
```
|
|
3083
|
+
|
|
3084
|
+
---
|
|
3085
|
+
|
|
2972
3086
|
### `svg-component-icon-naming`
|
|
2973
3087
|
|
|
2974
3088
|
**What it does:** Enforces naming conventions for SVG icon components:
|
|
@@ -3161,6 +3275,172 @@ export const Button = ({
|
|
|
3161
3275
|
|
|
3162
3276
|
---
|
|
3163
3277
|
|
|
3278
|
+
### `prop-naming-convention`
|
|
3279
|
+
|
|
3280
|
+
**What it does:** Enforces naming conventions for boolean and callback props in TypeScript interfaces, types, and inline type definitions:
|
|
3281
|
+
- Boolean props must start with: `is`, `has`, `with`, or `without` (followed by capital letter)
|
|
3282
|
+
- Callback props must start with: `on` (followed by capital letter)
|
|
3283
|
+
- Detects React event handler types: `MouseEventHandler`, `ChangeEventHandler`, `FormEventHandler`, `KeyboardEventHandler`, etc.
|
|
3284
|
+
- Applies to all nesting levels (nested object types are checked recursively)
|
|
3285
|
+
- Does NOT apply to JSX element attributes (external components have their own props)
|
|
3286
|
+
|
|
3287
|
+
**Why use it:** Consistent prop naming makes props self-documenting. Boolean prefixes clarify intent (`isLoading` vs `loading`), and `on` prefix clearly identifies event handlers.
|
|
3288
|
+
|
|
3289
|
+
**Options:**
|
|
3290
|
+
|
|
3291
|
+
| Option | Type | Default | Description |
|
|
3292
|
+
|--------|------|---------|-------------|
|
|
3293
|
+
| `booleanPrefixes` | `string[]` | - | Replace default prefixes entirely (overrides defaults) |
|
|
3294
|
+
| `extendBooleanPrefixes` | `string[]` | `[]` | Add to default prefixes (`is`, `has`, `with`, `without`) |
|
|
3295
|
+
| `allowPastVerbBoolean` | `boolean` | `false` | Allow past verb booleans (e.g., `disabled`, `selected`, `checked`, `opened`) |
|
|
3296
|
+
| `allowContinuousVerbBoolean` | `boolean` | `false` | Allow continuous verb booleans (e.g., `loading`, `saving`, `fetching`) |
|
|
3297
|
+
| `callbackPrefix` | `string` | `"on"` | Required prefix for callback props |
|
|
3298
|
+
| `allowActionSuffix` | `boolean` | `false` | Allow `xxxAction` pattern for callbacks |
|
|
3299
|
+
|
|
3300
|
+
```typescript
|
|
3301
|
+
// ✅ Good — proper prop naming
|
|
3302
|
+
interface ButtonPropsInterface {
|
|
3303
|
+
isDisabled: boolean,
|
|
3304
|
+
isLoading: boolean,
|
|
3305
|
+
hasError: boolean,
|
|
3306
|
+
onClick: () => void,
|
|
3307
|
+
onSubmit: (data: FormData) => void,
|
|
3308
|
+
}
|
|
3309
|
+
|
|
3310
|
+
type CardPropsType = {
|
|
3311
|
+
isExpanded: boolean,
|
|
3312
|
+
hasChildren: boolean,
|
|
3313
|
+
onToggle: () => void,
|
|
3314
|
+
};
|
|
3315
|
+
|
|
3316
|
+
// ✅ Good — nested types are also checked
|
|
3317
|
+
interface FormPropsInterface {
|
|
3318
|
+
isValid: boolean,
|
|
3319
|
+
config: {
|
|
3320
|
+
isEnabled: boolean, // Nested - checked
|
|
3321
|
+
onValidate: () => void, // Nested - checked
|
|
3322
|
+
settings: {
|
|
3323
|
+
isActive: boolean, // Deep nested - also checked
|
|
3324
|
+
},
|
|
3325
|
+
},
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
// ✅ Good — inline component props
|
|
3329
|
+
const Button = ({
|
|
3330
|
+
isLoading,
|
|
3331
|
+
onClick,
|
|
3332
|
+
}: {
|
|
3333
|
+
isLoading: boolean,
|
|
3334
|
+
onClick: () => void,
|
|
3335
|
+
}) => { ... };
|
|
3336
|
+
|
|
3337
|
+
// ❌ Bad — missing prefixes
|
|
3338
|
+
interface ButtonPropsInterface {
|
|
3339
|
+
disabled: boolean, // Should be isDisabled
|
|
3340
|
+
loading: boolean, // Should be isLoading
|
|
3341
|
+
error: boolean, // Should be hasError
|
|
3342
|
+
click: () => void, // Should be onClick
|
|
3343
|
+
handleSubmit: () => void, // Should be onSubmit
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3346
|
+
// ❌ Bad — nested types also checked
|
|
3347
|
+
type PropsType = {
|
|
3348
|
+
config: {
|
|
3349
|
+
enabled: boolean, // Should be isEnabled
|
|
3350
|
+
toggle: () => void, // Should be onToggle
|
|
3351
|
+
},
|
|
3352
|
+
};
|
|
3353
|
+
```
|
|
3354
|
+
|
|
3355
|
+
**Past Verb Booleans** (`allowPastVerbBoolean: true`):
|
|
3356
|
+
|
|
3357
|
+
When enabled, allows boolean props that are past tense verbs (ending in `-ed`):
|
|
3358
|
+
|
|
3359
|
+
```typescript
|
|
3360
|
+
// ✅ Allowed with allowPastVerbBoolean: true
|
|
3361
|
+
interface PropsInterface {
|
|
3362
|
+
disabled: boolean, // Past verb - ends with -ed
|
|
3363
|
+
selected: boolean, // Past verb - ends with -ed
|
|
3364
|
+
checked: boolean, // Past verb - ends with -ed
|
|
3365
|
+
opened: boolean, // Past verb - ends with -ed
|
|
3366
|
+
closed: boolean, // Past verb - ends with -ed
|
|
3367
|
+
expanded: boolean, // Past verb - ends with -ed
|
|
3368
|
+
collapsed: boolean, // Past verb - ends with -ed
|
|
3369
|
+
focused: boolean, // Past verb - ends with -ed
|
|
3370
|
+
hidden: boolean, // Past verb - ends with -ed
|
|
3371
|
+
connected: boolean, // Past verb - ends with -ed
|
|
3372
|
+
}
|
|
3373
|
+
```
|
|
3374
|
+
|
|
3375
|
+
**Continuous Verb Booleans** (`allowContinuousVerbBoolean: true`):
|
|
3376
|
+
|
|
3377
|
+
When enabled, allows boolean props that are continuous tense verbs (ending in `-ing`):
|
|
3378
|
+
|
|
3379
|
+
```typescript
|
|
3380
|
+
// ✅ Allowed with allowContinuousVerbBoolean: true
|
|
3381
|
+
interface PropsInterface {
|
|
3382
|
+
loading: boolean, // Continuous verb - ends with -ing
|
|
3383
|
+
saving: boolean, // Continuous verb - ends with -ing
|
|
3384
|
+
fetching: boolean, // Continuous verb - ends with -ing
|
|
3385
|
+
closing: boolean, // Continuous verb - ends with -ing
|
|
3386
|
+
opening: boolean, // Continuous verb - ends with -ing
|
|
3387
|
+
submitting: boolean, // Continuous verb - ends with -ing
|
|
3388
|
+
processing: boolean, // Continuous verb - ends with -ing
|
|
3389
|
+
updating: boolean, // Continuous verb - ends with -ing
|
|
3390
|
+
deleting: boolean, // Continuous verb - ends with -ing
|
|
3391
|
+
pending: boolean, // Continuous verb - ends with -ing
|
|
3392
|
+
}
|
|
3393
|
+
```
|
|
3394
|
+
|
|
3395
|
+
**Configuration Examples:**
|
|
3396
|
+
|
|
3397
|
+
```javascript
|
|
3398
|
+
// Default configuration (strict)
|
|
3399
|
+
"code-style/prop-naming-convention": "error"
|
|
3400
|
+
|
|
3401
|
+
// Allow past verb booleans (disabled, selected, checked, etc.)
|
|
3402
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3403
|
+
allowPastVerbBoolean: true,
|
|
3404
|
+
}]
|
|
3405
|
+
|
|
3406
|
+
// Allow continuous verb booleans (loading, saving, fetching, etc.)
|
|
3407
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3408
|
+
allowContinuousVerbBoolean: true,
|
|
3409
|
+
}]
|
|
3410
|
+
|
|
3411
|
+
// Allow both past and continuous verb booleans
|
|
3412
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3413
|
+
allowPastVerbBoolean: true,
|
|
3414
|
+
allowContinuousVerbBoolean: true,
|
|
3415
|
+
}]
|
|
3416
|
+
|
|
3417
|
+
// Extend default prefixes with additional ones
|
|
3418
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3419
|
+
extendBooleanPrefixes: ["should", "can", "will", "did"],
|
|
3420
|
+
}]
|
|
3421
|
+
|
|
3422
|
+
// Replace default prefixes entirely
|
|
3423
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3424
|
+
booleanPrefixes: ["is", "has"], // Only these prefixes allowed
|
|
3425
|
+
}]
|
|
3426
|
+
|
|
3427
|
+
// Allow "xxxAction" suffix for callbacks
|
|
3428
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3429
|
+
allowActionSuffix: true, // Allows: submitAction, copyAction, deleteAction
|
|
3430
|
+
}]
|
|
3431
|
+
|
|
3432
|
+
// Full custom configuration
|
|
3433
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3434
|
+
extendBooleanPrefixes: ["should", "can"],
|
|
3435
|
+
allowPastVerbBoolean: true,
|
|
3436
|
+
allowContinuousVerbBoolean: true,
|
|
3437
|
+
callbackPrefix: "on",
|
|
3438
|
+
allowActionSuffix: true,
|
|
3439
|
+
}]
|
|
3440
|
+
```
|
|
3441
|
+
|
|
3442
|
+
---
|
|
3443
|
+
|
|
3164
3444
|
### `type-format`
|
|
3165
3445
|
|
|
3166
3446
|
**What it does:** Enforces consistent formatting for TypeScript type aliases:
|
|
@@ -3168,6 +3448,8 @@ export const Button = ({
|
|
|
3168
3448
|
- Properties must be camelCase
|
|
3169
3449
|
- No empty lines between properties
|
|
3170
3450
|
- Properties must end with commas, not semicolons
|
|
3451
|
+
- Union types with 5+ members must be multiline (one per line)
|
|
3452
|
+
- Union types with <5 members must be single line
|
|
3171
3453
|
|
|
3172
3454
|
**Why use it:** Consistent type naming makes types instantly recognizable. The suffix clearly distinguishes types from interfaces and classes.
|
|
3173
3455
|
|
|
@@ -3185,6 +3467,26 @@ export type ApiResponseType<T> = {
|
|
|
3185
3467
|
status: number,
|
|
3186
3468
|
};
|
|
3187
3469
|
|
|
3470
|
+
// ✅ Good — union type with 6 members (multiline)
|
|
3471
|
+
export type ButtonVariantType =
|
|
3472
|
+
"danger"
|
|
3473
|
+
| "ghost"
|
|
3474
|
+
| "ghost-danger"
|
|
3475
|
+
| "link"
|
|
3476
|
+
| "muted"
|
|
3477
|
+
| "primary";
|
|
3478
|
+
|
|
3479
|
+
// ✅ Good — union type with 2 members (single line)
|
|
3480
|
+
export type CodeLayoutVariantType = "default" | "error";
|
|
3481
|
+
|
|
3482
|
+
// ❌ Bad — 6 members should be multiline
|
|
3483
|
+
export type BadUnionType = "a" | "b" | "c" | "d" | "e" | "f";
|
|
3484
|
+
|
|
3485
|
+
// ❌ Bad — 2 members should be single line
|
|
3486
|
+
export type BadSingleType =
|
|
3487
|
+
"default"
|
|
3488
|
+
| "error";
|
|
3489
|
+
|
|
3188
3490
|
// ❌ Bad — wrong naming
|
|
3189
3491
|
export type User = { // Missing Type suffix
|
|
3190
3492
|
Email: string; // Should be camelCase
|
|
@@ -3199,6 +3501,17 @@ export type ConfigType = {
|
|
|
3199
3501
|
};
|
|
3200
3502
|
```
|
|
3201
3503
|
|
|
3504
|
+
**Options:**
|
|
3505
|
+
|
|
3506
|
+
| Option | Type | Default | Description |
|
|
3507
|
+
|--------|------|---------|-------------|
|
|
3508
|
+
| `minUnionMembersForMultiline` | `integer` | `5` | Minimum number of union members to require multiline format |
|
|
3509
|
+
|
|
3510
|
+
```javascript
|
|
3511
|
+
// Configuration example - require multiline for 4+ union members
|
|
3512
|
+
"code-style/type-format": ["error", { minUnionMembersForMultiline: 4 }]
|
|
3513
|
+
```
|
|
3514
|
+
|
|
3202
3515
|
---
|
|
3203
3516
|
|
|
3204
3517
|
### `type-annotation-spacing`
|
|
@@ -3581,7 +3894,7 @@ const UseAuth = () => {}; // hooks should be camelCase
|
|
|
3581
3894
|
|
|
3582
3895
|
## 🔧 Auto-fixing
|
|
3583
3896
|
|
|
3584
|
-
|
|
3897
|
+
67 of 76 rules support auto-fixing. Run ESLint with the `--fix` flag:
|
|
3585
3898
|
|
|
3586
3899
|
```bash
|
|
3587
3900
|
# Fix all files in src directory
|
package/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export type RuleNames =
|
|
|
24
24
|
| "code-style/empty-line-after-block"
|
|
25
25
|
| "code-style/enum-type-enforcement"
|
|
26
26
|
| "code-style/export-format"
|
|
27
|
+
| "code-style/folder-component-suffix"
|
|
27
28
|
| "code-style/function-arguments-format"
|
|
28
29
|
| "code-style/function-call-spacing"
|
|
29
30
|
| "code-style/function-declaration-style"
|
|
@@ -32,6 +33,7 @@ export type RuleNames =
|
|
|
32
33
|
| "code-style/function-params-per-line"
|
|
33
34
|
| "code-style/hook-callback-format"
|
|
34
35
|
| "code-style/hook-deps-per-line"
|
|
36
|
+
| "code-style/use-state-naming-convention"
|
|
35
37
|
| "code-style/if-else-spacing"
|
|
36
38
|
| "code-style/if-statement-format"
|
|
37
39
|
| "code-style/import-format"
|
|
@@ -67,6 +69,7 @@ export type RuleNames =
|
|
|
67
69
|
| "code-style/object-property-value-brace"
|
|
68
70
|
| "code-style/object-property-value-format"
|
|
69
71
|
| "code-style/opening-brackets-same-line"
|
|
72
|
+
| "code-style/prop-naming-convention"
|
|
70
73
|
| "code-style/simple-call-single-line"
|
|
71
74
|
| "code-style/single-argument-on-one-line"
|
|
72
75
|
| "code-style/string-property-spacing"
|
|
@@ -119,6 +122,7 @@ interface PluginRules {
|
|
|
119
122
|
"empty-line-after-block": Rule.RuleModule;
|
|
120
123
|
"enum-type-enforcement": Rule.RuleModule;
|
|
121
124
|
"export-format": Rule.RuleModule;
|
|
125
|
+
"folder-component-suffix": Rule.RuleModule;
|
|
122
126
|
"function-arguments-format": Rule.RuleModule;
|
|
123
127
|
"function-call-spacing": Rule.RuleModule;
|
|
124
128
|
"function-declaration-style": Rule.RuleModule;
|
|
@@ -162,6 +166,7 @@ interface PluginRules {
|
|
|
162
166
|
"object-property-value-brace": Rule.RuleModule;
|
|
163
167
|
"object-property-value-format": Rule.RuleModule;
|
|
164
168
|
"opening-brackets-same-line": Rule.RuleModule;
|
|
169
|
+
"prop-naming-convention": Rule.RuleModule;
|
|
165
170
|
"simple-call-single-line": Rule.RuleModule;
|
|
166
171
|
"single-argument-on-one-line": Rule.RuleModule;
|
|
167
172
|
"string-property-spacing": Rule.RuleModule;
|