@@ -12,8 +12,12 @@ import type {
12
12
FunctionDeclaration ,
13
13
ArrowFunction ,
14
14
FunctionExpression ,
15
- Expression ,
16
15
JSDocTagInfo ,
16
+ ExpressionStatement ,
17
+ ReturnStatement ,
18
+ Modifier ,
19
+ ConciseBody ,
20
+ Block ,
17
21
Declaration
18
22
} from 'typescript'
19
23
@@ -104,7 +108,7 @@ class Transform {
104
108
return ts . visitEachChild ( node , this . constEnumVisitor , this . ctx )
105
109
}
106
110
107
- expandMacro ( node : CallExpression , valueDeclaration : FunctionDeclaration | ArrowFunction | FunctionExpression , type : JSDocTagType ) : VisitResult < Node > {
111
+ expandMacro ( node : CallExpression , valueDeclaration : FunctionDeclaration | ArrowFunction | FunctionExpression , type : JSDocTagType , originalNode : ExpressionStatement | ReturnStatement | CallExpression ) : VisitResult < Node > {
108
112
const factory = this . ctx . factory
109
113
const checker = this . typeChecker
110
114
const cloneOptions : any = {
@@ -122,17 +126,16 @@ class Transform {
122
126
preserveSymbols : true
123
127
}
124
128
125
- const decl = cloneNode ( this . visitor ( valueDeclaration ) as ( FunctionDeclaration | ArrowFunction ) , cloneOptions )
129
+ const decl = cloneNode ( valueDeclaration , cloneOptions )
126
130
const args = node . arguments . map ( a =>
127
- ts . visitEachChild (
128
- ts . visitEachChild ( a , this . visitor , this . ctx ) ,
129
- this . constEnumVisitor ,
130
- this . ctx
131
- )
131
+ ts . visitNode (
132
+ ts . visitNode ( a , this . visitor ) ,
133
+ this . constEnumVisitor
134
+ ) as ts . Expression
132
135
)
133
136
const paramNames = valueDeclaration . parameters . map ( p => p . name . getText ( ) )
134
137
const macroBodyVisitor : Visitor = ( nodeInMacro ) => {
135
- const newNode = this . constEnumVisitor ( nodeInMacro )
138
+ const newNode = nodeInMacro
136
139
let result : VisitResult < Node > = newNode
137
140
138
141
if ( ( ts . isExpressionStatement ( newNode ) && ts . isCallExpression ( newNode . expression ) ) || ( ts . isReturnStatement ( newNode ) && newNode . expression && ts . isCallExpression ( newNode . expression ) ) ) {
@@ -157,46 +160,71 @@ class Transform {
157
160
return ts . visitEachChild ( n , replaceIdentifierVisitor , this . ctx )
158
161
}
159
162
const b = ts . visitEachChild ( arg . body , replaceIdentifierVisitor , this . ctx )
160
- result = type === JSDocTagType . INLINE ? b : b . statements
163
+ result = b . statements
161
164
}
162
165
}
163
166
}
164
- } else if ( ts . isIdentifier ( newNode ) ) {
167
+ } else if ( ts . isIdentifier ( newNode ) /* && !ts.isParameter(newNode.parent) */ ) {
165
168
const sym = checker . getSymbolAtLocation ( newNode ) ?. valueDeclaration
166
169
if ( sym && paramNames . includes ( newNode . text ) ) {
167
170
const index = paramNames . indexOf ( newNode . text )
168
- result = this . visitor ( cloneNode ( args [ index ] , cloneOptions ) )
171
+ result = cloneNode ( args [ index ] , cloneOptions )
169
172
}
170
173
}
171
174
172
- if ( ! Array . isArray ( result ) ) {
173
- result = this . visitor ( result as Node )
174
- }
175
-
176
175
if ( Array . isArray ( result ) ) {
177
176
return result . map ( n => ts . visitEachChild ( n , macroBodyVisitor , this . ctx ) )
178
177
}
179
178
180
179
return ts . visitEachChild ( result as Node , macroBodyVisitor , this . ctx )
181
180
}
182
181
183
- const body = decl . body !
184
- if ( ts . isBlock ( body ! ) ) {
185
- const transformedBody = ts . visitEachChild (
186
- body ! ,
187
- macroBodyVisitor ,
188
- this . ctx
189
- )
190
- return type === JSDocTagType . INLINE ? transformedBody : transformedBody . statements
182
+ if ( type === JSDocTagType . INLINE ) {
183
+ const body = decl . body !
184
+ const transformedBody = ts . visitNode ( ts . visitNode ( body , this . visitor ) , this . constEnumVisitor )
185
+ const f = ts . isArrowFunction ( decl )
186
+ ? factory . updateArrowFunction ( decl , decl . modifiers , decl . typeParameters , decl . parameters , decl . type , decl . equalsGreaterThanToken , transformedBody as ConciseBody )
187
+ : factory . createFunctionExpression ( decl . modifiers ?. filter ( d => d . kind !== ts . SyntaxKind . Decorator && d . kind !== ts . SyntaxKind . ExportKeyword ) as ( readonly Modifier [ ] | undefined ) , decl . asteriskToken , undefined , decl . typeParameters , decl . parameters , decl . type , transformedBody as Block )
188
+ if ( ts . isCallExpression ( originalNode ) ) {
189
+ return factory . updateCallExpression ( originalNode , factory . createParenthesizedExpression ( f ) , originalNode . typeArguments , args )
190
+ }
191
+ if ( ts . isExpressionStatement ( originalNode ) ) {
192
+ const callExpression = originalNode . expression as CallExpression
193
+ return factory . updateExpressionStatement ( originalNode ,
194
+ factory . updateCallExpression ( callExpression , factory . createParenthesizedExpression ( f ) , callExpression . typeArguments , args ) )
195
+ }
196
+ if ( ts . isReturnStatement ( originalNode ) ) {
197
+ const callExpression = originalNode . expression as CallExpression
198
+ return factory . updateReturnStatement ( originalNode ,
199
+ factory . updateCallExpression ( callExpression , factory . createParenthesizedExpression ( f ) , callExpression . typeArguments , args ) )
200
+ }
201
+ throw new Error ( 'unreachable' )
202
+ } else {
203
+ const body = decl . body !
204
+ if ( ts . isBlock ( body ! ) ) {
205
+ const transformedBody = ts . visitEachChild (
206
+ ts . visitEachChild (
207
+ ts . visitEachChild (
208
+ body ! ,
209
+ macroBodyVisitor ,
210
+ this . ctx
211
+ ) ,
212
+ this . visitor ,
213
+ this . ctx
214
+ ) ,
215
+ this . constEnumVisitor ,
216
+ this . ctx
217
+ )
218
+ return transformedBody . statements
219
+ }
220
+ return ts . visitNode ( body , macroBodyVisitor ) !
191
221
}
192
-
193
- return ts . visitNode ( body , macroBodyVisitor ) !
194
222
}
195
223
196
- getDeclarationIfMacroCall ( node : Expression ) : { valueDeclaration : Declaration | undefined ; type : JSDocTagType } {
224
+ getDeclarationIfMacroCall ( node : CallExpression ) : { valueDeclaration : Declaration | undefined ; type : JSDocTagType } {
197
225
if ( ! this . test ) {
198
- let t = JSDocTagType . INLINE
199
- if ( ts . isCallExpression ( node ) && ( ( ts . isNonNullExpression ( node . expression ) && ts . isIdentifier ( node . expression . expression ) ) || ts . isIdentifier ( node . expression ) ) ) {
226
+ let t = JSDocTagType . MACRO
227
+ if ( ( ( ts . isNonNullExpression ( node . expression ) && ts . isIdentifier ( node . expression . expression ) ) || ts . isIdentifier ( node . expression ) ) ) {
200
228
const identifier = ts . isNonNullExpression ( node . expression ) ? node . expression . expression : node . expression as Identifier
201
229
const type = this . typeChecker . getTypeAtLocation ( identifier )
202
230
const sym = type . getSymbol ( )
@@ -213,36 +241,52 @@ class Transform {
213
241
}
214
242
return { valueDeclaration : undefined , type : t }
215
243
} else {
216
- if ( ts . isCallExpression ( node ) &&
217
- ts . isNonNullExpression ( node . expression ) &&
244
+ if ( ts . isNonNullExpression ( node . expression ) &&
218
245
ts . isIdentifier ( node . expression . expression ) &&
219
246
this . testMacroName ( node . expression . expression . text )
220
247
) {
221
248
const type = this . typeChecker . getTypeAtLocation ( node . expression . expression )
222
249
const sym = type . getSymbol ( )
223
250
if ( sym ) {
224
- return { valueDeclaration : sym . valueDeclaration , type : JSDocTagType . INLINE }
251
+ return { valueDeclaration : sym . valueDeclaration , type : JSDocTagType . MACRO }
225
252
}
226
253
}
227
- return { valueDeclaration : undefined , type : JSDocTagType . INLINE }
254
+ return { valueDeclaration : undefined , type : JSDocTagType . MACRO }
228
255
}
229
256
}
230
257
231
258
visitor ( n : Node ) : VisitResult < Node > {
232
259
// const factory = this.ctx.factory
233
260
// const checker = this.typeChecker
234
261
235
- if ( ( ts . isExpressionStatement ( n ) || ts . isReturnStatement ( n ) ) && n . expression ) {
262
+ if ( ( ( ts . isFunctionDeclaration ( n ) && n . name ) || ( ( ts . isArrowFunction ( n ) || ts . isFunctionExpression ( n ) ) && n . parent && ts . isVariableDeclaration ( n . parent ) && ts . isIdentifier ( n . parent . name ) ) ) ) {
263
+ const type = this . typeChecker . getTypeAtLocation ( ts . isFunctionDeclaration ( n ) ? n . name ! : ( ( n . parent as ts . VariableDeclaration ) . name as Identifier ) )
264
+ const sym = type . getSymbol ( )
265
+ const someFn = ( info : JSDocTagInfo ) : boolean => {
266
+ if ( info . name === JSDocTagType . INLINE || info . name === JSDocTagType . MACRO ) {
267
+ return true
268
+ }
269
+ return false
270
+ }
271
+ if ( sym ?. getJsDocTags ( this . typeChecker ) . reverse ( ) . some ( someFn ) ) {
272
+ return n
273
+ }
274
+ }
275
+
276
+ if ( ( ts . isExpressionStatement ( n ) || ts . isReturnStatement ( n ) ) && n . expression && ts . isCallExpression ( n . expression ) ) {
236
277
const { valueDeclaration, type } = this . getDeclarationIfMacroCall ( n . expression )
237
278
if ( valueDeclaration && ( ts . isFunctionDeclaration ( valueDeclaration ) || ts . isArrowFunction ( valueDeclaration ) || ts . isFunctionExpression ( valueDeclaration ) ) && valueDeclaration . body ) {
238
- return this . expandMacro ( n . expression as CallExpression , valueDeclaration , type )
279
+ return this . expandMacro ( n . expression , valueDeclaration , type , n )
239
280
}
240
281
}
241
282
242
- if ( ts . isExpression ( n ) ) {
283
+ if ( ts . isCallExpression ( n ) ) {
243
284
const { valueDeclaration, type } = this . getDeclarationIfMacroCall ( n )
244
- if ( valueDeclaration && ts . isArrowFunction ( valueDeclaration ) && ts . isExpression ( valueDeclaration . body ) ) {
245
- return this . expandMacro ( n as CallExpression , valueDeclaration , type )
285
+ if ( valueDeclaration && (
286
+ ( ts . isArrowFunction ( valueDeclaration ) && ts . isExpression ( valueDeclaration . body ) ) ||
287
+ ( ( ts . isFunctionDeclaration ( valueDeclaration ) || ts . isArrowFunction ( valueDeclaration ) || ts . isFunctionExpression ( valueDeclaration ) ) && valueDeclaration . body && type === JSDocTagType . INLINE )
288
+ ) ) {
289
+ return this . expandMacro ( n , valueDeclaration , type , n )
246
290
}
247
291
}
248
292
0 commit comments