eslint-plugin-nextfriday 1.5.3 → 1.6.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,14 @@
1
1
  # eslint-plugin-nextfriday
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#36](https://github.com/next-friday/eslint-plugin-nextfriday/pull/36) [`f819ffa`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/f819ffa8eed179e38eed4ec51a05dec53dd979d0) Thanks [@joetakara](https://github.com/joetakara)! - Add three new ESLint rules:
8
+ - `jsx-no-non-component-function`: Prevent non-component functions at top level in .tsx/.jsx files
9
+ - `enforce-sorted-destructuring`: Enforce alphabetical sorting of destructured properties with defaults first
10
+ - `jsx-no-variable-in-callback`: Prevent variable declarations inside JSX callbacks for cleaner code
11
+
3
12
  ## 1.5.3
4
13
 
5
14
  ### Patch Changes
package/README.md CHANGED
@@ -118,12 +118,16 @@ module.exports = {
118
118
  | [md-filename-case-restriction](docs/rules/MD_FILENAME_CASE_RESTRICTION.md) | Enforce SNAKE_CASE filenames for .md files | ❌ |
119
119
  | [prefer-destructuring-params](docs/rules/PREFER_DESTRUCTURING_PARAMS.md) | Enforce destructuring for functions with multiple parameters | ❌ |
120
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 | ❌ |
121
123
  | [prefer-import-type](docs/rules/PREFER_IMPORT_TYPE.md) | Enforce using 'import type' for type-only imports | ✅ |
122
124
  | [prefer-named-param-types](docs/rules/PREFER_NAMED_PARAM_TYPES.md) | Enforce named types for function parameters with object types | ❌ |
123
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 | ✅ |
124
127
  | [prefer-react-import-types](docs/rules/PREFER_REACT_IMPORT_TYPES.md) | Enforce direct imports from 'react' instead of React.X | ✅ |
125
128
  | [react-props-destructure](docs/rules/REACT_PROPS_DESTRUCTURE.md) | Enforce destructuring props inside React component body | ❌ |
126
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 | ❌ |
127
131
  | [no-complex-inline-return](docs/rules/NO_COMPLEX_INLINE_RETURN.md) | Disallow complex inline expressions in return statements - prefer const first | ❌ |
128
132
  | [no-logic-in-params](docs/rules/NO_LOGIC_IN_PARAMS.md) | Disallow logic or conditions in function parameters - extract to const first | ❌ |
129
133
  | [no-env-fallback](docs/rules/NO_ENV_FALLBACK.md) | Disallow fallback values for environment variables as they can be dangerous | ❌ |
@@ -0,0 +1,122 @@
1
+ # enforce-sorted-destructuring
2
+
3
+ Enforce alphabetical sorting of destructured properties with defaults first.
4
+
5
+ ## Rule Details
6
+
7
+ This rule enforces that object destructuring properties are sorted alphabetically, with properties that have default values coming first. Default values are further sorted by type (string, number, boolean, object) and then alphabetically within each type.
8
+
9
+ ### Why?
10
+
11
+ 1. **Consistency**: Alphabetical ordering makes code more predictable and easier to scan
12
+ 2. **Readability**: Sorted properties are easier to find in large destructuring statements
13
+ 3. **Organization**: Grouping defaults first keeps the destructuring organized by intent
14
+ 4. **Maintainability**: Clear structure makes it easier to add or remove properties
15
+
16
+ ### Sorting Order
17
+
18
+ Properties are sorted in this order:
19
+
20
+ 1. **Properties with defaults** (sorted by type, then alphabetically):
21
+ - String defaults (alphabetically)
22
+ - Number defaults (alphabetically)
23
+ - Boolean defaults (alphabetically)
24
+ - Object/Array defaults (alphabetically)
25
+ - Other defaults (alphabetically)
26
+
27
+ 2. **Properties without defaults** (alphabetically)
28
+
29
+ ## Examples
30
+
31
+ ### ❌ Incorrect
32
+
33
+ ```js
34
+ // Bad: Not sorted alphabetically
35
+ const { d, b, a, c } = foo;
36
+ ```
37
+
38
+ ```js
39
+ // Bad: Completely unsorted
40
+ const { z, a, m } = foo;
41
+ ```
42
+
43
+ ```js
44
+ // Bad: Default in the middle (should be first)
45
+ const { a, b, d = "string", c } = foo;
46
+ ```
47
+
48
+ ```js
49
+ // Bad: Non-default before defaults
50
+ const { a, d = "string", e = 0 } = foo;
51
+ ```
52
+
53
+ ```js
54
+ // Bad: Defaults not sorted by type (number before string)
55
+ const { e = 0, d = "string", a, b } = foo;
56
+ ```
57
+
58
+ ```js
59
+ // Bad: String defaults not sorted alphabetically
60
+ const { b = "beta", a = "alpha", c } = foo;
61
+ ```
62
+
63
+ ```js
64
+ // Bad: Properties reversed
65
+ const { b, a } = foo;
66
+ ```
67
+
68
+ ### ✅ Correct
69
+
70
+ ```js
71
+ // Good: Alphabetically sorted without defaults
72
+ const { a, b, c, d } = foo;
73
+ ```
74
+
75
+ ```js
76
+ // Good: Defaults first, sorted by type (string, number, boolean), then non-defaults
77
+ const { d = "string", e = 0, f = true, a, b, c } = foo;
78
+ ```
79
+
80
+ ```js
81
+ // Good: String defaults first (sorted alphabetically), then non-defaults
82
+ const { a = "alpha", b = "beta", c, d } = foo;
83
+ ```
84
+
85
+ ```js
86
+ // Good: Number defaults first (sorted alphabetically), then non-defaults
87
+ const { a = 1, b = 2, c, d } = foo;
88
+ ```
89
+
90
+ ```js
91
+ // Good: Boolean defaults first (sorted alphabetically), then non-defaults
92
+ const { a = true, b = false, c, d } = foo;
93
+ ```
94
+
95
+ ```js
96
+ // Good: Object defaults first (sorted alphabetically), then non-defaults
97
+ const { a = {}, b = [], c, d } = foo;
98
+ ```
99
+
100
+ ```js
101
+ // Good: Mixed default types sorted by type order, then non-defaults
102
+ const { name = "default", age = 0, active = true, data = {}, x, y, z } = foo;
103
+ ```
104
+
105
+ ```js
106
+ // Good: All defaults sorted by type and alphabetically
107
+ const { a = "test", b = "value", c = 1, d = 2 } = foo;
108
+ ```
109
+
110
+ ```js
111
+ // Good: With rest element at end
112
+ const { a, b, ...rest } = foo;
113
+ ```
114
+
115
+ ## When Not To Use It
116
+
117
+ If you prefer a different sorting strategy for destructured properties or don't want to enforce any particular order, you can disable this rule.
118
+
119
+ ## Further Reading
120
+
121
+ - [Destructuring Assignment (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)
122
+ - [Default Parameters (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters)
@@ -0,0 +1,114 @@
1
+ # jsx-no-non-component-function
2
+
3
+ Disallow non-component functions defined at top level in .tsx and .jsx files.
4
+
5
+ ## Rule Details
6
+
7
+ This rule prevents non-component functions from being defined at the top level in `.tsx` and `.jsx` files. These functions should either be:
8
+
9
+ 1. Extracted to separate files and imported
10
+ 2. Defined inside the component function if they are component-specific
11
+
12
+ ### Why?
13
+
14
+ 1. **Better Organization**: Top-level functions in component files can accumulate and make files messy and hard to maintain
15
+ 2. **Proper Separation of Concerns**: Utility/helper functions belong in separate files, not in component files
16
+ 3. **Improved Reusability**: Extracting functions to separate files makes them easier to reuse across components
17
+ 4. **Cleaner Component Files**: Component files should focus on component logic only
18
+
19
+ ## Examples
20
+
21
+ ### ❌ Incorrect
22
+
23
+ ```tsx
24
+ // Bad: Non-component function defined at top level in .tsx file
25
+ const helper = (name: string) => {
26
+ const words = name.trim().split(/\s+/);
27
+ if (words.length === 1) {
28
+ return words[0].charAt(0).toUpperCase();
29
+ }
30
+ return words
31
+ .slice(0, 2)
32
+ .map((word) => word.charAt(0).toUpperCase())
33
+ .join("");
34
+ };
35
+
36
+ const Component = () => {
37
+ return <div>{helper("test")}</div>;
38
+ };
39
+ ```
40
+
41
+ ```tsx
42
+ // Bad: Function declaration at top level
43
+ function formatName(name: string) {
44
+ return name.toUpperCase();
45
+ }
46
+
47
+ const Component = () => {
48
+ return <div>{formatName("test")}</div>;
49
+ };
50
+ ```
51
+
52
+ ```tsx
53
+ // Bad: Non-component function before exported component
54
+ const calculateTotal = (items: number[]) => {
55
+ return items.reduce((sum, item) => sum + item, 0);
56
+ };
57
+
58
+ export const OrderSummary = () => {
59
+ return <div>Total</div>;
60
+ };
61
+ ```
62
+
63
+ ### ✅ Correct
64
+
65
+ ```tsx
66
+ // Good: Function imported from separate file
67
+ import { helper } from "./helper";
68
+
69
+ const Component = () => {
70
+ return <div>{helper("test")}</div>;
71
+ };
72
+ ```
73
+
74
+ ```tsx
75
+ // Good: Function defined inside component
76
+ const Component = () => {
77
+ const helper = (name: string) => {
78
+ return name.toUpperCase();
79
+ };
80
+
81
+ return <div>{helper("test")}</div>;
82
+ };
83
+ ```
84
+
85
+ ```tsx
86
+ // Good: Component only
87
+ const Component = () => {
88
+ return <div>Hello</div>;
89
+ };
90
+ ```
91
+
92
+ ```tsx
93
+ // Good: Functions in .ts or .js files are allowed
94
+ // utils.ts
95
+ export const helper = (name: string) => {
96
+ return name.toUpperCase();
97
+ };
98
+ ```
99
+
100
+ ```tsx
101
+ // Good: Exported component functions are allowed
102
+ export const Component = () => {
103
+ return <div>Hello</div>;
104
+ };
105
+ ```
106
+
107
+ ## When Not To Use It
108
+
109
+ If you prefer to keep utility/helper functions in the same file as your components, you can disable this rule. However, this may lead to less organized code and reduced reusability.
110
+
111
+ ## Further Reading
112
+
113
+ - [React Component File Structure Best Practices](https://react.dev/learn/thinking-in-react)
114
+ - [Separation of Concerns](https://en.wikipedia.org/wiki/Separation_of_concerns)
@@ -0,0 +1,144 @@
1
+ # jsx-no-variable-in-callback
2
+
3
+ Disallow variable declarations inside callback functions within JSX.
4
+
5
+ ## Rule Details
6
+
7
+ This rule prevents variable declarations inside callback functions that are directly used within JSX expressions. This enforces cleaner, more maintainable code by extracting complex logic to separate functions.
8
+
9
+ ### Why?
10
+
11
+ 1. **Readability**: Keeps JSX clean and focused on rendering, not logic
12
+ 2. **Maintainability**: Extracted functions are easier to test and modify
13
+ 3. **Separation of Concerns**: Logic belongs in functions, not inline in JSX
14
+ 4. **Consistency**: Enforces a uniform pattern across the codebase
15
+
16
+ ## Examples
17
+
18
+ ### ❌ Incorrect
19
+
20
+ ```tsx
21
+ // Bad: Variable declared inside map callback in JSX
22
+ const UserList = ({ users }) => {
23
+ return (
24
+ <div>
25
+ {users.map((user) => {
26
+ const displayName = user.firstName + " " + user.lastName;
27
+ return <div key={user.id}>{displayName}</div>;
28
+ })}
29
+ </div>
30
+ );
31
+ };
32
+ ```
33
+
34
+ ```tsx
35
+ // Bad: Variable in filter callback
36
+ const ProductList = ({ products }) => {
37
+ return (
38
+ <ul>
39
+ {products.filter((product) => {
40
+ const isAvailable = product.stock > 0 && product.active;
41
+ return isAvailable;
42
+ })}
43
+ </ul>
44
+ );
45
+ };
46
+ ```
47
+
48
+ ```tsx
49
+ // Bad: Multiple variables in callback
50
+ const OrderSummary = ({ orders }) => {
51
+ return (
52
+ <div>
53
+ {orders.map((order) => {
54
+ const total = order.price * order.quantity;
55
+ const discount = total * 0.1;
56
+ const final = total - discount;
57
+ return <div key={order.id}>{final}</div>;
58
+ })}
59
+ </div>
60
+ );
61
+ };
62
+ ```
63
+
64
+ ### ✅ Correct
65
+
66
+ ```tsx
67
+ // Good: Extract logic to a separate function
68
+ const UserList = ({ users }) => {
69
+ const renderUsers = () =>
70
+ users.map((user) => {
71
+ const displayName = user.firstName + " " + user.lastName;
72
+ return <div key={user.id}>{displayName}</div>;
73
+ });
74
+
75
+ return <div>{renderUsers()}</div>;
76
+ };
77
+ ```
78
+
79
+ ```tsx
80
+ // Good: Use helper function outside JSX
81
+ const ProductList = ({ products }) => {
82
+ const isProductAvailable = (product) => {
83
+ const isAvailable = product.stock > 0 && product.active;
84
+ return isAvailable;
85
+ };
86
+
87
+ return <ul>{products.filter(isProductAvailable)}</ul>;
88
+ };
89
+ ```
90
+
91
+ ```tsx
92
+ // Good: No variable declaration in callback
93
+ const UserList = ({ users }) => {
94
+ return (
95
+ <div>
96
+ {users.map((user) => (
97
+ <div key={user.id}>
98
+ {user.firstName} {user.lastName}
99
+ </div>
100
+ ))}
101
+ </div>
102
+ );
103
+ };
104
+ ```
105
+
106
+ ```tsx
107
+ // Good: Variable declared outside JSX
108
+ const OrderSummary = ({ orders }) => {
109
+ const discount = 0.1;
110
+
111
+ return (
112
+ <div>
113
+ {orders.map((order) => {
114
+ const total = order.price * order.quantity;
115
+ return <div key={order.id}>{total - total * discount}</div>;
116
+ })}
117
+ </div>
118
+ );
119
+ };
120
+ ```
121
+
122
+ ```tsx
123
+ // Good: Extract rendering to a function
124
+ const OrderSummary = ({ orders }) => {
125
+ const calculateFinalPrice = (order) => {
126
+ const total = order.price * order.quantity;
127
+ const discount = total * 0.1;
128
+ return total - discount;
129
+ };
130
+
131
+ const renderOrders = () => orders.map((order) => <div key={order.id}>{calculateFinalPrice(order)}</div>);
132
+
133
+ return <div>{renderOrders()}</div>;
134
+ };
135
+ ```
136
+
137
+ ## When Not To Use It
138
+
139
+ If you prefer keeping all logic inline within JSX callbacks and don't mind the reduced readability, you can disable this rule. However, this is generally not recommended as it leads to harder-to-maintain code.
140
+
141
+ ## Further Reading
142
+
143
+ - [React Component Best Practices](https://react.dev/learn/keeping-components-pure)
144
+ - [Clean Code Principles](https://clean-code-developer.com/)
@@ -0,0 +1,78 @@
1
+ # prefer-jsx-template-literals
2
+
3
+ Enforce using template literals instead of mixing text and JSX expressions.
4
+
5
+ ## Rule Details
6
+
7
+ This rule prevents mixing plain text with JSX expressions in JSX elements, which can lead to incorrect spacing and readability issues. Instead, it enforces using template literals to combine text and expressions.
8
+
9
+ ### Why?
10
+
11
+ Mixing text and JSX expressions without proper spacing can cause:
12
+
13
+ 1. **Spacing issues**: `<div>+ {value}</div>` renders as "+ value" with unexpected spacing
14
+ 2. **Inconsistent formatting**: Hard to maintain consistent spacing across the codebase
15
+ 3. **Readability problems**: Mixed syntax makes code harder to read and understand
16
+
17
+ Using template literals ensures:
18
+
19
+ - Explicit control over spacing
20
+ - Consistent formatting
21
+ - Better readability
22
+ - Easier to maintain
23
+
24
+ ## Examples
25
+
26
+ ### ❌ Incorrect
27
+
28
+ ```tsx
29
+ // Bad: Text followed by expression
30
+ <div>+ {fooVariable}</div>
31
+ <div>+{fooVariable}</div>
32
+ <div>Price: {price}</div>
33
+ <div>$ {amount}</div>
34
+ <span>Total: {total}</span>
35
+ <p>Hello {name}</p>
36
+
37
+ // Bad: Expression followed by text
38
+ <div>{count} items</div>
39
+ <div>{price}$</div>
40
+ ```
41
+
42
+ ### ✅ Correct
43
+
44
+ ```tsx
45
+ // Good: Using template literals
46
+ <div>{`+${fooVariable}`}</div>
47
+ <div>{`+ ${fooVariable}`}</div>
48
+ <div>{`Price: ${price}`}</div>
49
+ <div>{`$ ${amount}`}</div>
50
+ <span>{`Total: ${total}`}</span>
51
+ <p>{`Hello ${name}`}</p>
52
+
53
+ // Good: Using template literals for expression + text
54
+ <div>{`${count}items`}</div>
55
+ <div>{`${price}$`}</div>
56
+
57
+ // Good: Expression only
58
+ <div>{fooVariable}</div>
59
+ <div>{price}</div>
60
+
61
+ // Good: Text only
62
+ <div>Some static text</div>
63
+
64
+ // Good: Expression with whitespace only around it
65
+ <div> {fooVariable} </div>
66
+ <div>
67
+ {fooVariable}
68
+ </div>
69
+ ```
70
+
71
+ ## When Not To Use It
72
+
73
+ If you prefer mixing text and JSX expressions, you can disable this rule. However, this may lead to inconsistent spacing and formatting issues.
74
+
75
+ ## Further Reading
76
+
77
+ - [Template Literals (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)
78
+ - [JSX in React](https://react.dev/learn/writing-markup-with-jsx)