@@ -55,35 +55,50 @@ process.argv.slice(2).forEach((file) => {
55
55
const ast = acorn . parse ( source , { ecmaVersion : 10 , locations : true } ) ;
56
56
const program = ast . body ;
57
57
58
+ // Build link
59
+ const link = `https://github.com/${ repo } /blob/${ tag } /` +
60
+ path . relative ( '.' , file ) . replace ( / \\ / g, '/' ) ;
61
+
58
62
// Scan for exports.
59
63
const exported = { constructors : [ ] , identifiers : [ ] } ;
60
64
program . forEach ( ( statement ) => {
61
- if ( statement . type !== 'ExpressionStatement' ) return ;
62
- const expr = statement . expression ;
63
- if ( expr . type !== 'AssignmentExpression' ) return ;
64
-
65
- let lhs = expr . left ;
66
- if ( expr . left . object . type === 'MemberExpression' ) lhs = lhs . object ;
67
- if ( lhs . type !== 'MemberExpression' ) return ;
68
- if ( lhs . object . name !== 'module' ) return ;
69
- if ( lhs . property . name !== 'exports' ) return ;
70
-
71
- let rhs = expr . right ;
72
- while ( rhs . type === 'AssignmentExpression' ) rhs = rhs . right ;
73
-
74
- if ( rhs . type === 'NewExpression' ) {
75
- exported . constructors . push ( rhs . callee . name ) ;
76
- } else if ( rhs . type === 'ObjectExpression' ) {
77
- rhs . properties . forEach ( ( property ) => {
78
- if ( property . value . type === 'Identifier' ) {
79
- exported . identifiers . push ( property . value . name ) ;
80
- if ( / ^ [ A - Z ] / . test ( property . value . name [ 0 ] ) ) {
81
- exported . constructors . push ( property . value . name ) ;
65
+ if ( statement . type === 'ExpressionStatement' ) {
66
+ const expr = statement . expression ;
67
+ if ( expr . type !== 'AssignmentExpression' ) return ;
68
+
69
+ let lhs = expr . left ;
70
+ if ( expr . left . object . type === 'MemberExpression' ) lhs = lhs . object ;
71
+ if ( lhs . type !== 'MemberExpression' ) return ;
72
+ if ( lhs . object . name !== 'module' ) return ;
73
+ if ( lhs . property . name !== 'exports' ) return ;
74
+
75
+ let rhs = expr . right ;
76
+ while ( rhs . type === 'AssignmentExpression' ) rhs = rhs . right ;
77
+
78
+ if ( rhs . type === 'NewExpression' ) {
79
+ exported . constructors . push ( rhs . callee . name ) ;
80
+ } else if ( rhs . type === 'ObjectExpression' ) {
81
+ rhs . properties . forEach ( ( property ) => {
82
+ if ( property . value . type === 'Identifier' ) {
83
+ exported . identifiers . push ( property . value . name ) ;
84
+ if ( / ^ [ A - Z ] / . test ( property . value . name [ 0 ] ) ) {
85
+ exported . constructors . push ( property . value . name ) ;
86
+ }
82
87
}
83
- }
84
- } ) ;
85
- } else if ( rhs . type === 'Identifier' ) {
86
- exported . identifiers . push ( rhs . name ) ;
88
+ } ) ;
89
+ } else if ( rhs . type === 'Identifier' ) {
90
+ exported . identifiers . push ( rhs . name ) ;
91
+ }
92
+ } else if ( statement . type === 'VariableDeclaration' ) {
93
+ for ( const decl of statement . declarations ) {
94
+ let init = decl . init ;
95
+ while ( init && init . type === 'AssignmentExpression' ) init = init . left ;
96
+ if ( ! init || init . type !== 'MemberExpression' ) continue ;
97
+ if ( init . object . name !== 'module' ) continue ;
98
+ if ( init . property . name !== 'exports' ) continue ;
99
+ exported . constructors . push ( decl . id . name ) ;
100
+ definition [ decl . id . name ] = `${ link } #L${ statement . loc . start . line } ` ;
101
+ }
87
102
}
88
103
} ) ;
89
104
@@ -93,8 +108,7 @@ process.argv.slice(2).forEach((file) => {
93
108
// ClassName.prototype.foo = ...;
94
109
// function Identifier(...) {...};
95
110
//
96
- const link = `https://github.com/${ repo } /blob/${ tag } /` +
97
- path . relative ( '.' , file ) . replace ( / \\ / g, '/' ) ;
111
+ const indirect = { } ;
98
112
99
113
program . forEach ( ( statement ) => {
100
114
if ( statement . type === 'ExpressionStatement' ) {
@@ -128,6 +142,11 @@ process.argv.slice(2).forEach((file) => {
128
142
}
129
143
130
144
definition [ name ] = `${ link } #L${ statement . loc . start . line } ` ;
145
+
146
+ if ( expr . left . property . name === expr . right . name ) {
147
+ indirect [ expr . right . name ] = name ;
148
+ }
149
+
131
150
} else if ( statement . type === 'FunctionDeclaration' ) {
132
151
const name = statement . id . name ;
133
152
if ( ! exported . identifiers . includes ( name ) ) return ;
@@ -136,6 +155,18 @@ process.argv.slice(2).forEach((file) => {
136
155
`${ link } #L${ statement . loc . start . line } ` ;
137
156
}
138
157
} ) ;
158
+
159
+ // Search for indirect references of the form ClassName.foo = foo;
160
+ if ( Object . keys ( indirect ) . length > 0 ) {
161
+ program . forEach ( ( statement ) => {
162
+ if ( statement . type === 'FunctionDeclaration' ) {
163
+ const name = statement . id . name ;
164
+ if ( indirect [ name ] ) {
165
+ definition [ indirect [ name ] ] = `${ link } #L${ statement . loc . start . line } ` ;
166
+ }
167
+ }
168
+ } ) ;
169
+ }
139
170
} ) ;
140
171
141
172
console . log ( JSON . stringify ( definition , null , 2 ) ) ;
0 commit comments