Skip to content

Commit ac38c0c

Browse files
committed
refactor: remove duplicate code
1 parent a751054 commit ac38c0c

File tree

10 files changed

+64
-103
lines changed

10 files changed

+64
-103
lines changed

packages/core/docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
- [getComponentNameFromIdentifier](functions/getComponentNameFromIdentifier.md)
5151
- [getFunctionComponentIdentifier](functions/getFunctionComponentIdentifier.md)
5252
- [hasNoneOrValidComponentName](functions/hasNoneOrValidComponentName.md)
53+
- [isAssignmentToThisState](functions/isAssignmentToThisState.md)
5354
- [isChildrenCount](functions/isChildrenCount.md)
5455
- [isChildrenCountCall](functions/isChildrenCountCall.md)
5556
- [isChildrenForEach](functions/isChildrenForEach.md)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[**@eslint-react/core**](../README.md)
2+
3+
***
4+
5+
[@eslint-react/core](../README.md) / isAssignmentToThisState
6+
7+
# Function: isAssignmentToThisState()
8+
9+
> **isAssignmentToThisState**(`node`): `boolean`
10+
11+
## Parameters
12+
13+
### node
14+
15+
[`AssignmentExpression`](../-internal-/interfaces/AssignmentExpression.md)
16+
17+
## Returns
18+
19+
`boolean`

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,10 @@ export function isThisSetState(node: TSESTree.CallExpression) {
1313
&& callee.property.name === "setState"
1414
);
1515
}
16+
17+
export function isAssignmentToThisState(node: TSESTree.AssignmentExpression) {
18+
const { left } = node;
19+
return left.type === T.MemberExpression
20+
&& AST.isThisExpression(left.object)
21+
&& AST.getPropertyName(left.property) === "state";
22+
}

packages/plugins/eslint-plugin-react-x/src/rules/no-access-state-in-setstate.ts

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as AST from "@eslint-react/ast";
22
import { isClassComponent, isThisSetState } from "@eslint-react/core";
3-
import { _, constFalse, constTrue } from "@eslint-react/eff";
3+
import { constFalse, constTrue } from "@eslint-react/eff";
44
import type { RuleFeature } from "@eslint-react/shared";
55
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
66
import type { TSESTree } from "@typescript-eslint/utils";
@@ -32,23 +32,6 @@ function isKeyLiteral(
3232
.otherwise(constFalse);
3333
}
3434

