eslint-plugin-code-style 1.15.0 → 1.17.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/AGENTS.md +26 -26
- package/CHANGELOG.md +80 -0
- package/README.md +198 -40
- package/index.d.ts +8 -4
- package/index.js +709 -87
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -4,9 +4,9 @@ Instructions for AI coding agents working with this codebase.
|
|
|
4
4
|
|
|
5
5
|
## Project Overview
|
|
6
6
|
|
|
7
|
-
**eslint-plugin-code-style** is an ESLint plugin providing
|
|
7
|
+
**eslint-plugin-code-style** is an ESLint plugin providing 79 custom formatting rules (70 auto-fixable, 19 configurable, 9 report-only) for React/JSX projects. It's designed for ESLint v9+ flat config system.
|
|
8
8
|
|
|
9
|
-
- **Main entry:** `index.js` - Contains all
|
|
9
|
+
- **Main entry:** `index.js` - Contains all 79 rules in a single file
|
|
10
10
|
- **Type definitions:** `index.d.ts` - TypeScript declarations for IDE support
|
|
11
11
|
- **Recommended configs:** `recommended-configs/` - Ready-to-use ESLint configurations
|
|
12
12
|
- **Test apps:** `_tests_/` - Sample apps for testing rules
|
|
@@ -33,7 +33,7 @@ Each test project in `_tests_/` corresponds to a specific tech stack. Rules shou
|
|
|
33
33
|
| **TypeScript rules** | ❌ | ✅ | ✅ | ❌ |
|
|
34
34
|
| **Tailwind rules** | ❌ | ✅ | ❌ | ✅ |
|
|
35
35
|
|
|
36
|
-
**TypeScript-only rules** (
|
|
36
|
+
**TypeScript-only rules** (71 rules in JS projects, 79 in TS projects):
|
|
37
37
|
- `component-props-inline-type`
|
|
38
38
|
- `enum-format`
|
|
39
39
|
- `interface-format`
|
|
@@ -87,7 +87,7 @@ index.js
|
|
|
87
87
|
├── imports (fs, path, url)
|
|
88
88
|
├── Rule 1 definition (const ruleName = { create(), meta: {} })
|
|
89
89
|
├── Rule 2 definition
|
|
90
|
-
├── ... (
|
|
90
|
+
├── ... (79 rules total)
|
|
91
91
|
└── export default { meta: {}, rules: {} }
|
|
92
92
|
```
|
|
93
93
|
|
|
@@ -651,7 +651,7 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
|
|
|
651
651
|
- **Comment Rules** — Comment formatting
|
|
652
652
|
- `comment-format`
|
|
653
653
|
- **Component Rules** — React component patterns
|
|
654
|
-
- `component-props-destructure`, `component-props-inline-type`, `folder-
|
|
654
|
+
- `component-props-destructure`, `component-props-inline-type`, `folder-based-naming-convention`, `folder-structure-consistency`, `no-redundant-folder-suffix`, `svg-icon-naming-convention`
|
|
655
655
|
- **Control Flow Rules** — if/switch/block statements
|
|
656
656
|
- `block-statement-newlines`, `if-else-spacing`, `if-statement-format`, `multiline-if-conditions`, `no-empty-lines-in-switch-cases`, `ternary-condition-multiline`
|
|
657
657
|
- **Function Rules** — Function declarations and params
|
|
@@ -659,7 +659,7 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
|
|
|
659
659
|
- **Hook Rules** — React hooks formatting
|
|
660
660
|
- `hook-callback-format`, `hook-deps-per-line`
|
|
661
661
|
- **Import/Export Rules** — Import/export statements
|
|
662
|
-
- `absolute-imports-only`, `export-format`, `import-format`, `import-source-spacing`, `index-export-style`, `index-exports-only`, `module-index-exports`
|
|
662
|
+
- `absolute-imports-only`, `export-format`, `import-format`, `import-source-spacing`, `index-export-style`, `index-exports-only`, `inline-export-declaration`, `module-index-exports`
|
|
663
663
|
- **JSX Rules** — JSX elements and attributes
|
|
664
664
|
- `classname-dynamic-at-end`, `classname-multiline`, `classname-no-extra-spaces`, `classname-order`, `jsx-children-on-new-line`, `jsx-closing-bracket-spacing`, `jsx-element-child-new-line`, `jsx-logical-expression-simplify`, `jsx-parentheses-position`, `jsx-prop-naming-convention`, `jsx-simple-element-one-line`, `jsx-string-value-trim`, `jsx-ternary-format`, `no-empty-lines-in-jsx`
|
|
665
665
|
- **Object Rules** — Object literal formatting
|
|
@@ -687,7 +687,7 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
|
|
|
687
687
|
|
|
688
688
|
## Documentation Files
|
|
689
689
|
|
|
690
|
-
- `README.md` - Main documentation with all
|
|
690
|
+
- `README.md` - Main documentation with all 79 rules
|
|
691
691
|
- `recommended-configs/<config-name>/README.md` - Config-specific documentation (references main README for rule details)
|
|
692
692
|
- `index.d.ts` - TypeScript types for IDE autocomplete
|
|
693
693
|
|
|
@@ -695,7 +695,7 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
|
|
|
695
695
|
|
|
696
696
|
- Most rules should be auto-fixable (`fixable: "code"` or `fixable: "whitespace"` in meta)
|
|
697
697
|
- Rules that require file creation/movement or architectural decisions may be report-only
|
|
698
|
-
- Currently:
|
|
698
|
+
- Currently: 70 auto-fixable rules, 19 configurable rules, 9 report-only rules
|
|
699
699
|
- Use 4-space indentation throughout
|
|
700
700
|
- Object properties in `context.report()` must be alphabetically sorted
|
|
701
701
|
- Keep rules self-sufficient (no dependencies on other ESLint rules)
|
|
@@ -708,10 +708,10 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
|
|
|
708
708
|
**IMPORTANT:** When adding/removing rules, update the rule counts in ALL these locations:
|
|
709
709
|
|
|
710
710
|
### Current Counts (update these when changing rules)
|
|
711
|
-
- **Total rules:**
|
|
712
|
-
- **Auto-fixable:**
|
|
713
|
-
- **Configurable:**
|
|
714
|
-
- **Report-only:**
|
|
711
|
+
- **Total rules:** 79
|
|
712
|
+
- **Auto-fixable:** 70
|
|
713
|
+
- **Configurable:** 19 (rules with ⚙️ that have options)
|
|
714
|
+
- **Report-only:** 9
|
|
715
715
|
|
|
716
716
|
**IMPORTANT:** All counts must be uniform across ALL files. When updating:
|
|
717
717
|
- Total rules, auto-fixable count, configurable count, and report-only count must match everywhere
|
|
@@ -722,21 +722,21 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
|
|
|
722
722
|
|
|
723
723
|
| File | Line(s) | What to Update |
|
|
724
724
|
|------|---------|----------------|
|
|
725
|
-
| `README.md` | ~22 | `*
|
|
726
|
-
| `README.md` | ~30 | `**
|
|
727
|
-
| `README.md` | ~39 | `
|
|
728
|
-
| `README.md` | ~100 | `**
|
|
729
|
-
| `README.md` | ~266 | `**
|
|
730
|
-
| `README.md` | ~3650 | `
|
|
731
|
-
| `AGENTS.md` | ~7 | `
|
|
732
|
-
| `AGENTS.md` | ~9 | `Contains all
|
|
733
|
-
| `AGENTS.md` | ~36 | `(
|
|
734
|
-
| `AGENTS.md` | ~89 | `(
|
|
735
|
-
| `AGENTS.md` | ~675 | `all
|
|
736
|
-
| `AGENTS.md` | ~697 | `
|
|
725
|
+
| `README.md` | ~22 | `*79 rules (70 auto-fixable, 19 configurable)*` |
|
|
726
|
+
| `README.md` | ~30 | `**79 custom rules** (70 auto-fixable, 19 configurable)` |
|
|
727
|
+
| `README.md` | ~39 | `70 of 79 rules support auto-fix` |
|
|
728
|
+
| `README.md` | ~100 | `**70 rules** support automatic fixing. **19 rules** have configurable options` |
|
|
729
|
+
| `README.md` | ~266 | `**79 rules total** — 70 with auto-fix, 19 configurable` |
|
|
730
|
+
| `README.md` | ~3650 | `70 of 79 rules support auto-fixing` |
|
|
731
|
+
| `AGENTS.md` | ~7 | `79 custom formatting rules (70 auto-fixable, 19 configurable, 9 report-only)` |
|
|
732
|
+
| `AGENTS.md` | ~9 | `Contains all 79 rules` |
|
|
733
|
+
| `AGENTS.md` | ~36 | `(71 rules in JS projects, 79 in TS projects)` |
|
|
734
|
+
| `AGENTS.md` | ~89 | `(79 rules total)` |
|
|
735
|
+
| `AGENTS.md` | ~675 | `all 79 rules` |
|
|
736
|
+
| `AGENTS.md` | ~697 | `70 auto-fixable rules, 19 configurable rules, 9 report-only` |
|
|
737
737
|
| `AGENTS.md` | Rule Count Locations section | Current Counts table |
|
|
738
|
-
| `recommended-configs/react-ts-tw/README.md` | ~396 | `**
|
|
739
|
-
| `recommended-configs/react/README.md` | ~286 | `**
|
|
738
|
+
| `recommended-configs/react-ts-tw/README.md` | ~396 | `**70 auto-fixable rules** (79 total, 19 configurable, 9 report-only)` |
|
|
739
|
+
| `recommended-configs/react/README.md` | ~286 | `**70 auto-fixable rules** (79 total, 19 configurable, 9 report-only)` |
|
|
740
740
|
|
|
741
741
|
### Quick Verification Commands
|
|
742
742
|
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,84 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [1.17.0] - 2026-02-09
|
|
11
|
+
|
|
12
|
+
**New Rule + Enhancements to Naming & Import Rules**
|
|
13
|
+
|
|
14
|
+
**Version Range:** v1.16.0 → v1.17.0
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
**New Rules (1)**
|
|
19
|
+
- `inline-export-declaration` - Enforce inline export declarations (`export const x = ...`) instead of grouped export statements (`export { x }`) in non-index files 🔧
|
|
20
|
+
- Auto-fixable: adds `export` to each declaration and removes the grouped export statement
|
|
21
|
+
- Skips index files (barrel re-exports) and aliased exports (`export { a as b }`)
|
|
22
|
+
|
|
23
|
+
### Enhanced
|
|
24
|
+
|
|
25
|
+
- **`folder-based-naming-convention`** - Extended camelCase suffix enforcement for data/constants/strings/services/reducers folders
|
|
26
|
+
- Exports in `data/` must end with `Data` (e.g., `buttonTypeData`)
|
|
27
|
+
- Exports in `constants/` must end with `Constants` (e.g., `localeConstants`)
|
|
28
|
+
- Exports in `strings/` must end with `Strings` (e.g., `appStrings`)
|
|
29
|
+
- Exports in `services/` must end with `Service`, `reducers/` with `Reducer`
|
|
30
|
+
- **`absolute-imports-only`** - Files within the same module folder must use relative imports instead of absolute to avoid circular dependencies 🔧
|
|
31
|
+
- Detects files at any depth inside module folders (e.g., `data/auth/login/guest.tsx`)
|
|
32
|
+
- Allows both `./` and `../` relative imports within the same module folder
|
|
33
|
+
- Auto-fixes absolute imports to own module folder (e.g., `@/data/auth/login/guest` → `../../login/guest`)
|
|
34
|
+
- Now marked as auto-fixable (`fixable: "code"`)
|
|
35
|
+
- **`folder-structure-consistency`** - Added loose module file detection: standalone files matching module folder names (e.g., `data.js`, `strings.js`) are flagged — must use folder structure instead
|
|
36
|
+
|
|
37
|
+
### Stats
|
|
38
|
+
|
|
39
|
+
- Total Rules: 79 (was 78)
|
|
40
|
+
- Auto-fixable: 70 rules (was 69) 🔧
|
|
41
|
+
- Configurable: 19 rules (was 18)
|
|
42
|
+
- Report-only: 9 rules (was 10)
|
|
43
|
+
|
|
44
|
+
**Full Changelog:** [v1.16.0...v1.17.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.16.0...v1.17.0)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## [1.16.0] - 2026-02-09
|
|
49
|
+
|
|
50
|
+
**New Rule + Enhancements + Rule Renames**
|
|
51
|
+
|
|
52
|
+
**Version Range:** v1.15.0 → v1.16.0
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
**New Rules (1)**
|
|
57
|
+
- `folder-structure-consistency` - Enforce consistent folder structure (flat vs wrapped) in module folders
|
|
58
|
+
- Applies to all module folders (same list as `module-index-exports`)
|
|
59
|
+
- Detects mixed structures (some flat files, some in subfolders)
|
|
60
|
+
- Flags unnecessary wrapper folders when each has only one file
|
|
61
|
+
- Configurable `moduleFolders` and `extraModuleFolders` options
|
|
62
|
+
|
|
63
|
+
### Enhanced
|
|
64
|
+
|
|
65
|
+
- **`folder-based-naming-convention`** (renamed from `folder-component-suffix`)
|
|
66
|
+
- Support nested files with chained folder names (e.g., `layouts/auth/login.tsx` → `LoginAuthLayout`)
|
|
67
|
+
- Match files at any depth within module folders
|
|
68
|
+
- Expanded to cover: views, layouts, pages, providers, reducers, services, contexts, themes (with suffix), atoms and components (chaining only, no suffix)
|
|
69
|
+
- Added `VariableDeclarator` detection for non-JSX folders (contexts, themes)
|
|
70
|
+
- **`no-redundant-folder-suffix`** - Also check folder names for redundant suffixes (e.g., `views/access-control-view/` is now flagged)
|
|
71
|
+
|
|
72
|
+
### Renamed
|
|
73
|
+
|
|
74
|
+
- `folder-component-suffix` → `folder-based-naming-convention` (now handles more than just components)
|
|
75
|
+
- `svg-component-icon-naming` → `svg-icon-naming-convention` (consistent with other naming convention rules)
|
|
76
|
+
|
|
77
|
+
### Stats
|
|
78
|
+
|
|
79
|
+
- Total Rules: 78 (was 77)
|
|
80
|
+
- Auto-fixable: 67 rules
|
|
81
|
+
- Configurable: 18 rules (was 17)
|
|
82
|
+
- Report-only: 11 rules (was 10)
|
|
83
|
+
|
|
84
|
+
**Full Changelog:** [v1.15.0...v1.16.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.15.0...v1.16.0)
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
10
88
|
## [1.15.0] - 2026-02-06
|
|
11
89
|
|
|
12
90
|
**New Rule: no-redundant-folder-suffix**
|
|
@@ -1728,6 +1806,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1728
1806
|
|
|
1729
1807
|
---
|
|
1730
1808
|
|
|
1809
|
+
[1.17.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.16.0...v1.17.0
|
|
1810
|
+
[1.16.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.15.0...v1.16.0
|
|
1731
1811
|
[1.15.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.4...v1.15.0
|
|
1732
1812
|
[1.14.4]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.3...v1.14.4
|
|
1733
1813
|
[1.14.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.2...v1.14.3
|
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
|
+
*79 rules (70 auto-fixable, 19 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 **79 custom rules** (70 auto-fixable, 19 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 **77 custom rules** (67 auto-fixable, 17 configurable) for
|
|
|
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** — 70 of 79 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
|
|
|
@@ -60,7 +60,7 @@ We provide **ready-to-use ESLint flat configuration files** that combine `eslint
|
|
|
60
60
|
|
|
61
61
|
### 💡 Why Use These Configs?
|
|
62
62
|
|
|
63
|
-
- **Complete Coverage** — Combines ESLint built-in rules, third-party plugins, and all
|
|
63
|
+
- **Complete Coverage** — Combines ESLint built-in rules, third-party plugins, and all 79 code-style rules
|
|
64
64
|
- **Ready-to-Use** — Copy the config file and start linting immediately
|
|
65
65
|
- **Battle-Tested** — These configurations have been refined through real-world usage
|
|
66
66
|
- **Fully Documented** — Each config includes detailed instructions and explanations
|
|
@@ -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
|
+
**70 rules** support automatic fixing with `eslint --fix`. **19 rules** have configurable options. 9 rules are report-only (require manual changes).
|
|
101
101
|
|
|
102
102
|
</td>
|
|
103
103
|
<td width="50%">
|
|
@@ -199,13 +199,14 @@ rules: {
|
|
|
199
199
|
"code-style/comment-format": "error",
|
|
200
200
|
"code-style/component-props-destructure": "error",
|
|
201
201
|
"code-style/component-props-inline-type": "error",
|
|
202
|
-
"code-style/svg-
|
|
202
|
+
"code-style/svg-icon-naming-convention": "error",
|
|
203
203
|
"code-style/curried-arrow-same-line": "error",
|
|
204
204
|
"code-style/empty-line-after-block": "error",
|
|
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-
|
|
208
|
+
"code-style/folder-based-naming-convention": "error",
|
|
209
|
+
"code-style/folder-structure-consistency": "error",
|
|
209
210
|
"code-style/no-redundant-folder-suffix": "error",
|
|
210
211
|
"code-style/function-arguments-format": "error",
|
|
211
212
|
"code-style/function-call-spacing": "error",
|
|
@@ -222,6 +223,7 @@ rules: {
|
|
|
222
223
|
"code-style/import-source-spacing": "error",
|
|
223
224
|
"code-style/index-export-style": "error",
|
|
224
225
|
"code-style/index-exports-only": "error",
|
|
226
|
+
"code-style/inline-export-declaration": "error",
|
|
225
227
|
"code-style/interface-format": "error",
|
|
226
228
|
"code-style/jsx-children-on-new-line": "error",
|
|
227
229
|
"code-style/jsx-closing-bracket-spacing": "error",
|
|
@@ -267,7 +269,7 @@ rules: {
|
|
|
267
269
|
|
|
268
270
|
## 📖 Rules Categories
|
|
269
271
|
|
|
270
|
-
> **
|
|
272
|
+
> **79 rules total** — 70 with auto-fix 🔧, 19 configurable ⚙️, 9 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
|
|
271
273
|
>
|
|
272
274
|
> **Legend:** 🔧 Auto-fixable with `eslint --fix` • ⚙️ Customizable options
|
|
273
275
|
|
|
@@ -294,9 +296,10 @@ rules: {
|
|
|
294
296
|
| **Component Rules** | |
|
|
295
297
|
| `component-props-destructure` | Component props must be destructured `({ prop })` not received as `(props)` 🔧 |
|
|
296
298
|
| `component-props-inline-type` | Inline type annotation `} : {` with matching props, proper spacing, commas, no interface reference 🔧 |
|
|
297
|
-
| `folder-
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
299
|
+
| `folder-based-naming-convention` | Enforce naming based on folder: suffix for views/layouts/pages/providers/reducers/contexts/themes, camelCase suffix for data/constants/strings/services/reducers folders, chained folder names for nested files 🔧 |
|
|
300
|
+
| `folder-structure-consistency` | Enforce consistent folder structure (flat vs wrapped) in module folders (atoms, components, hooks, enums, views, etc.) ⚙️ |
|
|
301
|
+
| `no-redundant-folder-suffix` | Disallow file and folder names that redundantly include the parent folder name as a suffix |
|
|
302
|
+
| `svg-icon-naming-convention` | SVG components must end with "Icon" suffix; "Icon" suffix components must return SVG |
|
|
300
303
|
| **Class Rules** | |
|
|
301
304
|
| `class-method-definition-format` | Consistent spacing in class/method definitions: space before `{`, no space before `(` 🔧 |
|
|
302
305
|
| `class-naming-convention` | Class declarations must end with "Class" suffix (e.g., `ApiServiceClass`) 🔧 |
|
|
@@ -321,12 +324,13 @@ rules: {
|
|
|
321
324
|
| `hook-deps-per-line` | Collapse deps ≤ threshold to one line; expand larger arrays with each dep on own line (default: >2) 🔧 ⚙️ |
|
|
322
325
|
| `use-state-naming-convention` | Boolean useState variables must start with is/has/with/without prefix 🔧 ⚙️ |
|
|
323
326
|
| **Import/Export Rules** | |
|
|
324
|
-
| `absolute-imports-only` | Use alias imports from index files only (not deep paths), no relative imports (default: `@/`) ⚙️ |
|
|
327
|
+
| `absolute-imports-only` | Use alias imports from index files only (not deep paths), no relative imports; files within the same module folder must use relative imports — auto-fixes absolute imports to relative (default: `@/`) 🔧 ⚙️ |
|
|
325
328
|
| `export-format` | `export {` on same line; collapse ≤ threshold to one line; expand larger with each specifier on own line (default: ≤3) 🔧 ⚙️ |
|
|
326
329
|
| `import-format` | `import {` and `} from` on same line; collapse ≤ threshold; expand larger with each specifier on own line (default: ≤3) 🔧 ⚙️ |
|
|
327
330
|
| `import-source-spacing` | No leading/trailing spaces inside import path quotes 🔧 |
|
|
328
331
|
| `index-export-style` | Index files: no blank lines, enforce shorthand or import-export style; Regular files: require blank lines between exports (default: shorthand) 🔧 ⚙️ |
|
|
329
332
|
| `index-exports-only` | Index files should only contain imports and re-exports, not code definitions (types, functions, variables, classes) |
|
|
333
|
+
| `inline-export-declaration` | Enforce inline export declarations instead of grouped export statements in non-index files 🔧 ⚙️ |
|
|
330
334
|
| `module-index-exports` | Index files must export all folder contents (files and subfolders) ⚙️ |
|
|
331
335
|
| **JSX Rules** | |
|
|
332
336
|
| `classname-dynamic-at-end` | Dynamic expressions (`${className}`) must be at the end of class strings (JSX and variables) 🔧 |
|
|
@@ -1812,13 +1816,14 @@ const [error, setError] = useState<boolean>(false);
|
|
|
1812
1816
|
|
|
1813
1817
|
### `absolute-imports-only`
|
|
1814
1818
|
|
|
1815
|
-
**What it does:** Enforces importing from folder index files using absolute paths (aliases like `@/`) instead of relative paths or deep file imports.
|
|
1819
|
+
**What it does:** Enforces importing from folder index files using absolute paths (aliases like `@/`) instead of relative paths or deep file imports. Files within the same module folder must use relative imports (`./` or `../`) instead of absolute paths to avoid circular dependencies through the index file. Auto-fixes absolute imports to own module folder into relative paths. 🔧
|
|
1816
1820
|
|
|
1817
1821
|
**Why use it:**
|
|
1818
1822
|
- Absolute imports are cleaner than `../../../components`
|
|
1819
1823
|
- Index imports create a public API for each folder
|
|
1820
1824
|
- Refactoring file locations doesn't break imports
|
|
1821
1825
|
- Encourages proper module organization
|
|
1826
|
+
- Relative imports within the same module folder avoid circular dependencies
|
|
1822
1827
|
|
|
1823
1828
|
```javascript
|
|
1824
1829
|
// ✅ Good — import from index files using alias
|
|
@@ -1830,7 +1835,20 @@ import { formatDate } from "@/utils";
|
|
|
1830
1835
|
// ✅ Good — assets allow deep imports by default
|
|
1831
1836
|
import logo from "@/assets/images/logo.png";
|
|
1832
1837
|
|
|
1833
|
-
//
|
|
1838
|
+
// ✅ Good — relative import within the same module folder (siblings)
|
|
1839
|
+
// File: utils/formatters.js
|
|
1840
|
+
import { isNumber } from "./validators";
|
|
1841
|
+
|
|
1842
|
+
// ✅ Good — relative import within the same module folder (nested)
|
|
1843
|
+
// File: data/auth/forget-password/index.ts
|
|
1844
|
+
import { guestLoginData } from "../../login/guest";
|
|
1845
|
+
|
|
1846
|
+
// ❌ Bad — absolute import to own module folder (should use relative)
|
|
1847
|
+
// File: data/auth/forget-password/index.ts
|
|
1848
|
+
import { guestLoginData } from "@/data";
|
|
1849
|
+
// → use relative import instead: import { guestLoginData } from "../../login/guest";
|
|
1850
|
+
|
|
1851
|
+
// ❌ Bad — relative imports across different folders
|
|
1834
1852
|
import { Button } from "../../components";
|
|
1835
1853
|
import { useAuth } from "../../../hooks";
|
|
1836
1854
|
|
|
@@ -2084,6 +2102,46 @@ export function helper() { ... } // Move to utils.ts
|
|
|
2084
2102
|
|
|
2085
2103
|
---
|
|
2086
2104
|
|
|
2105
|
+
### `inline-export-declaration`
|
|
2106
|
+
|
|
2107
|
+
**What it does:** Enforces that exports are declared inline with the declaration (`export const`, `export function`) instead of using grouped export statements (`export { ... }`). Auto-fixable: adds `export` to each declaration and removes the grouped export statement.
|
|
2108
|
+
|
|
2109
|
+
**Why use it:** Inline exports make it immediately clear which declarations are public. Grouped exports at the bottom of a file require scrolling to discover what's exported, and they can become stale or inconsistent with the actual declarations.
|
|
2110
|
+
|
|
2111
|
+
**Important exceptions:**
|
|
2112
|
+
- **Index files** (barrel re-exports) are skipped entirely -- they should use grouped/re-export syntax
|
|
2113
|
+
- **Aliased exports** (`export { a as b }`) are skipped since they cannot be expressed as inline exports
|
|
2114
|
+
|
|
2115
|
+
```javascript
|
|
2116
|
+
// ✅ Good — inline export declarations
|
|
2117
|
+
export const strings = {
|
|
2118
|
+
title: "Hello",
|
|
2119
|
+
subtitle: "World",
|
|
2120
|
+
};
|
|
2121
|
+
|
|
2122
|
+
export const MAX_RETRIES = 3;
|
|
2123
|
+
|
|
2124
|
+
export function fetchData() {
|
|
2125
|
+
return fetch("/api/data");
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
// ❌ Bad — grouped export statement
|
|
2129
|
+
const strings = {
|
|
2130
|
+
title: "Hello",
|
|
2131
|
+
subtitle: "World",
|
|
2132
|
+
};
|
|
2133
|
+
|
|
2134
|
+
const MAX_RETRIES = 3;
|
|
2135
|
+
|
|
2136
|
+
function fetchData() {
|
|
2137
|
+
return fetch("/api/data");
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
export { strings, MAX_RETRIES, fetchData };
|
|
2141
|
+
```
|
|
2142
|
+
|
|
2143
|
+
---
|
|
2144
|
+
|
|
2087
2145
|
### `module-index-exports`
|
|
2088
2146
|
|
|
2089
2147
|
**What it does:** Ensures module folders have index files that export all their contents, creating a proper public API for each module.
|
|
@@ -3061,65 +3119,163 @@ export const Card = ({ a, b } : { a: string, b: string }) => (
|
|
|
3061
3119
|
|
|
3062
3120
|
---
|
|
3063
3121
|
|
|
3064
|
-
### `folder-
|
|
3122
|
+
### `folder-based-naming-convention`
|
|
3123
|
+
|
|
3124
|
+
**What it does:** Enforces naming conventions based on folder location, with chained folder names for nested files. Also enforces camelCase suffix for data/constants/strings/services/reducers folders (e.g., `authData`, `apiConstants`, `loginStrings`, `userServices`):
|
|
3125
|
+
|
|
3126
|
+
| Folder | Suffix | Example |
|
|
3127
|
+
|--------|--------|---------|
|
|
3128
|
+
| `views/` | View | `DashboardView` |
|
|
3129
|
+
| `layouts/` | Layout | `MainLayout` |
|
|
3130
|
+
| `pages/` | Page | `HomePage` |
|
|
3131
|
+
| `providers/` | Provider | `AuthProvider` |
|
|
3132
|
+
| `reducers/` | Reducer | `UserReducer` |
|
|
3133
|
+
| `contexts/` | Context | `AuthContext` |
|
|
3134
|
+
| `theme/` / `themes/` | Theme | `DarkTheme` |
|
|
3135
|
+
| `data/` | Data (camelCase) | `authData` |
|
|
3136
|
+
| `constants/` | Constants (camelCase) | `apiConstants` |
|
|
3137
|
+
| `strings/` | Strings (camelCase) | `loginStrings` |
|
|
3138
|
+
| `services/` | Services (camelCase) | `userServices` |
|
|
3139
|
+
| `atoms/` | *(none)* | `Button` |
|
|
3140
|
+
| `components/` | *(none)* | `Card` |
|
|
3065
3141
|
|
|
3066
|
-
|
|
3067
|
-
- Components in `views/` folder must end with "View" suffix
|
|
3068
|
-
- Components in `pages/` folder must end with "Page" suffix
|
|
3069
|
-
- Components in `layouts/` folder must end with "Layout" suffix
|
|
3142
|
+
Nested files chain folder names (e.g., `layouts/auth/login.tsx` → `LoginAuthLayout`, `atoms/input/password.tsx` → `PasswordInput`).
|
|
3070
3143
|
|
|
3071
|
-
**Why use it:** Consistent naming based on folder structure makes
|
|
3144
|
+
**Why use it:** Consistent naming based on folder structure makes purpose immediately clear. The chained naming encodes the full path context into the name. The camelCase suffix for data/constants/strings/services/reducers folders distinguishes these utility modules from PascalCase component-like entities.
|
|
3072
3145
|
|
|
3073
3146
|
```tsx
|
|
3074
|
-
// ✅ Good —
|
|
3147
|
+
// ✅ Good — suffix folders
|
|
3148
|
+
// in views/dashboard.tsx
|
|
3075
3149
|
export const DashboardView = () => <div>Dashboard</div>;
|
|
3076
3150
|
|
|
3077
|
-
//
|
|
3078
|
-
export const
|
|
3151
|
+
// in layouts/auth/login.tsx (chained: Login + Auth + Layout)
|
|
3152
|
+
export const LoginAuthLayout = () => <div>Login</div>;
|
|
3079
3153
|
|
|
3080
|
-
//
|
|
3081
|
-
export const
|
|
3154
|
+
// in providers/auth.tsx
|
|
3155
|
+
export const AuthProvider = ({ children }) => <AuthContext.Provider>{children}</AuthContext.Provider>;
|
|
3082
3156
|
|
|
3083
|
-
//
|
|
3084
|
-
export const
|
|
3157
|
+
// in contexts/auth.ts
|
|
3158
|
+
export const AuthContext = createContext(null);
|
|
3085
3159
|
|
|
3086
|
-
//
|
|
3087
|
-
export const
|
|
3160
|
+
// in reducers/user.ts
|
|
3161
|
+
export const UserReducer = (state, action) => { ... };
|
|
3088
3162
|
|
|
3089
|
-
//
|
|
3090
|
-
export const
|
|
3163
|
+
// in themes/dark.ts
|
|
3164
|
+
export const DarkTheme = { primary: "#000" };
|
|
3165
|
+
|
|
3166
|
+
// ✅ Good — camelCase suffix folders
|
|
3167
|
+
// in data/auth.ts
|
|
3168
|
+
export const authData = { ... };
|
|
3169
|
+
|
|
3170
|
+
// in constants/api.ts
|
|
3171
|
+
export const apiConstants = { ... };
|
|
3172
|
+
|
|
3173
|
+
// in strings/login.ts
|
|
3174
|
+
export const loginStrings = { ... };
|
|
3175
|
+
|
|
3176
|
+
// in services/user.ts
|
|
3177
|
+
export const userServices = { ... };
|
|
3178
|
+
|
|
3179
|
+
// ✅ Good — no-suffix folders (chaining only)
|
|
3180
|
+
// in atoms/input/password.tsx (chained: Password + Input)
|
|
3181
|
+
export const PasswordInput = () => <input type="password" />;
|
|
3182
|
+
|
|
3183
|
+
// in atoms/button.tsx
|
|
3184
|
+
export const Button = () => <button>Click</button>;
|
|
3185
|
+
|
|
3186
|
+
// in components/card.tsx
|
|
3187
|
+
export const Card = () => <div>Card</div>;
|
|
3188
|
+
|
|
3189
|
+
// ❌ Bad
|
|
3190
|
+
// in layouts/auth/login.tsx (should be "LoginAuthLayout")
|
|
3191
|
+
export const Login = () => <div>Login</div>;
|
|
3192
|
+
|
|
3193
|
+
// in reducers/user.ts (should be "UserReducer")
|
|
3194
|
+
export const User = (state, action) => { ... };
|
|
3195
|
+
|
|
3196
|
+
// in atoms/input/password.tsx (should be "PasswordInput")
|
|
3197
|
+
export const Password = () => <input type="password" />;
|
|
3198
|
+
```
|
|
3199
|
+
|
|
3200
|
+
> **Note:** Module barrel files (e.g., `views/index.ts`) are skipped. Interfaces, enums, and types have their own naming rules (`interface-format`, `enum-format`, `type-format`). Auto-fix renames the identifier and all its references.
|
|
3201
|
+
|
|
3202
|
+
---
|
|
3203
|
+
|
|
3204
|
+
### `folder-structure-consistency`
|
|
3205
|
+
|
|
3206
|
+
**What it does:** Enforces that module folders have a consistent internal structure — either all flat files or all wrapped in subfolders. Wrapped mode is only justified when at least one subfolder contains 2+ files. Applies to the same folders as `module-index-exports`: atoms, components, hooks, utils, enums, types, interfaces, reducers, layouts, views, pages, and more.
|
|
3207
|
+
|
|
3208
|
+
**Why use it:** Mixing flat files and wrapped folders in the same directory creates inconsistency. This rule ensures a uniform structure — if one item needs a folder (because it has multiple files), all items should be wrapped; if none do, keep everything flat.
|
|
3209
|
+
|
|
3210
|
+
**Configurable options:**
|
|
3211
|
+
| Option | Default | Description |
|
|
3212
|
+
|--------|---------|-------------|
|
|
3213
|
+
| `moduleFolders` | Same as `module-index-exports` (atoms, components, hooks, utils, enums, types, views, layouts, pages, etc.) | Replace the entire folder list |
|
|
3214
|
+
| `extraModuleFolders` | `[]` | Add extra folders on top of the defaults |
|
|
3215
|
+
|
|
3216
|
+
```
|
|
3217
|
+
// ✅ Good — flat mode (all direct files)
|
|
3218
|
+
atoms/input.tsx
|
|
3219
|
+
atoms/calendar.tsx
|
|
3220
|
+
|
|
3221
|
+
// ✅ Good — wrapped mode (justified — input has multiple files)
|
|
3222
|
+
atoms/input/index.tsx
|
|
3223
|
+
atoms/input/helpers.ts
|
|
3224
|
+
atoms/calendar/index.tsx
|
|
3225
|
+
|
|
3226
|
+
// ❌ Bad — mixed (some flat, some wrapped with justification)
|
|
3227
|
+
atoms/input.tsx → "all items should be wrapped in folders"
|
|
3228
|
+
atoms/calendar/index.tsx
|
|
3229
|
+
atoms/calendar/helpers.ts
|
|
3230
|
+
|
|
3231
|
+
// ❌ Bad — wrapped but unnecessary (each folder has only 1 file)
|
|
3232
|
+
atoms/input/index.tsx → "use direct files instead"
|
|
3233
|
+
atoms/calendar/index.tsx
|
|
3234
|
+
|
|
3235
|
+
// ❌ Bad — mixed without justification
|
|
3236
|
+
atoms/input.tsx
|
|
3237
|
+
atoms/calendar/index.tsx → "use direct files instead"
|
|
3091
3238
|
```
|
|
3092
3239
|
|
|
3240
|
+
> **Note:** This rule applies equally to all module folders — component folders (atoms, components, views), data folders (enums, types, interfaces), and utility folders (hooks, utils, helpers). The `folder-based-naming-convention` naming rule is separate and enforces export naming based on folder location.
|
|
3241
|
+
|
|
3093
3242
|
---
|
|
3094
3243
|
|
|
3095
3244
|
### `no-redundant-folder-suffix`
|
|
3096
3245
|
|
|
3097
|
-
**What it does:** Flags files whose name redundantly includes the parent (or ancestor) folder name as a suffix. Since the folder already provides context, the
|
|
3246
|
+
**What it does:** Flags files and folders whose name redundantly includes the parent (or ancestor) folder name as a suffix. Since the folder already provides context, the name doesn't need to repeat it.
|
|
3098
3247
|
|
|
3099
|
-
**Why use it:** This complements `folder-
|
|
3248
|
+
**Why use it:** This complements `folder-based-naming-convention` — the *file name* should stay clean while the *exported component name* carries the suffix. For example, `layouts/main.tsx` exporting `MainLayout` is better than `layouts/main-layout.tsx` exporting `MainLayout`.
|
|
3100
3249
|
|
|
3101
3250
|
```
|
|
3102
|
-
// ✅ Good —
|
|
3251
|
+
// ✅ Good — names don't repeat the folder name
|
|
3103
3252
|
layouts/main.tsx → export const MainLayout = ...
|
|
3104
3253
|
atoms/button.tsx → file "button" has no redundant suffix
|
|
3105
3254
|
views/dashboard.tsx → file "dashboard" has no redundant suffix
|
|
3106
|
-
|
|
3255
|
+
views/access-control/... → folder "access-control" has no redundant suffix
|
|
3256
|
+
atoms/input/index.tsx → uses "index" inside folder (correct)
|
|
3257
|
+
|
|
3258
|
+
// ❌ Bad — file name matches parent folder name (use index instead)
|
|
3259
|
+
atoms/input/input.tsx → use "input/index.tsx" instead
|
|
3260
|
+
components/card/card.tsx → use "card/index.tsx" instead
|
|
3107
3261
|
|
|
3108
3262
|
// ❌ Bad — file names redundantly include the folder suffix
|
|
3109
3263
|
layouts/main-layout.tsx → redundant "-layout" (already in layouts/)
|
|
3110
3264
|
atoms/button-atom.tsx → redundant "-atom" (already in atoms/)
|
|
3111
3265
|
views/dashboard-view.tsx → redundant "-view" (already in views/)
|
|
3112
|
-
hooks/use-auth-hook.ts → redundant "-hook" (already in hooks/)
|
|
3113
3266
|
|
|
3114
|
-
//
|
|
3267
|
+
// ❌ Bad — folder names redundantly include the ancestor suffix
|
|
3268
|
+
views/access-control-view/ → redundant "-view" (already in views/)
|
|
3269
|
+
|
|
3270
|
+
// Nested names are also checked against ancestor folders
|
|
3115
3271
|
atoms/forms/input-atom.tsx → redundant "-atom" from ancestor "atoms/"
|
|
3116
3272
|
```
|
|
3117
3273
|
|
|
3118
|
-
> **Note:** Index files (`index.ts`, `index.js`, etc.) are skipped. Folder names are singularized automatically (e.g., `layouts` → `layout`, `categories` → `category`, `classes` → `class`).
|
|
3274
|
+
> **Note:** Index files (`index.ts`, `index.js`, etc.) are skipped for file name checks. Folder names are singularized automatically (e.g., `layouts` → `layout`, `categories` → `category`, `classes` → `class`).
|
|
3119
3275
|
|
|
3120
3276
|
---
|
|
3121
3277
|
|
|
3122
|
-
### `svg-
|
|
3278
|
+
### `svg-icon-naming-convention`
|
|
3123
3279
|
|
|
3124
3280
|
**What it does:** Enforces naming conventions for SVG icon components:
|
|
3125
3281
|
- Components that return only an SVG element must have a name ending with "Icon"
|
|
@@ -3930,7 +4086,7 @@ const UseAuth = () => {}; // hooks should be camelCase
|
|
|
3930
4086
|
|
|
3931
4087
|
## 🔧 Auto-fixing
|
|
3932
4088
|
|
|
3933
|
-
|
|
4089
|
+
70 of 79 rules support auto-fixing. Run ESLint with the `--fix` flag:
|
|
3934
4090
|
|
|
3935
4091
|
```bash
|
|
3936
4092
|
# Fix all files in src directory
|
|
@@ -3983,6 +4139,8 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
3983
4139
|
|
|
3984
4140
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
3985
4141
|
|
|
4142
|
+
Copyright (c) 2026 Eslint Plugin Code Style. All rights reserved.
|
|
4143
|
+
|
|
3986
4144
|
<br />
|
|
3987
4145
|
|
|
3988
4146
|
---
|