@@ -2,6 +2,33 @@ import { TSESTree, AST_NODE_TYPES } from "@typescript-eslint/utils";
2
2
import { Scope } from "@typescript-eslint/utils/ts-eslint" ;
3
3
import createRule from "../utils/createRule.js" ;
4
4
5
+ /**
6
+ * Rule to optimize repeated member access patterns by extracting variables
7
+ * For more rule details refer to docs/rules/no-repeated-member-access.md
8
+ *
9
+ * The following material is an overview of implementation details
10
+ * It is divided into several phases
11
+ *
12
+ * 1. Analysis Phase:
13
+ * - Traverse AST to identify member access chains (e.g., obj.prop.val)
14
+ * - Store chains into hierarchical structures (e.g., ["obj", "obj.prop", "obj.prop.val"])
15
+ * - Cache analysis results to avoid repeatedly processing
16
+ *
17
+ * 2. Tracking Phase:
18
+ * - Count usage frequency of each chain within current scope
19
+ * - Identify modified chains (assignments, increments, function calls, etc.)
20
+ * - Mark all parts alongside the chain as modified
21
+ *
22
+ * 3. Reporting Phase:
23
+ * - For chains that meet usage threshold and are not modified, suggest variable extraction
24
+ * - Report only the longest valid chains
25
+ *
26
+ * Things to note:
27
+ * - Only process chains starting with identifiers or "this" (avoid function call results)
28
+ * - Skip computed property access (e.g., obj[key])
29
+ * - Mark modified chains as un-extractable
30
+ * - Support TypeScript non-null assertion operator (!) (minor bugs might still persist in some cases)
31
+ */
5
32
const noRepeatedMemberAccess = createRule ( {
6
33
name : "no-repeated-member-access" ,
7
34
meta : {
@@ -42,7 +69,6 @@ const noRepeatedMemberAccess = createRule({
42
69
modified : boolean ; // Whether this chain is modified (written to)
43
70
}
44
71
> ;
45
- variables : Set < string > ; // Variables already declared in this scope
46
72
} ;
47
73
48
74
// Stores data for each scope using WeakMap to avoid memory leaks
@@ -63,15 +89,8 @@ const noRepeatedMemberAccess = createRule({
63
89
modified : boolean ;
64
90
}
65
91
> ( ) ,
66
- variables : new Set < string > ( ) ,
67
92
} ;
68
93
69
- // Add existing variable names to the set
70
- for ( let i = 0 ; i < scope . variables . length ; i ++ ) {
71
- const variable = scope . variables [ i ] ;
72
- newScopeData . variables . add ( variable . name ) ;
73
- }
74
-
75
94
scopeDataMap . set ( scope , newScopeData ) ;
76
95
}
77
96
@@ -132,8 +151,7 @@ const noRepeatedMemberAccess = createRule({
132
151
parts . push ( "this" ) ;
133
152
} else {
134
153
// Skip chains with non-identifier base objects
135
- // Example: (getObject()).prop is not optimized because
136
- // function call results shouldn't be cached
154
+ // Example: (getObject()).prop is not optimized because function call results shouldn't be cached
137
155
isValid = false ;
138
156
}
139
157
@@ -200,7 +218,7 @@ const noRepeatedMemberAccess = createRule({
200
218
}
201
219
}
202
220
// Mark the chain as modified regardless of it has been created or not!! Otherwise properties that get written will be reported in the first time, but they should not be reported.
203
- // Examples :
221
+ // Here is a more concrete example :
204
222
// "this.vehicleSys!" should not be extracted as it is written later
205
223
// this.vehicleSys!.automobile = new TransportCore(new TransportBlueprint()); // THIS line will get reported if we don't mark the chain as modified
206
224
// this.vehicleSys!.automobile!.apple = new ChassisAssembly(new ChassisSchema());
0 commit comments