diff --git a/packages/core/docs/README.md b/packages/core/docs/README.md index 73c54f2094..1d676a6edf 100644 --- a/packages/core/docs/README.md +++ b/packages/core/docs/README.md @@ -95,19 +95,28 @@ - [isClassComponent](functions/isClassComponent.md) - [isComponentDidCatch](functions/isComponentDidCatch.md) - [isComponentDidMount](functions/isComponentDidMount.md) +- [isComponentDidUpdate](functions/isComponentDidUpdate.md) - [isComponentName](functions/isComponentName.md) - [isComponentNameLoose](functions/isComponentNameLoose.md) +- [isComponentWillMount](functions/isComponentWillMount.md) +- [isComponentWillReceiveProps](functions/isComponentWillReceiveProps.md) - [isComponentWillUnmount](functions/isComponentWillUnmount.md) +- [isComponentWillUpdate](functions/isComponentWillUpdate.md) - [isComponentWrapperCall](functions/isComponentWrapperCall.md) - [isComponentWrapperCallLoose](functions/isComponentWrapperCallLoose.md) - [isDeclaredInRenderPropLoose](functions/isDeclaredInRenderPropLoose.md) - [isFunctionOfComponentDidMount](functions/isFunctionOfComponentDidMount.md) - [isFunctionOfComponentWillUnmount](functions/isFunctionOfComponentWillUnmount.md) +- [isFunctionOfRender](functions/isFunctionOfRender.md) - [isFunctionOfRenderMethod](functions/isFunctionOfRenderMethod.md) - [isFunctionOfUseEffectCleanup](functions/isFunctionOfUseEffectCleanup.md) - [isFunctionOfUseEffectSetup](functions/isFunctionOfUseEffectSetup.md) +- [isGetChildContext](functions/isGetChildContext.md) +- [isGetDefaultProps](functions/isGetDefaultProps.md) - [isGetDerivedStateFromError](functions/isGetDerivedStateFromError.md) - [isGetDerivedStateFromProps](functions/isGetDerivedStateFromProps.md) +- [isGetInitialState](functions/isGetInitialState.md) +- [isGetSnapshotBeforeUpdate](functions/isGetSnapshotBeforeUpdate.md) - [isInitializedFromReact](functions/isInitializedFromReact.md) - [isInsideRenderMethod](functions/isInsideRenderMethod.md) - [isPureComponent](functions/isPureComponent.md) @@ -121,9 +130,14 @@ - [isReactHookName](functions/isReactHookName.md) - [isReactHookNameLoose](functions/isReactHookNameLoose.md) - [isRenderFunctionLoose](functions/isRenderFunctionLoose.md) +- [isRenderLike](functions/isRenderLike.md) - [isRenderMethodLike](functions/isRenderMethodLike.md) - [isRenderPropLoose](functions/isRenderPropLoose.md) +- [isShouldComponentUpdate](functions/isShouldComponentUpdate.md) - [isThisSetState](functions/isThisSetState.md) +- [isUnsafeComponentWillMount](functions/isUnsafeComponentWillMount.md) +- [isUnsafeComponentWillReceiveProps](functions/isUnsafeComponentWillReceiveProps.md) +- [isUnsafeComponentWillUpdate](functions/isUnsafeComponentWillUpdate.md) - [isUseEffectCallLoose](functions/isUseEffectCallLoose.md) - [isValidComponentDefinition](functions/isValidComponentDefinition.md) - [useComponentCollector](functions/useComponentCollector.md) diff --git a/packages/core/docs/functions/isComponentDidUpdate.md b/packages/core/docs/functions/isComponentDidUpdate.md new file mode 100644 index 0000000000..50e89919b2 --- /dev/null +++ b/packages/core/docs/functions/isComponentDidUpdate.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isComponentDidUpdate + +# Function: isComponentDidUpdate() + +> **isComponentDidUpdate**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isComponentWillMount.md b/packages/core/docs/functions/isComponentWillMount.md new file mode 100644 index 0000000000..a99ad58fec --- /dev/null +++ b/packages/core/docs/functions/isComponentWillMount.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isComponentWillMount + +# Function: isComponentWillMount() + +> **isComponentWillMount**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isComponentWillReceiveProps.md b/packages/core/docs/functions/isComponentWillReceiveProps.md new file mode 100644 index 0000000000..958ebc220f --- /dev/null +++ b/packages/core/docs/functions/isComponentWillReceiveProps.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isComponentWillReceiveProps + +# Function: isComponentWillReceiveProps() + +> **isComponentWillReceiveProps**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isComponentWillUpdate.md b/packages/core/docs/functions/isComponentWillUpdate.md new file mode 100644 index 0000000000..cf85eb66b0 --- /dev/null +++ b/packages/core/docs/functions/isComponentWillUpdate.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isComponentWillUpdate + +# Function: isComponentWillUpdate() + +> **isComponentWillUpdate**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isFunctionOfRender.md b/packages/core/docs/functions/isFunctionOfRender.md new file mode 100644 index 0000000000..101137ec8e --- /dev/null +++ b/packages/core/docs/functions/isFunctionOfRender.md @@ -0,0 +1,32 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isFunctionOfRender + +# Function: isFunctionOfRender() + +> **isFunctionOfRender**(`node`): `boolean` + +Check whether given node is a function of a render function of a class component + +## Parameters + +### node + +`TSESTreeFunction` + +The AST node to check + +## Returns + +`boolean` + +`true` if node is a render function, `false` if not + +## Example + +```tsx +class Component extends React.Component { + render = () =>
; +``` diff --git a/packages/core/docs/functions/isFunctionOfRenderMethod.md b/packages/core/docs/functions/isFunctionOfRenderMethod.md index 928679d5ad..159ad67b0c 100644 --- a/packages/core/docs/functions/isFunctionOfRenderMethod.md +++ b/packages/core/docs/functions/isFunctionOfRenderMethod.md @@ -8,12 +8,27 @@ > **isFunctionOfRenderMethod**(`node`): `boolean` +Check whether given node is a function of a render method of a class component + ## Parameters ### node `TSESTreeFunction` +The AST node to check + ## Returns `boolean` + +`true` if node is a render function, `false` if not + +## Example + +```tsx +class Component extends React.Component { + renderHeader = () => ; + renderFooter = () => ; +} +``` diff --git a/packages/core/docs/functions/isGetChildContext.md b/packages/core/docs/functions/isGetChildContext.md new file mode 100644 index 0000000000..bbd8d27eed --- /dev/null +++ b/packages/core/docs/functions/isGetChildContext.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isGetChildContext + +# Function: isGetChildContext() + +> **isGetChildContext**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isGetDefaultProps.md b/packages/core/docs/functions/isGetDefaultProps.md new file mode 100644 index 0000000000..f6e18a39b2 --- /dev/null +++ b/packages/core/docs/functions/isGetDefaultProps.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isGetDefaultProps + +# Function: isGetDefaultProps() + +> **isGetDefaultProps**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isGetInitialState.md b/packages/core/docs/functions/isGetInitialState.md new file mode 100644 index 0000000000..47dbcf4cde --- /dev/null +++ b/packages/core/docs/functions/isGetInitialState.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isGetInitialState + +# Function: isGetInitialState() + +> **isGetInitialState**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isGetSnapshotBeforeUpdate.md b/packages/core/docs/functions/isGetSnapshotBeforeUpdate.md new file mode 100644 index 0000000000..c631b21d36 --- /dev/null +++ b/packages/core/docs/functions/isGetSnapshotBeforeUpdate.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isGetSnapshotBeforeUpdate + +# Function: isGetSnapshotBeforeUpdate() + +> **isGetSnapshotBeforeUpdate**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isRenderLike.md b/packages/core/docs/functions/isRenderLike.md new file mode 100644 index 0000000000..e70b29348f --- /dev/null +++ b/packages/core/docs/functions/isRenderLike.md @@ -0,0 +1,35 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isRenderLike + +# Function: isRenderLike() + +> **isRenderLike**(`node`): `node is TSESTreeMethodOrProperty` + +Check whether given node is a render function of a class component + +## Parameters + +### node + +`Node` + +The AST node to check + +## Returns + +`node is TSESTreeMethodOrProperty` + +`true` if node is a render function, `false` if not + +## Example + +```tsx +class Component extends React.Component { + render() { + return ; + } +} +``` diff --git a/packages/core/docs/functions/isRenderMethodLike.md b/packages/core/docs/functions/isRenderMethodLike.md index 84454afac0..48750271a5 100644 --- a/packages/core/docs/functions/isRenderMethodLike.md +++ b/packages/core/docs/functions/isRenderMethodLike.md @@ -8,12 +8,27 @@ > **isRenderMethodLike**(`node`): `node is TSESTreeMethodOrProperty` +Check whether given node is a render method of a class component + ## Parameters ### node `Node` +The AST node to check + ## Returns `node is TSESTreeMethodOrProperty` + +`true` if node is a render function, `false` if not + +## Example + +```tsx +class Component extends React.Component { + renderHeader = () => ; + renderFooter = () => ; +} +``` diff --git a/packages/core/docs/functions/isShouldComponentUpdate.md b/packages/core/docs/functions/isShouldComponentUpdate.md new file mode 100644 index 0000000000..c7889a76d9 --- /dev/null +++ b/packages/core/docs/functions/isShouldComponentUpdate.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isShouldComponentUpdate + +# Function: isShouldComponentUpdate() + +> **isShouldComponentUpdate**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isUnsafeComponentWillMount.md b/packages/core/docs/functions/isUnsafeComponentWillMount.md new file mode 100644 index 0000000000..4c016983ab --- /dev/null +++ b/packages/core/docs/functions/isUnsafeComponentWillMount.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isUnsafeComponentWillMount + +# Function: isUnsafeComponentWillMount() + +> **isUnsafeComponentWillMount**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isUnsafeComponentWillReceiveProps.md b/packages/core/docs/functions/isUnsafeComponentWillReceiveProps.md new file mode 100644 index 0000000000..19dc7162b7 --- /dev/null +++ b/packages/core/docs/functions/isUnsafeComponentWillReceiveProps.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isUnsafeComponentWillReceiveProps + +# Function: isUnsafeComponentWillReceiveProps() + +> **isUnsafeComponentWillReceiveProps**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/docs/functions/isUnsafeComponentWillUpdate.md b/packages/core/docs/functions/isUnsafeComponentWillUpdate.md new file mode 100644 index 0000000000..2aade9ddcc --- /dev/null +++ b/packages/core/docs/functions/isUnsafeComponentWillUpdate.md @@ -0,0 +1,19 @@ +[**@eslint-react/core**](../README.md) + +*** + +[@eslint-react/core](../README.md) / isUnsafeComponentWillUpdate + +# Function: isUnsafeComponentWillUpdate() + +> **isUnsafeComponentWillUpdate**(`node`): `node is TSESTreeMethodOrProperty` + +## Parameters + +### node + +`Node` + +## Returns + +`node is TSESTreeMethodOrProperty` diff --git a/packages/core/src/component/component-definition.ts b/packages/core/src/component/component-definition.ts index 7b63c74518..7761e86a90 100644 --- a/packages/core/src/component/component-definition.ts +++ b/packages/core/src/component/component-definition.ts @@ -4,8 +4,7 @@ import { type RuleContext } from "@eslint-react/kit"; import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; import { isMatching, P } from "ts-pattern"; import { ComponentDetectionHint } from "./component-detection-hint"; -import { isFunctionOfRenderMethod } from "./component-lifecycle"; -import { isChildrenOfCreateElement } from "./hierarchy"; +import { isChildrenOfCreateElement, isFunctionOfRenderMethod } from "./hierarchy"; const isFunctionOfClassMethod = isMatching({ type: P.union(T.ArrowFunctionExpression, T.FunctionExpression), diff --git a/packages/core/src/component/component-lifecycle.ts b/packages/core/src/component/component-lifecycle.ts index a92caccbc3..032666b9df 100644 --- a/packages/core/src/component/component-lifecycle.ts +++ b/packages/core/src/component/component-lifecycle.ts @@ -2,64 +2,121 @@ import type { TSESTree } from "@typescript-eslint/types"; import * as AST from "@eslint-react/ast"; import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; -import { isClassComponent } from "./is"; +export function isComponentDidCatch(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "componentDidCatch"; +} export function isComponentDidMount(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { return AST.isMethodOrProperty(node) + && !node.static && node.key.type === T.Identifier && node.key.name === "componentDidMount"; } +export function isComponentDidUpdate(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "componentDidUpdate"; +} + +export function isComponentWillMount(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "componentWillMount"; +} + +export function isComponentWillReceiveProps(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "componentWillReceiveProps"; +} + export function isComponentWillUnmount(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { return AST.isMethodOrProperty(node) + && !node.static && node.key.type === T.Identifier && node.key.name === "componentWillUnmount"; } -export function isComponentDidCatch(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { +export function isComponentWillUpdate(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { return AST.isMethodOrProperty(node) && !node.static && node.key.type === T.Identifier - && node.key.name === "componentDidCatch"; + && node.key.name === "componentWillUpdate"; } -export function isGetDerivedStateFromError(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { +export function isGetChildContext(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { return AST.isMethodOrProperty(node) - && node.static + && !node.static && node.key.type === T.Identifier - && node.key.name === "getDerivedStateFromError"; + && node.key.name === "getChildContext"; } -export function isGetDerivedStateFromProps(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { +export function isGetDefaultProps(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { return AST.isMethodOrProperty(node) && node.static && node.key.type === T.Identifier - && node.key.name === "getDerivedStateFromProps"; + && node.key.name === "getDefaultProps"; +} + +export function isGetInitialState(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "getInitialState"; +} + +export function isGetSnapshotBeforeUpdate(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "getSnapshotBeforeUpdate"; +} + +export function isShouldComponentUpdate(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "shouldComponentUpdate"; } -export function isFunctionOfComponentDidMount(node: TSESTree.Node) { - return AST.isFunction(node) - && isComponentDidMount(node.parent) - && node.parent.value === node; +export function isUnsafeComponentWillMount(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "UNSAFE_componentWillMount"; } -export function isFunctionOfComponentWillUnmount(node: TSESTree.Node) { - return AST.isFunction(node) - && isComponentWillUnmount(node.parent) - && node.parent.value === node; +export function isUnsafeComponentWillReceiveProps(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && !node.static + && node.key.type === T.Identifier + && node.key.name === "UNSAFE_componentWillReceiveProps"; } -export function isRenderMethodLike(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { +export function isUnsafeComponentWillUpdate(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { return AST.isMethodOrProperty(node) + && !node.static && node.key.type === T.Identifier - && node.key.name === "render" - && node.parent.parent.type === T.ClassDeclaration; + && node.key.name === "UNSAFE_componentWillUpdate"; } -export function isFunctionOfRenderMethod(node: AST.TSESTreeFunction) { - if (!isRenderMethodLike(node.parent)) { - return false; - } +export function isGetDerivedStateFromProps(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && node.static + && node.key.type === T.Identifier + && node.key.name === "getDerivedStateFromProps"; +} - return isClassComponent(node.parent.parent.parent); +export function isGetDerivedStateFromError(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && node.static + && node.key.type === T.Identifier + && node.key.name === "getDerivedStateFromError"; } diff --git a/packages/core/src/component/component-render-method.ts b/packages/core/src/component/component-render-method.ts new file mode 100644 index 0000000000..1af98beb99 --- /dev/null +++ b/packages/core/src/component/component-render-method.ts @@ -0,0 +1,22 @@ +import type { TSESTree } from "@typescript-eslint/types"; +import * as AST from "@eslint-react/ast"; +import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; + +/** + * Check whether given node is a render method of a class component + * @example + * ```tsx + * class Component extends React.Component { + * renderHeader = () => ; + * renderFooter = () => ; + * } + * ``` + * @param node The AST node to check + * @returns `true` if node is a render function, `false` if not + */ +export function isRenderMethodLike(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && node.key.type === T.Identifier + && node.key.name.startsWith("render") + && node.parent.parent.type === T.ClassDeclaration; +} diff --git a/packages/core/src/component/component-render.ts b/packages/core/src/component/component-render.ts new file mode 100644 index 0000000000..80072aeada --- /dev/null +++ b/packages/core/src/component/component-render.ts @@ -0,0 +1,43 @@ +import type { TSESTree } from "@typescript-eslint/types"; +import * as AST from "@eslint-react/ast"; +import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; + +import { isClassComponent } from "./is"; + +/** + * Check whether given node is a render function of a class component + * @example + * ```tsx + * class Component extends React.Component { + * render() { + * return ; + * } + * } + * ``` + * @param node The AST node to check + * @returns `true` if node is a render function, `false` if not + */ +export function isRenderLike(node: TSESTree.Node): node is AST.TSESTreeMethodOrProperty { + return AST.isMethodOrProperty(node) + && node.key.type === T.Identifier + && node.key.name === "render" + && node.parent.parent.type === T.ClassDeclaration; +} + +/** + * Check whether given node is a function of a render function of a class component + * @example + * ```tsx + * class Component extends React.Component { + * render = () => ; + * ``` + * @param node The AST node to check + * @returns `true` if node is a render function, `false` if not + */ +export function isFunctionOfRender(node: AST.TSESTreeFunction) { + if (!isRenderLike(node.parent)) { + return false; + } + + return isClassComponent(node.parent.parent.parent); +} diff --git a/packages/core/src/component/hierarchy.ts b/packages/core/src/component/hierarchy.ts index 32d8ad2fe4..611de781a6 100644 --- a/packages/core/src/component/hierarchy.ts +++ b/packages/core/src/component/hierarchy.ts @@ -4,7 +4,9 @@ import { type RuleContext } from "@eslint-react/kit"; import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; import { isCreateElementCall } from "../utils"; -import { isRenderMethodLike } from "./component-lifecycle"; +import { isComponentDidMount, isComponentWillUnmount } from "./component-lifecycle"; +import { isRenderLike } from "./component-render"; +import { isRenderMethodLike } from "./component-render-method"; import { isClassComponent } from "./is"; /** @@ -38,5 +40,37 @@ export function isChildrenOfCreateElement(context: RuleContext, node: TSESTree.N * @returns `true` if node is inside class component's render block, `false` if not */ export function isInsideRenderMethod(node: TSESTree.Node) { - return AST.findParentNode(node, (n) => isRenderMethodLike(n) && isClassComponent(n.parent.parent)) != null; + return AST.findParentNode(node, (n) => isRenderLike(n) && isClassComponent(n.parent.parent)) != null; +} + +export function isFunctionOfComponentDidMount(node: TSESTree.Node) { + return AST.isFunction(node) + && isComponentDidMount(node.parent) + && node.parent.value === node; +} + +export function isFunctionOfComponentWillUnmount(node: TSESTree.Node) { + return AST.isFunction(node) + && isComponentWillUnmount(node.parent) + && node.parent.value === node; +} + +/** + * Check whether given node is a function of a render method of a class component + * @example + * ```tsx + * class Component extends React.Component { + * renderHeader = () => ; + * renderFooter = () => ; + * } + * ``` + * @param node The AST node to check + * @returns `true` if node is a render function, `false` if not + */ +export function isFunctionOfRenderMethod(node: AST.TSESTreeFunction) { + if (!isRenderMethodLike(node.parent)) { + return false; + } + + return isClassComponent(node.parent.parent.parent); } diff --git a/packages/core/src/component/index.ts b/packages/core/src/component/index.ts index d9f4e58b5b..3bdaa05f41 100644 --- a/packages/core/src/component/index.ts +++ b/packages/core/src/component/index.ts @@ -9,6 +9,8 @@ export type * from "./component-kind"; export * from "./component-lifecycle"; export * from "./component-name"; export * from "./component-phase"; +export * from "./component-render"; +export * from "./component-render-method"; export * from "./component-render-prop"; export type * from "./component-semantic-node"; export * from "./component-state"; diff --git a/packages/core/src/effect/index.ts b/packages/core/src/effect/index.ts index 6b21c480da..6c74d535ed 100644 --- a/packages/core/src/effect/index.ts +++ b/packages/core/src/effect/index.ts @@ -1,2 +1 @@ export type * from "./effect-kind"; -export * from "./is"; diff --git a/packages/core/src/effect/is.ts b/packages/core/src/hook/hierarchy.ts similarity index 95% rename from packages/core/src/effect/is.ts rename to packages/core/src/hook/hierarchy.ts index 5efaa3df1d..2cc3ee0642 100644 --- a/packages/core/src/effect/is.ts +++ b/packages/core/src/hook/hierarchy.ts @@ -2,8 +2,7 @@ import type { _ } from "@eslint-react/eff"; import type { TSESTree } from "@typescript-eslint/types"; import * as AST from "@eslint-react/ast"; import { AST_NODE_TYPES as T } from "@typescript-eslint/types"; - -import { isUseEffectCallLoose } from "../hook"; +import { isUseEffectCallLoose } from "./is"; export function isFunctionOfUseEffectSetup(node: TSESTree.Node | _) { if (node == null) return false; diff --git a/packages/core/src/hook/index.ts b/packages/core/src/hook/index.ts index 74507b5c9f..822a4fd297 100644 --- a/packages/core/src/hook/index.ts +++ b/packages/core/src/hook/index.ts @@ -1,3 +1,4 @@ +export * from "./hierarchy"; export * from "./hook-collector"; export type * from "./hook-kind"; export * from "./hook-name"; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 8b12f171a1..e561220a50 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,6 +1,6 @@ export * from "./component"; export * from "./constants"; -export * from "./effect"; +export type * from "./effect"; export * from "./hook"; export type * from "./semantic-entry"; export type * from "./semantic-node";