Skip to content

Commit 722b106

Browse files
authored
Merge branch 'main' into fix/prefer-for-chainexpression
2 parents 38671b7 + 42be78a commit 722b106

File tree

3 files changed

+139
-35
lines changed

3 files changed

+139
-35
lines changed

docs/prefer-show.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,48 @@ function Component(props) {
4747
);
4848
}
4949

50+
function Component(props) {
51+
return (
52+
<For each={props.someList}>
53+
{(listItem) => listItem.cond && <span>Content</span>}
54+
</For>
55+
);
56+
}
57+
// after eslint --fix:
58+
function Component(props) {
59+
return (
60+
<For each={props.someList}>
61+
{(listItem) => (
62+
<Show when={listItem.cond}>
63+
<span>Content</span>
64+
</Show>
65+
)}
66+
</For>
67+
);
68+
}
69+
70+
function Component(props) {
71+
return (
72+
<For each={props.someList}>
73+
{(listItem) =>
74+
listItem.cond ? <span>Content</span> : <span>Fallback</span>
75+
}
76+
</For>
77+
);
78+
}
79+
// after eslint --fix:
80+
function Component(props) {
81+
return (
82+
<For each={props.someList}>
83+
{(listItem) => (
84+
<Show when={listItem.cond} fallback={<span>Fallback</span>}>
85+
<span>Content</span>
86+
</Show>
87+
)}
88+
</For>
89+
);
90+
}
91+
5092
```
5193

5294
### Valid Examples

src/rules/prefer-show.ts

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,44 +26,63 @@ const rule: TSESLint.RuleModule<"preferShowAnd" | "preferShowTernary", []> = {
2626
return node.type === "JSXElement" || node.type === "JSXFragment" ? text : `{${text}}`;
2727
};
2828

29+
const logicalExpressionHandler = (node: T.LogicalExpression) => {
30+
if (node.operator === "&&" && EXPENSIVE_TYPES.includes(node.right.type)) {
31+
context.report({
32+
node,
33+
messageId: "preferShowAnd",
34+
fix: (fixer) =>
35+
fixer.replaceText(
36+
node.parent?.type === "JSXExpressionContainer" &&
37+
node.parent.parent?.type === "JSXElement"
38+
? node.parent
39+
: node,
40+
`<Show when={${sourceCode.getText(node.left)}}>${putIntoJSX(node.right)}</Show>`
41+
),
42+
});
43+
}
44+
};
45+
const conditionalExpressionHandler = (node: T.ConditionalExpression) => {
46+
if (
47+
EXPENSIVE_TYPES.includes(node.consequent.type) ||
48+
EXPENSIVE_TYPES.includes(node.alternate.type)
49+
) {
50+
context.report({
51+
node,
52+
messageId: "preferShowTernary",
53+
fix: (fixer) =>
54+
fixer.replaceText(
55+
node.parent?.type === "JSXExpressionContainer" &&
56+
node.parent.parent?.type === "JSXElement"
57+
? node.parent
58+
: node,
59+
`<Show when={${sourceCode.getText(node.test)}} fallback={${sourceCode.getText(
60+
node.alternate
61+
)}}>${putIntoJSX(node.consequent)}</Show>`
62+
),
63+
});
64+
}
65+
};
66+
2967
return {
30-
"JSXElement > JSXExpressionContainer > LogicalExpression": (node: T.LogicalExpression) => {
31-
if (node.operator === "&&" && EXPENSIVE_TYPES.includes(node.right.type)) {
32-
context.report({
33-
node,
34-
messageId: "preferShowAnd",
35-
fix: (fixer) =>
36-
fixer.replaceText(
37-
node.parent?.type === "JSXExpressionContainer" &&
38-
node.parent.parent?.type === "JSXElement"
39-
? node.parent
40-
: node,
41-
`<Show when={${sourceCode.getText(node.left)}}>${putIntoJSX(node.right)}</Show>`
42-
),
43-
});
68+
JSXExpressionContainer(node) {
69+
if (node.parent?.type !== "JSXElement") {
70+
return;
4471
}
45-
},
46-
"JSXElement > JSXExpressionContainer > ConditionalExpression": (
47-
node: T.ConditionalExpression
48-
) => {
49-
if (
50-
EXPENSIVE_TYPES.includes(node.consequent.type) ||
51-
EXPENSIVE_TYPES.includes(node.alternate.type)
72+
if (node.expression.type === "LogicalExpression") {
73+
logicalExpressionHandler(node.expression);
74+
} else if (
75+
node.expression.type === "ArrowFunctionExpression" &&
76+
node.expression.body.type === "LogicalExpression"
77+
) {
78+
logicalExpressionHandler(node.expression.body);
79+
} else if (node.expression.type === "ConditionalExpression") {
80+
conditionalExpressionHandler(node.expression);
81+
} else if (
82+
node.expression.type === "ArrowFunctionExpression" &&
83+
node.expression.body.type === "ConditionalExpression"
5284
) {
53-
context.report({
54-
node,
55-
messageId: "preferShowTernary",
56-
fix: (fixer) =>
57-
fixer.replaceText(
58-
node.parent?.type === "JSXExpressionContainer" &&
59-
node.parent.parent?.type === "JSXElement"
60-
? node.parent
61-
: node,
62-
`<Show when={${sourceCode.getText(node.test)}} fallback={${sourceCode.getText(
63-
node.alternate
64-
)}}>${putIntoJSX(node.consequent)}</Show>`
65-
),
66-
});
85+
conditionalExpressionHandler(node.expression.body);
6786
}
6887
},
6988
};

test/rules/prefer-show.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,48 @@ export const cases = run("prefer-show", rule, {
4545
);
4646
}`,
4747
},
48+
// Check that it also works with control flow function children
49+
{
50+
code: `
51+
function Component(props) {
52+
return (
53+
<For each={props.someList}>
54+
{(listItem) => listItem.cond && <span>Content</span>}
55+
</For>
56+
);
57+
}`,
58+
errors: [{ messageId: "preferShowAnd" }],
59+
output: `
60+
function Component(props) {
61+
return (
62+
<For each={props.someList}>
63+
{(listItem) => <Show when={listItem.cond}><span>Content</span></Show>}
64+
</For>
65+
);
66+
}`,
67+
},
68+
{
69+
code: `
70+
function Component(props) {
71+
return (
72+
<For each={props.someList}>
73+
{(listItem) => (listItem.cond ? (
74+
<span>Content</span>
75+
) : (
76+
<span>Fallback</span>
77+
))}
78+
</For>
79+
);
80+
}`,
81+
errors: [{ messageId: "preferShowTernary" }],
82+
output: `
83+
function Component(props) {
84+
return (
85+
<For each={props.someList}>
86+
{(listItem) => (<Show when={listItem.cond} fallback={<span>Fallback</span>}><span>Content</span></Show>)}
87+
</For>
88+
);
89+
}`,
90+
},
4891
],
4992
});

0 commit comments

Comments
 (0)