Skip to content

Commit 6a98e66

Browse files
committed
In components-return-once, don't treat callback functions as components.
1 parent 8372d35 commit 6a98e66

File tree

4 files changed

+55
-24
lines changed

4 files changed

+55
-24
lines changed

README.md

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -119,27 +119,25 @@ const [editedValue, setEditedValue] = createSignal(props.value);
119119
🔧: Fixable with [`eslint --fix`](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems)/IDE auto-fix.
120120

121121
<!-- AUTO-GENERATED-CONTENT:START (RULES) -->
122-
123-
|| 🔧 | Rule | Description |
124-
| :-: | :-: | :--------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
125-
|| 🔧 | [solid/components-return-once](docs/components-return-once.md) | Disallow early returns in components. Solid components only run once, and so conditionals should be inside JSX. |
126-
|| 🔧 | [solid/event-handlers](docs/event-handlers.md) | Enforce naming DOM element event handlers consistently and prevent Solid's analysis from misunderstanding whether a prop should be an event handler. |
127-
|| 🔧 | [solid/imports](docs/imports.md) | Enforce consistent imports from "solid-js", "solid-js/web", and "solid-js/store". |
128-
|| | [solid/jsx-no-duplicate-props](docs/jsx-no-duplicate-props.md) | Disallow passing the same prop twice in JSX. |
129-
|| | [solid/jsx-no-script-url](docs/jsx-no-script-url.md) | Disallow javascript: URLs. |
130-
|| 🔧 | [solid/jsx-no-undef](docs/jsx-no-undef.md) | Disallow references to undefined variables in JSX. Handles custom directives. |
131-
|| | [solid/jsx-uses-vars](docs/jsx-uses-vars.md) | Prevent variables used in JSX from being marked as unused. |
132-
|| 🔧 | [solid/no-destructure](docs/no-destructure.md) | Disallow destructuring props. In Solid, props must be used with property accesses (`props.foo`) to preserve reactivity. This rule only tracks destructuring in the parameter list. |
133-
|| 🔧 | [solid/no-innerhtml](docs/no-innerhtml.md) | Disallow usage of the innerHTML attribute, which can often lead to security vulnerabilities. |
134-
|| 🔧 | [solid/no-react-specific-props](docs/no-react-specific-props.md) | Disallow usage of React-specific `className`/`htmlFor` props, which were deprecated in v1.4.0. |
135-
|| | [solid/no-unknown-namespaces](docs/no-unknown-namespaces.md) | Enforce using only Solid-specific namespaced attribute names (i.e. `'on:'` in `<div on:click={...} />`). |
136-
|| 🔧 | [solid/prefer-classlist](docs/prefer-classlist.md) | Enforce using the classlist prop over importing a classnames helper. The classlist prop accepts an object `{ [class: string]: boolean }` just like classnames. |
137-
|| 🔧 | [solid/prefer-for](docs/prefer-for.md) | Enforce using Solid's `<For />` component for mapping an array to JSX elements. |
138-
|| 🔧 | [solid/prefer-show](docs/prefer-show.md) | Enforce using Solid's `<Show />` component for conditionally showing content. Solid's compiler covers this case, so it's a stylistic rule only. |
139-
|| | [solid/reactivity](docs/reactivity.md) | Enforce that reactive expressions (props, signals, memos, etc.) are only used in tracked scopes; otherwise, they won't update the view as expected. |
140-
|| 🔧 | [solid/self-closing-comp](docs/self-closing-comp.md) | Disallow extra closing tags for components without children. |
141-
|| 🔧 | [solid/style-prop](docs/style-prop.md) | Require CSS properties in the `style` prop to be valid and kebab-cased (ex. 'font-size'), not camel-cased (ex. 'fontSize') like in React, and that property values with dimensions are strings, not numbers with implicit 'px' units. |
142-
122+
|| 🔧 | Rule | Description |
123+
| :---: | :---: | :--- | :--- |
124+
|| 🔧 | [solid/components-return-once](docs/components-return-once.md) | Disallow early returns in components. Solid components only run once, and so conditionals should be inside JSX. |
125+
|| 🔧 | [solid/event-handlers](docs/event-handlers.md) | Enforce naming DOM element event handlers consistently and prevent Solid's analysis from misunderstanding whether a prop should be an event handler. |
126+
|| 🔧 | [solid/imports](docs/imports.md) | Enforce consistent imports from "solid-js", "solid-js/web", and "solid-js/store". |
127+
|| | [solid/jsx-no-duplicate-props](docs/jsx-no-duplicate-props.md) | Disallow passing the same prop twice in JSX. |
128+
|| | [solid/jsx-no-script-url](docs/jsx-no-script-url.md) | Disallow javascript: URLs. |
129+
|| 🔧 | [solid/jsx-no-undef](docs/jsx-no-undef.md) | Disallow references to undefined variables in JSX. Handles custom directives. |
130+
|| | [solid/jsx-uses-vars](docs/jsx-uses-vars.md) | Prevent variables used in JSX from being marked as unused. |
131+
|| 🔧 | [solid/no-destructure](docs/no-destructure.md) | Disallow destructuring props. In Solid, props must be used with property accesses (`props.foo`) to preserve reactivity. This rule only tracks destructuring in the parameter list. |
132+
|| 🔧 | [solid/no-innerhtml](docs/no-innerhtml.md) | Disallow usage of the innerHTML attribute, which can often lead to security vulnerabilities. |
133+
|| 🔧 | [solid/no-react-specific-props](docs/no-react-specific-props.md) | Disallow usage of React-specific `className`/`htmlFor` props, which were deprecated in v1.4.0. |
134+
|| | [solid/no-unknown-namespaces](docs/no-unknown-namespaces.md) | Enforce using only Solid-specific namespaced attribute names (i.e. `'on:'` in `<div on:click={...} />`). |
135+
|| 🔧 | [solid/prefer-classlist](docs/prefer-classlist.md) | Enforce using the classlist prop over importing a classnames helper. The classlist prop accepts an object `{ [class: string]: boolean }` just like classnames. |
136+
|| 🔧 | [solid/prefer-for](docs/prefer-for.md) | Enforce using Solid's `<For />` component for mapping an array to JSX elements. |
137+
|| 🔧 | [solid/prefer-show](docs/prefer-show.md) | Enforce using Solid's `<Show />` component for conditionally showing content. Solid's compiler covers this case, so it's a stylistic rule only. |
138+
|| | [solid/reactivity](docs/reactivity.md) | Enforce that reactive expressions (props, signals, memos, etc.) are only used in tracked scopes; otherwise, they won't update the view as expected. |
139+
|| 🔧 | [solid/self-closing-comp](docs/self-closing-comp.md) | Disallow extra closing tags for components without children. |
140+
|| 🔧 | [solid/style-prop](docs/style-prop.md) | Require CSS properties in the `style` prop to be valid and kebab-cased (ex. 'font-size'), not camel-cased (ex. 'fontSize') like in React, and that property values with dimensions are strings, not numbers with implicit 'px' units. |
143141
<!-- AUTO-GENERATED-CONTENT:END -->
144142

