eslint-plugin-code-style 1.2.6 → 1.2.8

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 60 custom auto-fixable formatting rules for React/JSX projects. It's designed for ESLint v9+ flat config system.
7
+ **eslint-plugin-code-style** is an ESLint plugin providing 61 custom auto-fixable formatting rules for React/JSX projects. It's designed for ESLint v9+ flat config system.
8
8
 
9
- - **Main entry:** `index.js` - Contains all 60 rules in a single file
9
+ - **Main entry:** `index.js` - Contains all 61 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
@@ -44,7 +44,7 @@ index.js
44
44
  ├── imports (fs, path, url)
45
45
  ├── Rule 1 definition (const ruleName = { create(), meta: {} })
46
46
  ├── Rule 2 definition
47
- ├── ... (60 rules total)
47
+ ├── ... (61 rules total)
48
48
  └── export default { meta: {}, rules: {} }
49
49
  ```
50
50
 
@@ -206,7 +206,7 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
206
206
  - **Comment Rules:** `comment-format`
207
207
  - **Component Rules:** `component-props-destructure`, `component-props-inline-type`
208
208
  - **Control Flow Rules:** `block-statement-newlines`, `if-statement-format`, `multiline-if-conditions`, `no-empty-lines-in-switch-cases`
209
- - **Function Rules:** `function-call-spacing`, `function-naming-convention`, `function-object-destructure`, `function-params-per-line`, `no-empty-lines-in-function-params`
209
+ - **Function Rules:** `function-call-spacing`, `function-declaration-style`, `function-naming-convention`, `function-object-destructure`, `function-params-per-line`, `no-empty-lines-in-function-params`
210
210
  - **Hook Rules:** `hook-callback-format`, `hook-deps-per-line`
211
211
  - **Import/Export Rules:** `absolute-imports-only`, `export-format`, `import-format`, `import-source-spacing`, `index-export-style`, `module-index-exports`
212
212
  - **JSX Rules:** `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`
@@ -230,7 +230,7 @@ Rules are organized in these categories (alphabetically sorted in index.js and R
230
230
 
231
231
  ## Documentation Files
232
232
 
233
- - `README.md` - Main documentation with all 60 rules
233
+ - `README.md` - Main documentation with all 61 rules
234
234
  - `recommended-configs/<config-name>/README.md` - Config-specific documentation (references main README for rule details)
235
235
  - `index.d.ts` - TypeScript types for IDE autocomplete
236
236
 
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D20.0.0-339933?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org/)
11
11
  [![React](https://img.shields.io/badge/React-JSX%20Support-61DAFB?style=for-the-badge&logo=react&logoColor=black)](https://react.dev/)
12
12
  [![TypeScript](https://img.shields.io/badge/TypeScript-%3E%3D5.0.0-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
13
- [![Tailwind CSS](https://img.shields.io/badge/Tailwind%20CSS-%3E%3D4.0.0-06B6D4?style=for-the-badge&logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)
13
+ [![Tailwind CSS](https://img.shields.io/badge/Tailwind%20CSS-%3E%3D3.0.0-06B6D4?style=for-the-badge&logo=tailwindcss&logoColor=white)](https://tailwindcss.com/)
14
14
 
15
15
  [![GitHub stars](https://img.shields.io/github/stars/Mohamed-Elhawary/eslint-plugin-code-style?style=for-the-badge&logo=github&color=yellow)](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/stargazers)
16
16
  [![GitHub issues](https://img.shields.io/github/issues/Mohamed-Elhawary/eslint-plugin-code-style?style=for-the-badge&logo=github)](https://github.com/Mohamed-Elhawary/eslint-plugin-code-style/issues)
@@ -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
- *60 auto-fixable rules to keep your codebase clean and consistent*
22
+ *61 auto-fixable rules 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 **60 custom auto-fixable rules** for code formatting. Built for **ESLint v9 flat configs**.
30
+ This plugin provides **61 custom auto-fixable rules** 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 **60 custom auto-fixable rules** for code formatting. Built
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
- - **Fully automated** — All 60 rules support auto-fix, eliminating manual style reviews
39
+ - **Fully automated** — All 61 rules support auto-fix, eliminating manual style reviews
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 60 code-style rules
63
+ - **Complete Coverage** — Combines ESLint built-in rules, third-party plugins, and all 61 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
- All **60 rules** support automatic fixing with `eslint --fix`. No manual code changes needed.
100
+ All **61 rules** support automatic fixing with `eslint --fix`. No manual code changes needed.
101
101
 
102
102
  </td>
103
103
  <td width="50%">
@@ -200,6 +200,7 @@ rules: {
200
200
  "code-style/export-format": "error",
201
201
  "code-style/function-arguments-format": "error",
202
202
  "code-style/function-call-spacing": "error",
203
+ "code-style/function-declaration-style": "error",
203
204
  "code-style/function-naming-convention": "error",
204
205
  "code-style/function-object-destructure": "error",
205
206
  "code-style/function-params-per-line": "error",
@@ -249,7 +250,7 @@ rules: {
249
250
 
250
251
  ## 📖 Rules Summary
251
252
 
252
- > All **60 rules** are auto-fixable. See detailed examples for each rule in the [Rules Reference](#-rules-reference) section below.
253
+ > All **61 rules** are auto-fixable. See detailed examples for each rule in the [Rules Reference](#-rules-reference) section below.
253
254
  >
254
255
  > Rules marked with ⚙️ support customization options (e.g., extending default folder lists).
255
256
 
@@ -282,6 +283,7 @@ rules: {
282
283
  | `no-empty-lines-in-switch-cases` | No empty line after `case X:` before code, no empty lines between cases |
283
284
  | **Function Rules** | |
284
285
  | `function-call-spacing` | No space between function name and `(`: `fn()` not `fn ()` |
286
+ | `function-declaration-style` | Auto-fix for `func-style`: converts function declarations to arrow expressions |
285
287
  | `function-naming-convention` | Functions use camelCase, start with verb (get/set/handle/is/has), handlers end with Handler |
286
288
  | `function-object-destructure` | Non-component functions: use typed params (not destructured), destructure in body; report dot notation access |
287
289
  | `function-params-per-line` | When multiline, each param on own line with consistent indentation |
@@ -1079,6 +1081,46 @@ array.map ((x) => x * 2);
1079
1081
 
1080
1082
  ---
1081
1083
 
1084
+ ### `function-declaration-style`
1085
+
1086
+ **What it does:** Converts function declarations to `const` arrow function expressions. This is the auto-fixable companion to ESLint's built-in `func-style` rule.
1087
+
1088
+ **Why use it:** The built-in `func-style: ["error", "expression"]` rule reports function declarations but does not auto-fix them. This rule provides the auto-fix. Both rules should be used together for the best experience.
1089
+
1090
+ > **Important:** This rule depends on `func-style: ["error", "expression"]` being configured. If `func-style` is set to `"declaration"` or is disabled, do not enable this rule — it would conflict.
1091
+
1092
+ ```typescript
1093
+ // ✅ Good — arrow function expression
1094
+ export const getToken = (): string | null => getCookie(tokenKey);
1095
+
1096
+ export const clearAuth = (): void => {
1097
+ removeToken();
1098
+ clearStorage();
1099
+ };
1100
+
1101
+ const isAuthenticated = (): boolean => {
1102
+ const token = getToken();
1103
+ return !!token;
1104
+ };
1105
+
1106
+ // ❌ Bad — function declaration
1107
+ export function getToken(): string | null {
1108
+ return getCookie(tokenKey);
1109
+ }
1110
+
1111
+ export function clearAuth(): void {
1112
+ removeToken();
1113
+ clearStorage();
1114
+ }
1115
+
1116
+ function isAuthenticated(): boolean {
1117
+ const token = getToken();
1118
+ return !!token;
1119
+ }
1120
+ ```
1121
+
1122
+ ---
1123
+
1082
1124
  ### `function-naming-convention`
1083
1125
 
1084
1126
  **What it does:** Enforces naming conventions for functions:
@@ -1373,24 +1415,24 @@ import { fetchUsers } from "@/apis/users/fetchUsers";
1373
1415
  ```
1374
1416
 
1375
1417
  **Default Allowed Folders:**
1376
- `actions`, `apis`, `assets`, `atoms`, `components`, `config`, `configs`, `constants`, `contexts`, `data`, `enums`, `helpers`, `hooks`, `interfaces`, `layouts`, `lib`, `middlewares`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `ui`, `utils`, `utilities`, `views`
1418
+ `actions`, `apis`, `assets`, `atoms`, `components`, `config`, `configs`, `constants`, `contexts`, `data`, `enums`, `helpers`, `hooks`, `interfaces`, `layouts`, `lib`, `middlewares`, `pages`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `ui`, `utils`, `utilities`, `views`
1377
1419
 
1378
1420
  **Customization Options:**
1379
1421
 
1380
1422
  | Option | Type | Description |
1381
1423
  |--------|------|-------------|
1382
- | `extraAllowedFolders` | `string[]` | Add extra folders to the default list |
1383
- | `extraReduxSubfolders` | `string[]` | Add extra redux subfolders (default: `actions`, `reducers`, `store`, `thunks`, `types`) |
1384
- | `extraDeepImportFolders` | `string[]` | Add extra folders that allow deep imports (default: `assets`) |
1385
- | `aliasPrefix` | `string` | Change the import alias prefix (default: `@/`) |
1386
- | `allowedFolders` | `string[]` | Replace default folders entirely |
1387
- | `reduxSubfolders` | `string[]` | Replace default redux subfolders entirely |
1388
- | `deepImportFolders` | `string[]` | Replace default deep import folders entirely |
1424
+ | `extraAllowedFolders` | `string[]` | Add custom folders that can be imported with `@/folder`. Extends defaults without replacing them. Use when your project has folders like `features/`, `modules/`, etc. |
1425
+ | `extraReduxSubfolders` | `string[]` | Add Redux-related subfolders that can be imported directly (`@/selectors`) or nested (`@/redux/selectors`). Default subfolders: `actions`, `reducers`, `store`, `thunks`, `types` |
1426
+ | `extraDeepImportFolders` | `string[]` | Add folders where direct file imports are allowed (`@/assets/images/logo.svg`). Use for folders without index files like images, fonts, etc. Default: `assets` |
1427
+ | `aliasPrefix` | `string` | Change the path alias prefix if your project uses something other than `@/` (e.g., `~/`, `src/`) |
1428
+ | `allowedFolders` | `string[]` | Completely replace the default allowed folders list. Use only if you need full control over which folders are valid |
1429
+ | `reduxSubfolders` | `string[]` | Completely replace the default Redux subfolders list |
1430
+ | `deepImportFolders` | `string[]` | Completely replace the default deep import folders list |
1389
1431
 
1390
1432
  ```javascript
1391
1433
  // Example: Add custom folders to the defaults
1392
1434
  "code-style/absolute-imports-only": ["error", {
1393
- extraAllowedFolders: ["features", "modules", "lib"],
1435
+ extraAllowedFolders: ["features", "modules"],
1394
1436
  extraDeepImportFolders: ["images", "fonts"]
1395
1437
  }]
1396
1438
  ```
@@ -1617,7 +1659,7 @@ import { Button } from "@/components/Button/Button"; // Avoid this!
1617
1659
  ```
1618
1660
 
1619
1661
  **Default Module Folders:**
1620
- `actions`, `apis`, `assets`, `atoms`, `components`, `config`, `configs`, `constants`, `contexts`, `data`, `enums`, `helpers`, `hooks`, `interfaces`, `layouts`, `lib`, `middlewares`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `ui`, `utils`, `utilities`, `views`
1662
+ `actions`, `apis`, `assets`, `atoms`, `components`, `config`, `configs`, `constants`, `contexts`, `data`, `enums`, `helpers`, `hooks`, `interfaces`, `layouts`, `lib`, `middlewares`, `pages`, `providers`, `reducers`, `redux`, `requests`, `routes`, `schemas`, `services`, `store`, `styles`, `theme`, `thunks`, `types`, `ui`, `utils`, `utilities`, `views`
1621
1663
 
1622
1664
  **Default Ignore Patterns:**
1623
1665
  `index.js`, `index.jsx`, `index.ts`, `index.tsx`, `.DS_Store`, `__tests__`, `__mocks__`, `*.test.js`, `*.test.jsx`, `*.test.ts`, `*.test.tsx`, `*.spec.js`, `*.spec.jsx`, `*.spec.ts`, `*.spec.tsx`
@@ -1626,18 +1668,18 @@ import { Button } from "@/components/Button/Button"; // Avoid this!
1626
1668
 
1627
1669
  | Option | Type | Description |
1628
1670
  |--------|------|-------------|
1629
- | `extraModuleFolders` | `string[]` | Add extra module folders to the default list |
1630
- | `extraLazyLoadFolders` | `string[]` | Add extra lazy load folders (default: `views`) |
1631
- | `extraIgnorePatterns` | `string[]` | Add extra ignore patterns (supports wildcards) |
1632
- | `moduleFolders` | `string[]` | Replace default module folders entirely |
1633
- | `lazyLoadFolders` | `string[]` | Replace default lazy load folders entirely |
1634
- | `ignorePatterns` | `string[]` | Replace default ignore patterns entirely |
1671
+ | `extraModuleFolders` | `string[]` | Add folders that should have an `index.js` re-exporting all public files. Use for project-specific folders like `features/`, `modules/` that follow the same pattern |
1672
+ | `extraLazyLoadFolders` | `string[]` | Add folders exempt from index file requirements. Use for route/page components loaded via dynamic `import()`. Default: `pages`, `views` |
1673
+ | `extraIgnorePatterns` | `string[]` | Add file patterns to skip when checking for index exports. Supports wildcards like `*.stories.js`, `*.mock.js` |
1674
+ | `moduleFolders` | `string[]` | Completely replace the default module folders list. Use only if you need full control over which folders require index files |
1675
+ | `lazyLoadFolders` | `string[]` | Completely replace the default lazy load folders list |
1676
+ | `ignorePatterns` | `string[]` | Completely replace the default ignore patterns list |
1635
1677
 
1636
1678
  ```javascript
1637
1679
  // Example: Add custom folders and patterns
1638
1680
  "code-style/module-index-exports": ["error", {
1639
- extraModuleFolders: ["features", "modules", "lib"],
1640
- extraLazyLoadFolders: ["pages"],
1681
+ extraModuleFolders: ["features", "modules"],
1682
+ extraLazyLoadFolders: ["screens"],
1641
1683
  extraIgnorePatterns: ["*.stories.js", "*.mock.js"]
1642
1684
  }]
1643
1685
  ```
package/index.d.ts CHANGED
@@ -20,6 +20,7 @@ export type RuleNames =
20
20
  | "code-style/export-format"
21
21
  | "code-style/function-arguments-format"
22
22
  | "code-style/function-call-spacing"
23
+ | "code-style/function-declaration-style"
23
24
  | "code-style/function-naming-convention"
24
25
  | "code-style/function-object-destructure"
25
26
  | "code-style/function-params-per-line"
@@ -101,6 +102,7 @@ interface PluginRules {
101
102
  "export-format": Rule.RuleModule;
102
103
  "function-arguments-format": Rule.RuleModule;
103
104
  "function-call-spacing": Rule.RuleModule;
105
+ "function-declaration-style": Rule.RuleModule;
104
106
  "function-naming-convention": Rule.RuleModule;
105
107
  "function-object-destructure": Rule.RuleModule;
106
108
  "function-params-per-line": Rule.RuleModule;
package/index.js CHANGED
@@ -1679,6 +1679,92 @@ const functionCallSpacing = {
1679
1679
  },
1680
1680
  };
1681
1681
 
1682
+ /**
1683
+ * ───────────────────────────────────────────────────────────────
1684
+ * Rule: Function Declaration Style
1685
+ * ───────────────────────────────────────────────────────────────
1686
+ *
1687
+ * Description:
1688
+ * Enforce function expressions (arrow functions) instead of
1689
+ * function declarations. Auto-fixes by converting to const
1690
+ * arrow function expressions.
1691
+ *
1692
+ * ✓ Good:
1693
+ * const getToken = (): string | null => getCookie(tokenKey);
1694
+ * const clearAuth = (): void => {
1695
+ * removeToken();
1696
+ * clearStorage();
1697
+ * };
1698
+ *
1699
+ * ✗ Bad:
1700
+ * function getToken(): string | null { return getCookie(tokenKey); }
1701
+ * function clearAuth(): void {
1702
+ * removeToken();
1703
+ * clearStorage();
1704
+ * }
1705
+ */
1706
+ const functionDeclarationStyle = {
1707
+ create(context) {
1708
+ const sourceCode = context.sourceCode || context.getSourceCode();
1709
+
1710
+ return {
1711
+ FunctionDeclaration(node) {
1712
+ if (!node.id) return;
1713
+
1714
+ const name = node.id.name;
1715
+
1716
+ // Build the params text
1717
+ const paramsText = node.params.map((p) => sourceCode.getText(p)).join(", ");
1718
+
1719
+ // Build return type annotation if present
1720
+ let returnType = "";
1721
+
1722
+ if (node.returnType) {
1723
+ returnType = sourceCode.getText(node.returnType);
1724
+ }
1725
+
1726
+ // Build type parameters if present (generics)
1727
+ let typeParams = "";
1728
+
1729
+ if (node.typeParameters) {
1730
+ typeParams = sourceCode.getText(node.typeParameters);
1731
+ }
1732
+
1733
+ // Check if async
1734
+ const isAsync = node.async;
1735
+ const asyncPrefix = isAsync ? "async " : "";
1736
+
1737
+ // Get the body text
1738
+ const bodyText = sourceCode.getText(node.body);
1739
+
1740
+ // Check for export keywords
1741
+ const parentNode = node.parent;
1742
+ const isExported = parentNode && parentNode.type === "ExportNamedDeclaration";
1743
+
1744
+ const exportPrefix = isExported ? "export " : "";
1745
+
1746
+ context.report({
1747
+ fix(fixer) {
1748
+ const fixTarget = isExported ? parentNode : node;
1749
+
1750
+ const replacement = `${exportPrefix}const ${name} = ${asyncPrefix}(${paramsText})${returnType} => ${bodyText};`;
1751
+
1752
+ return fixer.replaceText(fixTarget, replacement);
1753
+ },
1754
+ message: `Expected a function expression. Use \`const ${name} = ${asyncPrefix}(${paramsText})${returnType} => ...\` instead.`,
1755
+ node: node.id,
1756
+ });
1757
+ },
1758
+ };
1759
+ },
1760
+ meta: {
1761
+ docs: { description: "Enforce arrow function expressions instead of function declarations" },
1762
+ fixable: "code",
1763
+ schema: [],
1764
+ type: "suggestion",
1765
+ },
1766
+ };
1767
+
1682
1768
  /**
1683
1769
  * ───────────────────────────────────────────────────────────────
1684
1770
  * Rule: Function Naming Convention
@@ -1772,9 +1858,37 @@ const functionNamingConvention = {
1772
1858
  node: node.id || node.parent.id,
1773
1859
  });
1774
1860
  } else if (!hasHandlerSuffix) {
1861
+ const identifierNode = node.id || node.parent.id;
1862
+ const newName = `${name}Handler`;
1863
+
1775
1864
  context.report({
1776
- message: `Function "${name}" should end with "Handler" suffix (e.g., ${name}Handler)`,
1777
- node: node.id || node.parent.id,
1865
+ fix(fixer) {
1866
+ const scope = context.sourceCode
1867
+ ? context.sourceCode.getScope(node)
1868
+ : context.getScope();
1869
+
1870
+ // Find all references to this variable in the scope
1871
+ const variable = scope.variables.find((v) => v.name === name)
1872
+ || (scope.upper && scope.upper.variables.find((v) => v.name === name));
1873
+
1874
+ if (!variable) return fixer.replaceText(identifierNode, newName);
1875
+
1876
+ const fixes = [];
1877
+
1878
+ // Fix the definition
1879
+ variable.defs.forEach((def) => {
1880
+ fixes.push(fixer.replaceText(def.name, newName));
1881
+ });
1882
+
1883
+ // Fix all references
1884
+ variable.references.forEach((ref) => {
1885
+ fixes.push(fixer.replaceText(ref.identifier, newName));
1886
+ });
1887
+
1888
+ return fixes;
1889
+ },
1890
+ message: `Function "${name}" should end with "Handler" suffix (e.g., ${newName})`,
1891
+ node: identifierNode,
1778
1892
  });
1779
1893
  }
1780
1894
  };
@@ -1787,6 +1901,7 @@ const functionNamingConvention = {
1787
1901
  },
1788
1902
  meta: {
1789
1903
  docs: { description: "Enforce function names to start with a verb AND end with Handler" },
1904
+ fixable: "code",
1790
1905
  schema: [],
1791
1906
  type: "suggestion",
1792
1907
  },
@@ -3113,13 +3228,13 @@ const multilineIfConditions = {
3113
3228
  * folder-level index files.
3114
3229
  *
3115
3230
  * Options:
3116
- * - aliasPrefix: string (default: "@/") - The import alias prefix
3117
- * - extraAllowedFolders: string[] - Additional folders to allow (extends defaults)
3118
- * - extraReduxSubfolders: string[] - Additional redux subfolders (extends defaults)
3119
- * - extraDeepImportFolders: string[] - Additional folders allowing deep imports (extends "assets")
3120
- * - allowedFolders: string[] - Replace default folders entirely (use extraAllowedFolders to extend)
3121
- * - reduxSubfolders: string[] - Replace default redux subfolders entirely
3122
- * - deepImportFolders: string[] - Replace default deep import folders entirely
3231
+ * - aliasPrefix: string (default: "@/") - Change path alias prefix if your project uses something other than @/ (e.g., ~/, src/)
3232
+ * - extraAllowedFolders: string[] - Add custom folders that can be imported with @/folder. Extends defaults without replacing them
3233
+ * - extraReduxSubfolders: string[] - Add Redux subfolders importable directly (@/selectors) or nested (@/redux/selectors). Default: actions, reducers, store, thunks, types
3234
+ * - extraDeepImportFolders: string[] - Add folders where direct file imports are allowed (@/assets/images/logo.svg). Use for folders without index files. Default: assets
3235
+ * - allowedFolders: string[] - Completely replace the default allowed folders list. Use only if you need full control
3236
+ * - reduxSubfolders: string[] - Completely replace the default Redux subfolders list
3237
+ * - deepImportFolders: string[] - Completely replace the default deep import folders list
3123
3238
  *
3124
3239
  * ✓ Good:
3125
3240
  * import { Button } from "@/components";
@@ -3131,7 +3246,7 @@ const multilineIfConditions = {
3131
3246
  *
3132
3247
  * Configuration Example:
3133
3248
  * "code-style/absolute-imports-only": ["error", {
3134
- * extraAllowedFolders: ["features", "modules", "lib"],
3249
+ * extraAllowedFolders: ["features", "modules"],
3135
3250
  * extraDeepImportFolders: ["images", "fonts"]
3136
3251
  * }]
3137
3252
  */
