eslint-plugin-nextfriday 1.6.0 → 1.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # eslint-plugin-nextfriday
2
2
 
3
+ ## 1.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#41](https://github.com/next-friday/eslint-plugin-nextfriday/pull/41) [`10b67d9`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/10b67d941c47fef5b72408bfff2b56e98a46c26c) Thanks [@nextfridaydeveloper](https://github.com/nextfridaydeveloper)! - Add no-direct-date rule to disallow direct usage of Date constructor and methods (new Date(), Date.now(), Date.parse()) to enforce centralized date utilities like dayjs
8
+
3
9
  ## 1.6.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -22,7 +22,7 @@ pnpm add -D eslint-plugin-nextfriday
22
22
  import nextfriday from "eslint-plugin-nextfriday";
23
23
 
24
24
  export default [nextfriday.configs.base];
25
- // or use the recommended preset
25
+ // or use the recommended preset (stricter)
26
26
  export default [nextfriday.configs["base/recommended"]];
27
27
  ```
28
28
 
@@ -59,19 +59,37 @@ export default [
59
59
  nextfriday,
60
60
  },
61
61
  rules: {
62
- "nextfriday/no-emoji": "error",
62
+ // Variable Naming
63
+ "nextfriday/no-single-char-variables": "error",
64
+ "nextfriday/boolean-naming-prefix": "error",
65
+
66
+ // File Naming
63
67
  "nextfriday/file-kebab-case": "error",
68
+ "nextfriday/jsx-pascal-case": "error",
64
69
  "nextfriday/md-filename-case-restriction": "error",
70
+
71
+ // Code Style
72
+ "nextfriday/no-emoji": "error",
65
73
  "nextfriday/prefer-destructuring-params": "error",
66
- "nextfriday/no-explicit-return-type": "error",
67
- "nextfriday/prefer-import-type": "error",
68
- "nextfriday/prefer-named-param-types": "error",
69
- "nextfriday/prefer-react-import-types": "error",
74
+ "nextfriday/prefer-function-declaration": "error",
75
+ "nextfriday/require-explicit-return-type": "error",
70
76
  "nextfriday/no-complex-inline-return": "error",
71
77
  "nextfriday/no-logic-in-params": "error",
78
+ "nextfriday/enforce-sorted-destructuring": "error",
72
79
  "nextfriday/no-env-fallback": "error",
73
- "nextfriday/jsx-pascal-case": "error",
80
+
81
+ // Import Optimization
82
+ "nextfriday/prefer-import-type": "error",
83
+ "nextfriday/prefer-react-import-types": "error",
84
+
85
+ // Type Patterns
86
+ "nextfriday/prefer-named-param-types": "error",
74
87
  "nextfriday/prefer-interface-over-inline-types": "error",
88
+
89
+ // React/JSX
90
+ "nextfriday/jsx-no-non-component-function": "error",
91
+ "nextfriday/jsx-no-variable-in-callback": "error",
92
+ "nextfriday/prefer-jsx-template-literals": "error",
75
93
  "nextfriday/react-props-destructure": "error",
76
94
  "nextfriday/enforce-readonly-component-props": "error",
77
95
  },
@@ -110,91 +128,119 @@ module.exports = {
110
128
 
111
129
  ## Rules
112
130
 
113
- | Rule | Description | Fixable |
114
- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------- |
115
- | [no-emoji](docs/rules/NO_EMOJI.md) | Disallow emojis in code | ❌ |
116
- | [file-kebab-case](docs/rules/FILE_KEBAB_CASE.md) | Enforce kebab-case filenames for .ts and .js files | ❌ |
117
- | [jsx-pascal-case](docs/rules/JSX_PASCAL_CASE.md) | Enforce PascalCase filenames for .jsx and .tsx files | ❌ |
118
- | [md-filename-case-restriction](docs/rules/MD_FILENAME_CASE_RESTRICTION.md) | Enforce SNAKE_CASE filenames for .md files | ❌ |
119
- | [prefer-destructuring-params](docs/rules/PREFER_DESTRUCTURING_PARAMS.md) | Enforce destructuring for functions with multiple parameters | ❌ |
120
- | [no-explicit-return-type](docs/rules/NO_EXPLICIT_RETURN_TYPE.md) | Disallow explicit return types on functions | ✅ |
121
- | [jsx-no-non-component-function](docs/rules/JSX_NO_NON_COMPONENT_FUNCTION.md) | Disallow non-component functions at top level in .tsx and .jsx files | ❌ |
122
- | [jsx-no-variable-in-callback](docs/rules/JSX_NO_VARIABLE_IN_CALLBACK.md) | Disallow variable declarations inside callback functions within JSX | ❌ |
123
- | [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md) | Enforce using 'import type' for type-only imports | ✅ |
124
- | [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
125
- | [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
126
- | [prefer-jsx-template-literals](docs/rules/PREFER_JSX_TEMPLATE_LITERALS.md) | Enforce using template literals instead of mixing text and JSX expressions | ✅ |
127
- | [prefer-react-import-types](docs/rules/PREFER_REACT_IMPORT_TYPES.md) | Enforce direct imports from 'react' instead of React.X | ✅ |
128
- | [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | ❌ |
129
- | [enforce-readonly-component-props](docs/rules/ENFORCE_READONLY_COMPONENT_PROPS.md) | Enforce Readonly wrapper for React component props | ✅ |
130
- | [enforce-sorted-destructuring](docs/rules/ENFORCE_SORTED_DESTRUCTURING.md) | Enforce alphabetical sorting of destructured properties with defaults first | ❌ |
131
- | [no-complex-inline-return](docs/rules/NO_COMPLEX_INLINE_RETURN.md) | Disallow complex inline expressions in return statements - prefer const first | ❌ |
132
- | [no-logic-in-params](docs/rules/NO_LOGIC_IN_PARAMS.md) | Disallow logic or conditions in function parameters - extract to const first | ❌ |
133
- | [no-env-fallback](docs/rules/NO_ENV_FALLBACK.md) | Disallow fallback values for environment variables as they can be dangerous | ❌ |
134
-
135
- ## Configurations
136
-
137
- ### Base Configurations (for pure JS/TS projects)
138
-
139
- #### `base`
140
-
141
- Basic configuration without JSX-specific rules:
131
+ ### Variable Naming Rules
142
132
 
143
- - `nextfriday/no-emoji`: `"error"`
144
- - `nextfriday/file-kebab-case`: `"error"`
145
- - `nextfriday/md-filename-case-restriction`: `"error"`
146
- - `nextfriday/prefer-destructuring-params`: `"error"`
147
- - `nextfriday/no-explicit-return-type`: `"error"`
148
- - `nextfriday/prefer-import-type`: `"error"`
149
- - `nextfriday/prefer-named-param-types`: `"error"`
150
- - `nextfriday/prefer-react-import-types`: `"error"`
151
- - `nextfriday/no-complex-inline-return`: `"error"`
152
- - `nextfriday/no-logic-in-params`: `"error"`
153
- - `nextfriday/no-env-fallback`: `"error"`
133
+ | Rule | Description | Fixable |
134
+ | ------------------------------------------------------------------ | --------------------------------------------------------------------- | ------- |
135
+ | [no-single-char-variables](docs/rules/NO_SINGLE_CHAR_VARIABLES.md) | Disallow single character variable names (e.g., `d`, `u`, `l`) | ❌ |
136
+ | [boolean-naming-prefix](docs/rules/BOOLEAN_NAMING_PREFIX.md) | Enforce boolean variables to have prefix (is, has, should, can, etc.) | ❌ |
154
137
 
155
- #### `base/recommended`
138
+ ### File Naming Rules
156
139
 
157
- Same as `base` configuration (recommended preset for pure JS/TS projects).
140
+ | Rule | Description | Fixable |
141
+ | -------------------------------------------------------------------------- | ---------------------------------------------------- | ------- |
142
+ | [file-kebab-case](docs/rules/FILE_KEBAB_CASE.md) | Enforce kebab-case filenames for .ts and .js files | ❌ |
143
+ | [jsx-pascal-case](docs/rules/JSX_PASCAL_CASE.md) | Enforce PascalCase filenames for .jsx and .tsx files | ❌ |
144
+ | [md-filename-case-restriction](docs/rules/MD_FILENAME_CASE_RESTRICTION.md) | Enforce SNAKE_CASE filenames for .md files | ❌ |
158
145
 
159
- ### React Configurations
146
+ ### Code Style Rules
160
147
 
161
- #### `react`
148
+ | Rule | Description | Fixable |
149
+ | -------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------- |
150
+ | [no-emoji](docs/rules/NO_EMOJI.md) | Disallow emoji characters in source code | ❌ |
151
+ | [prefer-destructuring-params](docs/rules/PREFER_DESTRUCTURING_PARAMS.md) | Enforce destructuring for functions with multiple parameters | ❌ |
152
+ | [prefer-function-declaration](docs/rules/PREFER_FUNCTION_DECLARATION.md) | Enforce function declarations over arrow functions in .ts files | ❌ |
153
+ | [require-explicit-return-type](docs/rules/REQUIRE_EXPLICIT_RETURN_TYPE.md) | Require explicit return types on functions for better documentation | ❌ |
154
+ | [no-complex-inline-return](docs/rules/NO_COMPLEX_INLINE_RETURN.md) | Disallow complex inline expressions in return - extract to const first | ❌ |
155
+ | [no-logic-in-params](docs/rules/NO_LOGIC_IN_PARAMS.md) | Disallow logic/conditions in function parameters - extract to const | ❌ |
156
+ | [enforce-sorted-destructuring](docs/rules/ENFORCE_SORTED_DESTRUCTURING.md) | Enforce alphabetical sorting of destructured properties | ❌ |
157
+ | [no-env-fallback](docs/rules/NO_ENV_FALLBACK.md) | Disallow fallback values for environment variables | ❌ |
158
+ | [no-direct-date](docs/rules/NO_DIRECT_DATE.md) | Disallow direct usage of Date constructor and methods | ❌ |
162
159
 
163
- Includes all base rules plus React-specific rules:
160
+ ### Import Optimization Rules
164
161
 
165
- - All base rules above
166
- - `nextfriday/jsx-pascal-case`: `"error"`
167
- - `nextfriday/prefer-interface-over-inline-types`: `"error"`
168
- - `nextfriday/react-props-destructure`: `"error"`
169
- - `nextfriday/enforce-readonly-component-props`: `"error"`
162
+ | Rule | Description | Fixable |
163
+ | -------------------------------------------------------------------- | ------------------------------------------------------ | ------- |
164
+ | [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md) | Enforce using 'import type' for type-only imports | ✅ |
165
+ | [prefer-react-import-types](docs/rules/PREFER_REACT_IMPORT_TYPES.md) | Enforce direct imports from 'react' instead of React.X | ✅ |
170
166
 
171
- #### `react/recommended`
167
+ ### Type Pattern Rules
172
168
 
173
- Same as `react` configuration (recommended preset for React projects).
169
+ | Rule | Description | Fixable |
170
+ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- |
171
+ | [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
172
+ | [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
174
173
 
175
- ### Next.js Configurations
174
+ ### React/JSX Rules
176
175
 
177
- #### `nextjs`
176
+ | Rule | Description | Fixable |
177
+ | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------- | ------- |
178
+ | [jsx-no-non-component-function](docs/rules/JSX_NO_NON_COMPONENT_FUNCTION.md) | Disallow non-component functions at top level in .tsx/.jsx files | ❌ |
179
+ | [jsx-no-variable-in-callback](docs/rules/JSX_NO_VARIABLE_IN_CALLBACK.md) | Disallow variable declarations inside callback functions in JSX | ❌ |
180
+ | [prefer-jsx-template-literals](docs/rules/PREFER_JSX_TEMPLATE_LITERALS.md) | Enforce template literals instead of mixing text and JSX expressions | ✅ |
181
+ | [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | ❌ |
182
+ | [enforce-readonly-component-props](docs/rules/ENFORCE_READONLY_COMPONENT_PROPS.md) | Enforce Readonly wrapper for React component props | ✅ |
178
183
 
179
- Includes all rules suitable for Next.js projects:
180
-
181
- - All base rules
182
- - `nextfriday/jsx-pascal-case`: `"error"`
183
- - `nextfriday/prefer-interface-over-inline-types`: `"error"`
184
- - `nextfriday/react-props-destructure`: `"error"`
185
- - `nextfriday/enforce-readonly-component-props`: `"error"`
186
-
187
- #### `nextjs/recommended`
184
+ ## Configurations
188
185
 
189
- Same as `nextjs` configuration (recommended preset for Next.js projects).
186
+ ### Configuration Presets Overview
187
+
188
+ | Preset | Severity | Base Rules | JSX Rules | Total Rules |
189
+ | -------------------- | -------- | ---------- | --------- | ----------- |
190
+ | `base` | warn | 16 | 0 | 16 |
191
+ | `base/recommended` | error | 16 | 0 | 16 |
192
+ | `react` | warn | 16 | 7 | 23 |
193
+ | `react/recommended` | error | 16 | 7 | 23 |
194
+ | `nextjs` | warn | 16 | 7 | 23 |
195
+ | `nextjs/recommended` | error | 16 | 7 | 23 |
196
+
197
+ ### Base Configuration Rules (16 rules)
198
+
199
+ Included in `base`, `base/recommended`, and all other presets:
200
+
201
+ - `nextfriday/boolean-naming-prefix`
202
+ - `nextfriday/enforce-sorted-destructuring`
203
+ - `nextfriday/file-kebab-case`
204
+ - `nextfriday/md-filename-case-restriction`
205
+ - `nextfriday/no-complex-inline-return`
206
+ - `nextfriday/no-direct-date`
207
+ - `nextfriday/no-emoji`
208
+ - `nextfriday/no-env-fallback`
209
+ - `nextfriday/require-explicit-return-type`
210
+ - `nextfriday/no-logic-in-params`
211
+ - `nextfriday/no-single-char-variables`
212
+ - `nextfriday/prefer-destructuring-params`
213
+ - `nextfriday/prefer-function-declaration`
214
+ - `nextfriday/prefer-import-type`
215
+ - `nextfriday/prefer-named-param-types`
216
+ - `nextfriday/prefer-react-import-types`
217
+
218
+ ### JSX Rules (7 rules)
219
+
220
+ Additionally included in `react`, `react/recommended`, `nextjs`, `nextjs/recommended`:
221
+
222
+ - `nextfriday/enforce-readonly-component-props`
223
+ - `nextfriday/jsx-no-non-component-function`
224
+ - `nextfriday/jsx-no-variable-in-callback`
225
+ - `nextfriday/jsx-pascal-case`
226
+ - `nextfriday/prefer-interface-over-inline-types`
227
+ - `nextfriday/prefer-jsx-template-literals`
228
+ - `nextfriday/react-props-destructure`
229
+
230
+ ### Severity Levels
231
+
232
+ - **`base` / `react` / `nextjs`**: All rules set to `"warn"`
233
+ - **`base/recommended` / `react/recommended` / `nextjs/recommended`**: All rules set to `"error"`
190
234
 
191
235
  ## Features
192
236
 
193
- - **File naming enforcement**: Ensure consistent file naming conventions across your project
237
+ - **Variable naming enforcement**: Prevent cryptic single-character names and enforce boolean prefixes
238
+ - **File naming enforcement**: Ensure consistent file naming conventions (kebab-case, PascalCase, SNAKE_CASE)
239
+ - **Function style**: Enforce function declarations over arrow functions in utility files
194
240
  - **Import optimization**: Automatically suggests better import patterns for TypeScript
195
241
  - **Code cleanup**: Helps remove unnecessary explicit type annotations
196
- - **React component conventions**: Enforces naming standards for JSX/TSX files
197
- - **Clean code practices**: Prevents emoji usage and enforces parameter destructuring
242
+ - **React component conventions**: Enforces naming standards and patterns for JSX/TSX files
243
+ - **Clean code practices**: Prevents emoji usage, enforces parameter destructuring, and more
198
244
 
199
245
  ## Need Help?
200
246
 
@@ -0,0 +1,102 @@
1
+ # boolean-naming-prefix
2
+
3
+ Enforce boolean variables and parameters to have a prefix like is, has, should, can, did, will for better readability.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces that boolean variables and parameters use a descriptive prefix that makes them read like English sentences. Variables like `open`, `valid`, `user` are ambiguous - it's unclear whether they represent a value or a state. Boolean prefixes make the intent clear.
8
+
9
+ **Recommended prefixes:** `is`, `has`, `should`, `can`, `did`, `will`, `was`, `are`, `does`, `had`
10
+
11
+ **Incorrect** code for this rule:
12
+
13
+ ```typescript
14
+ const valid = true;
15
+ const user = false;
16
+ const open = true;
17
+ const closed = false;
18
+ const active: boolean = true;
19
+ const enabled: boolean = checkEnabled();
20
+
21
+ const equal = a === b;
22
+ const different = a !== b;
23
+ const bigger = a > b;
24
+ const negated = !value;
25
+ const combined = a && b;
26
+ const either = a || b;
27
+
28
+ function process(active: boolean) {}
29
+ const fn = (enabled: boolean) => {};
30
+ function toggle(active = true) {}
31
+ ```
32
+
33
+ **Correct** code for this rule:
34
+
35
+ ```typescript
36
+ const isValid = true;
37
+ const hasUser = false;
38
+ const isOpen = true;
39
+ const isClosed = false;
40
+ const isActive: boolean = true;
41
+ const isEnabled: boolean = checkEnabled();
42
+
43
+ const isEqual = a === b;
44
+ const isDifferent = a !== b;
45
+ const isBigger = a > b;
46
+ const isNegated = !value;
47
+ const areCombined = a && b;
48
+ const hasEither = a || b;
49
+
50
+ function process(isActive: boolean) {}
51
+ const fn = (hasAccess: boolean) => {};
52
+ function toggle(isActive = true) {}
53
+ ```
54
+
55
+ ## What This Rule Detects
56
+
57
+ The rule identifies boolean variables and parameters by:
58
+
59
+ 1. **Boolean type annotations**: Variables explicitly typed as `boolean`
60
+ 2. **Boolean literals**: Variables initialized with `true` or `false`
61
+ 3. **Comparison expressions**: `===`, `!==`, `==`, `!=`, `<`, `>`, `<=`, `>=`, `in`, `instanceof`
62
+ 4. **Logical expressions**: `&&`, `||`
63
+ 5. **Negation**: `!value`
64
+ 6. **Function parameters**: With boolean type annotation or default boolean value
65
+
66
+ ## Allowed Prefixes
67
+
68
+ | Prefix | Usage | Example |
69
+ | -------- | ----------------------------- | --------------------------------------------- |
70
+ | `is` | State or condition | `isActive`, `isValid`, `isLoading` |
71
+ | `has` | Possession or existence | `hasUser`, `hasPermission`, `hasError` |
72
+ | `can` | Ability or permission | `canSubmit`, `canEdit`, `canDelete` |
73
+ | `should` | Recommendation or expectation | `shouldRender`, `shouldUpdate`, `shouldFetch` |
74
+ | `will` | Future action | `willUpdate`, `willRedirect`, `willExpire` |
75
+ | `did` | Past action | `didLoad`, `didSubmit`, `didFail` |
76
+ | `was` | Past state | `wasActive`, `wasVisible`, `wasProcessed` |
77
+ | `are` | Plural state | `areEqual`, `areValid`, `areLoaded` |
78
+ | `does` | Action capability | `doesExist`, `doesMatch`, `doesContain` |
79
+ | `had` | Past possession | `hadError`, `hadAccess`, `hadPrevious` |
80
+
81
+ ## Benefits
82
+
83
+ - **Self-documenting code**: Boolean intent is immediately clear
84
+ - **Reads like English**: `if (isActive)` reads as "if is active"
85
+ - **Reduced ambiguity**: `user = false` vs `hasUser = false` - the latter is clear
86
+ - **Consistent codebase**: Enforces uniform boolean naming across the project
87
+ - **Better code review**: Reviewers can quickly understand boolean logic
88
+
89
+ ## When Not To Use
90
+
91
+ - When working with external APIs that return boolean fields with different naming conventions
92
+ - In mathematical or scientific code where single-letter variables are conventional
93
+ - When interfacing with legacy code that would require extensive refactoring
94
+
95
+ ## Configuration
96
+
97
+ This rule has no configuration options.
98
+
99
+ ## Related Rules
100
+
101
+ - [no-single-char-variables](./NO_SINGLE_CHAR_VARIABLES.md) - Disallows single character variable names
102
+ - [@typescript-eslint/naming-convention](https://typescript-eslint.io/rules/naming-convention/) - More comprehensive naming convention rule
@@ -0,0 +1,36 @@
1
+ # no-direct-date
2
+
3
+ Disallow direct usage of Date constructor and methods to enforce centralized date utilities.
4
+
5
+ ## Rule Details
6
+
7
+ This rule prevents the use of the native JavaScript `Date` constructor and its static methods (`Date.now()`, `Date.parse()`). Using a centralized date utility library like dayjs, date-fns, or Luxon provides better consistency, easier testing, and more predictable date handling across your application.
8
+
9
+ ## Examples
10
+
11
+ **Incorrect** code for this rule:
12
+
13
+ ```js
14
+ const now = new Date();
15
+ const timestamp = Date.now();
16
+ const parsed = Date.parse("2024-01-01");
17
+ const specificDate = new Date("2024-01-01");
18
+ const dateFromTimestamp = new Date(1704067200000);
19
+ const dateFromParts = new Date(2024, 0, 1);
20
+ ```
21
+
22
+ **Correct** code for this rule:
23
+
24
+ ```js
25
+ import dayjs from "dayjs";
26
+
27
+ const now = dayjs();
28
+ const timestamp = dayjs().valueOf();
29
+ const parsed = dayjs("2024-01-01");
30
+ const specificDate = dayjs("2024-01-01");
31
+ const dateFromTimestamp = dayjs(1704067200000);
32
+ ```
33
+
34
+ ## When Not To Use It
35
+
36
+ If your project does not use a centralized date utility library and you prefer to work directly with the native JavaScript Date API, you can disable this rule.
@@ -0,0 +1,108 @@
1
+ # no-single-char-variables
2
+
3
+ Disallow single character variable and parameter names for better code readability.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces descriptive variable and parameter names by disallowing single character identifiers. Single character names like `d`, `u`, `l`, `r` are cryptic and make code harder to understand. They require readers to guess or track what each variable represents.
8
+
9
+ **Incorrect** code for this rule:
10
+
11
+ ```typescript
12
+ const d = new Date();
13
+ const u = await getUser();
14
+ const l = list.length;
15
+ const r = await fetch(url);
16
+
17
+ users.map((u) => u.id);
18
+ onClick((e) => e.preventDefault());
19
+
20
+ const add = (a, b) => a + b;
21
+ const e = (x) => x * 2;
22
+
23
+ function f() {
24
+ return 1;
25
+ }
26
+
27
+ const { a } = obj;
28
+ const [x] = array;
29
+
30
+ try {
31
+ } catch (e) {}
32
+ ```
33
+
34
+ **Correct** code for this rule:
35
+
36
+ ```typescript
37
+ const currentDate = new Date();
38
+ const currentUser = await getUser();
39
+ const itemCount = list.length;
40
+ const response = await fetch(url);
41
+
42
+ users.map((user) => user.id);
43
+ onClick((event) => event.preventDefault());
44
+
45
+ const add = (val1, val2) => val1 + val2;
46
+ const add = (width, height) => width * height;
47
+ const calculateDouble = (value) => value * 2;
48
+
49
+ function getName() {
50
+ return "test";
51
+ }
52
+
53
+ const { alpha } = obj;
54
+ const { a: alpha } = obj;
55
+ const [first] = array;
56
+
57
+ try {
58
+ } catch (error) {}
59
+ ```
60
+
61
+ ## Exceptions
62
+
63
+ The rule allows the following exceptions:
64
+
65
+ ### Loop Counters
66
+
67
+ Single character loop counters `i`, `j`, `k`, `n` are allowed in traditional for loops:
68
+
69
+ ```typescript
70
+ for (let i = 0; i < 10; i++) {}
71
+ for (let j = 0; j < items.length; j++) {}
72
+ for (let i = 0, j = 10; i < j; i++, j--) {}
73
+ ```
74
+
75
+ Note: These are only allowed in traditional `for` loops, not in `for...of` or `for...in` loops.
76
+
77
+ ### Underscore for Unused Variables
78
+
79
+ A single underscore `_` is allowed to indicate intentionally unused variables:
80
+
81
+ ```typescript
82
+ const _ = unusedValue;
83
+ const [_, second] = array;
84
+ array.map((_, index) => index);
85
+ ```
86
+
87
+ ## Benefits
88
+
89
+ - **Self-documenting code**: Descriptive names make code readable without additional comments
90
+ - **Reduced cognitive load**: No need to track or guess what single letters represent
91
+ - **Better IDE support**: Meaningful names provide better autocomplete and search results
92
+ - **Easier debugging**: Clear variable names make debugging and code review faster
93
+ - **Improved collaboration**: Team members can understand code without additional context
94
+
95
+ ## When Not To Use
96
+
97
+ - For very short scripts or throwaway code
98
+ - When working with mathematical formulas where single letters are conventional (e.g., `x`, `y` for coordinates)
99
+ - In legacy codebases where this pattern is established and changing would be disruptive
100
+
101
+ ## Configuration
102
+
103
+ This rule has no configuration options.
104
+
105
+ ## Related Rules
106
+
107
+ - [prefer-destructuring-params](./PREFER_DESTRUCTURING_PARAMS.md) - Encourages destructuring for function parameters
108
+ - [prefer-named-param-types](./PREFER_NAMED_PARAM_TYPES.md) - Encourages named parameters for better readability
@@ -0,0 +1,139 @@
1
+ # prefer-function-declaration
2
+
3
+ Enforce function declarations over arrow functions assigned to variables in `.ts` files for better readability and hoisting.
4
+
5
+ ## Rule Details
6
+
7
+ This rule requires using function declarations instead of arrow functions or function expressions when defining named functions in TypeScript utility files. Arrow functions used as callbacks (in `.map()`, `.filter()`, etc.) are still allowed.
8
+
9
+ **Target:** `.ts` files only (not `.tsx`, `.js`, or `.d.ts`)
10
+
11
+ **Incorrect** code for this rule:
12
+
13
+ ```typescript
14
+ // utils/date.ts
15
+ const formatThaiDate = (date: Date) => {
16
+ return date.toLocaleDateString("th-TH");
17
+ };
18
+
19
+ const formatDate = (date: Date) => date.toISOString();
20
+
21
+ export const add = (a: number, b: number) => a + b;
22
+
23
+ const greet = function (name: string) {
24
+ return `Hello ${name}`;
25
+ };
26
+
27
+ const fetchUser = async (id: string) => {
28
+ return await api.get(`/users/${id}`);
29
+ };
30
+ ```
31
+
32
+ **Correct** code for this rule:
33
+
34
+ ```typescript
35
+ // utils/date.ts
36
+ function formatThaiDate(date: Date) {
37
+ return date.toLocaleDateString("th-TH");
38
+ }
39
+
40
+ function formatDate(date: Date) {
41
+ return date.toISOString();
42
+ }
43
+
44
+ export function add(a: number, b: number) {
45
+ return a + b;
46
+ }
47
+
48
+ function greet(name: string) {
49
+ return `Hello ${name}`;
50
+ }
51
+
52
+ async function fetchUser(id: string) {
53
+ return await api.get(`/users/${id}`);
54
+ }
55
+ ```
56
+
57
+ ## What This Rule Allows
58
+
59
+ Arrow functions are still allowed in the following contexts:
60
+
61
+ ### Callbacks
62
+
63
+ ```typescript
64
+ // All of these are allowed
65
+ const years = dates.map((date) => date.getFullYear());
66
+ const active = items.filter((item) => item.active);
67
+ const sorted = items.sort((a, b) => a.name.localeCompare(b.name));
68
+ items.forEach((item) => console.log(item));
69
+ const total = items.reduce((sum, item) => sum + item.price, 0);
70
+ setTimeout(() => console.log("done"), 1000);
71
+ promise.then((result) => result.data);
72
+ ```
73
+
74
+ ### Object Properties
75
+
76
+ ```typescript
77
+ const handler = {
78
+ onClick: () => console.log("clicked"),
79
+ onHover: () => setHovered(true),
80
+ };
81
+ ```
82
+
83
+ ### Array Elements
84
+
85
+ ```typescript
86
+ const callbacks = [() => 1, () => 2, () => 3];
87
+ ```
88
+
89
+ ### Return Values
90
+
91
+ ```typescript
92
+ function createHandler() {
93
+ return () => console.log("handled");
94
+ }
95
+ ```
96
+
97
+ ### Conditional/Logical Expressions
98
+
99
+ ```typescript
100
+ const fn = condition ? () => valueA : () => valueB;
101
+ const handler = defaultFn || (() => fallback);
102
+ ```
103
+
104
+ ### TSX Files
105
+
106
+ ```typescript
107
+ // components/Button.tsx - Arrow functions allowed
108
+ const Button = () => <button>Click me</button>;
109
+ const handleClick = () => console.log("clicked");
110
+ ```
111
+
112
+ ## Benefits
113
+
114
+ - **Hoisting**: Function declarations are hoisted, allowing you to call functions before they're defined
115
+ - **Better readability**: Function declarations are more explicit about intent
116
+ - **Clearer stack traces**: Named function declarations provide better debugging information
117
+ - **Consistent style**: Enforces uniform function definition patterns in utility files
118
+ - **Self-documenting**: `function formatDate()` is clearer than `const formatDate = () =>`
119
+
120
+ ## Why Only `.ts` Files?
121
+
122
+ - **`.tsx` files**: Arrow functions are commonly used for React components and event handlers
123
+ - **`.js` files**: JavaScript projects may have different conventions
124
+ - **`.d.ts` files**: Declaration files don't contain implementations
125
+
126
+ ## When Not To Use
127
+
128
+ - When you prefer arrow functions for all function definitions
129
+ - In projects where arrow function style is established
130
+ - When you need lexical `this` binding (arrow functions don't have their own `this`)
131
+
132
+ ## Configuration
133
+
134
+ This rule has no configuration options.
135
+
136
+ ## Related Rules
137
+
138
+ - [func-style](https://eslint.org/docs/rules/func-style) - Built-in ESLint rule for function style
139
+ - [arrow-body-style](https://eslint.org/docs/rules/arrow-body-style) - Enforce arrow function body style