145143
## Versioning
@@ -149,10 +147,8 @@ stable across patch (`0.0.x`) versions, but may change across minor (`0.x`) vers
149147
If you want to pin a minor version, use a tilde in your `package.json`.
150148

151149
<!-- AUTO-GENERATED-CONTENT:START (TILDE) -->
152-
153150
```diff
154151
- "eslint-plugin-solid": "^0.7.4"
155152
+ "eslint-plugin-solid": "~0.7.4"
156153
```
157-
158154
<!-- AUTO-GENERATED-CONTENT:END -->

docs/components-return-once.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ function Component(props) {
106106
return props.primary || <div>{props.secondaryText}</div>;
107107
}
108108

109+
HOC(() => {
110+
if (condition) {
111+
return <div />;
112+
}
113+
return <div />;
114+
});
115+
109116
```
110117

111118
### Valid Examples
@@ -131,5 +138,12 @@ function notAComponent() {
131138
return <div />;
132139
}
133140

141+
callback(() => {
142+
if (condition) {
143+
return <div />;
144+
}
145+
return <div />;
146+
});
147+
134148
```
135149
<!-- AUTO-GENERATED-CONTENT:END -->

src/rules/components-return-once.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,12 @@ const rule: TSESLint.RuleModule<"noEarlyReturn" | "noConditionalReturn", []> = {
6262
const onFunctionExit = (node: FunctionNode) => {
6363
if (
6464
(node.type === "FunctionDeclaration" && node.id?.name?.match(/^[a-z]/)) ||
65-
node.parent?.type === "JSXExpressionContainer" // "render props" aren't components
65+
// "render props" aren't components
66+
node.parent?.type === "JSXExpressionContainer" ||
67+
// ignore createMemo(() => conditional JSX), report HOC(() => conditional JSX)
68+
(node.parent?.type === "CallExpression" &&
69+
node.parent.arguments.some((n) => n === node) &&
70+
!(node.parent.callee as T.Identifier).name?.match(/^[A-Z]/))
6671
) {
6772
currentFunction().isComponent = false;
6873
}

test/rules/components-return-once.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ export const cases = run("components-return-once", rule, {
1818
}
1919
return <div />;
2020
}`,
21+
`callback(() => {
22+
if (condition) {
23+
return <div />;
24+
}
25+
return <div />;
26+
});`,
2127
],
2228
invalid: [
2329
// Early returns
@@ -111,5 +117,15 @@ export const cases = run("components-return-once", rule, {
111117
}`,
112118
errors: [{ messageId: "noConditionalReturn" }],
113119
},
120+
// HOCs
121+
{
122+
code: `HOC(() => {
123+
if (condition) {
124+
return <div />;
125+
}
126+
return <div />;
127+
});`,
128+
errors: [{ messageId: "noEarlyReturn" }],
129+
},
114130
],
115131
});

0 commit comments

Comments
 (0)