Skip to content

Commit 724f2b6

Browse files
committed
refactor: simplify utility functions
1 parent 6e71499 commit 724f2b6

23 files changed

+157
-199
lines changed

packages/core/docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
- [getComponentNameFromIdentifier](functions/getComponentNameFromIdentifier.md)
5353
- [getFunctionComponentIdentifier](functions/getFunctionComponentIdentifier.md)
5454
- [hasNoneOrValidComponentName](functions/hasNoneOrValidComponentName.md)
55+
- [hasValidHierarchy](functions/hasValidHierarchy.md)
5556
- [isCallFromReact](functions/isCallFromReact.md)
5657
- [isCallFromReactMember](functions/isCallFromReactMember.md)
5758
- [isChildrenCount](functions/isChildrenCount.md)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[**@eslint-react/core**](../README.md)
2+
3+
***
4+
5+
[@eslint-react/core](../README.md) / hasValidHierarchy
6+
7+
# Function: hasValidHierarchy()
8+
9+
> **hasValidHierarchy**(`node`, `context`, `hint`): `boolean`
10+
11+
internal
12+
13+
## Parameters
14+
15+
### node
16+
17+
[`TSESTreeFunction`](../-internal-/type-aliases/TSESTreeFunction.md)
18+
19+
### context
20+
21+
[`Readonly`](../-internal-/type-aliases/Readonly.md)
22+
23+
### hint
24+
25+
`bigint`
26+
27+
## Returns
28+
29+
`boolean`

packages/core/src/component/component-collector.ts

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ import type { TSESTree } from "@typescript-eslint/types";
77
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
88
import type { ESLintUtils } from "@typescript-eslint/utils";
99

10-
import { isChildrenOfCreateElement } from "../element";
1110
import { isReactHookCall } from "../hook";
1211
import { DISPLAY_NAME_ASSIGNMENT_SELECTOR } from "../utils";
13-
import { DEFAULT_COMPONENT_HINT, ERComponentHint } from "./component-collector-hint";
12+
import { DEFAULT_COMPONENT_HINT } from "./component-collector-hint";
1413
import { ERComponentFlag } from "./component-flag";
1514
import { getFunctionComponentIdentifier } from "./component-id";
16-
import { isFunctionOfRenderMethod } from "./component-lifecycle";
1715
import { getComponentNameFromIdentifier, hasNoneOrValidComponentName } from "./component-name";
1816
import type { ERFunctionComponent } from "./component-semantic-node";
17+
import { hasValidHierarchy } from "./hierarchy";
1918

