@@ -40,7 +40,7 @@ import {
4040import { NOOP , isObject , isString } from '@vue/shared'
4141import type { PropsExpression } from './transforms/transformElement'
4242import { parseExpression } from '@babel/parser'
43- import type { Expression } from '@babel/types'
43+ import type { Expression , Node } from '@babel/types'
4444import { unwrapTSNode } from './babelUtils'
4545
4646export const isStaticExp = ( p : JSChildNode ) : p is SimpleExpressionNode =>
@@ -78,15 +78,20 @@ const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/
7878const validIdentCharRE = / [ \. \? \w $ \xA0 - \uFFFF ] /
7979const whitespaceRE = / \s + [ . [ ] \s * | \s * [ . [ ] \s + / g
8080
81+ const getExpSource = ( exp : ExpressionNode ) : string =>
82+ exp . type === NodeTypes . SIMPLE_EXPRESSION ? exp . content : exp . loc . source
83+
8184/**
8285 * Simple lexer to check if an expression is a member expression. This is
8386 * lax and only checks validity at the root level (i.e. does not validate exps
8487 * inside square brackets), but it's ok since these are only used on template
8588 * expressions and false positives are invalid expressions in the first place.
8689 */
87- export const isMemberExpressionBrowser = ( path : string ) : boolean => {
90+ export const isMemberExpressionBrowser = ( exp : ExpressionNode ) : boolean => {
8891 // 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 ( ) )
9095
9196 let state = MemberExpLexState . inMemberExp
9297 let stateStack : MemberExpLexState [ ] = [ ]
@@ -154,15 +159,19 @@ export const isMemberExpressionBrowser = (path: string): boolean => {
154159}
155160
156161export const isMemberExpressionNode : (
157- path : string ,
162+ exp : ExpressionNode ,
158163 context : TransformContext ,
159164) => boolean = __BROWSER__
160165 ? ( NOOP as any )
161- : ( path : string , context : TransformContext ) : boolean => {
166+ : ( exp , context ) => {
162167 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+ } )
166175 ret = unwrapTSNode ( ret ) as Expression
167176 return (
168177 ret . type === 'MemberExpression' ||
@@ -175,10 +184,52 @@ export const isMemberExpressionNode: (
175184 }
176185
177186export const isMemberExpression : (
178- path : string ,
187+ exp : ExpressionNode ,
179188 context : TransformContext ,
180189) => boolean = __BROWSER__ ? isMemberExpressionBrowser : isMemberExpressionNode
181190
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+
182233export function advancePositionWithClone (
183234 pos : Position ,
184235 source : string ,
0 commit comments