eslint-plugin-code-style 1.14.3 β 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 +1358 -0
- package/CHANGELOG.md +123 -0
- package/CLAUDE.md +12 -0
- package/README.md +221 -27
- package/index.d.ts +10 -4
- package/index.js +794 -70
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,125 @@ 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
|
+
|
|
88
|
+
## [1.15.0] - 2026-02-06
|
|
89
|
+
|
|
90
|
+
**New Rule: no-redundant-folder-suffix**
|
|
91
|
+
|
|
92
|
+
**Version Range:** v1.14.1 β v1.15.0
|
|
93
|
+
|
|
94
|
+
### Added
|
|
95
|
+
|
|
96
|
+
**New Rules (1)**
|
|
97
|
+
- `no-redundant-folder-suffix` - Disallow file names that redundantly include the parent or ancestor folder name as a suffix
|
|
98
|
+
- Flags files like `layouts/main-layout.tsx` (redundant "-layout" since already in `layouts/`)
|
|
99
|
+
- Checks all ancestor folders from `src/` onwards
|
|
100
|
+
- Singularizes folder names automatically (layoutsβlayout, categoriesβcategory, classesβclass)
|
|
101
|
+
- Skips index files
|
|
102
|
+
|
|
103
|
+
### Enhanced
|
|
104
|
+
|
|
105
|
+
- **`folder-component-suffix`** - Add `layouts` folder support: components in `layouts/` must end with "Layout" suffix (with auto-fix) (v1.14.4)
|
|
106
|
+
- **`type-annotation-spacing`** - Add auto-fix to collapse function types with β€2 params to one line; add spacing rules for async keyword and function types (v1.14.2βv1.14.3)
|
|
107
|
+
- **`interface-format`** - Fix circular fix conflict by skipping collapse when property has multi-line function type (v1.14.3)
|
|
108
|
+
- **`function-naming-convention`** - Detect functions destructured from hooks without proper naming, with auto-fix (v1.14.1)
|
|
109
|
+
|
|
110
|
+
### Stats
|
|
111
|
+
|
|
112
|
+
- Total Rules: 77 (was 76)
|
|
113
|
+
- Auto-fixable: 67 rules π§
|
|
114
|
+
- Configurable: 17 rules βοΈ
|
|
115
|
+
- Report-only: 10 rules (was 9)
|
|
116
|
+
|
|
117
|
+
**Full Changelog:** [v1.14.1...v1.15.0](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.1...v1.15.0)
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## [1.14.4] - 2026-02-06
|
|
122
|
+
|
|
123
|
+
### Enhanced
|
|
124
|
+
|
|
125
|
+
- **`folder-component-suffix`** - Add `layouts` folder support: components in `layouts/` must end with "Layout" suffix (with auto-fix)
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
10
129
|
## [1.14.3] - 2026-02-05
|
|
11
130
|
|
|
12
131
|
### Enhanced
|
|
@@ -1687,6 +1806,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1687
1806
|
|
|
1688
1807
|
---
|
|
1689
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
|
|
1811
|
+
[1.15.0]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.4...v1.15.0
|
|
1812
|
+
[1.14.4]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.3...v1.14.4
|
|
1690
1813
|
[1.14.3]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.2...v1.14.3
|
|
1691
1814
|
[1.14.2]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.1...v1.14.2
|
|
1692
1815
|
[1.14.1]: https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/compare/v1.14.0...v1.14.1
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Claude Code Configuration
|
|
2
|
+
|
|
3
|
+
> For general project instructions, see [AGENTS.md](./AGENTS.md).
|
|
4
|
+
|
|
5
|
+
## Claude-Specific Behavior
|
|
6
|
+
|
|
7
|
+
When working on this codebase, Claude Code should:
|
|
8
|
+
|
|
9
|
+
- Do NOT include `Co-Authored-By` lines in commits
|
|
10
|
+
- Do NOT include Claude Code signature/footer in commits
|
|
11
|
+
- Keep commit messages clean and standard (no AI attribution)
|
|
12
|
+
- When user asks to "commit" with approval, follow the full release workflow in [AGENTS.md](./AGENTS.md#release-steps)
|
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 **75 custom rules** (66 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,15 @@ 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",
|
|
210
|
+
"code-style/no-redundant-folder-suffix": "error",
|
|
209
211
|
"code-style/function-arguments-format": "error",
|
|
210
212
|
"code-style/function-call-spacing": "error",
|
|
211
213
|
"code-style/function-declaration-style": "error",
|
|
@@ -221,6 +223,7 @@ rules: {
|
|
|
221
223
|
"code-style/import-source-spacing": "error",
|
|
222
224
|
"code-style/index-export-style": "error",
|
|
223
225
|
"code-style/index-exports-only": "error",
|
|
226
|
+
"code-style/inline-export-declaration": "error",
|
|
224
227
|
"code-style/interface-format": "error",
|
|
225
228
|
"code-style/jsx-children-on-new-line": "error",
|
|
226
229
|
"code-style/jsx-closing-bracket-spacing": "error",
|
|
@@ -266,7 +269,7 @@ rules: {
|
|
|
266
269
|
|
|
267
270
|
## π Rules Categories
|
|
268
271
|
|
|
269
|
-
> **
|
|
272
|
+
> **79 rules total** β 70 with auto-fix π§, 19 configurable βοΈ, 9 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
|
|
270
273
|
>
|
|
271
274
|
> **Legend:** π§ Auto-fixable with `eslint --fix` β’ βοΈ Customizable options
|
|
272
275
|
|
|
@@ -293,8 +296,10 @@ rules: {
|
|
|
293
296
|
| **Component Rules** | |
|
|
294
297
|
| `component-props-destructure` | Component props must be destructured `({ prop })` not received as `(props)` π§ |
|
|
295
298
|
| `component-props-inline-type` | Inline type annotation `} : {` with matching props, proper spacing, commas, no interface reference π§ |
|
|
296
|
-
| `folder-
|
|
297
|
-
| `
|
|
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 |
|
|
298
303
|
| **Class Rules** | |
|
|
299
304
|
| `class-method-definition-format` | Consistent spacing in class/method definitions: space before `{`, no space before `(` π§ |
|
|
300
305
|
| `class-naming-convention` | Class declarations must end with "Class" suffix (e.g., `ApiServiceClass`) π§ |
|
|
@@ -319,12 +324,13 @@ rules: {
|
|
|
319
324
|
| `hook-deps-per-line` | Collapse deps β€ threshold to one line; expand larger arrays with each dep on own line (default: >2) π§ βοΈ |
|
|
320
325
|
| `use-state-naming-convention` | Boolean useState variables must start with is/has/with/without prefix π§ βοΈ |
|
|
321
326
|
| **Import/Export Rules** | |
|
|
322
|
-
| `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: `@/`) π§ βοΈ |
|
|
323
328
|
| `export-format` | `export {` on same line; collapse β€ threshold to one line; expand larger with each specifier on own line (default: β€3) π§ βοΈ |
|
|
324
329
|
| `import-format` | `import {` and `} from` on same line; collapse β€ threshold; expand larger with each specifier on own line (default: β€3) π§ βοΈ |
|
|
325
330
|
| `import-source-spacing` | No leading/trailing spaces inside import path quotes π§ |
|
|
326
331
|
| `index-export-style` | Index files: no blank lines, enforce shorthand or import-export style; Regular files: require blank lines between exports (default: shorthand) π§ βοΈ |
|
|
327
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 π§ βοΈ |
|
|
328
334
|
| `module-index-exports` | Index files must export all folder contents (files and subfolders) βοΈ |
|
|
329
335
|
| **JSX Rules** | |
|
|
330
336
|
| `classname-dynamic-at-end` | Dynamic expressions (`${className}`) must be at the end of class strings (JSX and variables) π§ |
|
|
@@ -1810,13 +1816,14 @@ const [error, setError] = useState<boolean>(false);
|
|
|
1810
1816
|
|
|
1811
1817
|
### `absolute-imports-only`
|
|
1812
1818
|
|
|
1813
|
-
**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. π§
|
|
1814
1820
|
|
|
1815
1821
|
**Why use it:**
|
|
1816
1822
|
- Absolute imports are cleaner than `../../../components`
|
|
1817
1823
|
- Index imports create a public API for each folder
|
|
1818
1824
|
- Refactoring file locations doesn't break imports
|
|
1819
1825
|
- Encourages proper module organization
|
|
1826
|
+
- Relative imports within the same module folder avoid circular dependencies
|
|
1820
1827
|
|
|
1821
1828
|
```javascript
|
|
1822
1829
|
// β
Good β import from index files using alias
|
|
@@ -1828,7 +1835,20 @@ import { formatDate } from "@/utils";
|
|
|
1828
1835
|
// β
Good β assets allow deep imports by default
|
|
1829
1836
|
import logo from "@/assets/images/logo.png";
|
|
1830
1837
|
|
|
1831
|
-
//
|
|
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
|
|
1832
1852
|
import { Button } from "../../components";
|
|
1833
1853
|
import { useAuth } from "../../../hooks";
|
|
1834
1854
|
|
|
@@ -2082,6 +2102,46 @@ export function helper() { ... } // Move to utils.ts
|
|
|
2082
2102
|
|
|
2083
2103
|
---
|
|
2084
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
|
+
|
|
2085
2145
|
### `module-index-exports`
|
|
2086
2146
|
|
|
2087
2147
|
**What it does:** Ensures module folders have index files that export all their contents, creating a proper public API for each module.
|
|
@@ -3059,31 +3119,163 @@ export const Card = ({ a, b } : { a: string, b: string }) => (
|
|
|
3059
3119
|
|
|
3060
3120
|
---
|
|
3061
3121
|
|
|
3062
|
-
### `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`):
|
|
3063
3125
|
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
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` |
|
|
3067
3141
|
|
|
3068
|
-
|
|
3142
|
+
Nested files chain folder names (e.g., `layouts/auth/login.tsx` β `LoginAuthLayout`, `atoms/input/password.tsx` β `PasswordInput`).
|
|
3143
|
+
|
|
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.
|
|
3069
3145
|
|
|
3070
3146
|
```tsx
|
|
3071
|
-
// β
Good β
|
|
3147
|
+
// β
Good β suffix folders
|
|
3148
|
+
// in views/dashboard.tsx
|
|
3072
3149
|
export const DashboardView = () => <div>Dashboard</div>;
|
|
3073
3150
|
|
|
3074
|
-
//
|
|
3075
|
-
export const
|
|
3151
|
+
// in layouts/auth/login.tsx (chained: Login + Auth + Layout)
|
|
3152
|
+
export const LoginAuthLayout = () => <div>Login</div>;
|
|
3153
|
+
|
|
3154
|
+
// in providers/auth.tsx
|
|
3155
|
+
export const AuthProvider = ({ children }) => <AuthContext.Provider>{children}</AuthContext.Provider>;
|
|
3156
|
+
|
|
3157
|
+
// in contexts/auth.ts
|
|
3158
|
+
export const AuthContext = createContext(null);
|
|
3159
|
+
|
|
3160
|
+
// in reducers/user.ts
|
|
3161
|
+
export const UserReducer = (state, action) => { ... };
|
|
3162
|
+
|
|
3163
|
+
// in themes/dark.ts
|
|
3164
|
+
export const DarkTheme = { primary: "#000" };
|
|
3076
3165
|
|
|
3077
|
-
//
|
|
3078
|
-
|
|
3166
|
+
// β
Good β camelCase suffix folders
|
|
3167
|
+
// in data/auth.ts
|
|
3168
|
+
export const authData = { ... };
|
|
3079
3169
|
|
|
3080
|
-
//
|
|
3081
|
-
export const
|
|
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" />;
|
|
3082
3198
|
```
|
|
3083
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
|
+
|
|
3084
3202
|
---
|
|
3085
3203
|
|
|
3086
|
-
### `
|
|
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"
|
|
3238
|
+
```
|
|
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
|
+
|
|
3242
|
+
---
|
|
3243
|
+
|
|
3244
|
+
### `no-redundant-folder-suffix`
|
|
3245
|
+
|
|
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.
|
|
3247
|
+
|
|
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`.
|
|
3249
|
+
|
|
3250
|
+
```
|
|
3251
|
+
// β
Good β names don't repeat the folder name
|
|
3252
|
+
layouts/main.tsx β export const MainLayout = ...
|
|
3253
|
+
atoms/button.tsx β file "button" has no redundant suffix
|
|
3254
|
+
views/dashboard.tsx β file "dashboard" has no redundant suffix
|
|
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
|
|
3261
|
+
|
|
3262
|
+
// β Bad β file names redundantly include the folder suffix
|
|
3263
|
+
layouts/main-layout.tsx β redundant "-layout" (already in layouts/)
|
|
3264
|
+
atoms/button-atom.tsx β redundant "-atom" (already in atoms/)
|
|
3265
|
+
views/dashboard-view.tsx β redundant "-view" (already in views/)
|
|
3266
|
+
|
|
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
|
|
3271
|
+
atoms/forms/input-atom.tsx β redundant "-atom" from ancestor "atoms/"
|
|
3272
|
+
```
|
|
3273
|
+
|
|
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`).
|
|
3275
|
+
|
|
3276
|
+
---
|
|
3277
|
+
|
|
3278
|
+
### `svg-icon-naming-convention`
|
|
3087
3279
|
|
|
3088
3280
|
**What it does:** Enforces naming conventions for SVG icon components:
|
|
3089
3281
|
- Components that return only an SVG element must have a name ending with "Icon"
|
|
@@ -3894,7 +4086,7 @@ const UseAuth = () => {}; // hooks should be camelCase
|
|
|
3894
4086
|
|
|
3895
4087
|
## π§ Auto-fixing
|
|
3896
4088
|
|
|
3897
|
-
|
|
4089
|
+
70 of 79 rules support auto-fixing. Run ESLint with the `--fix` flag:
|
|
3898
4090
|
|
|
3899
4091
|
```bash
|
|
3900
4092
|
# Fix all files in src directory
|
|
@@ -3947,6 +4139,8 @@ Contributions are welcome! Please feel free to submit a Pull Request.
|
|
|
3947
4139
|
|
|
3948
4140
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
3949
4141
|
|
|
4142
|
+
Copyright (c) 2026 Eslint Plugin Code Style. All rights reserved.
|
|
4143
|
+
|
|
3950
4144
|
<br />
|
|
3951
4145
|
|
|
3952
4146
|
---
|
package/index.d.ts
CHANGED
|
@@ -19,12 +19,13 @@ export type RuleNames =
|
|
|
19
19
|
| "code-style/component-props-destructure"
|
|
20
20
|
| "code-style/react-code-order"
|
|
21
21
|
| "code-style/component-props-inline-type"
|
|
22
|
-
| "code-style/svg-
|
|
22
|
+
| "code-style/svg-icon-naming-convention"
|
|
23
23
|
| "code-style/curried-arrow-same-line"
|
|
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-
|
|
27
|
+
| "code-style/folder-based-naming-convention"
|
|
28
|
+
| "code-style/folder-structure-consistency"
|
|
28
29
|
| "code-style/function-arguments-format"
|
|
29
30
|
| "code-style/function-call-spacing"
|
|
30
31
|
| "code-style/function-declaration-style"
|
|
@@ -40,6 +41,7 @@ export type RuleNames =
|
|
|
40
41
|
| "code-style/import-source-spacing"
|
|
41
42
|
| "code-style/index-export-style"
|
|
42
43
|
| "code-style/index-exports-only"
|
|
44
|
+
| "code-style/inline-export-declaration"
|
|
43
45
|
| "code-style/classname-dynamic-at-end"
|
|
44
46
|
| "code-style/classname-multiline"
|
|
45
47
|
| "code-style/classname-no-extra-spaces"
|
|
@@ -59,6 +61,7 @@ export type RuleNames =
|
|
|
59
61
|
| "code-style/multiline-if-conditions"
|
|
60
62
|
| "code-style/nested-call-closing-brackets"
|
|
61
63
|
| "code-style/no-inline-type-definitions"
|
|
64
|
+
| "code-style/no-redundant-folder-suffix"
|
|
62
65
|
| "code-style/no-empty-lines-in-function-calls"
|
|
63
66
|
| "code-style/no-empty-lines-in-function-params"
|
|
64
67
|
| "code-style/no-empty-lines-in-jsx"
|
|
@@ -117,12 +120,13 @@ interface PluginRules {
|
|
|
117
120
|
"component-props-destructure": Rule.RuleModule;
|
|
118
121
|
"react-code-order": Rule.RuleModule;
|
|
119
122
|
"component-props-inline-type": Rule.RuleModule;
|
|
120
|
-
"svg-
|
|
123
|
+
"svg-icon-naming-convention": Rule.RuleModule;
|
|
121
124
|
"curried-arrow-same-line": Rule.RuleModule;
|
|
122
125
|
"empty-line-after-block": Rule.RuleModule;
|
|
123
126
|
"enum-type-enforcement": Rule.RuleModule;
|
|
124
127
|
"export-format": Rule.RuleModule;
|
|
125
|
-
"folder-
|
|
128
|
+
"folder-based-naming-convention": Rule.RuleModule;
|
|
129
|
+
"folder-structure-consistency": Rule.RuleModule;
|
|
126
130
|
"function-arguments-format": Rule.RuleModule;
|
|
127
131
|
"function-call-spacing": Rule.RuleModule;
|
|
128
132
|
"function-declaration-style": Rule.RuleModule;
|
|
@@ -137,6 +141,7 @@ interface PluginRules {
|
|
|
137
141
|
"import-source-spacing": Rule.RuleModule;
|
|
138
142
|
"index-export-style": Rule.RuleModule;
|
|
139
143
|
"index-exports-only": Rule.RuleModule;
|
|
144
|
+
"inline-export-declaration": Rule.RuleModule;
|
|
140
145
|
"classname-dynamic-at-end": Rule.RuleModule;
|
|
141
146
|
"classname-multiline": Rule.RuleModule;
|
|
142
147
|
"classname-no-extra-spaces": Rule.RuleModule;
|
|
@@ -156,6 +161,7 @@ interface PluginRules {
|
|
|
156
161
|
"multiline-if-conditions": Rule.RuleModule;
|
|
157
162
|
"nested-call-closing-brackets": Rule.RuleModule;
|
|
158
163
|
"no-inline-type-definitions": Rule.RuleModule;
|
|
164
|
+
"no-redundant-folder-suffix": Rule.RuleModule;
|
|
159
165
|
"no-empty-lines-in-function-calls": Rule.RuleModule;
|
|
160
166
|
"no-empty-lines-in-function-params": Rule.RuleModule;
|
|
161
167
|
"no-empty-lines-in-jsx": Rule.RuleModule;
|