eslint-plugin-code-style 1.11.4 → 1.13.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 +126 -0
- package/README.md +275 -7
- package/index.d.ts +4 -0
- package/index.js +898 -97
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,124 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.13.0] - 2026-02-05
|
|
11
|
+
|
|
12
|
+
**New Rule: Prop Naming Convention & Auto-Fix Enhancements**
|
|
13
|
+
|
|
14
|
+
**Version Range:** v1.12.1 → v1.13.0
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
**New Rules (1)**
|
|
19
|
+
- `prop-naming-convention` - Enforce naming conventions for boolean and callback props 🔧
|
|
20
|
+
- Boolean props must start with: `is`, `has`, `with`, `without` (configurable)
|
|
21
|
+
- Callback props must start with: `on` (configurable)
|
|
22
|
+
- Detects React event handler types (`MouseEventHandler`, `ChangeEventHandler`, `FormEventHandler`, etc.)
|
|
23
|
+
- Supports nested types at any depth
|
|
24
|
+
- Applies to interfaces, type aliases, and inline types (NOT JSX attributes)
|
|
25
|
+
- Options: `booleanPrefixes`, `extendBooleanPrefixes`, `allowPastVerbBoolean`, `allowContinuousVerbBoolean`, `callbackPrefix`, `allowActionSuffix`
|
|
26
|
+
|
|
27
|
+
### Enhanced
|
|
28
|
+
|
|
29
|
+
- **`enum-format`** - Add auto-fix for member names (convert to UPPER_SNAKE_CASE)
|
|
30
|
+
- **`interface-format`** - Add auto-fix for property names (convert to camelCase); collapse single-member nested object types to one line
|
|
31
|
+
- **`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)
|
|
32
|
+
|
|
33
|
+
### Stats
|
|
34
|
+
|
|
35
|
+
- Total Rules: 75 (was 74)
|
|
36
|
+
- Auto-fixable: 66 rules 🔧
|
|
37
|
+
- Configurable: 17 rules ⚙️
|
|
38
|
+
- Report-only: 9 rules
|
|
39
|
+
|
|
40
|
+
**Full Changelog:** [v1.12.1...v1.13.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.12.1...v1.13.0)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## [1.12.1] - 2026-02-04
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- **`function-object-destructure`** - Skip when param is used in spread operations, exclude object property keys from reference counting
|
|
49
|
+
- **`no-empty-lines-in-function-params`** - Only check parens within function's own range (fix for `.map(config => ...)` false positives)
|
|
50
|
+
- **`jsx-children-on-new-line`** - Remove blank line check after opening tag (handled by `no-empty-lines-in-jsx` rule)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## [1.12.0] - 2026-02-04
|
|
55
|
+
|
|
56
|
+
**New Rule: Folder Component Suffix**
|
|
57
|
+
|
|
58
|
+
**Version Range:** v1.11.1 → v1.12.0
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
|
|
62
|
+
**New Rules (1)**
|
|
63
|
+
- `folder-component-suffix` - Enforce naming conventions based on folder location:
|
|
64
|
+
- Components in `views/` folder must end with `View` suffix
|
|
65
|
+
- Components in `pages/` folder must end with `Page` suffix
|
|
66
|
+
|
|
67
|
+
### Stats
|
|
68
|
+
|
|
69
|
+
- Total Rules: 74 (was 73)
|
|
70
|
+
- Auto-fixable: 65 rules 🔧
|
|
71
|
+
- Report-only: 9 rules
|
|
72
|
+
|
|
73
|
+
**Full Changelog:** [v1.11.1...v1.12.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.1...v1.12.0)
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## [1.11.9] - 2026-02-04
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- **`variable-naming-convention`** - Enforce camelCase for object property keys (no longer allows SCREAMING_SNAKE_CASE like `APP_NAME`)
|
|
82
|
+
- **`variable-naming-convention`** - Add auto-fix to convert property names to camelCase (e.g., `APP_NAME` → `appName`)
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## [1.11.8] - 2026-02-04
|
|
87
|
+
|
|
88
|
+
### Fixed
|
|
89
|
+
|
|
90
|
+
- **`comment-format`** - Allow `/* */` syntax for ESLint directive comments (`/* eslint-disable ... */`, `/* eslint-enable ... */`, etc.) since these must use block comment syntax
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## [1.11.7] - 2026-02-04
|
|
95
|
+
|
|
96
|
+
### Changed
|
|
97
|
+
|
|
98
|
+
- **`no-hardcoded-strings`**
|
|
99
|
+
- Remove UI component pattern exemption - ALL enum-like attribute values are now flagged (e.g., `variant="primary"`, `size="large"`, `color="danger"`)
|
|
100
|
+
- Enforce consistent use of enums for component props to prevent typos
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## [1.11.6] - 2026-02-04
|
|
105
|
+
|
|
106
|
+
### Changed
|
|
107
|
+
|
|
108
|
+
- **`no-hardcoded-strings`**
|
|
109
|
+
- Flag `type` attribute in JSX elements (e.g., `<input type="text" />`) - should use enums to prevent typos
|
|
110
|
+
- Remove `type` from default ignored attributes list
|
|
111
|
+
- Remove "text" from UI component pattern (conflicts with input type)
|
|
112
|
+
- Update error message for JSX attributes: "should be imported from @/enums (preferred) or @/data to prevent typos"
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## [1.11.5] - 2026-02-04
|
|
117
|
+
|
|
118
|
+
### Fixed
|
|
119
|
+
|
|
120
|
+
- **`no-hardcoded-strings`**
|
|
121
|
+
- Flag hardcoded strings in component default params (e.g., `type = "text"`, `variant = "ghost"`)
|
|
122
|
+
- Flag hardcoded strings in ternary expressions (e.g., `showPassword ? "text" : "password"`)
|
|
123
|
+
- Remove overly broad HTML input type exemption from general string checks
|
|
124
|
+
- Remove "text" from CSS cursor pattern (conflicts with common input type usage)
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
10
128
|
## [1.11.4] - 2026-02-04
|
|
11
129
|
|
|
12
130
|
### Fixed
|
|
@@ -1504,6 +1622,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1504
1622
|
|
|
1505
1623
|
---
|
|
1506
1624
|
|
|
1625
|
+
[1.13.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.12.1...v1.13.0
|
|
1626
|
+
[1.12.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.12.0...v1.12.1
|
|
1627
|
+
[1.12.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.9...v1.12.0
|
|
1628
|
+
[1.11.9]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.8...v1.11.9
|
|
1629
|
+
[1.11.8]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.7...v1.11.8
|
|
1630
|
+
[1.11.7]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.6...v1.11.7
|
|
1631
|
+
[1.11.6]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.5...v1.11.6
|
|
1632
|
+
[1.11.5]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.4...v1.11.5
|
|
1507
1633
|
[1.11.4]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.3...v1.11.4
|
|
1508
1634
|
[1.11.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.2...v1.11.3
|
|
1509
1635
|
[1.11.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.11.1...v1.11.2
|
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
|
+
*75 rules (66 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** — 66 of 75 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
|
+
**66 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",
|
|
@@ -229,6 +230,7 @@ rules: {
|
|
|
229
230
|
"code-style/jsx-simple-element-one-line": "error",
|
|
230
231
|
"code-style/jsx-string-value-trim": "error",
|
|
231
232
|
"code-style/jsx-ternary-format": "error",
|
|
233
|
+
"code-style/logical-expression-multiline": "error",
|
|
232
234
|
"code-style/member-expression-bracket-spacing": "error",
|
|
233
235
|
"code-style/module-index-exports": "error",
|
|
234
236
|
"code-style/multiline-if-conditions": "error",
|
|
@@ -244,6 +246,7 @@ rules: {
|
|
|
244
246
|
"code-style/object-property-value-brace": "error",
|
|
245
247
|
"code-style/object-property-value-format": "error",
|
|
246
248
|
"code-style/opening-brackets-same-line": "error",
|
|
249
|
+
"code-style/prop-naming-convention": "error",
|
|
247
250
|
"code-style/react-code-order": "error",
|
|
248
251
|
"code-style/simple-call-single-line": "error",
|
|
249
252
|
"code-style/single-argument-on-one-line": "error",
|
|
@@ -262,7 +265,7 @@ rules: {
|
|
|
262
265
|
|
|
263
266
|
## 📖 Rules Categories
|
|
264
267
|
|
|
265
|
-
> **
|
|
268
|
+
> **75 rules total** — 66 with auto-fix 🔧, 17 configurable ⚙️, 9 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
|
|
266
269
|
>
|
|
267
270
|
> **Legend:** 🔧 Auto-fixable with `eslint --fix` • ⚙️ Customizable options
|
|
268
271
|
|
|
@@ -289,6 +292,7 @@ rules: {
|
|
|
289
292
|
| **Component Rules** | |
|
|
290
293
|
| `component-props-destructure` | Component props must be destructured `({ prop })` not received as `(props)` 🔧 |
|
|
291
294
|
| `component-props-inline-type` | Inline type annotation `} : {` with matching props, proper spacing, commas, no interface reference 🔧 |
|
|
295
|
+
| `folder-component-suffix` | Components in `views/` folder must end with "View", components in `pages/` folder must end with "Page" |
|
|
292
296
|
| `svg-component-icon-naming` | SVG components must end with "Icon" suffix; "Icon" suffix components must return SVG |
|
|
293
297
|
| **Class Rules** | |
|
|
294
298
|
| `class-method-definition-format` | Consistent spacing in class/method definitions: space before `{`, no space before `(` 🔧 |
|
|
@@ -298,6 +302,7 @@ rules: {
|
|
|
298
302
|
| `empty-line-after-block` | Empty line required between closing `}` of block and next statement 🔧 |
|
|
299
303
|
| `if-else-spacing` | Empty line between consecutive if blocks, no empty line between single-line if/else 🔧 |
|
|
300
304
|
| `if-statement-format` | `{` on same line as `if`/`else if`, `else` on same line as `}`, proper spacing 🔧 |
|
|
305
|
+
| `logical-expression-multiline` | Logical expressions (&&, \|\|) with >maxOperands get one operand per line (default: >3) 🔧 ⚙️ |
|
|
301
306
|
| `multiline-if-conditions` | Conditions exceeding threshold get one operand per line with proper indentation (default: >3) 🔧 ⚙️ |
|
|
302
307
|
| `no-empty-lines-in-switch-cases` | No empty line after `case X:` before code, no empty lines between cases 🔧 |
|
|
303
308
|
| `ternary-condition-multiline` | ≤maxOperands always single line; >maxOperands multiline (based on operand count, not line length) 🔧 ⚙️ |
|
|
@@ -348,8 +353,9 @@ rules: {
|
|
|
348
353
|
| `enum-type-enforcement` | Enforce using enum values instead of string literals for variables typed with `*Type` (e.g., use `ButtonVariantEnum.PRIMARY` not `"primary"`) 🔧 |
|
|
349
354
|
| `interface-format` | Enforce interface naming (PascalCase + Interface suffix), camelCase properties, no empty lines, and trailing commas 🔧 |
|
|
350
355
|
| `no-inline-type-definitions` | Inline union types in function params should be extracted to named types ⚙️ |
|
|
356
|
+
| `prop-naming-convention` | Enforce boolean props start with is/has/with/without, callback props start with on 🔧 ⚙️ |
|
|
351
357
|
| `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,
|
|
358
|
+
| `type-format` | Enforce type naming (PascalCase + Type suffix), camelCase properties, union type formatting, and trailing commas 🔧 ⚙️ |
|
|
353
359
|
| `typescript-definition-location` | Enforce TypeScript definitions (interfaces, types, enums) to be in designated folders ⚙️ |
|
|
354
360
|
| **React Rules** | |
|
|
355
361
|
| `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 +1172,45 @@ else
|
|
|
1166
1172
|
|
|
1167
1173
|
---
|
|
1168
1174
|
|
|
1175
|
+
### `logical-expression-multiline`
|
|
1176
|
+
|
|
1177
|
+
**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.
|
|
1178
|
+
|
|
1179
|
+
**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.
|
|
1180
|
+
|
|
1181
|
+
```javascript
|
|
1182
|
+
// ✅ Good — 3 or fewer operands stay inline
|
|
1183
|
+
const isValid = a && b && c;
|
|
1184
|
+
const result = x || y;
|
|
1185
|
+
|
|
1186
|
+
// ✅ Good — 4+ operands get one per line
|
|
1187
|
+
const err = data.error
|
|
1188
|
+
|| data.message
|
|
1189
|
+
|| data.status
|
|
1190
|
+
|| data.fallback;
|
|
1191
|
+
|
|
1192
|
+
const isComplete = hasName
|
|
1193
|
+
&& hasEmail
|
|
1194
|
+
&& hasPhone
|
|
1195
|
+
&& hasAddress;
|
|
1196
|
+
|
|
1197
|
+
// ❌ Bad — 4+ operands on single line
|
|
1198
|
+
const err = data.error || data.message || data.status || data.fallback;
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
**Options:**
|
|
1202
|
+
|
|
1203
|
+
| Option | Type | Default | Description |
|
|
1204
|
+
|--------|------|---------|-------------|
|
|
1205
|
+
| `maxOperands` | `integer` | `3` | Maximum operands allowed on a single line |
|
|
1206
|
+
|
|
1207
|
+
```javascript
|
|
1208
|
+
// Configuration example - allow up to 4 operands on single line
|
|
1209
|
+
"code-style/logical-expression-multiline": ["error", { maxOperands: 4 }]
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
---
|
|
1213
|
+
|
|
1169
1214
|
### `multiline-if-conditions`
|
|
1170
1215
|
|
|
1171
1216
|
**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.
|
|
@@ -2969,6 +3014,30 @@ export const Card = ({ a, b } : { a: string, b: string }) => (
|
|
|
2969
3014
|
|
|
2970
3015
|
---
|
|
2971
3016
|
|
|
3017
|
+
### `folder-component-suffix`
|
|
3018
|
+
|
|
3019
|
+
**What it does:** Enforces naming conventions for components based on folder location:
|
|
3020
|
+
- Components in `views/` folder must end with "View" suffix
|
|
3021
|
+
- Components in `pages/` folder must end with "Page" suffix
|
|
3022
|
+
|
|
3023
|
+
**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.
|
|
3024
|
+
|
|
3025
|
+
```tsx
|
|
3026
|
+
// ✅ Good — in views/dashboard-view.tsx
|
|
3027
|
+
export const DashboardView = () => <div>Dashboard</div>;
|
|
3028
|
+
|
|
3029
|
+
// ✅ Good — in pages/home-page.tsx
|
|
3030
|
+
export const HomePage = () => <div>Home</div>;
|
|
3031
|
+
|
|
3032
|
+
// ❌ Bad — in views/dashboard.tsx (missing "View" suffix)
|
|
3033
|
+
export const Dashboard = () => <div>Dashboard</div>;
|
|
3034
|
+
|
|
3035
|
+
// ❌ Bad — in pages/home.tsx (missing "Page" suffix)
|
|
3036
|
+
export const Home = () => <div>Home</div>;
|
|
3037
|
+
```
|
|
3038
|
+
|
|
3039
|
+
---
|
|
3040
|
+
|
|
2972
3041
|
### `svg-component-icon-naming`
|
|
2973
3042
|
|
|
2974
3043
|
**What it does:** Enforces naming conventions for SVG icon components:
|
|
@@ -3161,6 +3230,172 @@ export const Button = ({
|
|
|
3161
3230
|
|
|
3162
3231
|
---
|
|
3163
3232
|
|
|
3233
|
+
### `prop-naming-convention`
|
|
3234
|
+
|
|
3235
|
+
**What it does:** Enforces naming conventions for boolean and callback props in TypeScript interfaces, types, and inline type definitions:
|
|
3236
|
+
- Boolean props must start with: `is`, `has`, `with`, or `without` (followed by capital letter)
|
|
3237
|
+
- Callback props must start with: `on` (followed by capital letter)
|
|
3238
|
+
- Detects React event handler types: `MouseEventHandler`, `ChangeEventHandler`, `FormEventHandler`, `KeyboardEventHandler`, etc.
|
|
3239
|
+
- Applies to all nesting levels (nested object types are checked recursively)
|
|
3240
|
+
- Does NOT apply to JSX element attributes (external components have their own props)
|
|
3241
|
+
|
|
3242
|
+
**Why use it:** Consistent prop naming makes props self-documenting. Boolean prefixes clarify intent (`isLoading` vs `loading`), and `on` prefix clearly identifies event handlers.
|
|
3243
|
+
|
|
3244
|
+
**Options:**
|
|
3245
|
+
|
|
3246
|
+
| Option | Type | Default | Description |
|
|
3247
|
+
|--------|------|---------|-------------|
|
|
3248
|
+
| `booleanPrefixes` | `string[]` | - | Replace default prefixes entirely (overrides defaults) |
|
|
3249
|
+
| `extendBooleanPrefixes` | `string[]` | `[]` | Add to default prefixes (`is`, `has`, `with`, `without`) |
|
|
3250
|
+
| `allowPastVerbBoolean` | `boolean` | `false` | Allow past verb booleans (e.g., `disabled`, `selected`, `checked`, `opened`) |
|
|
3251
|
+
| `allowContinuousVerbBoolean` | `boolean` | `false` | Allow continuous verb booleans (e.g., `loading`, `saving`, `fetching`) |
|
|
3252
|
+
| `callbackPrefix` | `string` | `"on"` | Required prefix for callback props |
|
|
3253
|
+
| `allowActionSuffix` | `boolean` | `false` | Allow `xxxAction` pattern for callbacks |
|
|
3254
|
+
|
|
3255
|
+
```typescript
|
|
3256
|
+
// ✅ Good — proper prop naming
|
|
3257
|
+
interface ButtonPropsInterface {
|
|
3258
|
+
isDisabled: boolean,
|
|
3259
|
+
isLoading: boolean,
|
|
3260
|
+
hasError: boolean,
|
|
3261
|
+
onClick: () => void,
|
|
3262
|
+
onSubmit: (data: FormData) => void,
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
type CardPropsType = {
|
|
3266
|
+
isExpanded: boolean,
|
|
3267
|
+
hasChildren: boolean,
|
|
3268
|
+
onToggle: () => void,
|
|
3269
|
+
};
|
|
3270
|
+
|
|
3271
|
+
// ✅ Good — nested types are also checked
|
|
3272
|
+
interface FormPropsInterface {
|
|
3273
|
+
isValid: boolean,
|
|
3274
|
+
config: {
|
|
3275
|
+
isEnabled: boolean, // Nested - checked
|
|
3276
|
+
onValidate: () => void, // Nested - checked
|
|
3277
|
+
settings: {
|
|
3278
|
+
isActive: boolean, // Deep nested - also checked
|
|
3279
|
+
},
|
|
3280
|
+
},
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
// ✅ Good — inline component props
|
|
3284
|
+
const Button = ({
|
|
3285
|
+
isLoading,
|
|
3286
|
+
onClick,
|
|
3287
|
+
}: {
|
|
3288
|
+
isLoading: boolean,
|
|
3289
|
+
onClick: () => void,
|
|
3290
|
+
}) => { ... };
|
|
3291
|
+
|
|
3292
|
+
// ❌ Bad — missing prefixes
|
|
3293
|
+
interface ButtonPropsInterface {
|
|
3294
|
+
disabled: boolean, // Should be isDisabled
|
|
3295
|
+
loading: boolean, // Should be isLoading
|
|
3296
|
+
error: boolean, // Should be hasError
|
|
3297
|
+
click: () => void, // Should be onClick
|
|
3298
|
+
handleSubmit: () => void, // Should be onSubmit
|
|
3299
|
+
}
|
|
3300
|
+
|
|
3301
|
+
// ❌ Bad — nested types also checked
|
|
3302
|
+
type PropsType = {
|
|
3303
|
+
config: {
|
|
3304
|
+
enabled: boolean, // Should be isEnabled
|
|
3305
|
+
toggle: () => void, // Should be onToggle
|
|
3306
|
+
},
|
|
3307
|
+
};
|
|
3308
|
+
```
|
|
3309
|
+
|
|
3310
|
+
**Past Verb Booleans** (`allowPastVerbBoolean: true`):
|
|
3311
|
+
|
|
3312
|
+
When enabled, allows boolean props that are past tense verbs (ending in `-ed`):
|
|
3313
|
+
|
|
3314
|
+
```typescript
|
|
3315
|
+
// ✅ Allowed with allowPastVerbBoolean: true
|
|
3316
|
+
interface PropsInterface {
|
|
3317
|
+
disabled: boolean, // Past verb - ends with -ed
|
|
3318
|
+
selected: boolean, // Past verb - ends with -ed
|
|
3319
|
+
checked: boolean, // Past verb - ends with -ed
|
|
3320
|
+
opened: boolean, // Past verb - ends with -ed
|
|
3321
|
+
closed: boolean, // Past verb - ends with -ed
|
|
3322
|
+
expanded: boolean, // Past verb - ends with -ed
|
|
3323
|
+
collapsed: boolean, // Past verb - ends with -ed
|
|
3324
|
+
focused: boolean, // Past verb - ends with -ed
|
|
3325
|
+
hidden: boolean, // Past verb - ends with -ed
|
|
3326
|
+
connected: boolean, // Past verb - ends with -ed
|
|
3327
|
+
}
|
|
3328
|
+
```
|
|
3329
|
+
|
|
3330
|
+
**Continuous Verb Booleans** (`allowContinuousVerbBoolean: true`):
|
|
3331
|
+
|
|
3332
|
+
When enabled, allows boolean props that are continuous tense verbs (ending in `-ing`):
|
|
3333
|
+
|
|
3334
|
+
```typescript
|
|
3335
|
+
// ✅ Allowed with allowContinuousVerbBoolean: true
|
|
3336
|
+
interface PropsInterface {
|
|
3337
|
+
loading: boolean, // Continuous verb - ends with -ing
|
|
3338
|
+
saving: boolean, // Continuous verb - ends with -ing
|
|
3339
|
+
fetching: boolean, // Continuous verb - ends with -ing
|
|
3340
|
+
closing: boolean, // Continuous verb - ends with -ing
|
|
3341
|
+
opening: boolean, // Continuous verb - ends with -ing
|
|
3342
|
+
submitting: boolean, // Continuous verb - ends with -ing
|
|
3343
|
+
processing: boolean, // Continuous verb - ends with -ing
|
|
3344
|
+
updating: boolean, // Continuous verb - ends with -ing
|
|
3345
|
+
deleting: boolean, // Continuous verb - ends with -ing
|
|
3346
|
+
pending: boolean, // Continuous verb - ends with -ing
|
|
3347
|
+
}
|
|
3348
|
+
```
|
|
3349
|
+
|
|
3350
|
+
**Configuration Examples:**
|
|
3351
|
+
|
|
3352
|
+
```javascript
|
|
3353
|
+
// Default configuration (strict)
|
|
3354
|
+
"code-style/prop-naming-convention": "error"
|
|
3355
|
+
|
|
3356
|
+
// Allow past verb booleans (disabled, selected, checked, etc.)
|
|
3357
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3358
|
+
allowPastVerbBoolean: true,
|
|
3359
|
+
}]
|
|
3360
|
+
|
|
3361
|
+
// Allow continuous verb booleans (loading, saving, fetching, etc.)
|
|
3362
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3363
|
+
allowContinuousVerbBoolean: true,
|
|
3364
|
+
}]
|
|
3365
|
+
|
|
3366
|
+
// Allow both past and continuous verb booleans
|
|
3367
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3368
|
+
allowPastVerbBoolean: true,
|
|
3369
|
+
allowContinuousVerbBoolean: true,
|
|
3370
|
+
}]
|
|
3371
|
+
|
|
3372
|
+
// Extend default prefixes with additional ones
|
|
3373
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3374
|
+
extendBooleanPrefixes: ["should", "can", "will", "did"],
|
|
3375
|
+
}]
|
|
3376
|
+
|
|
3377
|
+
// Replace default prefixes entirely
|
|
3378
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3379
|
+
booleanPrefixes: ["is", "has"], // Only these prefixes allowed
|
|
3380
|
+
}]
|
|
3381
|
+
|
|
3382
|
+
// Allow "xxxAction" suffix for callbacks
|
|
3383
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3384
|
+
allowActionSuffix: true, // Allows: submitAction, copyAction, deleteAction
|
|
3385
|
+
}]
|
|
3386
|
+
|
|
3387
|
+
// Full custom configuration
|
|
3388
|
+
"code-style/prop-naming-convention": ["error", {
|
|
3389
|
+
extendBooleanPrefixes: ["should", "can"],
|
|
3390
|
+
allowPastVerbBoolean: true,
|
|
3391
|
+
allowContinuousVerbBoolean: true,
|
|
3392
|
+
callbackPrefix: "on",
|
|
3393
|
+
allowActionSuffix: true,
|
|
3394
|
+
}]
|
|
3395
|
+
```
|
|
3396
|
+
|
|
3397
|
+
---
|
|
3398
|
+
|
|
3164
3399
|
### `type-format`
|
|
3165
3400
|
|
|
3166
3401
|
**What it does:** Enforces consistent formatting for TypeScript type aliases:
|
|
@@ -3168,6 +3403,8 @@ export const Button = ({
|
|
|
3168
3403
|
- Properties must be camelCase
|
|
3169
3404
|
- No empty lines between properties
|
|
3170
3405
|
- Properties must end with commas, not semicolons
|
|
3406
|
+
- Union types with 5+ members must be multiline (one per line)
|
|
3407
|
+
- Union types with <5 members must be single line
|
|
3171
3408
|
|
|
3172
3409
|
**Why use it:** Consistent type naming makes types instantly recognizable. The suffix clearly distinguishes types from interfaces and classes.
|
|
3173
3410
|
|
|
@@ -3185,6 +3422,26 @@ export type ApiResponseType<T> = {
|
|
|
3185
3422
|
status: number,
|
|
3186
3423
|
};
|
|
3187
3424
|
|
|
3425
|
+
// ✅ Good — union type with 6 members (multiline)
|
|
3426
|
+
export type ButtonVariantType =
|
|
3427
|
+
"danger"
|
|
3428
|
+
| "ghost"
|
|
3429
|
+
| "ghost-danger"
|
|
3430
|
+
| "link"
|
|
3431
|
+
| "muted"
|
|
3432
|
+
| "primary";
|
|
3433
|
+
|
|
3434
|
+
// ✅ Good — union type with 2 members (single line)
|
|
3435
|
+
export type CodeLayoutVariantType = "default" | "error";
|
|
3436
|
+
|
|
3437
|
+
// ❌ Bad — 6 members should be multiline
|
|
3438
|
+
export type BadUnionType = "a" | "b" | "c" | "d" | "e" | "f";
|
|
3439
|
+
|
|
3440
|
+
// ❌ Bad — 2 members should be single line
|
|
3441
|
+
export type BadSingleType =
|
|
3442
|
+
"default"
|
|
3443
|
+
| "error";
|
|
3444
|
+
|
|
3188
3445
|
// ❌ Bad — wrong naming
|
|
3189
3446
|
export type User = { // Missing Type suffix
|
|
3190
3447
|
Email: string; // Should be camelCase
|
|
@@ -3199,6 +3456,17 @@ export type ConfigType = {
|
|
|
3199
3456
|
};
|
|
3200
3457
|
```
|
|
3201
3458
|
|
|
3459
|
+
**Options:**
|
|
3460
|
+
|
|
3461
|
+
| Option | Type | Default | Description |
|
|
3462
|
+
|--------|------|---------|-------------|
|
|
3463
|
+
| `minUnionMembersForMultiline` | `integer` | `5` | Minimum number of union members to require multiline format |
|
|
3464
|
+
|
|
3465
|
+
```javascript
|
|
3466
|
+
// Configuration example - require multiline for 4+ union members
|
|
3467
|
+
"code-style/type-format": ["error", { minUnionMembersForMultiline: 4 }]
|
|
3468
|
+
```
|
|
3469
|
+
|
|
3202
3470
|
---
|
|
3203
3471
|
|
|
3204
3472
|
### `type-annotation-spacing`
|
|
@@ -3581,7 +3849,7 @@ const UseAuth = () => {}; // hooks should be camelCase
|
|
|
3581
3849
|
|
|
3582
3850
|
## 🔧 Auto-fixing
|
|
3583
3851
|
|
|
3584
|
-
|
|
3852
|
+
66 of 75 rules support auto-fixing. Run ESLint with the `--fix` flag:
|
|
3585
3853
|
|
|
3586
3854
|
```bash
|
|
3587
3855
|
# 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"
|
|
@@ -67,6 +68,7 @@ export type RuleNames =
|
|
|
67
68
|
| "code-style/object-property-value-brace"
|
|
68
69
|
| "code-style/object-property-value-format"
|
|
69
70
|
| "code-style/opening-brackets-same-line"
|
|
71
|
+
| "code-style/prop-naming-convention"
|
|
70
72
|
| "code-style/simple-call-single-line"
|
|
71
73
|
| "code-style/single-argument-on-one-line"
|
|
72
74
|
| "code-style/string-property-spacing"
|
|
@@ -119,6 +121,7 @@ interface PluginRules {
|
|
|
119
121
|
"empty-line-after-block": Rule.RuleModule;
|
|
120
122
|
"enum-type-enforcement": Rule.RuleModule;
|
|
121
123
|
"export-format": Rule.RuleModule;
|
|
124
|
+
"folder-component-suffix": Rule.RuleModule;
|
|
122
125
|
"function-arguments-format": Rule.RuleModule;
|
|
123
126
|
"function-call-spacing": Rule.RuleModule;
|
|
124
127
|
"function-declaration-style": Rule.RuleModule;
|
|
@@ -162,6 +165,7 @@ interface PluginRules {
|
|
|
162
165
|
"object-property-value-brace": Rule.RuleModule;
|
|
163
166
|
"object-property-value-format": Rule.RuleModule;
|
|
164
167
|
"opening-brackets-same-line": Rule.RuleModule;
|
|
168
|
+
"prop-naming-convention": Rule.RuleModule;
|
|
165
169
|
"simple-call-single-line": Rule.RuleModule;
|
|
166
170
|
"single-argument-on-one-line": Rule.RuleModule;
|
|
167
171
|
"string-property-spacing": Rule.RuleModule;
|