})
})
+ test('should handle multiple inline statement', () => {
+ const { node } = parseWithVOn(`<div @click="foo();bar()"/>`)
+ const props = (node.codegenNode as CallExpression)
+ .arguments[1] as ObjectExpression
+ expect(props.properties[0]).toMatchObject({
+ key: { content: `onClick` },
+ value: {
+ type: NodeTypes.COMPOUND_EXPRESSION,
+ // should wrap with `{` for multiple statements
+ // in this case the return value is discarded and the behavior is
+ // consistent with 2.x
+ children: [`$event => {`, { content: `foo();bar()` }, `}`]
+ }
+ })
+ })
+
test('inline statement w/ prefixIdentifiers: true', () => {
const { node } = parseWithVOn(`<div @click="foo($event)"/>`, {
prefixIdentifiers: true
})
})
+ test('multiple inline statements w/ prefixIdentifiers: true', () => {
+ const { node } = parseWithVOn(`<div @click="foo($event);bar()"/>`, {
+ prefixIdentifiers: true
+ })
+ const props = (node.codegenNode as CallExpression)
+ .arguments[1] as ObjectExpression
+ expect(props.properties[0]).toMatchObject({
+ key: { content: `onClick` },
+ value: {
+ type: NodeTypes.COMPOUND_EXPRESSION,
+ children: [
+ `$event => {`,
+ { content: `_ctx.foo` },
+ `(`,
+ // should NOT prefix $event
+ { content: `$event` },
+ `);`,
+ { content: `_ctx.bar` },
+ `()`,
+ `}`
+ ]
+ }
+ })
+ })
+
test('should NOT wrap as function if expression is already function expression', () => {
const { node } = parseWithVOn(`<div @click="$event => foo($event)"/>`)
const props = (node.codegenNode as CallExpression)
context: TransformContext,
// some expressions like v-slot props & v-for aliases should be parsed as
// function params
- asParams: boolean = false
+ asParams = false,
+ // v-on handler values may contain multiple statements
+ asRawStatements = false
): ExpressionNode {
if (!context.prefixIdentifiers || !node.content.trim()) {
return node
}
let ast: any
- // if the expression is supposed to be used in a function params position
- // we need to parse it differently.
- const source = `(${rawExp})${asParams ? `=>{}` : ``}`
+ // exp needs to be parsed differently:
+ // 1. Multiple inline statements (v-on, with presence of `;`): parse as raw
+ // exp, but make sure to pad with spaces for consistent ranges
+ // 2. Expressions: wrap with parens (for e.g. object expressions)
+ // 3. Function arguments (v-for, v-slot): place in a function argument position
+ const source = asRawStatements
+ ? ` ${rawExp} `
+ : `(${rawExp})${asParams ? `=>{}` : ``}`
try {
ast = parseJS(source, { ranges: true })
} catch (e) {
if (exp) {
const isMemberExp = isMemberExpression(exp.content)
const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content))
+ const hasMultipleStatements = exp.content.includes(`;`)
// process the expression since it's been skipped
if (!__BROWSER__ && context.prefixIdentifiers) {
context.addIdentifiers(`$event`)
- exp = processExpression(exp, context)
+ exp = processExpression(exp, context, false, hasMultipleStatements)
context.removeIdentifiers(`$event`)
// with scope analysis, the function is hoistable if it has no reference
// to scope variables.
if (isInlineStatement || (isCacheable && isMemberExp)) {
// wrap inline statement in a function expression
exp = createCompoundExpression([
- `$event => (`,
+ `$event => ${hasMultipleStatements ? `{` : `(`}`,
...(exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children),
- `)`
+ hasMultipleStatements ? `}` : `)`
])
}
}