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