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 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
- *73 rules (65 auto-fixable) to keep your codebase clean and consistent*
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 **73 custom rules** (65 auto-fixable) for code formatting. Built for **ESLint v9 flat configs**.
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** — 65 of 73 rules support auto-fix with `eslint --fix`
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
- **65 rules** support automatic fixing with `eslint --fix`. 6 rules are report-only (require manual changes).
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
- > **73 rules total** — 65 with auto-fix 🔧, 8 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
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, no empty lines, and trailing commas 🔧 |
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
- 65 of 73 rules support auto-fixing. Run ESLint with the `--fix` flag:
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;