@@ -40,7 +40,7 @@ import {
40
40
import { NOOP , isObject , isString } from '@vue/shared'
41
41
import type { PropsExpression } from './transforms/transformElement'
42
42
import { parseExpression } from '@babel/parser'
43
- import type { Expression } from '@babel/types'
43
+ import type { Expression , Node } from '@babel/types'
44
44
import { unwrapTSNode } from './babelUtils'
45
45
46
46
export const isStaticExp = ( p : JSChildNode ) : p is SimpleExpressionNode =>
@@ -78,15 +78,20 @@ const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/
78
78
const validIdentCharRE = / [ \. \? \w $ \xA0 - \uFFFF ] /
79
79
const whitespaceRE = / \s + [ . [ ] \s * | \s * [ . [ ] \s + / g
80
80
81
+ const getExpSource = ( exp : ExpressionNode ) : string =>
82
+ exp . type === NodeTypes . SIMPLE_EXPRESSION ? exp . content : exp . loc . source
83
+
81
84
/**
82
85
* Simple lexer to check if an expression is a member expression. This is
83
86
* lax and only checks validity at the root level (i.e. does not validate exps
84
87
* inside square brackets), but it's ok since these are only used on template
85
88
* expressions and false positives are invalid expressions in the first place.
86
89
*/
87
- export const isMemberExpressionBrowser = ( path : string ) : boolean => {
90
+ export const isMemberExpressionBrowser = ( exp : ExpressionNode ) : boolean => {
88
91
// remove whitespaces around . or [ first
89
- path = path . trim ( ) . replace ( whitespaceRE , s => s . trim ( ) )
92
+ const path = getExpSource ( exp )
93
+ . trim ( )
94
+ . replace ( whitespaceRE , s => s . trim ( ) )
90
95
91
96
let state = MemberExpLexState . inMemberExp
92
97
let stateStack : MemberExpLexState [ ] = [ ]
@@ -154,15 +159,19 @@ export const isMemberExpressionBrowser = (path: string): boolean => {
154
159
}
155
160
156
161
export const isMemberExpressionNode : (
157
- path : string ,
162
+ exp : ExpressionNode ,
158
163
context : TransformContext ,
159
164
) => boolean = __BROWSER__
160
165
? ( NOOP as any )
161
- : ( path : string , context : TransformContext ) : boolean => {
166
+ : ( exp , context ) => {
162
167
try {
163
- let ret : Expression = parseExpression ( path , {
164
- plugins : context . expressionPlugins ,
165
- } )
168
+ let ret : Node =
169
+ exp . ast ||
170
+ parseExpression ( getExpSource ( exp ) , {
171
+ plugins : context . expressionPlugins
172
+ ? [ ...context . expressionPlugins , 'typescript' ]
173
+ : [ 'typescript' ] ,
174
+ } )
166
175
ret = unwrapTSNode ( ret ) as Expression
167
176
return (
168
177
ret . type === 'MemberExpression' ||
@@ -175,10 +184,52 @@ export const isMemberExpressionNode: (
175
184
}
176
185
177
186
export const isMemberExpression : (
178
- path : string ,
187
+ exp : ExpressionNode ,
179
188
context : TransformContext ,
180
189
) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
181
190
191
+ const fnExpRE =
192
+ / ^ \s * ( a s y n c \s * ) ? ( \( [ ^ ) ] * ?\) | [ \w $ _ ] + ) \s * ( : [ ^ = ] + ) ? = > | ^ \s * ( a s y n c \s + ) ? f u n c t i o n (?: \s + [ \w $ ] + ) ? \s * \( /
193
+
194
+ export const isFnExpressionBrowser : ( exp : ExpressionNode ) => boolean = exp =>
195
+ fnExpRE . test ( getExpSource ( exp ) )
196
+
197
+ export const isFnExpressionNode : (
198
+ exp : ExpressionNode ,
199
+ context : TransformContext ,
200
+ ) => boolean = __BROWSER__
201
+ ? ( NOOP as any )
202
+ : ( exp , context ) => {
203
+ try {
204
+ let ret : Node =
205
+ exp . ast ||
206
+ parseExpression ( getExpSource ( exp ) , {
207
+ plugins : context . expressionPlugins
208
+ ? [ ...context . expressionPlugins , 'typescript' ]
209
+ : [ 'typescript' ] ,
210
+ } )
211
+ // parser may parse the exp as statements when it contains semicolons
212
+ if ( ret . type === 'Program' ) {
213
+ ret = ret . body [ 0 ]
214
+ if ( ret . type === 'ExpressionStatement' ) {
215
+ ret = ret . expression
216
+ }
217
+ }
218
+ ret = unwrapTSNode ( ret ) as Expression
219
+ return (
220
+ ret . type === 'FunctionExpression' ||
221
+ ret . type === 'ArrowFunctionExpression'
222
+ )
223
+ } catch ( e ) {
224
+ return false
225
+ }
226
+ }
227
+
228
+ export const isFnExpression : (
229
+ exp : ExpressionNode ,
230
+ context : TransformContext ,
231
+ ) => boolean = __BROWSER__ ? isFnExpressionBrowser : isFnExpressionNode
232
+
182
233
export function advancePositionWithClone (
183
234
pos : Position ,
184
235
source : string ,
0 commit comments