35-
function getName(node: TSESTree.Expression | TSESTree.PrivateIdentifier): string | _ {
36-
if (AST.isTypeExpression(node)) {
37-
return getName(node.expression);
38-
}
39-
if (node.type === T.Identifier || node.type === T.PrivateIdentifier) {
40-
return node.name;
41-
}
42-
if (node.type === T.Literal) {
43-
return String(node.value);
44-
}
45-
if (node.type === T.TemplateLiteral && node.expressions.length === 0) {
46-
return node.quasis[0]?.value.raw;
47-
}
48-
49-
return _;
50-
}
51-
5235
export default createRule<[], MessageID>({
5336
meta: {
5437
type: "problem",
@@ -119,7 +102,7 @@ export default createRule<[], MessageID>({
119102
if (setState == null || hasThisState) {
120103
return;
121104
}
122-
if (getName(node.property) !== "state") {
105+
if (AST.getPropertyName(node.property) !== "state") {
123106
return;
124107
}
125108
context.report({ messageId: "noAccessStateInSetstate", node });
@@ -159,7 +142,7 @@ export default createRule<[], MessageID>({
159142
.some((prop) =>
160143
prop.type === T.Property
161144
&& isKeyLiteral(prop, prop.key)
162-
&& getName(prop.key) === "state"
145+
&& AST.getPropertyName(prop.key) === "state"
163146
);
164147
if (!hasState) {
165148
return;

packages/plugins/eslint-plugin-react-x/src/rules/no-direct-mutation-state.ts

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as AST from "@eslint-react/ast";
2-
import { isClassComponent } from "@eslint-react/core";
3-
import { _ } from "@eslint-react/eff";
2+
import { isAssignmentToThisState, isClassComponent } from "@eslint-react/core";
43
import type { RuleFeature } from "@eslint-react/shared";
54
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
65
import type { TSESTree } from "@typescript-eslint/utils";
@@ -16,33 +15,6 @@ export const RULE_FEATURES = [
1615

1716
export type MessageID = CamelCase<typeof RULE_NAME>;
1817

19-
function getName(node: TSESTree.Expression | TSESTree.PrivateIdentifier): string | _ {
20-
if (AST.isTypeExpression(node)) {
21-
return getName(node.expression);
22-
}
23-
if (node.type === T.Identifier || node.type === T.PrivateIdentifier) {
24-
return node.name;
25-
}
26-
if (node.type === T.Literal) {
27-
return node.value?.toString();
28-
}
29-
if (node.type === T.TemplateLiteral && node.expressions.length === 0) {
30-
return node.quasis[0]?.value.raw;
31-
}
32-
33-
return _;
34-
}
35-
36-
function isAssignmentToThisState(node: TSESTree.AssignmentExpression) {
37-
const { left } = node;
38-
39-
return (
40-
left.type === T.MemberExpression
41-
&& AST.isThisExpression(left.object)
42-
&& getName(left.property) === "state"
43-
);
44-
}
45-
4618
function isConstructorFunction(
4719
node: TSESTree.Node,
4820
): node is TSESTree.FunctionDeclaration | TSESTree.FunctionExpression {

packages/plugins/eslint-plugin-react-x/src/rules/no-unused-class-component-members.ts

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as AST from "@eslint-react/ast";
22
import { isClassComponent } from "@eslint-react/core";
3-
import { _, constFalse, constTrue } from "@eslint-react/eff";
3+
import { constFalse, constTrue } from "@eslint-react/eff";
44
import type { RuleFeature } from "@eslint-react/shared";
55
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
66
import type { TSESTree } from "@typescript-eslint/utils";
@@ -54,26 +54,6 @@ function isKeyLiteral(
5454
.otherwise(constFalse);
5555
}
5656

57-
// Return the name of an identifier or the string value of a literal. Useful
58-
// anywhere that a literal may be used as a key (e.g., member expressions,
59-
// method definitions, ObjectExpression property keys).
60-
function getName(node: TSESTree.Expression | TSESTree.PrivateIdentifier): string | _ {
61-
if (AST.isTypeExpression(node)) {
62-
return getName(node.expression);
63-
}
64-
if (node.type === T.Identifier || node.type === T.PrivateIdentifier) {
65-
return node.name;
66-
}
67-
if (node.type === T.Literal) {
68-
return node.value?.toString();
69-
}
70-
if (node.type === T.TemplateLiteral && node.expressions.length === 0) {
71-
return node.quasis[0]?.value.raw;
72-
}
73-
74-
return _;
75-
}
76-
7757
export default createRule<[], MessageID>({
7858
meta: {
7959
type: "problem",
@@ -112,7 +92,7 @@ export default createRule<[], MessageID>({
11292
return;
11393
}
11494
for (const def of defs) {
115-
const methodName = getName(def);
95+
const methodName = AST.getPropertyName(def);
11696
if (methodName == null) {
11797
continue;
11898
}
@@ -170,7 +150,7 @@ export default createRule<[], MessageID>({
170150
return;
171151
}
172152
// detect `this.property()`, `x = this.property`, etc.
173-
const propertyName = getName(node.property);
153+
const propertyName = AST.getPropertyName(node.property);
174154
if (propertyName != null) {
175155
propertyUsages.get(currentClass)?.add(propertyName);
176156
}
@@ -192,7 +172,7 @@ export default createRule<[], MessageID>({
192172
if (node.init != null && AST.isThisExpression(node.init) && node.id.type === T.ObjectPattern) {
193173
for (const prop of node.id.properties) {
194174
if (prop.type === T.Property && isKeyLiteral(prop, prop.key)) {
195-
const keyName = getName(prop.key);
175+
const keyName = AST.getPropertyName(prop.key);
196176
if (keyName != null) {
197177
propertyUsages.get(currentClass)?.add(keyName);
198178
}

packages/plugins/eslint-plugin-react-x/src/rules/no-unused-state.ts

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as AST from "@eslint-react/ast";
2-
import { isClassComponent, isGetDerivedStateFromProps } from "@eslint-react/core";
3-
import { _, constFalse, constTrue } from "@eslint-react/eff";
2+
import { isAssignmentToThisState, isClassComponent, isGetDerivedStateFromProps } from "@eslint-react/core";
3+
import type { _ } from "@eslint-react/eff";
4+
import { constFalse, constTrue } from "@eslint-react/eff";
45
import type { RuleFeature } from "@eslint-react/shared";
56
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
67
import type { TSESTree } from "@typescript-eslint/utils";
@@ -32,31 +33,6 @@ function isKeyLiteral(
3233
.otherwise(constFalse);
3334
}
3435

35-
function getName(node: TSESTree.Expression | TSESTree.PrivateIdentifier): string | _ {
36-
if (AST.isTypeExpression(node)) {
37-
return getName(node.expression);
38-
}
39-
if (node.type === T.Identifier || node.type === T.PrivateIdentifier) {
40-
return node.name;
41-
}
42-
if (node.type === T.Literal) {
43-
return String(node.value);
44-
}
45-
if (node.type === T.TemplateLiteral && node.expressions.length === 0) {
46-
return node.quasis[0]?.value.raw;
47-
}
48-
49-
return _;
50-
}
51-
52-
function isAssignmentToThisState(node: TSESTree.AssignmentExpression) {
53-
const { left } = node;
54-
55-
return left.type === T.MemberExpression
56-
&& AST.isThisExpression(left.object)
57-
&& getName(left.property) === "state";
58-
}
59-
6036
export default createRule<[], MessageID>({
6137
meta: {
6238
type: "problem",
@@ -109,7 +85,7 @@ export default createRule<[], MessageID>({
10985
}
11086
return;
11187
}
112-
if (getName(node.key) === "state") {
88+
if (AST.getPropertyName(node.key) === "state") {
11389
stateDefs.set(currentClass, { node: node.key, isUsed: false });
11490
}
11591
}
@@ -148,7 +124,7 @@ export default createRule<[], MessageID>({
148124
return;
149125
}
150126
// detect `this.state`
151-
if (getName(node.property) !== "state") {
127+
if (AST.getPropertyName(node.property) !== "state") {
152128
return;
153129
}
154130
const currentClass = classEntries.at(-1);
@@ -195,7 +171,7 @@ export default createRule<[], MessageID>({
195171
}
196172
const hasState = node.id.properties.some((prop) => {
197173
if (prop.type === T.Property && isKeyLiteral(prop, prop.key)) {
198-
return getName(prop.key) === "state";
174+
return AST.getPropertyName(prop.key) === "state";
199175
}
200176
return false;
201177
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { _ } from "@eslint-react/eff";
2+
import { AST_NODE_TYPES as T, type TSESTree } from "@typescript-eslint/types";
3+
4+
import { getEcmaExpression } from "./get-ecma-expression";
5+
import { isTypeExpression } from "./is";
6+
7+
export function getPropertyName(node: TSESTree.Node): string | _ {
8+
if (isTypeExpression(node)) {
9+
return getPropertyName(getEcmaExpression(node));
10+
}
11+
if (node.type === T.Identifier || node.type === T.PrivateIdentifier) {
12+
return node.name;
13+
}
14+
if (node.type === T.Literal) {
15+
return String(node.value);
16+
}
17+
if (node.type === T.TemplateLiteral && node.expressions.length === 0) {
18+
return node.quasis[0]?.value.raw;
19+
}
20+
return _;
21+
}

packages/utilities/ast/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export * from "./get-literal-value-type";
77
export * from "./get-nested-expressions";
88
export * from "./get-nested-identifiers";
99
export * from "./get-nested-return-statements";
10+
export * from "./get-property-name";
1011
export * from "./get-top-level-identifier";
1112
export * from "./is";
1213
export * from "./is-empty-function";

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export function toReadableNodeName(node: TSESTree.Node, getText: (node: TSESTree
1212
case T.CallExpression:
1313
return toReadableNodeName(node.callee, getText);
1414
case T.Identifier:
15+
case T.PrivateIdentifier:
1516
return node.name;
1617
case T.JSXIdentifier:
1718
return `<${node.name}>`;

0 commit comments

Comments
 (0)