eslint-plugin-nextfriday 1.2.3 → 1.4.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,17 @@
1
1
  # eslint-plugin-nextfriday
2
2
 
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#26](https://github.com/next-friday/eslint-plugin-nextfriday/pull/26) [`e90935a`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/e90935a56129ff84efc9df5de3f43e8e4a61af16) Thanks [@nextfridaydeveloper](https://github.com/nextfridaydeveloper)! - Add two new rules to improve code readability and debugging: `no-complex-inline-return` disallows complex inline expressions (such as ternary operators, logical expressions, or `new` expressions) directly in return statements, requiring extraction to a `const` variable instead; and `no-logic-in-params` prohibits using logic or conditions (e.g., ternary, logical, comparison, or negation operators) within function parameters, enforcing the use of intermediate `const` variables to enhance clarity and allow inspection of values.
8
+
9
+ ## 1.3.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#24](https://github.com/next-friday/eslint-plugin-nextfriday/pull/24) [`59d1932`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/59d193258d6ffd19d6fd90515626d826732e30b3) Thanks [@nextfridaydeveloper](https://github.com/nextfridaydeveloper)! - Add new prefer-named-param-types rule that enforces using named interfaces or type aliases instead of inline object type literals for function
14
+
3
15
  ## 1.2.3
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -65,7 +65,10 @@ export default [
65
65
  "nextfriday/prefer-destructuring-params": "error",
66
66
  "nextfriday/no-explicit-return-type": "error",
67
67
  "nextfriday/prefer-import-type": "error",
68
+ "nextfriday/prefer-named-param-types": "error",
68
69
  "nextfriday/prefer-react-import-types": "error",
70
+ "nextfriday/no-complex-inline-return": "error",
71
+ "nextfriday/no-logic-in-params": "error",
69
72
  "nextfriday/jsx-pascal-case": "error",
70
73
  "nextfriday/prefer-interface-over-inline-types": "error",
71
74
  "nextfriday/react-props-destructure": "error",
@@ -106,19 +109,22 @@ module.exports = {
106
109
 
107
110
  ## Rules
108
111
 
109
- | Rule | Description | Fixable |
110
- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- |
111
- | [no-emoji](docs/rules/NO_EMOJI.md) | Disallow emojis in code | ❌ |
112
- | [file-kebab-case](docs/rules/FILE_KEBAB_CASE.md) | Enforce kebab-case filenames for .ts and .js files | ❌ |
113
- | [jsx-pascal-case](docs/rules/JSX_PASCAL_CASE.md) | Enforce PascalCase filenames for .jsx and .tsx files | ❌ |
114
- | [md-filename-case-restriction](docs/rules/MD_FILENAME_CASE_RESTRICTION.md) | Enforce SNAKE_CASE filenames for .md files | ❌ |
115
- | [prefer-destructuring-params](docs/rules/PREFER_DESTRUCTURING_PARAMS.md) | Enforce destructuring for functions with multiple parameters | ❌ |
116
- | [no-explicit-return-type](docs/rules/NO_EXPLICIT_RETURN_TYPE.md) | Disallow explicit return types on functions | ✅ |
117
- | [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md) | Enforce using 'import type' for type-only imports | ✅ |
118
- | [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | ❌ |
119
- | [prefer-react-import-types](docs/rules/PREFER_REACT_IMPORT_TYPES.md) | Enforce direct imports from 'react' instead of React.X | |
120
- | [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | |
121
- | [enforce-readonly-component-props](docs/rules/ENFORCE_READONLY_COMPONENT_PROPS.md) | Enforce Readonly wrapper for React component props | |
112
+ | Rule | Description | Fixable |
113
+ | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------- |
114
+ | [no-emoji](docs/rules/NO_EMOJI.md) | Disallow emojis in code | ❌ |
115
+ | [file-kebab-case](docs/rules/FILE_KEBAB_CASE.md) | Enforce kebab-case filenames for .ts and .js files | ❌ |
116
+ | [jsx-pascal-case](docs/rules/JSX_PASCAL_CASE.md) | Enforce PascalCase filenames for .jsx and .tsx files | ❌ |
117
+ | [md-filename-case-restriction](docs/rules/MD_FILENAME_CASE_RESTRICTION.md) | Enforce SNAKE_CASE filenames for .md files | ❌ |
118
+ | [prefer-destructuring-params](docs/rules/PREFER_DESTRUCTURING_PARAMS.md) | Enforce destructuring for functions with multiple parameters | ❌ |
119
+ | [no-explicit-return-type](docs/rules/NO_EXPLICIT_RETURN_TYPE.md) | Disallow explicit return types on functions | ✅ |
120
+ | [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md) | Enforce using 'import type' for type-only imports | ✅ |
121
+ | [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
122
+ | [prefer-interface-over-inline-types](docs/rules/PREFER_INTERFACE_OVER_INLINE_TYPES.md) | Enforce interface declarations over inline types for React props | |
123
+ | [prefer-react-import-types](docs/rules/PREFER_REACT_IMPORT_TYPES.md) | Enforce direct imports from 'react' instead of React.X | |
124
+ | [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | |
125
+ | [enforce-readonly-component-props](docs/rules/ENFORCE_READONLY_COMPONENT_PROPS.md) | Enforce Readonly wrapper for React component props | ✅ |
126
+ | [no-complex-inline-return](docs/rules/NO_COMPLEX_INLINE_RETURN.md) | Disallow complex inline expressions in return statements - prefer const first | ❌ |
127
+ | [no-logic-in-params](docs/rules/NO_LOGIC_IN_PARAMS.md) | Disallow logic or conditions in function parameters - extract to const first | ❌ |
122
128
 
123
129
  ## Configurations
124
130
 
@@ -134,7 +140,10 @@ Basic configuration without JSX-specific rules:
134
140
  - `nextfriday/prefer-destructuring-params`: `"error"`
135
141
  - `nextfriday/no-explicit-return-type`: `"error"`
136
142
  - `nextfriday/prefer-import-type`: `"error"`
143
+ - `nextfriday/prefer-named-param-types`: `"error"`
137
144
  - `nextfriday/prefer-react-import-types`: `"error"`
145
+ - `nextfriday/no-complex-inline-return`: `"error"`
146
+ - `nextfriday/no-logic-in-params`: `"error"`
138
147
 
139
148
  #### `base/recommended`
140
149
 
@@ -0,0 +1,136 @@
1
+ # no-complex-inline-return
2
+
3
+ Disallow complex inline expressions in return statements - prefer extracting to a const first.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces a pattern where complex expressions (ternary operators, logical expressions, new expressions) are extracted to a const variable before being returned. This improves code readability and makes debugging easier by allowing you to inspect intermediate values.
8
+
9
+ **Incorrect** code for this rule:
10
+
11
+ ```typescript
12
+ function waitForLoad(targetWindow: Window) {
13
+ return targetWindow.document.readyState === "complete"
14
+ ? Promise.resolve()
15
+ : new Promise<void>((resolve) => {
16
+ targetWindow.addEventListener(
17
+ "load",
18
+ () => {
19
+ resolve();
20
+ },
21
+ {
22
+ once: true,
23
+ },
24
+ );
25
+ });
26
+ }
27
+
28
+ function getValue(condition: boolean) {
29
+ return condition ? "yes" : "no";
30
+ }
31
+
32
+ function getUser(user: User | null) {
33
+ return user || defaultUser;
34
+ }
35
+
36
+ function createInstance() {
37
+ return new MyClass();
38
+ }
39
+
40
+ function checkStatus(a: boolean, b: boolean) {
41
+ return a && b;
42
+ }
43
+ ```
44
+
45
+ **Correct** code for this rule:
46
+
47
+ ```typescript
48
+ function waitForLoad(targetWindow: Window) {
49
+ const loadPromise =
50
+ targetWindow.document.readyState === "complete"
51
+ ? Promise.resolve()
52
+ : new Promise<void>((resolve) => {
53
+ targetWindow.addEventListener(
54
+ "load",
55
+ () => {
56
+ resolve();
57
+ },
58
+ {
59
+ once: true,
60
+ },
61
+ );
62
+ });
63
+
64
+ return loadPromise;
65
+ }
66
+
67
+ function getValue(condition: boolean) {
68
+ const value = condition ? "yes" : "no";
69
+ return value;
70
+ }
71
+
72
+ function getUser(user: User | null) {
73
+ const activeUser = user || defaultUser;
74
+ return activeUser;
75
+ }
76
+
77
+ function createInstance() {
78
+ const instance = new MyClass();
79
+ return instance;
80
+ }
81
+
82
+ function checkStatus(a: boolean, b: boolean) {
83
+ const isValid = a && b;
84
+ return isValid;
85
+ }
86
+
87
+ // Simple returns are still allowed
88
+ function getName() {
89
+ return "John Doe";
90
+ }
91
+
92
+ function getAge() {
93
+ return 42;
94
+ }
95
+
96
+ function callFunction() {
97
+ return someFunction();
98
+ }
99
+
100
+ function getMath() {
101
+ return a + b;
102
+ }
103
+ ```
104
+
105
+ ## Benefits
106
+
107
+ - **Better readability**: Complex logic is separated from the return statement
108
+ - **Easier debugging**: Intermediate values can be inspected in debuggers
109
+ - **Self-documenting**: Variable names can describe what the complex expression represents
110
+ - **Consistent style**: Enforces a uniform approach to handling complex return values
111
+
112
+ ## When Not To Use
113
+
114
+ - For very simple projects where inline expressions are preferred
115
+ - When you prefer a more compact coding style
116
+ - In cases where the expression is trivial and doesn't benefit from extraction
117
+
118
+ ## What This Rule Checks
119
+
120
+ This rule flags the following patterns when used directly in return statements:
121
+
122
+ - **Ternary expressions** (conditional operators): `condition ? value1 : value2`
123
+ - **Logical expressions**: `a && b`, `a || b`, `a ?? b`
124
+ - **New expressions**: `new MyClass()`
125
+
126
+ The following are allowed in return statements:
127
+
128
+ - Simple values (literals, variables)
129
+ - Function calls
130
+ - Binary expressions (math operations like `a + b`)
131
+ - Object/array literals
132
+ - Member expressions (`obj.prop`)
133
+
134
+ ## Related Rules
135
+
136
+ - No related rules
@@ -0,0 +1,122 @@
1
+ # no-logic-in-params
2
+
3
+ Disallow logic or conditions in function parameters - extract to a const variable first.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces a pattern where complex expressions (logical operators, ternary operators, comparison operators) are extracted to a const variable before being passed as function arguments. This improves code readability, makes debugging easier, and helps maintain cleaner function calls.
8
+
9
+ **Incorrect** code for this rule:
10
+
11
+ ```typescript
12
+ // Nullish coalescing
13
+ functionFoo(bar ?? baz);
14
+
15
+ // Ternary operator
16
+ handleUser(isActive ? activeUser : inactiveUser);
17
+
18
+ // Logical AND
19
+ processData(hasPermission && isValid);
20
+
21
+ // Logical OR
22
+ setConfig(customConfig || defaultConfig);
23
+
24
+ // Comparison operators
25
+ validateInput(value > 100);
26
+ checkEquality(a === b);
27
+
28
+ // Negation
29
+ toggleFeature(!isEnabled);
30
+
31
+ // Multiple parameters with logic
32
+ createUser(username, age >= 18, status === "active");
33
+
34
+ // New expression with logic
35
+ new MyClass(a || b);
36
+ ```
37
+
38
+ **Correct** code for this rule:
39
+
40
+ ```typescript
41
+ // Extract logic to a variable first
42
+ const value = bar ?? baz;
43
+ functionFoo(value);
44
+
45
+ const user = isActive ? activeUser : inactiveUser;
46
+ handleUser(user);
47
+
48
+ const canProcess = hasPermission && isValid;
49
+ processData(canProcess);
50
+
51
+ const config = customConfig || defaultConfig;
52
+ setConfig(config);
53
+
54
+ const isValid = value > 100;
55
+ validateInput(isValid);
56
+
57
+ const areEqual = a === b;
58
+ checkEquality(areEqual);
59
+
60
+ const shouldDisable = !isEnabled;
61
+ toggleFeature(shouldDisable);
62
+
63
+ const isAdult = age >= 18;
64
+ const isActive = status === "active";
65
+ createUser(username, isAdult, isActive);
66
+
67
+ const param = a || b;
68
+ new MyClass(param);
69
+
70
+ // Simple values are still allowed
71
+ functionFoo(bar);
72
+ functionFoo(42);
73
+ functionFoo("string");
74
+ functionFoo(obj.property);
75
+ functionFoo(getValue());
76
+
77
+ // Arithmetic operations are allowed
78
+ calculate(a + b);
79
+ multiply(x * y);
80
+
81
+ // Object/array literals are allowed
82
+ configure({ key: "value" });
83
+ process([1, 2, 3]);
84
+ ```
85
+
86
+ ## Benefits
87
+
88
+ - **Better readability**: Logic is separated from function calls, making code easier to scan
89
+ - **Easier debugging**: Intermediate values can be inspected in debuggers before being passed to functions
90
+ - **Self-documenting**: Variable names describe what the complex expression represents
91
+ - **Consistent style**: Enforces a uniform approach to handling complex function arguments
92
+ - **Reduced cognitive load**: Readers don't need to mentally evaluate expressions while also understanding function calls
93
+
94
+ ## When Not To Use
95
+
96
+ - For very simple projects where inline expressions are preferred
97
+ - When you prefer a more compact coding style
98
+ - In cases where the expression is trivial and doesn't benefit from extraction
99
+
100
+ ## What This Rule Checks
101
+
102
+ This rule flags the following patterns when used as function arguments:
103
+
104
+ - **Ternary expressions** (conditional operators): `condition ? value1 : value2`
105
+ - **Logical expressions**: `a && b`, `a || b`, `a ?? b`
106
+ - **Comparison operators**: `===`, `!==`, `==`, `!=`, `>`, `<`, `>=`, `<=`
107
+ - **Type checking operators**: `in`, `instanceof`
108
+ - **Negation operator**: `!value`
109
+
110
+ The following are allowed as function arguments:
111
+
112
+ - Simple values (literals, variables)
113
+ - Function calls
114
+ - Member expressions (`obj.prop`)
115
+ - Arithmetic operations (`a + b`, `a * b`, etc.)
116
+ - Object/array literals
117
+ - Template literals
118
+ - Spread operators (`...args`)
119
+
120
+ ## Related Rules
121
+
122
+ - [no-complex-inline-return](./NO_COMPLEX_INLINE_RETURN.md) - Similar rule but for return statements
@@ -0,0 +1,172 @@
1
+ # prefer-named-param-types
2
+
3
+ Enforce named interfaces or types instead of inline object types for function parameters.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces extracting inline object type annotations for function parameters into named interfaces or type aliases. This promotes better code organization, reusability, and readability across your codebase.
8
+
9
+ Examples of **incorrect** code for this rule:
10
+
11
+ ```typescript
12
+ // Destructured parameter with inline type
13
+ const foo = ({ bar, baz }: { bar: string; baz: number }) => {
14
+ console.log(bar, baz);
15
+ };
16
+
17
+ // Regular parameter with inline type
18
+ const foo = (params: { bar: string; baz: number }) => {
19
+ const { bar, baz } = params;
20
+ console.log(bar, baz);
21
+ };
22
+
23
+ // Function declaration
24
+ function createUser(data: { name: string; email: string; role: "admin" | "user" }) {
25
+ return { ...data, createdAt: Date.now() };
26
+ }
27
+
28
+ // Function expression
29
+ const handler = function (data: { id: number; name: string }) {
30
+ return data.id;
31
+ };
32
+
33
+ // Multiple parameters with inline types
34
+ const foo = (first: { a: string; b: number }, second: { x: boolean; y: string }) => {
35
+ return { first, second };
36
+ };
37
+ ```
38
+
39
+ Examples of **correct** code for this rule:
40
+
41
+ ```typescript
42
+ // Using interface
43
+ interface Params {
44
+ bar: string;
45
+ baz: number;
46
+ }
47
+
48
+ const foo = (params: Params) => {
49
+ const { bar, baz } = params;
50
+ console.log(bar, baz);
51
+ };
52
+
53
+ // Using type alias
54
+ type UserData = {
55
+ name: string;
56
+ email: string;
57
+ role: "admin" | "user";
58
+ };
59
+
60
+ const createUser = (data: UserData) => {
61
+ return { ...data, createdAt: Date.now() };
62
+ };
63
+
64
+ // Primitive types are allowed
65
+ const foo = (value: string) => {
66
+ return value;
67
+ };
68
+
69
+ const bar = (count: number, enabled: boolean) => {
70
+ return count > 0 && enabled;
71
+ };
72
+
73
+ // Functions with no parameters
74
+ const baz = () => {
75
+ return "no params";
76
+ };
77
+
78
+ // Named types with destructuring
79
+ interface Config {
80
+ theme: string;
81
+ locale: string;
82
+ }
83
+
84
+ const setup = (config: Config) => {
85
+ const { theme, locale } = config;
86
+ console.log(theme, locale);
87
+ };
88
+ ```
89
+
90
+ ## Why?
91
+
92
+ ### Benefits of named parameter types:
93
+
94
+ 1. **Reusability**: Named types can be reused across multiple functions
95
+ 2. **Better organization**: Separates type definitions from function logic
96
+ 3. **Improved readability**: Makes function signatures cleaner and easier to understand
97
+ 4. **Better IDE support**: Enhanced autocomplete, refactoring, and navigation
98
+ 5. **Documentation**: Named types serve as clear documentation of function APIs
99
+ 6. **Extensibility**: Types and interfaces can be extended and composed more easily
100
+ 7. **Type inference**: Named types can improve TypeScript's type inference in complex scenarios
101
+
102
+ ## Rule Scope
103
+
104
+ This rule applies to:
105
+
106
+ - All function types: arrow functions, function expressions, and function declarations
107
+ - Function parameters with inline object type literals
108
+ - Method definitions with inline object type parameters
109
+ - TypeScript method signatures
110
+
111
+ The rule triggers when:
112
+
113
+ - A parameter has an inline object type literal (e.g., `{ bar: string; baz: number }`)
114
+ - The parameter is destructured with an inline type (e.g., `({ bar, baz }: { bar: string; baz: number })`)
115
+
116
+ The rule allows:
117
+
118
+ - Primitive type annotations (string, number, boolean, etc.)
119
+ - Named types and interfaces
120
+ - Type aliases
121
+ - Functions with no parameters
122
+ - Array types (e.g., `string[]`)
123
+ - Union/intersection types without object literals
124
+
125
+ ## When Not To Use It
126
+
127
+ This rule should not be used if you:
128
+
129
+ - Prefer inline types for simple, one-off function parameters
130
+ - Are working with very simple functions that don't benefit from type extraction
131
+ - Have specific code style requirements that favor inline types
132
+ - Are maintaining legacy code with established patterns
133
+
134
+ ## Configuration
135
+
136
+ This rule is included in the following configurations:
137
+
138
+ - `nextfriday/base`
139
+ - `nextfriday/base/recommended`
140
+ - `nextfriday/react`
141
+ - `nextfriday/react/recommended`
142
+ - `nextfriday/nextjs`
143
+ - `nextfriday/nextjs/recommended`
144
+
145
+ To enable this rule manually:
146
+
147
+ ```json
148
+ {
149
+ "rules": {
150
+ "nextfriday/prefer-named-param-types": "error"
151
+ }
152
+ }
153
+ ```
154
+
155
+ ## Relationship to Other Rules
156
+
157
+ This rule complements but differs from `prefer-interface-over-inline-types`:
158
+
159
+ - `prefer-interface-over-inline-types`: Focuses on React component props with complexity criteria
160
+ - `prefer-named-param-types`: Applies to ALL functions with inline object types, regardless of complexity
161
+
162
+ Both rules can be used together for comprehensive type organization.
163
+
164
+ ## Compatibility
165
+
166
+ - TypeScript 3.0+ (interface and type alias declarations)
167
+ - ESLint 9+ with flat config
168
+ - Works with all function types in JavaScript/TypeScript
169
+
170
+ ## Version
171
+
172
+ This rule was introduced in eslint-plugin-nextfriday v1.2.3.