@@ -32,19 +32,10 @@ const noRepeatedMemberAccess = createRule({
3232 private modified : boolean = false ;
3333 private parent ?: ChainNode ;
3434 private children : Map < string , ChainNode > = new Map ( ) ;
35- private path : string ;
3635
37- constructor ( name : string , parent ?: ChainNode ) {
36+ constructor ( parent ?: ChainNode ) {
3837 this . parent = parent ;
3938 this . modified = this . parent ?. modified || false ;
40-
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- }
4839 }
4940
5041 get getCount ( ) : number {
@@ -55,26 +46,18 @@ const noRepeatedMemberAccess = createRule({
5546 return this . modified ;
5647 }
5748
58- get getParent ( ) : ChainNode | undefined {
59- return this . parent ;
60- }
61-
6249 get getChildren ( ) : Map < string , ChainNode > {
6350 return this . children ;
6451 }
6552
66- get getPath ( ) : string {
67- return this . path ;
68- }
69-
7053 incrementCount ( ) : void {
7154 this . count ++ ;
7255 }
7356
7457 // Get or create child node
7558 getOrCreateChild ( childName : string ) : ChainNode {
7659 if ( ! this . children . has ( childName ) ) {
77- this . children . set ( childName , new ChainNode ( childName , this ) ) ;
60+ this . children . set ( childName , new ChainNode ( this ) ) ;
7861 }
7962 return this . children . get ( childName ) ! ;
8063 }
@@ -90,47 +73,49 @@ const noRepeatedMemberAccess = createRule({
9073
9174 // Root node for the tree (per scope)
9275 class ChainTree {
93- private root : ChainNode = new ChainNode ( "__root__" ) ;
76+ private root : ChainNode = new ChainNode ( ) ;
9477
95- // Insert a chain path into the tree and increment counts
96- insertChain ( properties : string [ ] ) : void {
78+ // Visitor function to navigate through property chain
79+ private visitChainPath (
80+ properties : string [ ] ,
81+ process : ( node : ChainNode ) => void
82+ ) : ChainNode {
9783 let current = this . root ;
9884
99- // Navigate/create path in tree
85+ // Navigate/process node in the tree
10086 for ( const prop of properties ) {
10187 const child = current . getOrCreateChild ( prop ) ;
10288 current = child ;
103-
104- // Only increment count for non-single properties (chains with dots)
105- if ( properties . length > 1 ) {
106- current . incrementCount ( ) ;
107- }
89+ process ( current ) ;
10890 }
91+
92+ return current ;
93+ }
94+
95+ // Insert a chain path into the tree and increment counts
96+ insertChain ( properties : string [ ] ) : void {
97+ this . visitChainPath ( properties , ( node ) => {
98+ node . incrementCount ( ) ;
99+ } ) ;
109100 }
110101
111102 // Mark a chain and its descendants as modified
112103 markChainAsModified ( properties : string [ ] ) : void {
113- let current = this . root ;
114-
115- // Navigate to the target node, creating nodes if they don't exist
116- for ( const prop of properties ) {
117- const newChild = current . getOrCreateChild ( prop ) ;
118- current = newChild ;
119- }
104+ const targetNode = this . visitChainPath ( properties , ( ) => { } ) ;
120105
121106 // Mark this node and all descendants as modified
122- current . markAsModified ( ) ;
107+ targetNode . markAsModified ( ) ;
123108 }
124109
125110 // Find any valid chain that meets the minimum occurrence threshold
126111 findValidChains ( ) {
127112 const validChains : Array < { chain : string } > = [ ] ;
128113
129- const traverse = ( node : ChainNode , depth : number ) => {
114+ const dfs = ( node : ChainNode , pathArray : string [ ] ) => {
130115 // Only consider chains with more than one segment (has dots)
131- if ( depth > 1 && ! node . isModified && node . getCount >= 2 ) {
116+ if ( pathArray . length > 1 && ! node . isModified && node . getCount >= 2 ) {
132117 validChains . push ( {
133- chain : node . getPath ,
118+ chain : pathArray . join ( "." ) ,
134119 } ) ;
135120 }
136121
@@ -140,12 +125,15 @@ const noRepeatedMemberAccess = createRule({
140125 }
141126
142127 // Recursively traverse children
143- for ( const child of node . getChildren . values ( ) ) {
144- traverse ( child , depth + 1 ) ;
128+ for ( const [ childName , child ] of node . getChildren ) {
129+ pathArray . push ( childName ) ;
130+ dfs ( child , pathArray ) ;
131+ pathArray . pop ( ) ;
145132 }
146133 } ;
147134
148- traverse ( this . root , 0 ) ;
135+ // Start DFS from root with empty path array
136+ dfs ( this . root , [ ] ) ;
149137 return validChains ;
150138 }
151139 }
0 commit comments