@@ -5,19 +5,65 @@ const { types: t } = babelDefault.babel;
55
66export class DependencyGraph {
77
8- get inner ( ) { return this . _inner }
8+ get programPath ( ) { return this . capabilities . programPath }
99
10- constructor ( code ) {
11- this . _inner = code . toAST ( ) ;
10+ constructor ( capabilities ) {
11+ this . capabilities = capabilities ;
1212
1313 //Stores globally a `map` of properties (`String`) to objectbindings of the objects, that have a property of that name.
1414 this . memberAssignments = new Map ( ) ;
15+ this . finishedEnrichment = false ;
1516 this . enrich ( ) ;
1617 }
18+
19+ getAexprAtCursor ( location ) {
20+ let aexprPath ;
21+ this . programPath . traverse ( {
22+ CallExpression ( path ) {
23+ if ( ! range ( path . node . loc ) . contains ( location ) ) {
24+ path . skip ( ) ;
25+ } else if ( isAExpr ( path ) ) {
26+ aexprPath = path ;
27+ path . stop ( ) ;
28+ }
29+ }
30+ } ) ;
31+ return aexprPath ;
32+ }
33+
34+ getAllActiveExpressions ( ) {
35+ const allAExpr = [ ] ;
36+ this . programPath . traverse ( {
37+ CallExpression ( path ) {
38+ if ( isAExpr ( path ) ) {
39+ allAExpr . push ( path ) ;
40+ }
41+ }
42+ } ) ;
43+ return allAExpr ;
44+ }
45+
46+ get hasActiveExpressionsDirective ( ) {
47+ return this . programPath . node . directives . some ( node => {
48+ return node . value . value === "enable aexpr" ;
49+ } ) ;
50+ }
51+
52+ ensureEnrichment ( ) {
53+ if ( this . finishedEnrichment ) return true ;
54+ if ( ! this . programPath || ! this . hasActiveExpressionsDirective ) return false ;
55+ try {
56+ this . enrich ( ) ;
57+ } catch ( err ) {
58+ console . error ( "Unable to process source code" , err ) ;
59+ return false ;
60+ }
61+ return true ;
62+ }
1763
1864 enrich ( ) {
1965 let self = this ;
20- this . _inner . traverseAsAST ( {
66+ this . programPath . traverse ( {
2167 enter ( path ) {
2268 path . node . extra = {
2369 // this in necessary due to possible circles
@@ -31,8 +77,8 @@ export class DependencyGraph {
3177 } ) ;
3278
3379 // adds the corresponding binding to every identifier
34- this . _inner . traverseAsAST ( {
35- Scope ( path ) {
80+ this . programPath . traverse ( {
81+ Scopable ( path ) {
3682 Object . entries ( path . scope . bindings ) . forEach ( ( [ _name , binding ] ) => {
3783 binding . referencePaths . forEach ( path => {
3884 path . node . extra . binding = binding ;
@@ -45,17 +91,18 @@ export class DependencyGraph {
4591
4692 this . enrichFunctionNodes ( ) ;
4793
48- this . _inner . traverseAsAST ( {
94+ this . programPath . traverse ( {
4995 Expression ( expr ) {
5096 self . collectExpressionInformation ( expr ) ;
5197 }
5298 } ) ;
99+ this . finishedEnrichment = true ;
53100 }
54101
55102 // Filters every memberassignment and registers it in `this.memberAssignments`
56103 extractMemberAssignments ( ) {
57104 let self = this ;
58- this . _inner . traverseAsAST ( {
105+ this . programPath . traverse ( {
59106 MemberExpression ( expr ) {
60107 if ( expr . node . computed ) return ;
61108 if ( ! expr . parentPath . isAssignmentExpression ( ) ) return ;
@@ -86,7 +133,7 @@ export class DependencyGraph {
86133
87134 enrichFunctionNodes ( ) {
88135 // adds bindings definend outside of the current scope(e.g. Function) to the scope
89- this . _inner . traverseAsAST ( {
136+ this . programPath . traverse ( {
90137 'Function|ArrowFunctionExpression|Program' ( path ) {
91138 path . node . extra . leakingBindings = leakingBindings ( path ) ;
92139 const callExpressions = path . node . extra . callExpressions = [ ] ;
@@ -130,17 +177,18 @@ export class DependencyGraph {
130177 *
131178 */
132179 collectExpressionInformation ( path ) {
133- //debugger;
180+ if ( path . node . extra . results ) {
181+ return path . node . extra . results
182+ }
183+
134184 if ( path . node . extra . returnVisited <= 0 ) {
185+ path . node . extra . resolvedObjects = [ ] ;
186+ path . node . extra . results = [ ] ;
135187 return [ ] ;
136188 }
137189
138190 path . node . extra . returnVisited -= 1 ;
139191
140- if ( path . node . extra . results ) {
141- return path . node . extra . results
142- }
143-
144192 let results = [ ] ;
145193 let resolvedObjects = [ ] ;
146194
@@ -163,9 +211,11 @@ export class DependencyGraph {
163211 } else if ( path . isAssignmentExpression ( ) || path . isVariableDeclarator ( ) ) {
164212
165213 let val = this . assignedValue ( path ) ;
166- this . collectExpressionInformation ( val ) ;
167- results = val . node . extra . results ;
168- resolvedObjects = val . node . extra . resolvedObjects ;
214+ if ( val && val . node ) {
215+ this . collectExpressionInformation ( val ) ;
216+ results = val . node . extra . results ;
217+ resolvedObjects = val . node . extra . resolvedObjects ;
218+ }
169219
170220 } else if ( path . isFunction ( ) ) {
171221 results = [ path ] ;
@@ -276,6 +326,7 @@ export class DependencyGraph {
276326 * //b is equal to {x:2}
277327 */
278328 shadowedBindings ( bindings ) {
329+ if ( ! bindings ) return [ ] ;
279330
280331 /* this should be stored in the members map or in an extra property.
281332 * DOES NOT DETECT DEPENDENCIES THROUGH SIMPLE ASSIGNMENTS (a la `a = b`)
@@ -297,14 +348,13 @@ export class DependencyGraph {
297348 * DOES NOT care for execution order of the code
298349 * uses heuristics e.g. fixed recursion depth
299350 */
300- resolveDependencies ( location ) {
301-
351+ resolveDependenciesAtLocation ( location ) {
302352 let node ;
303353 let dep ;
304354 let dependencyGraph = this ;
305- this . _inner . traverseAsAST ( {
355+ this . programPath . traverse ( {
306356 CallExpression ( path ) {
307- if ( isAExpr ( path ) && range ( path . node . loc ) . contains ( location ) ) {
357+ if ( isAExpr ( path ) && range ( path . node . loc ) . contains ( location . node . loc ) ) {
308358 if ( path . node . dependencies != null ) {
309359 dep = path . node . dependencies ;
310360 console . log ( "dependencies already collected: " , dep ) ;
@@ -321,8 +371,37 @@ export class DependencyGraph {
321371 }
322372 return node . extra . dependencies ;
323373 }
324-
325- _resolveDependencies ( path ) {
374+
375+ resolveDependenciesForMember ( memberName ) {
376+ let deps = [ ] ;
377+ const self = this ;
378+ let dependencyGraph = this ;
379+ this . programPath . traverse ( {
380+ Function ( path ) {
381+ if ( ! path . node . key || path . node . key . name !== memberName ) return ;
382+ if ( ! path . node . extra . dependencies ) {
383+ path . node . extra . dependencies = dependencyGraph . resolveDependencies ( path ) ;
384+ }
385+ deps . push ( ...( path . node . extra . dependencies || [ ] ) , path . get ( "key" ) ) ;
386+ } ,
387+ AssignmentExpression ( path ) {
388+ const left = path . node . left ;
389+ if ( t . isMemberExpression ( left ) , t . isThisExpression ( left . object ) && left . property . name === memberName ) {
390+ deps . push ( path ) ;
391+ }
392+ } ,
393+ UpdateExpression ( path ) {
394+ const argument = path . node . argument ;
395+ if ( t . isMemberExpression ( argument ) , t . isThisExpression ( argument . object ) && argument . property . name === memberName ) {
396+ deps . push ( path ) ;
397+ }
398+ }
399+ //Todo: Array stuff??
400+ } ) ;
401+ return deps ;
402+ }
403+
404+ resolveDependencies ( path ) {
326405 const self = this ;
327406 if ( ( path . node . extra . visited -= 1 ) <= 0 ) {
328407 return path . node . extra . dependencies || new Set ( ) ;
@@ -343,7 +422,7 @@ export class DependencyGraph {
343422 if ( t . isAssignmentExpression ( callee ) ) {
344423 const value = this . assignedValue ( callee ) ;
345424 if ( t . isFunction ( value ) || t . isArrowFunctionExpression ( value ) ) {
346- this . _resolveDependencies ( value ) . forEach ( dep => dependencies . add ( dep ) ) ;
425+ this . resolveDependencies ( value ) . forEach ( dep => dependencies . add ( dep ) ) ;
347426 }
348427 }
349428
@@ -356,7 +435,7 @@ export class DependencyGraph {
356435 if ( path . node . extra . objects . size ) {
357436 for ( const [ objExpr , members ] of path . node . extra . objects . entries ( ) ) {
358437 for ( const member of members ) {
359- self . assignmentsOf ( member , { bindings : new Set ( [ objExpr . extra . binding ] ) } ) . forEach ( assignment => {
438+ self . assignmentsOf ( member , { bindings : new Set ( objExpr . extra . binding ? [ objExpr . extra . binding ] : [ ] ) } ) . forEach ( assignment => {
360439 dependencies . add ( assignment )
361440 } ) ;
362441 }
0 commit comments