@@ -28,19 +28,23 @@ const noRepeatedMemberAccess = createRule({
28
28
// Tree-based approach for storing member access chains
29
29
// Each node represents a property in the chain (e.g., a -> b -> c for a.b.c)
30
30
class ChainNode {
31
- private name : string ;
32
31
private count : number = 0 ;
33
32
private modified : boolean = false ;
34
33
private parent ?: ChainNode ;
35
34
private children : Map < string , ChainNode > = new Map ( ) ;
35
+ private path : string ;
36
36
37
- constructor ( name : string ) {
38
- this . name = name ;
39
- }
37
+ constructor ( name : string , parent ?: ChainNode ) {
38
+ this . parent = parent ;
39
+ this . modified = this . parent ?. modified || false ;
40
40
41
- // Getter methods for private properties
42
- get getName ( ) : string {
43
- return this . name ;
41
+ if ( name === "__root__" ) {
42
+ this . path = "" ;
43
+ } else if ( ! this . parent || this . parent . path === "" ) {
44
+ this . path = name ;
45
+ } else {
46
+ this . path = this . parent . path + "." + name ;
47
+ }
44
48
}
45
49
46
50
get getCount ( ) : number {
@@ -59,9 +63,8 @@ const noRepeatedMemberAccess = createRule({
59
63
return this . children ;
60
64
}
61
65
62
- // Setter methods for private properties
63
- set setParent ( parent : ChainNode | undefined ) {
64
- this . parent = parent ;
66
+ get getPath ( ) : string {
67
+ return this . path ;
65
68
}
66
69
67
70
incrementCount ( ) : void {
@@ -71,30 +74,15 @@ const noRepeatedMemberAccess = createRule({
71
74
// Get or create child node
72
75
getOrCreateChild ( childName : string ) : ChainNode {
73
76
if ( ! this . children . has ( childName ) ) {
74
- this . children . set ( childName , new ChainNode ( childName ) ) ;
77
+ this . children . set ( childName , new ChainNode ( childName , this ) ) ;
75
78
}
76
79
return this . children . get ( childName ) ! ;
77
80
}
78
81
79
- // Get the full chain path from root to this node
80
- getChainPath ( ) : string {
81
- // Build path from child to root, then reverse at the end
82
- const path : string [ ] = [ ] ;
83
- let current = this as ChainNode | undefined ;
84
- while ( current && current . getName !== "__root__" ) {
85
- path . push ( current . getName ) ;
86
- current = current . getParent ;
87
- }
88
-
89
- // Reverse the array once at the end
90
- path . reverse ( ) ;
91
- return path . join ( "." ) ;
92
- }
93
-
94
82
// Mark this node and all its descendants as modified
95
83
markAsModified ( ) : void {
96
84
this . modified = true ;
97
- for ( const child of this . getChildren . values ( ) ) {
85
+ for ( const child of this . children . values ( ) ) {
98
86
child . markAsModified ( ) ;
99
87
}
100
88
}
@@ -103,8 +91,6 @@ const noRepeatedMemberAccess = createRule({
103
91
// Root node for the tree (per scope)
104
92
class ChainTree {
105
93
private root : ChainNode = new ChainNode ( "__root__" ) ;
106
- private validChainsCache : Array < { chain : string } > = [ ] ;
107
- private cacheValid : boolean = false ;
108
94
109
95
// Insert a chain path into the tree and increment counts
110
96
insertChain ( properties : string [ ] ) : void {
@@ -113,15 +99,13 @@ const noRepeatedMemberAccess = createRule({
113
99
// Navigate/create path in tree
114
100
for ( const prop of properties ) {
115
101
const child = current . getOrCreateChild ( prop ) ;
116
- child . setParent = current ;
117
102
current = child ;
118
103
119
104
// Only increment count for non-single properties (chains with dots)
120
105
if ( properties . length > 1 ) {
121
106
current . incrementCount ( ) ;
122
107
}
123
108
}
124
- this . cacheValid = false ;
125
109
}
126
110
127
111
// Mark a chain and its descendants as modified
@@ -131,28 +115,22 @@ const noRepeatedMemberAccess = createRule({
131
115
// Navigate to the target node, creating nodes if they don't exist
132
116
for ( const prop of properties ) {
133
117
const newChild = current . getOrCreateChild ( prop ) ;
134
- newChild . setParent = current ;
135
118
current = newChild ;
136
119
}
137
120
138
121
// Mark this node and all descendants as modified
139
122
current . markAsModified ( ) ;
140
- this . cacheValid = false ;
141
123
}
142
124
143
125
// Find any valid chain that meets the minimum occurrence threshold
144
126
findValidChains ( ) {
145
- if ( this . cacheValid ) {
146
- return this . validChainsCache ;
147
- }
148
127
const validChains : Array < { chain : string } > = [ ] ;
149
128
150
129
const traverse = ( node : ChainNode , depth : number ) => {
151
130
// Only consider chains with more than one segment (has dots)
152
131
if ( depth > 1 && ! node . isModified && node . getCount >= 2 ) {
153
- const chainPath = node . getChainPath ( ) ;
154
132
validChains . push ( {
155
- chain : chainPath ,
133
+ chain : node . getPath ,
156
134
} ) ;
157
135
}
158
136
@@ -168,8 +146,6 @@ const noRepeatedMemberAccess = createRule({
168
146
} ;
169
147
170
148
traverse ( this . root , 0 ) ;
171
- this . cacheValid = true ;
172
- this . validChainsCache = validChains ;
173
149
return validChains ;
174
150
}
175
151
}
0 commit comments