eslint-plugin-code-style 2.0.0 → 2.0.2

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.
@@ -1,147 +0,0 @@
1
- # Hook Rules
2
-
3
- ### `hook-callback-format`
4
-
5
- **What it does:** Enforces consistent multi-line formatting for React hooks that take a callback and dependency array (useEffect, useCallback, useMemo, useLayoutEffect).
6
-
7
- **Why use it:** Hooks with callbacks and dependencies are complex. Multi-line formatting makes the callback, return cleanup, and dependencies clearly visible.
8
-
9
- ```javascript
10
- // ✅ Good — callback and deps clearly separated
11
- useEffect(
12
- () => {
13
- fetchData();
14
- },
15
- [userId],
16
- );
17
-
18
- useCallback(
19
- () => {
20
- handleSubmit(data);
21
- },
22
- [data, handleSubmit],
23
- );
24
-
25
- useMemo(
26
- () => expensiveCalculation(items),
27
- [items],
28
- );
29
-
30
- // ✅ Good — cleanup function visible
31
- useEffect(
32
- () => {
33
- const subscription = subscribe();
34
-
35
- return () => subscription.unsubscribe();
36
- },
37
- [subscribe],
38
- );
39
-
40
- // ❌ Bad — everything crammed on one line
41
- useEffect(() => { fetchData(); }, [userId]);
42
-
43
- // ❌ Bad — hard to see dependencies
44
- useCallback(() => { handleSubmit(data); }, [data, handleSubmit]);
45
- ```
46
-
47
- ---
48
-
49
- ### `hook-deps-per-line`
50
-
51
- **What it does:** When a hook's dependency array exceeds the threshold (default: 2), each dependency goes on its own line.
52
-
53
- **Why use it:** Long dependency arrays are hard to scan and diff. One per line makes it easy to see what changed and catch missing/extra dependencies.
54
-
55
- ```javascript
56
- // ✅ Good — 2 or fewer deps stay inline
57
- useEffect(() => {}, [userId]);
58
- useEffect(() => {}, [userId, token]);
59
-
60
- // ✅ Good — 3+ deps get one per line
61
- useEffect(
62
- () => {},
63
- [
64
- userId,
65
- token,
66
- refreshToken,
67
- ],
68
- );
69
-
70
- useCallback(
71
- () => handleSubmit(data),
72
- [
73
- data,
74
- handleSubmit,
75
- validateForm,
76
- showError,
77
- ],
78
- );
79
-
80
- // ❌ Bad — too many deps on one line
81
- useEffect(() => {}, [userId, token, refreshToken, apiUrl]);
82
-
83
- // ❌ Bad — deps should be one per line when expanded
84
- useEffect(() => {}, [
85
- userId, token, refreshToken,
86
- ]);
87
- ```
88
-
89
- **Options:**
90
-
91
- | Option | Type | Default | Description |
92
- |--------|------|---------|-------------|
93
- | `maxDeps` | `integer` | `2` | Maximum dependencies to keep on single line |
94
-
95
- ```javascript
96
- // Example: Allow up to 3 dependencies on single line
97
- "code-style/hook-deps-per-line": ["error", { maxDeps: 3 }]
98
- ```
99
-
100
- <br />
101
-
102
- ### `use-state-naming-convention`
103
-
104
- **What it does:** Enforces boolean useState variables to start with valid prefixes (is, has, with, without).
105
-
106
- **Why use it:** Consistent boolean state naming makes code more predictable and self-documenting. When you see `isLoading`, you immediately know it's a boolean state.
107
-
108
- ```typescript
109
- // ✅ Good — boolean state with proper prefix
110
- const [isLoading, setIsLoading] = useState(false);
111
- const [hasError, setHasError] = useState<boolean>(false);
112
- const [isAuthenticated, setIsAuthenticated] = useState(true);
113
- const [withBorder, setWithBorder] = useState(false);
114
-
115
- // ❌ Bad — boolean state without prefix
116
- const [loading, setLoading] = useState(false);
117
- const [authenticated, setAuthenticated] = useState<boolean>(true);
118
- const [error, setError] = useState<boolean>(false);
119
- ```
120
-
121
- **Customization Options:**
122
-
123
- | Option | Type | Default | Description |
124
- |--------|------|---------|-------------|
125
- | `booleanPrefixes` | `string[]` | `["is", "has", "with", "without"]` | Replace default prefixes entirely |
126
- | `extendBooleanPrefixes` | `string[]` | `[]` | Add additional prefixes to defaults |
127
- | `allowPastVerbBoolean` | `boolean` | `false` | Allow past verb names without prefix (disabled, selected) |
128
- | `allowContinuousVerbBoolean` | `boolean` | `false` | Allow continuous verb names without prefix (loading, saving) |
129
-
130
- ```javascript
131
- // Example: Allow "loading" and "disabled" without prefix
132
- "code-style/use-state-naming-convention": ["error", {
133
- allowPastVerbBoolean: true,
134
- allowContinuousVerbBoolean: true
135
- }]
136
-
137
- // Example: Add "should" prefix
138
- "code-style/use-state-naming-convention": ["error", {
139
- extendBooleanPrefixes: ["should"]
140
- }]
141
- ```
142
-
143
- <br />
144
-
145
- ---
146
-
147
- [← Back to Rules Index](./README.md) | [← Back to Main README](../../README.md)
@@ -1,383 +0,0 @@
1
- # Import/Export Rules
2
-
3
- ### `absolute-imports-only`
4
-
5
- **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. 🔧
6
-
7
- **Why use it:**
8
- - Absolute imports are cleaner than `../../../components`
9
- - Index imports create a public API for each folder
10
- - Refactoring file locations doesn't break imports
11
- - Encourages proper module organization
12
- - Relative imports within the same module folder avoid circular dependencies
13
-
14
- ```javascript
15
- // ✅ Good — import from index files using alias
16
- import { Button, Input } from "@/components";
17
- import { useAuth, useUser } from "@/hooks";
18
- import { fetchUsers } from "@/apis";
19
- import { formatDate } from "@/utils";
20
-
21
- // ✅ Good — assets allow deep imports by default
22
- import logo from "@/assets/images/logo.png";
23
-
24
- // ✅ Good — relative import within the same module folder (siblings)
25
- // File: utils/formatters.js
26
- import { isNumber } from "./validators";
27
-
28
- // ✅ Good — relative import within the same module folder (nested)
29
- // File: data/auth/forget-password/index.ts
30
- import { guestLoginData } from "../../login/guest";
31
-
32
- // ❌ Bad — absolute import to own module folder (should use relative)
33
- // File: data/auth/forget-password/index.ts
34
- import { guestLoginData } from "@/data";
35
- // → use relative import instead: import { guestLoginData } from "../../login/guest";
36
-
37
- // ❌ Bad — relative imports across different folders
38
- import { Button } from "../../components";
39
- import { useAuth } from "../../../hooks";
40
-
41
- // ❌ Bad — deep imports into component internals
42
- import { Button } from "@/components/buttons/primary-button";
43
- import { useAuth } from "@/hooks/auth/useAuth";
44
- import { fetchUsers } from "@/apis/users/fetchUsers";
45
- ```
46
-
47
- **Default Allowed Folders:**
48
- `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`
49
-
50
- **Customization Options:**
51
-
52
- | Option | Type | Description |
53
- |--------|------|-------------|
54
- | `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. |
55
- | `extraReduxSubfolders` | `string[]` | Add Redux-related subfolders that can be imported directly (`@/selectors`) or nested (`@/redux/selectors`). Default subfolders: `actions`, `reducers`, `store`, `thunks`, `types` |
56
- | `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` |
57
- | `aliasPrefix` | `string` | Change the path alias prefix if your project uses something other than `@/` (e.g., `~/`, `src/`) |
58
- | `allowedFolders` | `string[]` | Completely replace the default allowed folders list. Use only if you need full control over which folders are valid |
59
- | `reduxSubfolders` | `string[]` | Completely replace the default Redux subfolders list |
60
- | `deepImportFolders` | `string[]` | Completely replace the default deep import folders list |
61
-
62
- ```javascript
63
- // Example: Add custom folders to the defaults
64
- "code-style/absolute-imports-only": ["error", {
65
- extraAllowedFolders: ["features", "modules"],
66
- extraDeepImportFolders: ["images", "fonts"]
67
- }]
68
- ```
69
-
70
- ---
71
-
72
- ### `export-format`
73
-
74
- **What it does:** Formats export statements consistently:
75
- - `export {` always on the same line as `export` keyword
76
- - ≤3 specifiers stay on one line (collapsed)
77
- - 4+ specifiers get one per line (expanded)
78
- - Proper spacing and trailing commas
79
-
80
- **Why use it:** Consistent export formatting improves readability. Short exports stay compact, long exports become scannable.
81
-
82
- ```javascript
83
- // ✅ Good — 3 or fewer specifiers stay compact
84
- export { Button };
85
- export { Button, Input };
86
- export { Button, Input, Select };
87
-
88
- // ✅ Good — 4+ specifiers expand with one per line
89
- export {
90
- Button,
91
- Input,
92
- Select,
93
- Checkbox,
94
- };
95
-
96
- // ✅ Good — re-exports follow same rules
97
- export { Button, Input, Select } from "./components";
98
- export {
99
- createUser,
100
- updateUser,
101
- deleteUser,
102
- getUser,
103
- } from "./api";
104
-
105
- // ❌ Bad — no spaces
106
- export {Button,Input,Select};
107
-
108
- // ❌ Bad — keyword on different line
109
- export
110
- { Button };
111
-
112
- // ❌ Bad — too many on one line
113
- export { Button, Input, Select, Checkbox, Radio };
114
- ```
115
-
116
- **Options:**
117
-
118
- | Option | Type | Default | Description |
119
- |--------|------|---------|-------------|
120
- | `maxSpecifiers` | `integer` | `3` | Maximum specifiers to keep on single line |
121
-
122
- ```javascript
123
- "code-style/export-format": ["error", { maxSpecifiers: 4 }]
124
- ```
125
-
126
- ---
127
-
128
- ### `import-format`
129
-
130
- **What it does:** Formats import statements consistently:
131
- - `import {` on the same line as `import` keyword
132
- - `} from` on the same line as closing brace
133
- - ≤3 specifiers stay on one line (collapsed)
134
- - 4+ specifiers get one per line (expanded)
135
-
136
- **Why use it:** Consistent import formatting improves readability and makes diffs cleaner when adding/removing imports.
137
-
138
- ```javascript
139
- // ✅ Good — 3 or fewer specifiers stay compact
140
- import { useState } from "react";
141
- import { Button, Input } from "@/components";
142
- import { get, post, put } from "@/api";
143
-
144
- // ✅ Good — 4+ specifiers expand with one per line
145
- import {
146
- useState,
147
- useEffect,
148
- useCallback,
149
- useMemo,
150
- } from "react";
151
-
152
- import {
153
- Button,
154
- Input,
155
- Select,
156
- Checkbox,
157
- } from "@/components";
158
-
159
- // ❌ Bad — no spaces
160
- import {useState,useEffect} from "react";
161
-
162
- // ❌ Bad — keyword on different line
163
- import
164
- { Button } from "@/components";
165
-
166
- // ❌ Bad — from on different line
167
- import { Button }
168
- from "@/components";
169
-
170
- // ❌ Bad — too many on one line
171
- import { useState, useEffect, useCallback, useMemo, useRef } from "react";
172
- ```
173
-
174
- **Options:**
175
-
176
- | Option | Type | Default | Description |
177
- |--------|------|---------|-------------|
178
- | `maxSpecifiers` | `integer` | `3` | Maximum specifiers to keep on single line |
179
-
180
- ```javascript
181
- "code-style/import-format": ["error", { maxSpecifiers: 4 }]
182
- ```
183
-
184
- ---
185
-
186
- ### `import-source-spacing`
187
-
188
- **What it does:** Removes any leading or trailing whitespace inside import path strings.
189
-
190
- **Why use it:** Spaces in module paths are almost always typos and can cause import resolution issues.
191
-
192
- ```javascript
193
- // ✅ Good — no extra spaces
194
- import { Button } from "@mui/material";
195
- import React from "react";
196
- import styles from "./styles.css";
197
-
198
- // ❌ Bad — leading space
199
- import { Button } from " @mui/material";
200
-
201
- // ❌ Bad — trailing space
202
- import React from "react ";
203
-
204
- // ❌ Bad — both
205
- import styles from " ./styles.css ";
206
- ```
207
-
208
- ---
209
-
210
- ### `index-export-style`
211
-
212
- **What it does:** Enforces different export formatting rules for index files vs regular files:
213
- - **Index files**: No blank lines between exports, use shorthand or import-export style
214
- - **Regular files**: Require blank lines between exports
215
-
216
- **Why use it:** Index files are re-export aggregators and should be compact. Regular files benefit from spacing between exports for readability.
217
-
218
- **Regular files (non-index):**
219
- ```javascript
220
- // ✅ Good — blank lines between exports
221
- export const API_URL = "/api";
222
-
223
- export const MAX_RETRIES = 3;
224
-
225
- export const fetchData = async () => {};
226
-
227
- // ❌ Bad — no blank lines in regular file
228
- export const API_URL = "/api";
229
- export const MAX_RETRIES = 3;
230
- export const fetchData = async () => {};
231
- ```
232
-
233
- **Index files — Style: "shorthand" (default):**
234
- ```javascript
235
- // ✅ Good — shorthand re-exports, no blank lines
236
- export { Button } from "./button";
237
- export { Input, Select } from "./form";
238
- export { Modal } from "./modal";
239
- export { useAuth, useUser } from "./hooks";
240
- ```
241
-
242
- **Index files — Style: "import-export":**
243
- ```javascript
244
- // ✅ Good — imports grouped, single export at bottom
245
- import { Button } from "./button";
246
- import { Input, Select } from "./form";
247
- import { Modal } from "./modal";
248
-
249
- export {
250
- Button,
251
- Input,
252
- Modal,
253
- Select,
254
- };
255
- ```
256
-
257
- **Options:**
258
-
259
- | Option | Type | Default | Description |
260
- |--------|------|---------|-------------|
261
- | `style` | `"shorthand"` \| `"import-export"` | `"shorthand"` | Export style for index files |
262
-
263
- ```javascript
264
- "code-style/index-export-style": ["error", { style: "import-export" }]
265
- ```
266
-
267
- ---
268
-
269
- ### `index-exports-only`
270
-
271
- **What it does:** Index files (`index.ts`, `index.tsx`, `index.js`, `index.jsx`) should only contain imports and re-exports, not any code definitions. All definitions (types, interfaces, functions, variables, classes) should be moved to separate files.
272
-
273
- **Why use it:** Index files should be "barrels" that aggregate exports from a module. Mixing definitions with re-exports makes the codebase harder to navigate and can cause circular dependency issues.
274
-
275
- ```javascript
276
- // ✅ Good — index.ts with only imports and re-exports
277
- export { Button } from "./Button";
278
- export { helper } from "./utils";
279
- export type { ButtonProps } from "./types";
280
- export * from "./constants";
281
-
282
- // ❌ Bad — index.ts with code definitions
283
- export type ButtonVariant = "primary" | "secondary"; // Move to types.ts
284
- export interface ButtonProps { ... } // Move to types.ts
285
- export const CONSTANT = "value"; // Move to constants.ts
286
- export function helper() { ... } // Move to utils.ts
287
- ```
288
-
289
- ---
290
-
291
- ### `inline-export-declaration`
292
-
293
- **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.
294
-
295
- **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.
296
-
297
- **Important exceptions:**
298
- - **Index files** (barrel re-exports) are skipped entirely -- they should use grouped/re-export syntax
299
- - **Aliased exports** (`export { a as b }`) are skipped since they cannot be expressed as inline exports
300
-
301
- ```javascript
302
- // ✅ Good — inline export declarations
303
- export const strings = {
304
- title: "Hello",
305
- subtitle: "World",
306
- };
307
-
308
- export const MAX_RETRIES = 3;
309
-
310
- export function fetchData() {
311
- return fetch("/api/data");
312
- }
313
-
314
- // ❌ Bad — grouped export statement
315
- const strings = {
316
- title: "Hello",
317
- subtitle: "World",
318
- };
319
-
320
- const MAX_RETRIES = 3;
321
-
322
- function fetchData() {
323
- return fetch("/api/data");
324
- }
325
-
326
- export { strings, MAX_RETRIES, fetchData };
327
- ```
328
-
329
- ---
330
-
331
- ### `module-index-exports`
332
-
333
- **What it does:** Ensures module folders have index files that export all their contents, creating a proper public API for each module.
334
-
335
- **Why use it:** Index files allow importing from the folder level (`@/components`) instead of deep paths (`@/components/Button/Button`). This enforces proper module boundaries.
336
-
337
- ```javascript
338
- // ✅ Good — components/index.js exports everything
339
- export { Button } from "./Button";
340
- export { Input } from "./Input";
341
- export { Select } from "./Select";
342
- export { Modal } from "./Modal";
343
-
344
- // Then consumers can import cleanly:
345
- import { Button, Input, Select } from "@/components";
346
-
347
- // ❌ Bad — missing exports in index.js
348
- // If Button exists but isn't exported from index.js,
349
- // consumers have to use deep imports:
350
- import { Button } from "@/components/Button/Button"; // Avoid this!
351
- ```
352
-
353
- **Default Module Folders:**
354
- `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`
355
-
356
- **Default Ignore Patterns:**
357
- `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`
358
-
359
- **Customization Options:**
360
-
361
- | Option | Type | Description |
362
- |--------|------|-------------|
363
- | `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 |
364
- | `extraLazyLoadFolders` | `string[]` | Add folders exempt from index file requirements. Use for route/page components loaded via dynamic `import()`. Default: `pages`, `views` |
365
- | `extraIgnorePatterns` | `string[]` | Add file patterns to skip when checking for index exports. Supports wildcards like `*.stories.js`, `*.mock.js` |
366
- | `moduleFolders` | `string[]` | Completely replace the default module folders list. Use only if you need full control over which folders require index files |
367
- | `lazyLoadFolders` | `string[]` | Completely replace the default lazy load folders list |
368
- | `ignorePatterns` | `string[]` | Completely replace the default ignore patterns list |
369
-
370
- ```javascript
371
- // Example: Add custom folders and patterns
372
- "code-style/module-index-exports": ["error", {
373
- extraModuleFolders: ["features", "modules"],
374
- extraLazyLoadFolders: ["screens"],
375
- extraIgnorePatterns: ["*.stories.js", "*.mock.js"]
376
- }]
377
- ```
378
-
379
- <br />
380
-
381
- ---
382
-
383
- [← Back to Rules Index](./README.md) | [← Back to Main README](../../README.md)