1
+ import { TEXT_NODE_TYPES } from './const.js' ;
2
+ import {
3
+ FileInfoTree ,
4
+ FuncCallSearchResult ,
5
+ NameAndPath ,
6
+ ImpactReason ,
7
+ TemplateImpact ,
8
+ TemplateKeyInfo ,
9
+ TemplateImpactResult
10
+ } from './type' ;
11
+ import { handleCircularPath } from './utils/handle_circular_path.js' ;
12
+
13
+ function getImpacts ( treeData : FileInfoTree , funcInfo : ImpactReason ) {
14
+ let templateImpact = [ ] as TemplateImpactResult [ ] ;
15
+
16
+ // function entrance
17
+ const main = {
18
+ name : funcInfo . name ,
19
+ file : funcInfo . filePath ,
20
+ } ;
21
+
22
+ let callList = [ funcInfo ] as ImpactReason [ ] ;
23
+ const impactReport = [ ] ;
24
+
25
+ while ( callList . length ) {
26
+ const curFuncInfo = callList . shift ( ) ;
27
+
28
+ if ( ! curFuncInfo ) {
29
+ continue ;
30
+ }
31
+
32
+ const { theyCallYou } = findWhoCallMe ( treeData , curFuncInfo , templateImpact ) ;
33
+ const [ isCircular , miniPath ] = handleCircularPath ( curFuncInfo . paths ) ;
34
+
35
+ if ( ! theyCallYou . length ) { // the end of function call stack
36
+ impactReport . push ( {
37
+ callPaths : curFuncInfo . paths ,
38
+ templateImpact
39
+ } ) ;
40
+ templateImpact = [ ] ;
41
+ } else if ( isCircular ) { // function calls are looped,stop here
42
+ impactReport . push ( {
43
+ callPaths : miniPath ,
44
+ templateImpact,
45
+ } ) ;
46
+ callList = [ ] ;
47
+ templateImpact = [ ] ;
48
+ } else { // keep finding
49
+ callList . push ( ...theyCallYou ) ;
50
+ }
51
+
52
+ }
53
+
54
+ return {
55
+ main,
56
+ impactReport
57
+ } ;
58
+ }
59
+
60
+ // find a function called by which function
61
+ function findWhoCallMe ( treeData : FileInfoTree , funcInfo : ImpactReason , reportInfo = [ ] as TemplateImpactResult [ ] ) {
62
+ const theyCallYou = [ ] as FuncCallSearchResult [ ] ;
63
+
64
+ const curFilePath = funcInfo . filePath ;
65
+ const funcName = funcInfo . name ;
66
+ const curPaths = funcInfo . paths ;
67
+
68
+ // these found functions are used to find the impact of template
69
+ // TODO: there is a bug: a same dom node will be found and push to the array twice
70
+ const templateImpactSearchFunc : NameAndPath = {
71
+ [ funcName ] : curFilePath
72
+ } ;
73
+
74
+ // because the mixin function is mixed into each file,it wil be found multiple times
75
+ // so we need a set
76
+ const set = new Set ( ) ;
77
+
78
+ for ( const fileInfo in treeData ) {
79
+ const allFuncsInfo = treeData [ fileInfo ] . allFuncsInfo ;
80
+ const templateKeyInfo = treeData [ fileInfo ] . templateKeyInfo ;
81
+
82
+ if ( ! Object . keys ( allFuncsInfo ) . length ) continue ;
83
+
84
+ // find the caller in current file
85
+ Object . values ( allFuncsInfo ) . forEach ( func => {
86
+ if ( func . calledFnList . includes ( funcName ) &&
87
+ func . calledFnFrom [ funcName ] . filePath === curFilePath &&
88
+ ! set . has ( `${ func . name } -${ func . filePath } ` )
89
+ ) {
90
+ set . add ( `${ func . name } -${ func . filePath } ` ) ;
91
+
92
+ // collect call paths
93
+ const paths = [ ...curPaths ] ;
94
+ paths . push ( [ func . name , func . filePath , func . position ] ) ;
95
+
96
+ theyCallYou . push ( {
97
+ filePath : func . filePath ,
98
+ name : func . name ,
99
+ paths,
100
+ } ) ;
101
+
102
+ templateImpactSearchFunc [ func . name ] = func . filePath ;
103
+ }
104
+ } ) ;
105
+
106
+ // find if the function in the paths is used in the template
107
+ if ( templateKeyInfo && templateKeyInfo . length ) {
108
+ const domInfo = getTemplateImpact ( templateKeyInfo , templateImpactSearchFunc ) ;
109
+ domInfo . length && reportInfo . push ( {
110
+ filePath : treeData [ fileInfo ] . file ,
111
+ domInfo
112
+ } ) ;
113
+ }
114
+
115
+ }
116
+
117
+ return {
118
+ theyCallYou,
119
+ reportInfo,
120
+ } ;
121
+
122
+ }
123
+
124
+ function getTemplateImpact ( templateKeyInfo : TemplateKeyInfo [ ] , templateImpactSearchFunc : NameAndPath ) {
125
+ const res = [ ] as TemplateImpact [ ] ;
126
+
127
+ const funcNameArr = Object . keys ( templateImpactSearchFunc ) ;
128
+
129
+ if ( ! funcNameArr . length ) {
130
+ return res ;
131
+ }
132
+
133
+ for ( const templateInfo of templateKeyInfo ) {
134
+ dfsTemplateInfo ( funcNameArr , templateInfo , [ ] , res ) ;
135
+ }
136
+
137
+ return res ;
138
+ }
139
+
140
+ function dfsTemplateInfo ( funcNameArr : string [ ] , templateInfo : TemplateKeyInfo , pathList : string [ ] , collect : TemplateImpact [ ] ) {
141
+ const { tag= '[blank]' , children, type } = templateInfo ;
142
+
143
+ if ( tag !== '[blank]' ) {
144
+ pathList . push ( tag ) ;
145
+ }
146
+ const curPath = pathList . join ( '->' ) ;
147
+
148
+ if ( type === 1 ) {
149
+ const { vIf, events, vBinds, classBinding } = templateInfo ;
150
+
151
+ vIf ?. forEach ( item => {
152
+ if ( funcNameArr . includes ( item ) ) {
153
+ collect . push ( {
154
+ curPath,
155
+ nodeInfo : {
156
+ type : 'if' ,
157
+ tag,
158
+ funcName : item ,
159
+ meta : 'if' ,
160
+ }
161
+ } )
162
+ }
163
+ } ) ;
164
+
165
+ events ?. forEach ( eventInfo => {
166
+ Object . keys ( eventInfo ) . forEach ( eventName => {
167
+ if ( funcNameArr . includes ( eventInfo [ eventName ] ) ) {
168
+ collect . push ( {
169
+ curPath,
170
+ nodeInfo : {
171
+ type : 'event' ,
172
+ tag,
173
+ funcName : eventInfo [ eventName ] ,
174
+ meta : eventName ,
175
+ }
176
+ } ) ;
177
+ }
178
+ } ) ;
179
+ } ) ;
180
+
181
+ vBinds ?. forEach ( bindInfo => {
182
+ const bindFunc = Object . values ( bindInfo ) [ 0 ] ;
183
+ const bindName = Object . keys ( bindInfo ) [ 0 ] ;
184
+
185
+ if ( funcNameArr . includes ( bindFunc ) ) {
186
+ collect . push ( {
187
+ curPath,
188
+ nodeInfo : {
189
+ type : 'bind' ,
190
+ tag,
191
+ funcName : bindFunc ,
192
+ meta : bindName ,
193
+ }
194
+ } ) ;
195
+ }
196
+ } ) ;
197
+
198
+ if ( classBinding ?. length ) {
199
+ for ( const item of classBinding ) {
200
+ funcNameArr . includes ( item ) &&
201
+ collect . push ( {
202
+ curPath,
203
+ nodeInfo : {
204
+ type : 'classBinding' ,
205
+ tag,
206
+ funcName : item ,
207
+ meta : 'class' ,
208
+ }
209
+ } ) ;
210
+ }
211
+ }
212
+ }
213
+
214
+ if ( TEXT_NODE_TYPES . includes ( type ) ) {
215
+ if ( templateInfo . text ) {
216
+ for ( const item of templateInfo . text ) {
217
+ funcNameArr . includes ( item ) &&
218
+ collect . push ( {
219
+ curPath,
220
+ nodeInfo : {
221
+ type : 'text' ,
222
+ tag,
223
+ funcName : item ,
224
+ }
225
+ } ) ;
226
+ }
227
+ }
228
+ }
229
+
230
+ children . forEach ( info => {
231
+ dfsTemplateInfo ( funcNameArr , info , pathList , collect ) ;
232
+ } ) ;
233
+ }
234
+
235
+ export {
236
+ getImpacts ,
237
+ findWhoCallMe ,
238
+ } ;
0 commit comments