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 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 77 custom formatting rules (67 auto-fixable, 17 configurable, 10 report-only) for React/JSX projects. It's designed for ESLint v9+ flat config system.
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 77 rules in a single file
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** (69 rules in JS projects, 77 in TS projects):
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
- ├── ... (77 rules total)
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-component-suffix`, `no-redundant-folder-suffix`, `svg-component-icon-naming`
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 77 rules
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: 67 auto-fixable rules, 17 configurable rules, 10 report-only rules
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:** 77
712
- - **Auto-fixable:** 67 (43 with `fixable: "code"` + 24 with `fixable: "whitespace"`)
713
- - **Configurable:** 17 (rules with ⚙️ that have options)
714
- - **Report-only:** 10
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 | `*77 rules (67 auto-fixable, 17 configurable)*` |
726
- | `README.md` | ~30 | `**76 custom rules** (66 auto-fixable, 17 configurable)` |
727
- | `README.md` | ~39 | `67 of 77 rules support auto-fix` |
728
- | `README.md` | ~100 | `**67 rules** support automatic fixing. **17 rules** have configurable options` |
729
- | `README.md` | ~266 | `**77 rules total** — 67 with auto-fix, 17 configurable` |
730
- | `README.md` | ~3650 | `67 of 77 rules support auto-fixing` |
731
- | `AGENTS.md` | ~7 | `77 custom formatting rules (67 auto-fixable, 17 configurable, 10 report-only)` |
732
- | `AGENTS.md` | ~9 | `Contains all 77 rules` |
733
- | `AGENTS.md` | ~36 | `(69 rules in JS projects, 77 in TS projects)` |
734
- | `AGENTS.md` | ~89 | `(77 rules total)` |
735
- | `AGENTS.md` | ~675 | `all 77 rules` |
736
- | `AGENTS.md` | ~697 | `67 auto-fixable rules, 17 configurable rules, 10 report-only` |
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 | `**67 auto-fixable rules** (77 total, 17 configurable, 10 report-only)` |
739
- | `recommended-configs/react/README.md` | ~286 | `**67 auto-fixable rules** (77 total, 17 configurable, 10 report-only)` |
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
- *77 rules (67 auto-fixable, 17 configurable) to keep your codebase clean and consistent*
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 **77 custom rules** (67 auto-fixable, 17 configurable) for code formatting. Built for **ESLint v9 flat configs**.
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** — 67 of 77 rules support auto-fix with `eslint --fix`
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 77 code-style rules
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
- **67 rules** support automatic fixing with `eslint --fix`. **17 rules** have configurable options. 10 rules are report-only (require manual changes).
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-component-icon-naming": "error",
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-component-suffix": "error",
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
- > **77 rules total** — 67 with auto-fix 🔧, 17 configurable ⚙️, 10 report-only. See detailed examples in [Rules Reference](#-rules-reference) below.
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-component-suffix` | Components in `views/` folder must end with "View", `pages/` with "Page", `layouts/` with "Layout" |
298
- | `no-redundant-folder-suffix` | Disallow file names that redundantly include the parent folder name as a suffix |
299
- | `svg-component-icon-naming` | SVG components must end with "Icon" suffix; "Icon" suffix components must return SVG |
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
- // Bad — relative imports
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-component-suffix`
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
- **What it does:** Enforces naming conventions for components based on folder location:
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 component purpose immediately clear. View components, page components, and layout components have different responsibilities, and the suffix reflects this.
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 — in views/dashboard-view.tsx
3147
+ // ✅ Good — suffix folders
3148
+ // in views/dashboard.tsx
3075
3149
  export const DashboardView = () => <div>Dashboard</div>;
3076
3150
 
3077
- // ✅ Good — in pages/home-page.tsx
3078
- export const HomePage = () => <div>Home</div>;
3151
+ // in layouts/auth/login.tsx (chained: Login + Auth + Layout)
3152
+ export const LoginAuthLayout = () => <div>Login</div>;
3079
3153
 
3080
- // ✅ Good — in layouts/main-layout.tsx
3081
- export const MainLayout = () => <div>Main</div>;
3154
+ // in providers/auth.tsx
3155
+ export const AuthProvider = ({ children }) => <AuthContext.Provider>{children}</AuthContext.Provider>;
3082
3156
 
3083
- // ❌ Bad — in views/dashboard.tsx (missing "View" suffix)
3084
- export const Dashboard = () => <div>Dashboard</div>;
3157
+ // in contexts/auth.ts
3158
+ export const AuthContext = createContext(null);
3085
3159
 
3086
- // ❌ Bad — in pages/home.tsx (missing "Page" suffix)
3087
- export const Home = () => <div>Home</div>;
3160
+ // in reducers/user.ts
3161
+ export const UserReducer = (state, action) => { ... };
3088
3162
 
3089
- // ❌ Bad — in layouts/main.tsx (missing "Layout" suffix)
3090
- export const Main = () => <div>Main</div>;
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 file name doesn't need to repeat it.
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-component-suffix` — 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`.
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 — file names don't repeat the folder name
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
- hooks/use-auth.ts file "use-auth" 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
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
- // Nested files are also checked against ancestor folders
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-component-icon-naming`
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
- 67 of 77 rules support auto-fixing. Run ESLint with the `--fix` flag:
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
  ---