@@ -3170,6 +3285,7 @@ const absoluteImportsOnly = {
3170
3285
  "layouts",
3171
3286
  "lib",
3172
3287
  "middlewares",
3288
+ "pages",
3173
3289
  "providers",
3174
3290
  "reducers",
3175
3291
  "redux",
@@ -3216,10 +3332,14 @@ const absoluteImportsOnly = {
3216
3332
  // for re-exporting their contents
3217
3333
  const isIndexFile = /\/index\.(js|jsx|ts|tsx)$/.test(normalizedFilename);
3218
3334
 
3335
+ // Check if this is an entry file (main.tsx, main.ts, etc.) - entry files are allowed
3336
+ // to use relative imports for app root and styles (e.g., ./index.css, ./app)
3337
+ const isEntryFile = /\/main\.(js|jsx|ts|tsx)$/.test(normalizedFilename);
3338
+
3219
3339
  // 1. Disallow relative imports (starting with ./ or ../)
3220
3340
  // EXCEPT in index files which need relative imports for re-exports
3221
3341
  if (importPath.startsWith("./") || importPath.startsWith("../")) {
3222
- if (!isIndexFile) {
3342
+ if (!isIndexFile && !isEntryFile) {
3223
3343
  context.report({
3224
3344
  message: `Relative imports are not allowed. Use absolute imports with "${aliasPrefix}" prefix instead.`,
3225
3345
  node: node.source,
@@ -3780,12 +3900,12 @@ const importSourceSpacing = {
3780
3900
  * subfolders and files in the module.
3781
3901
  *
3782
3902
  * Options:
3783
- * - extraModuleFolders: string[] - Additional module folders (extends defaults)
3784
- * - extraLazyLoadFolders: string[] - Additional lazy load folders (extends defaults)
3785
- * - extraIgnorePatterns: string[] - Additional ignore patterns (extends defaults)
3786
- * - moduleFolders: string[] - Replace default module folders entirely
3787
- * - lazyLoadFolders: string[] - Replace default lazy load folders entirely
3788
- * - ignorePatterns: string[] - Replace default ignore patterns entirely
3903
+ * - extraModuleFolders: string[] - Add folders that should have an index.js re-exporting all public files. Use for project-specific folders like features/, modules/
3904
+ * - extraLazyLoadFolders: string[] - Add folders exempt from index file requirements. Use for route/page components loaded via dynamic import(). Default: pages, views
3905
+ * - extraIgnorePatterns: string[] - Add file patterns to skip when checking for index exports. Supports wildcards like *.stories.js, *.mock.js
3906
+ * - moduleFolders: string[] - Completely replace the default module folders list. Use only if you need full control
3907
+ * - lazyLoadFolders: string[] - Completely replace the default lazy load folders list
3908
+ * - ignorePatterns: string[] - Completely replace the default ignore patterns list
3789
3909
  *
3790
3910
  * ✓ Good:
3791
3911
  * // index.js
@@ -3797,8 +3917,8 @@ const importSourceSpacing = {
3797
3917
  *
3798
3918
  * Configuration Example:
3799
3919
  * "code-style/module-index-exports": ["error", {
3800
- * extraModuleFolders: ["features", "modules", "lib"],
3801
- * extraLazyLoadFolders: ["pages"],
3920
+ * extraModuleFolders: ["features", "modules"],
3921
+ * extraLazyLoadFolders: ["screens"],
3802
3922
  * extraIgnorePatterns: ["*.stories.js", "*.mock.js"]
3803
3923
  * }]
3804
3924
  */
@@ -3829,6 +3949,7 @@ const moduleIndexExports = {
3829
3949
  "layouts",
3830
3950
  "lib",
3831
3951
  "middlewares",
3952
+ "pages",
3832
3953
  "providers",
3833
3954
  "reducers",
3834
3955
  "redux",
@@ -3853,7 +3974,7 @@ const moduleIndexExports = {
3853
3974
  || [...defaultModuleFolders, ...(options.extraModuleFolders || [])];
3854
3975
 
3855
3976
  // Default lazy load folders
3856
- const defaultLazyLoadFolders = ["views"];
3977
+ const defaultLazyLoadFolders = ["pages", "views"];
3857
3978
 
3858
3979
  // Folders that use lazy loading and shouldn't require index exports
3859
3980
  // These folders typically have components loaded via dynamic import()
@@ -14184,6 +14305,7 @@ export default {
14184
14305
 
14185
14306
  // Function rules
14186
14307
  "function-call-spacing": functionCallSpacing,
14308
+ "function-declaration-style": functionDeclarationStyle,
14187
14309
  "function-naming-convention": functionNamingConvention,
14188
14310
  "function-object-destructure": functionObjectDestructure,
14189
14311
  "function-params-per-line": functionParamsPerLine,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-code-style",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "description": "A custom ESLint plugin for enforcing consistent code formatting and style rules in React/JSX projects",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",