2019
type FunctionEntry = {
2120
key: string;
@@ -172,35 +171,6 @@ export function useComponentCollector(
172171
return { ctx, listeners } as const;
173172
}
174173

175-
function hasValidHierarchy(node: AST.TSESTreeFunction, context: RuleContext, hint: bigint) {
176-
if (isChildrenOfCreateElement(node, context) || isFunctionOfRenderMethod(node)) {
177-
return false;
178-
}
179-
if (hint & ERComponentHint.SkipMapCallback && AST.isMapCallLoose(node.parent)) {
180-
return false;
181-
}
182-
if (hint & ERComponentHint.SkipObjectMethod && AST.isFunctionOfObjectMethod(node.parent)) {
183-
return false;
184-
}
185-
if (hint & ERComponentHint.SkipClassMethod && AST.isFunctionOfClassMethod(node.parent)) {
186-
return false;
187-
}
188-
if (hint & ERComponentHint.SkipClassProperty && AST.isFunctionOfClassProperty(node.parent)) {
189-
return false;
190-
}
191-
const boundaryNode = AST.findParentNode(
192-
node,
193-
AST.isOneOf([
194-
T.JSXExpressionContainer,
195-
T.ArrowFunctionExpression,
196-
T.FunctionExpression,
197-
T.Property,
198-
T.ClassBody,
199-
]),
200-
);
201-
return boundaryNode == null || boundaryNode.type !== T.JSXExpressionContainer;
202-
}
203-
204174
function getComponentFlag(initPath: ERFunctionComponent["initPath"]) {
205175
let flag = ERComponentFlag.None;
206176
if (initPath != null && AST.hasCallInFunctionInitPath("memo", initPath)) {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* eslint-disable jsdoc/require-param */
2+
import * as AST from "@eslint-react/ast";
3+
import { type RuleContext } from "@eslint-react/shared";
4+
import type { TSESTree } from "@typescript-eslint/types";
5+
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
6+
7+
import { isChildrenOfCreateElement } from "../element";
8+
import { ERComponentHint } from "./component-collector-hint";
9+
import { isFunctionOfRenderMethod } from "./component-lifecycle";
10+
11+
/** internal */
12+
export function hasValidHierarchy(node: AST.TSESTreeFunction, context: RuleContext, hint: bigint) {
13+
if (isChildrenOfCreateElement(node, context) || isFunctionOfRenderMethod(node)) {
14+
return false;
15+
}
16+
if (hint & ERComponentHint.SkipMapCallback && AST.isMapCallLoose(node.parent)) {
17+
return false;
18+
}
19+
if (hint & ERComponentHint.SkipObjectMethod && isFunctionOfObjectMethod(node.parent)) {
20+
return false;
21+
}
22+
if (hint & ERComponentHint.SkipClassMethod && isFunctionOfClassMethod(node.parent)) {
23+
return false;
24+
}
25+
if (hint & ERComponentHint.SkipClassProperty && isFunctionOfClassProperty(node.parent)) {
26+
return false;
27+
}
28+
const boundaryNode = AST.findParentNode(
29+
node,
30+
AST.isOneOf([
31+
T.JSXExpressionContainer,
32+
T.ArrowFunctionExpression,
33+
T.FunctionExpression,
34+
T.Property,
35+
T.ClassBody,
36+
]),
37+
);
38+
return boundaryNode == null || boundaryNode.type !== T.JSXExpressionContainer;
39+
}
40+
41+
function isFunctionOfClassMethod(node: TSESTree.Node): node is
42+
| TSESTree.ArrowFunctionExpression
43+
| TSESTree.FunctionExpression
44+
{
45+
return (node.type === T.FunctionExpression || node.type === T.ArrowFunctionExpression)
46+
&& node.parent.type === T.MethodDefinition;
47+
}
48+
49+
function isFunctionOfClassProperty(node: TSESTree.Node): node is
50+
| TSESTree.ArrowFunctionExpression
51+
| TSESTree.FunctionExpression
52+
{
53+
return (node.type === T.FunctionExpression || node.type === T.ArrowFunctionExpression)
54+
&& node.parent.type === T.Property;
55+
}
56+
57+
function isFunctionOfObjectMethod(node: TSESTree.Node) {
58+
return (node.type === T.FunctionExpression || node.type === T.ArrowFunctionExpression)
59+
&& node.parent.type === T.Property
60+
&& node.parent.parent.type === T.ObjectExpression;
61+
}

packages/core/src/component/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ export * from "./component-phase";
1010
export * from "./component-render-prop";
1111
export type * from "./component-semantic-node";
1212
export * from "./component-state";
13+
export * from "./hierarchy";
1314
export * from "./is";

packages/core/src/utils/is-initialized-from-react.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function isInitializedFromReact(
4949
// check for: `variable = require('source')` or `variable = require('source').variable`
5050
const args = getRequireExpressionArguments(init);
5151
const arg0 = args?.[0];
52-
if (arg0 == null || !AST.isStringLiteral(arg0)) {
52+
if (arg0 == null || !AST.isKindOfLiteral(arg0, "string")) {
5353
return false;
5454
}
5555
// check for: `require('source')` or `require('source/...')`

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { match } from "ts-pattern";
1313
import {
1414
createRule,
1515
isFromUseStateCall,
16+
isFunctionOfImmediatelyInvoked,
1617
isSetFunctionCall,
1718
isThenCall,
1819
isVariableDeclaratorFromHookCall,
@@ -90,7 +91,7 @@ export default createRule<[], MessageID>({
9091
function getFunctionKind(node: AST.TSESTreeFunction) {
9192
return match<AST.TSESTreeFunction, FunctionKind>(node)
9293
.when(isFunctionOfUseEffectSetup, () => "setup")
93-
.when(AST.isFunctionOfImmediatelyInvoked, () => "immediate")
94+
.when(isFunctionOfImmediatelyInvoked, () => "immediate")
9495
.otherwise(() => "other");
9596
}
9697
return {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { match } from "ts-pattern";
1313
import {
1414
createRule,
1515
isFromUseStateCall,
16+
isFunctionOfImmediatelyInvoked,
1617
isSetFunctionCall,
1718
isThenCall,
1819
isVariableDeclaratorFromHookCall,
@@ -95,7 +96,7 @@ export default createRule<[], MessageID>({
9596
function getFunctionKind(node: AST.TSESTreeFunction) {
9697
return match<AST.TSESTreeFunction, FunctionKind>(node)
9798
.when(isFunctionOfUseEffectSetup, () => "setup")
98-
.when(AST.isFunctionOfImmediatelyInvoked, () => "immediate")
99+
.when(isFunctionOfImmediatelyInvoked, () => "immediate")
99100
.otherwise(() => "other");
100101
}
101102
return {

packages/plugins/eslint-plugin-react-hooks-extra/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "./create-rule";
22
export * from "./is-from-hook-call";
33
export * from "./is-from-use-state-call";
4+
export * from "./is-function-of-immediately-invoked";
45
export * from "./is-react-hook-identifier";
56
export * from "./is-set-function-call";
67
export * from "./is-then-call";

packages/utilities/ast/src/is-function-of-immediately-invoked.ts renamed to packages/plugins/eslint-plugin-react-hooks-extra/src/utils/is-function-of-immediately-invoked.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1+
import type * as AST from "@eslint-react/ast";
12
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
23

3-
import type { TSESTreeFunction } from "./types";
4-
5-
export function isFunctionOfImmediatelyInvoked(node: TSESTreeFunction): boolean {
4+
export function isFunctionOfImmediatelyInvoked(node: AST.TSESTreeFunction): boolean {
65
return node.type !== T.FunctionDeclaration
76
&& node.parent.type === T.CallExpression
87
&& node.parent.callee === node;

0 commit comments

Comments
 (0)