2019-09-23 10:19:42 +08:00
|
|
|
import { DirectiveTransform } from '../transform'
|
2019-09-27 23:42:02 +08:00
|
|
|
import {
|
2019-10-14 12:33:23 +08:00
|
|
|
DirectiveNode,
|
2019-09-27 23:42:02 +08:00
|
|
|
createObjectProperty,
|
|
|
|
createSimpleExpression,
|
|
|
|
ExpressionNode,
|
|
|
|
NodeTypes,
|
2019-10-04 05:47:00 +08:00
|
|
|
createCompoundExpression,
|
|
|
|
SimpleExpressionNode
|
2019-09-27 23:42:02 +08:00
|
|
|
} from '../ast'
|
2019-09-23 10:19:42 +08:00
|
|
|
import { capitalize } from '@vue/shared'
|
2019-09-25 10:39:20 +08:00
|
|
|
import { createCompilerError, ErrorCodes } from '../errors'
|
2019-10-04 05:47:00 +08:00
|
|
|
import { processExpression } from './transformExpression'
|
2019-10-10 23:15:24 +08:00
|
|
|
import { isMemberExpression } from '../utils'
|
2019-10-04 05:47:00 +08:00
|
|
|
|
|
|
|
const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/
|
2019-09-23 10:19:42 +08:00
|
|
|
|
2019-10-14 12:33:23 +08:00
|
|
|
export interface VOnDirectiveNode extends DirectiveNode {
|
|
|
|
// v-on without arg is handled directly in ./element.ts due to it affecting
|
|
|
|
// codegen for the entire props object. This transform here is only for v-on
|
|
|
|
// *with* args.
|
|
|
|
arg: ExpressionNode
|
|
|
|
// exp is guaranteed to be a simple expression here because v-on w/ arg is
|
|
|
|
// skipped by transformExpression as a special case.
|
|
|
|
exp: SimpleExpressionNode | undefined
|
|
|
|
}
|
|
|
|
|
|
|
|
export const transformOn: DirectiveTransform = (
|
|
|
|
dir: VOnDirectiveNode,
|
|
|
|
node,
|
|
|
|
context
|
|
|
|
) => {
|
|
|
|
const { loc, modifiers, arg } = dir
|
2019-10-04 05:47:00 +08:00
|
|
|
if (!dir.exp && !modifiers.length) {
|
2019-09-25 10:39:20 +08:00
|
|
|
context.onError(createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc))
|
|
|
|
}
|
|
|
|
let eventName: ExpressionNode
|
2019-09-27 23:42:02 +08:00
|
|
|
if (arg.type === NodeTypes.SIMPLE_EXPRESSION) {
|
|
|
|
if (arg.isStatic) {
|
|
|
|
eventName = createSimpleExpression(
|
|
|
|
`on${capitalize(arg.content)}`,
|
|
|
|
true,
|
|
|
|
arg.loc
|
|
|
|
)
|
|
|
|
} else {
|
2019-10-02 00:25:13 +08:00
|
|
|
eventName = createCompoundExpression([`"on" + (`, arg, `)`])
|
2019-09-27 23:42:02 +08:00
|
|
|
}
|
2019-09-25 10:39:20 +08:00
|
|
|
} else {
|
2019-10-05 11:12:49 +08:00
|
|
|
// already a compound expression.
|
2019-09-27 23:42:02 +08:00
|
|
|
eventName = arg
|
|
|
|
eventName.children.unshift(`"on" + (`)
|
|
|
|
eventName.children.push(`)`)
|
2019-09-25 10:39:20 +08:00
|
|
|
}
|
2019-09-23 10:19:42 +08:00
|
|
|
// TODO .once modifier handling since it is platform agnostic
|
|
|
|
// other modifiers are handled in compiler-dom
|
2019-10-04 05:47:00 +08:00
|
|
|
|
|
|
|
// handler processing
|
2019-10-14 12:33:23 +08:00
|
|
|
let exp: ExpressionNode | undefined = dir.exp
|
|
|
|
if (exp) {
|
2019-10-04 05:47:00 +08:00
|
|
|
const isInlineStatement = !(
|
2019-10-10 23:15:24 +08:00
|
|
|
isMemberExpression(exp.content) || fnExpRE.test(exp.content)
|
2019-10-04 05:47:00 +08:00
|
|
|
)
|
|
|
|
// process the expression since it's been skipped
|
|
|
|
if (!__BROWSER__ && context.prefixIdentifiers) {
|
|
|
|
context.addIdentifiers(`$event`)
|
|
|
|
exp = processExpression(exp, context)
|
|
|
|
context.removeIdentifiers(`$event`)
|
|
|
|
}
|
|
|
|
if (isInlineStatement) {
|
|
|
|
// wrap inline statement in a function expression
|
|
|
|
exp = createCompoundExpression([
|
|
|
|
`$event => (`,
|
|
|
|
...(exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children),
|
|
|
|
`)`
|
|
|
|
])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-23 10:19:42 +08:00
|
|
|
return {
|
2019-10-11 06:02:51 +08:00
|
|
|
props: [
|
|
|
|
createObjectProperty(
|
|
|
|
eventName,
|
2019-10-14 12:33:23 +08:00
|
|
|
exp || createSimpleExpression(`() => {}`, false, loc)
|
2019-10-11 06:02:51 +08:00
|
|
|
)
|
|
|
|
],
|
2019-09-23 10:19:42 +08:00
|
|
|
needRuntime: false
|
|
|
|
}
|
|
|
|
}
|