1
1
import * as acorn from 'acorn' ;
2
2
3
- function handleParam ( param ) {
3
+ function handleParam ( param , options ) {
4
4
const { type, left, right } = param ;
5
5
if ( type !== 'AssignmentPattern' ) {
6
6
throw new Error ( `handleParam() no type defined for ${ param } ` ) ;
7
7
}
8
8
if ( right . type === 'Identifier' ) {
9
9
const typeAnnotation = right . name ;
10
- return { ...left , typeAnnotation } ;
10
+ const p = { ...left , typeAnnotation } ;
11
+ options . scope [ left . name ] = typeAnnotation ;
12
+ return p ;
11
13
} else if ( right . type === 'CallExpression' ) {
12
14
param . left . typeAnnotation = right . callee . name ;
13
15
[ param . right ] = right . arguments ;
16
+ options . scope [ param . left . name ] = param . left . typeAnnotation ;
14
17
return param ;
15
18
}
16
19
throw new Error ( `dont know ${ right } ` ) ;
@@ -28,7 +31,7 @@ function handleParams(fn, options) {
28
31
[ param . right ] = right . arguments ;
29
32
}
30
33
31
- return handleParam ( param ) ;
34
+ return handleParam ( param , options ) ;
32
35
} ) ;
33
36
34
37
let { body } = fn ;
@@ -41,8 +44,22 @@ function handleParams(fn, options) {
41
44
return { ...fn , body, params } ;
42
45
}
43
46
47
+ function extractFromScope ( scope , name , args ) {
48
+ if ( ! scope ) {
49
+ return name ;
50
+ }
51
+ const sc = scope [ name ] ;
52
+ if ( ! sc ) {
53
+ return name ;
54
+ }
55
+ if ( typeof sc === 'function' ) {
56
+ return sc . apply ( undefined , args . map ( ( { name } ) => scope [ name ] ) ) ;
57
+ }
58
+ return sc ;
59
+ }
60
+
44
61
function extractType ( node , target , options ) {
45
- const { qualifiers, integer, float, string, boolean } = options ;
62
+ const { qualifiers, integer, float, string, boolean, scope , operators } = options ;
46
63
const { type, name, callee, arguments : args , value, raw } = node ;
47
64
48
65
if ( type === 'CallExpression' || type === 'NewExpression' ) {
@@ -73,13 +90,16 @@ function extractType(node, target, options) {
73
90
} else {
74
91
75
92
const typeAnnotation = callee . name ;
76
-
77
-
78
- target . typeAnnotation = typeAnnotation ;
93
+ target . typeAnnotation = extractFromScope ( scope , typeAnnotation , args ) ;
79
94
target . newInit = node ;
80
95
}
81
96
} else if ( type === 'Identifier' ) {
82
- target . typeAnnotation = name ;
97
+ if ( scope && scope [ name ] ) {
98
+ target . typeAnnotation = extractFromScope ( scope , name , [ ] ) ;
99
+ target . newInit = node ;
100
+ } else {
101
+ target . typeAnnotation = name ;
102
+ }
83
103
} else if ( type === 'NumericLiteral' || type === 'Literal' ) {
84
104
if ( typeof value === 'number' ) {
85
105
if ( raw . indexOf ( '.' ) < 0 ) {
@@ -113,8 +133,14 @@ function extractType(node, target, options) {
113
133
value : operator === '-' ? - value : value
114
134
} ;
115
135
} else if ( type === 'ArrowFunctionExpression' ) {
116
- target . newInit = handleParams ( node , options ) ;
136
+ const newScope = { ...scope } ;
137
+ target . newInit = handleParams ( node , { ...options , scope : newScope } ) ;
117
138
target . newInit . returnType = 'void' ;
139
+ } else if ( operators && type === 'BinaryExpression' ) {
140
+ const left = extractFromScope ( scope , node . left . name , [ ] ) ;
141
+ const right = extractFromScope ( scope , node . right . name , [ ] ) ;
142
+ target . typeAnnotation = operators ( left , node . operator , right ) ;
143
+ target . newInit = node ;
118
144
} else {
119
145
target . newInit = node ;
120
146
}
@@ -160,6 +186,9 @@ function handleNode(node, options) {
160
186
const { newInit = null , typeAnnotation = null , qualifier = null } = extractType ( init , { } , options ) ;
161
187
node . id = { ...node . id , typeAnnotation, qualifier } ;
162
188
node . init = newInit ;
189
+
190
+ options . scope [ node . id . name ] = typeAnnotation ;
191
+
163
192
return node ;
164
193
}
165
194
@@ -169,10 +198,10 @@ function handleNode(node, options) {
169
198
return node ;
170
199
}
171
200
172
- export function parse ( input , { qualifiers = [ ] , float = 'Number' , integer = float , string = 'String' , boolean = 'Boolean' , locations = false , ranges = false , ...options } = { } ) {
201
+ export function parse ( input , { qualifiers = [ ] , float = 'Number' , integer = float , string = 'String' , boolean = 'Boolean' , locations = false , ranges = false , operators , scope = { } , ...options } = { } ) {
173
202
// TODO: use onToken !!!!
174
203
const ast = acorn . parse ( input , { ...options , locations, ranges, ecmaVersion : 6 } ) ;
175
- const node = handleNode ( ast , { qualifiers, integer, float, string, boolean } ) ;
204
+ const node = handleNode ( ast , { qualifiers, integer, float, string, boolean, scope , operators } ) ;
176
205
177
206
return node ;
178
207
}
0 commit comments