Skip to content

Commit d3d6b28

Browse files
committed
fix: Fallthrough cases in switch case
1 parent 2455ab0 commit d3d6b28

File tree

10 files changed

+98
-96
lines changed

10 files changed

+98
-96
lines changed

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/no-direct-set-state-in-use-effect.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,20 @@ export default createRule<[], MessageID>({
136136
if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) return;
137137
if (!isIdFromUseStateCall(node)) return;
138138
switch (node.parent.type) {
139+
case AST_NODE_TYPES.ArrowFunctionExpression: {
140+
const parent = node.parent.parent;
141+
if (parent.type !== AST_NODE_TYPES.CallExpression) break;
142+
// const [state, setState] = useState();
143+
// const set = useMemo(() => setState, []);
144+
// useEffect(set, []);
145+
if (!isUseMemoCall(parent)) break;
146+
const maybeVd = AST.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
147+
if (O.isNone(maybeVd)) break;
148+
const vd = maybeVd.value;
149+
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
150+
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
151+
break;
152+
}
139153
case AST_NODE_TYPES.CallExpression: {
140154
const [firstArg] = node.parent.arguments;
141155
if (node !== firstArg) break;
@@ -157,19 +171,6 @@ export default createRule<[], MessageID>({
157171
}
158172
break;
159173
}
160-
case AST_NODE_TYPES.ArrowFunctionExpression: {
161-
const parent = node.parent.parent;
162-
if (parent.type !== AST_NODE_TYPES.CallExpression) break;
163-
// const [state, setState] = useState();
164-
// const set = useMemo(() => setState, []);
165-
// useEffect(set, []);
166-
if (!isUseMemoCall(parent)) break;
167-
const maybeVd = AST.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
168-
if (O.isNone(maybeVd)) break;
169-
const vd = maybeVd.value;
170-
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
171-
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
172-
}
173174
}
174175
},
175176
"Program:exit"() {
@@ -179,9 +180,9 @@ export default createRule<[], MessageID>({
179180
): TSESTree.CallExpression[] | TSESTree.Identifier[] => {
180181
const node = O.flatMap(VAR.findVariable(id, initialScope), VAR.getVariableNode(0)).pipe(O.getOrNull);
181182
switch (node?.type) {
183+
case AST_NODE_TYPES.ArrowFunctionExpression:
182184
case AST_NODE_TYPES.FunctionDeclaration:
183185
case AST_NODE_TYPES.FunctionExpression:
184-
case AST_NODE_TYPES.ArrowFunctionExpression:
185186
return indirectSetStateCalls.get(node) ?? [];
186187
case AST_NODE_TYPES.CallExpression:
187188
return indirectSetStateCallsInHooks.get(node) ?? indirectSetStateCallsAsArgs.get(node) ?? [];

packages/plugins/eslint-plugin-react-hooks-extra/src/rules/no-direct-set-state-in-use-layout-effect.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,20 @@ export default createRule<[], MessageID>({
141141
if (node.parent.type === AST_NODE_TYPES.CallExpression && node.parent.callee === node) return;
142142
if (!isIdFromUseStateCall(node)) return;
143143
switch (node.parent.type) {
144+
case AST_NODE_TYPES.ArrowFunctionExpression: {
145+
const parent = node.parent.parent;
146+
if (parent.type !== AST_NODE_TYPES.CallExpression) break;
147+
// const [state, setState] = useState();
148+
// const set = useMemo(() => setState, []);
149+
// useLayoutEffect(set, []);
150+
if (!isUseMemoCall(parent)) break;
151+
const maybeVd = AST.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
152+
if (O.isNone(maybeVd)) break;
153+
const vd = maybeVd.value;
154+
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
155+
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
156+
break;
157+
}
144158
case AST_NODE_TYPES.CallExpression: {
145159
const [firstArg] = node.parent.arguments;
146160
if (node !== firstArg) break;
@@ -162,19 +176,6 @@ export default createRule<[], MessageID>({
162176
}
163177
break;
164178
}
165-
case AST_NODE_TYPES.ArrowFunctionExpression: {
166-
const parent = node.parent.parent;
167-
if (parent.type !== AST_NODE_TYPES.CallExpression) break;
168-
// const [state, setState] = useState();
169-
// const set = useMemo(() => setState, []);
170-
// useLayoutEffect(set, []);
171-
if (!isUseMemoCall(parent)) break;
172-
const maybeVd = AST.traverseUpGuard(parent, isVariableDeclaratorFromHookCall);
173-
if (O.isNone(maybeVd)) break;
174-
const vd = maybeVd.value;
175-
const calls = indirectSetStateCallsAsArgs.get(vd.init) ?? [];
176-
indirectSetStateCallsAsArgs.set(vd.init, [...calls, node]);
177-
}
178179
}
179180
},
180181
"Program:exit"() {
@@ -184,9 +185,9 @@ export default createRule<[], MessageID>({
184185
): TSESTree.CallExpression[] | TSESTree.Identifier[] => {
185186
const node = O.flatMap(VAR.findVariable(id, initialScope), VAR.getVariableNode(0)).pipe(O.getOrNull);
186187
switch (node?.type) {
188+
case AST_NODE_TYPES.ArrowFunctionExpression:
187189
case AST_NODE_TYPES.FunctionDeclaration:
188190
case AST_NODE_TYPES.FunctionExpression:
189-
case AST_NODE_TYPES.ArrowFunctionExpression:
190191
return indirectSetStateCalls.get(node) ?? [];
191192
case AST_NODE_TYPES.CallExpression:
192193
return indirectSetStateCallsInHooks.get(node) ?? indirectSetStateCallsAsArgs.get(node) ?? [];

packages/plugins/eslint-plugin-react-hooks-extra/src/utils/is-set-function-call.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,6 @@ export function isSetFunctionCall(context: RuleContext, settings: ESLintReactSet
1111
const isIdFromUseStateCall = isFromUseStateCall(context, settings);
1212
return (node: TSESTree.CallExpression) => {
1313
switch (node.callee.type) {
14-
// const [data, setData] = useState();
15-
// setData();
16-
case AST_NODE_TYPES.Identifier: {
17-
return isIdFromUseStateCall(node.callee);
18-
}
19-
// const data = useState();
20-
// data[1]();
21-
case AST_NODE_TYPES.MemberExpression: {
22-
if (!("name" in node.callee.object)) return false;
23-
const initialScope = context.sourceCode.getScope(node);
24-
const property = getStaticValue(node.callee.property, initialScope);
25-
if (property?.value === 1) return isIdFromUseStateCall(node.callee.object);
26-
return false;
27-
}
2814
// const data = useState();
2915
// data.at(1)();
3016
case AST_NODE_TYPES.CallExpression: {
@@ -45,6 +31,20 @@ export function isSetFunctionCall(context: RuleContext, settings: ESLintReactSet
4531
if (value?.value === 1) return isIdFromUseStateCall(callee.object);
4632
return false;
4733
}
34+
// const [data, setData] = useState();
35+
// setData();
36+
case AST_NODE_TYPES.Identifier: {
37+
return isIdFromUseStateCall(node.callee);
38+
}
39+
// const data = useState();
40+
// data[1]();
41+
case AST_NODE_TYPES.MemberExpression: {
42+
if (!("name" in node.callee.object)) return false;
43+
const initialScope = context.sourceCode.getScope(node);
44+
const property = getStaticValue(node.callee.property, initialScope);
45+
if (property?.value === 1) return isIdFromUseStateCall(node.callee.object);
46+
return false;
47+
}
4848
default: {
4949
return false;
5050
}

packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ function getOptions(node: TSESTree.CallExpressionArgument, initialScope: Scope):
8484
};
8585
function getOpts(node: TSESTree.Node): typeof defaultOptions {
8686
switch (node.type) {
87+
case AST_NODE_TYPES.Identifier: {
88+
return F.pipe(
89+
VAR.findVariable(node, initialScope),
90+
O.flatMap(VAR.getVariableNode(0)),
91+
O.filter(AST.is(AST_NODE_TYPES.ObjectExpression)),
92+
O.map(getOpts),
93+
O.getOrElse(() => defaultOptions),
94+
);
95+
}
8796
case AST_NODE_TYPES.Literal: {
8897
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
8998
return Data.struct({ ...defaultOptions, capture: O.some(!!node.value) });
@@ -99,14 +108,14 @@ function getOptions(node: TSESTree.CallExpressionArgument, initialScope: Scope):
99108
const { value } = prop;
100109
const getSignalExp = (node: TSESTree.Node): O.Option<TSESTree.Node> => {
101110
switch (node.type) {
102-
case AST_NODE_TYPES.MemberExpression:
103-
return O.some(node);
104111
case AST_NODE_TYPES.Identifier:
105112
return F.pipe(
106113
VAR.findVariable(node, initialScope),
107114
O.flatMap(VAR.getVariableNode(0)),
108115
O.flatMap(getSignalExp),
109116
);
117+
case AST_NODE_TYPES.MemberExpression:
118+
return O.some(node);
110119
default:
111120
return O.none();
112121
}
@@ -115,15 +124,6 @@ function getOptions(node: TSESTree.CallExpressionArgument, initialScope: Scope):
115124
});
116125
return Data.struct({ capture: vCapture, once: vOnce, signal: vSignal });
117126
}
118-
case AST_NODE_TYPES.Identifier: {
119-
return F.pipe(
120-
VAR.findVariable(node, initialScope),
121-
O.flatMap(VAR.getVariableNode(0)),
122-
O.filter(AST.is(AST_NODE_TYPES.ObjectExpression)),
123-
O.map(getOpts),
124-
O.getOrElse(() => defaultOptions),
125-
);
126-
}
127127
default: {
128128
return defaultOptions;
129129
}

packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,13 @@ export default createRule<[], MessageID>({
9090
},
9191
["CallExpression"](node) {
9292
switch (getCallKind(node)) {
93-
case "setInterval": {
93+
case "clearInterval": {
9494
const [fNode, fKind] = fStack.findLast(f => f.at(1) !== "other") ?? [];
9595
if (!fNode || !fKind) break;
9696
if (!PHASE_RELEVANCE.has(fKind)) break;
97-
const intervalIdNode = O.getOrNull(VAR.getVariableDeclaratorID(node));
98-
if (!intervalIdNode) {
99-
context.report({
100-
messageId: "noLeakedIntervalNoIntervalId",
101-
node,
102-
});
103-
break;
104-
}
105-
sEntries.push({
97+
const [intervalIdNode] = node.arguments;
98+
if (!intervalIdNode) break;
99+
cEntries.push({
106100
kind: "interval",
107101
node,
108102
callee: node.callee,
@@ -111,13 +105,19 @@ export default createRule<[], MessageID>({
111105
});
112106
break;
113107
}
114-
case "clearInterval": {
108+
case "setInterval": {
115109
const [fNode, fKind] = fStack.findLast(f => f.at(1) !== "other") ?? [];
116110
if (!fNode || !fKind) break;
117111
if (!PHASE_RELEVANCE.has(fKind)) break;
118-
const [intervalIdNode] = node.arguments;
119-
if (!intervalIdNode) break;
120-
cEntries.push({
112+
const intervalIdNode = O.getOrNull(VAR.getVariableDeclaratorID(node));
113+
if (!intervalIdNode) {
114+
context.report({
115+
messageId: "noLeakedIntervalNoIntervalId",
116+
node,
117+
});
118+
break;
119+
}
120+
sEntries.push({
121121
kind: "interval",
122122
node,
123123
callee: node.callee,

packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ export default createRule<[], MessageID>({
9292
if (!fNode || !fKind) return;
9393
if (!PHASE_RELEVANCE.has(fKind)) return;
9494
switch (getCallKind(node)) {
95+
case "clearTimeout": {
96+
const [timeoutIdNode] = node.arguments;
97+
if (!timeoutIdNode) break;
98+
rEntries.push({
99+
kind: "timeout",
100+
node,
101+
callee: node.callee,
102+
phase: fKind,
103+
timerID: timeoutIdNode,
104+
});
105+
break;
106+
}
95107
case "setTimeout": {
96108
const timeoutIdNode = O.getOrNull(VAR.getVariableDeclaratorID(node));
97109
if (!timeoutIdNode) {
@@ -110,18 +122,6 @@ export default createRule<[], MessageID>({
110122
});
111123
break;
112124
}
113-
case "clearTimeout": {
114-
const [timeoutIdNode] = node.arguments;
115-
if (!timeoutIdNode) break;
116-
rEntries.push({
117-
kind: "timeout",
118-
node,
119-
callee: node.callee,
120-
phase: fKind,
121-
timerID: timeoutIdNode,
122-
});
123-
break;
124-
}
125125
}
126126
},
127127
["Program:exit"]() {

packages/plugins/eslint-plugin-react-x/src/rules/no-duplicate-key.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ export default createRule<[], MessageID>({
5454

5555
function checkExpression(node: TSESTree.Expression): O.Option<ReportDescriptor<MessageID>> {
5656
switch (node.type) {
57-
case AST_NODE_TYPES.JSXElement:
58-
case AST_NODE_TYPES.JSXFragment:
59-
return checkIteratorElement(node);
6057
case AST_NODE_TYPES.ConditionalExpression:
6158
if (!("consequent" in node)) return O.none();
6259
return F.pipe(
6360
checkIteratorElement(node.consequent),
6461
O.orElse(() => checkIteratorElement(node.alternate)),
6562
);
63+
case AST_NODE_TYPES.JSXElement:
64+
case AST_NODE_TYPES.JSXFragment:
65+
return checkIteratorElement(node);
6666
case AST_NODE_TYPES.LogicalExpression:
6767
if (!("left" in node)) return O.none();
6868
return F.pipe(

packages/plugins/eslint-plugin-react-x/src/rules/no-missing-key.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ export default createRule<[], MessageID>({
5555

5656
function checkExpression(node: TSESTree.Expression): O.Option<ReportDescriptor<MessageID>> {
5757
switch (node.type) {
58-
case AST_NODE_TYPES.JSXElement:
59-
case AST_NODE_TYPES.JSXFragment:
60-
return checkIteratorElement(node);
6158
case AST_NODE_TYPES.ConditionalExpression:
6259
if (!("consequent" in node)) return O.none();
6360
return O.orElse(checkIteratorElement(node.consequent), () => checkIteratorElement(node.alternate));
61+
case AST_NODE_TYPES.JSXElement:
62+
case AST_NODE_TYPES.JSXFragment:
63+
return checkIteratorElement(node);
6464
case AST_NODE_TYPES.LogicalExpression:
6565
if (!("left" in node)) return O.none();
6666
return O.orElse(checkIteratorElement(node.left), () => checkIteratorElement(node.right));

packages/utilities/ast/src/to-readable-node-name.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,10 @@ import { AST_NODE_TYPES } from "@typescript-eslint/types";
99
*/
1010
export function toReadableNodeName(node: TSESTree.Node, getText: (node: TSESTree.Node) => string): string {
1111
switch (node.type) {
12-
case AST_NODE_TYPES.Literal:
13-
return node.raw;
14-
case AST_NODE_TYPES.Identifier:
15-
return node.name;
16-
case AST_NODE_TYPES.MemberExpression:
17-
return `${toReadableNodeName(node.object, getText)}.${toReadableNodeName(node.property, getText)}`;
1812
case AST_NODE_TYPES.CallExpression:
1913
return toReadableNodeName(node.callee, getText);
14+
case AST_NODE_TYPES.Identifier:
15+
return node.name;
2016
case AST_NODE_TYPES.JSXIdentifier:
2117
return `<${node.name}>`;
2218
case AST_NODE_TYPES.JSXMemberExpression:
@@ -25,6 +21,10 @@ export function toReadableNodeName(node: TSESTree.Node, getText: (node: TSESTree
2521
return `${node.namespace.name}:${node.name.name}`;
2622
case AST_NODE_TYPES.JSXText:
2723
return node.value;
24+
case AST_NODE_TYPES.Literal:
25+
return node.raw;
26+
case AST_NODE_TYPES.MemberExpression:
27+
return `${toReadableNodeName(node.object, getText)}.${toReadableNodeName(node.property, getText)}`;
2828
default:
2929
return getText(node);
3030
}

packages/utilities/jsx/src/get-prop.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ export function findPropInAttributes(
133133
return getPropName(attr) === propName;
134134
case AST_NODE_TYPES.JSXSpreadAttribute:
135135
switch (attr.argument.type) {
136+
case AST_NODE_TYPES.CallExpression:
137+
// Not implemented
138+
return false;
136139
case AST_NODE_TYPES.Identifier: {
137140
const { name } = attr.argument;
138141
const maybeInit = O.flatMap(
@@ -144,14 +147,11 @@ export function findPropInAttributes(
144147
if (!AST.is(AST_NODE_TYPES.ObjectExpression)(init)) return false;
145148
return O.isSome(findPropInProperties(init.properties, initialScope)(propName));
146149
}
147-
case AST_NODE_TYPES.ObjectExpression:
148-
return O.isSome(findPropInProperties(attr.argument.properties, initialScope)(propName));
149150
case AST_NODE_TYPES.MemberExpression:
150151
// Not implemented
151152
return false;
152-
case AST_NODE_TYPES.CallExpression:
153-
// Not implemented
154-
return false;
153+
case AST_NODE_TYPES.ObjectExpression:
154+
return O.isSome(findPropInProperties(attr.argument.properties, initialScope)(propName));
155155
default:
156156
return false;
157157
}

0 commit comments

Comments
 (0)