2019-10-19 01:51:34 +00:00
|
|
|
import { DirectiveTransform } from '../transform'
|
2019-10-10 14:33:58 +00:00
|
|
|
import {
|
|
|
|
createSimpleExpression,
|
|
|
|
createObjectProperty,
|
|
|
|
createCompoundExpression,
|
|
|
|
NodeTypes,
|
2019-10-16 17:56:00 +00:00
|
|
|
Property,
|
2020-11-19 00:38:18 +00:00
|
|
|
ElementTypes,
|
2020-11-21 00:26:07 +00:00
|
|
|
ExpressionNode,
|
|
|
|
ConstantTypes
|
2019-10-10 14:33:58 +00:00
|
|
|
} from '../ast'
|
|
|
|
import { createCompilerError, ErrorCodes } from '../errors'
|
2020-07-13 20:48:16 +00:00
|
|
|
import {
|
|
|
|
isMemberExpression,
|
|
|
|
isSimpleIdentifier,
|
|
|
|
hasScopeRef,
|
|
|
|
isStaticExp
|
|
|
|
} from '../utils'
|
2020-11-19 00:38:18 +00:00
|
|
|
import { IS_REF } from '../runtimeHelpers'
|
|
|
|
import { BindingTypes } from '../options'
|
2019-10-10 14:33:58 +00:00
|
|
|
|
|
|
|
export const transformModel: DirectiveTransform = (dir, node, context) => {
|
|
|
|
const { exp, arg } = dir
|
|
|
|
if (!exp) {
|
2019-10-10 15:15:24 +00:00
|
|
|
context.onError(
|
|
|
|
createCompilerError(ErrorCodes.X_V_MODEL_NO_EXPRESSION, dir.loc)
|
|
|
|
)
|
2019-10-10 14:33:58 +00:00
|
|
|
return createTransformProps()
|
|
|
|
}
|
|
|
|
|
2020-11-17 17:42:58 +00:00
|
|
|
const rawExp = exp.loc.source
|
2019-10-10 15:15:24 +00:00
|
|
|
const expString =
|
2020-11-17 17:42:58 +00:00
|
|
|
exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : rawExp
|
2020-06-09 21:24:48 +00:00
|
|
|
|
2020-11-17 17:42:58 +00:00
|
|
|
// im SFC <script setup> inline mode, the exp may have been transformed into
|
|
|
|
// _unref(exp)
|
2020-11-19 00:38:18 +00:00
|
|
|
const bindingType = context.bindingMetadata[rawExp]
|
|
|
|
const maybeRef =
|
|
|
|
!__BROWSER__ &&
|
|
|
|
context.inline &&
|
|
|
|
bindingType &&
|
|
|
|
bindingType !== BindingTypes.SETUP_CONST
|
2020-11-17 17:42:58 +00:00
|
|
|
|
2020-11-19 00:38:18 +00:00
|
|
|
if (!isMemberExpression(expString) && !maybeRef) {
|
2019-10-10 14:33:58 +00:00
|
|
|
context.onError(
|
2019-10-10 15:15:24 +00:00
|
|
|
createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc)
|
2019-10-10 14:33:58 +00:00
|
|
|
)
|
|
|
|
return createTransformProps()
|
|
|
|
}
|
|
|
|
|
2019-10-16 18:05:18 +00:00
|
|
|
if (
|
|
|
|
!__BROWSER__ &&
|
|
|
|
context.prefixIdentifiers &&
|
|
|
|
isSimpleIdentifier(expString) &&
|
|
|
|
context.identifiers[expString]
|
|
|
|
) {
|
|
|
|
context.onError(
|
|
|
|
createCompilerError(ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE, exp.loc)
|
|
|
|
)
|
|
|
|
return createTransformProps()
|
|
|
|
}
|
|
|
|
|
2019-10-10 14:33:58 +00:00
|
|
|
const propName = arg ? arg : createSimpleExpression('modelValue', true)
|
|
|
|
const eventName = arg
|
2020-07-13 20:48:16 +00:00
|
|
|
? isStaticExp(arg)
|
2019-11-07 14:40:34 +00:00
|
|
|
? `onUpdate:${arg.content}`
|
2020-02-06 04:07:23 +00:00
|
|
|
: createCompoundExpression(['"onUpdate:" + ', arg])
|
2019-11-07 14:40:34 +00:00
|
|
|
: `onUpdate:modelValue`
|
2019-10-10 14:33:58 +00:00
|
|
|
|
2020-11-19 00:38:18 +00:00
|
|
|
let assignmentExp: ExpressionNode
|
|
|
|
const eventArg = context.isTS ? `($event: any)` : `$event`
|
|
|
|
if (maybeRef) {
|
|
|
|
if (bindingType === BindingTypes.SETUP_REF) {
|
|
|
|
// v-model used on known ref.
|
|
|
|
assignmentExp = createCompoundExpression([
|
|
|
|
`${eventArg} => (`,
|
|
|
|
createSimpleExpression(rawExp, false, exp.loc),
|
|
|
|
`.value = $event)`
|
|
|
|
])
|
|
|
|
} else {
|
|
|
|
// v-model used on a potentially ref binding in <script setup> inline mode.
|
2020-11-17 20:59:09 +00:00
|
|
|
// the assignment needs to check whether the binding is actually a ref.
|
2020-11-19 00:38:18 +00:00
|
|
|
const altAssignment =
|
|
|
|
bindingType === BindingTypes.SETUP_LET ? `${rawExp} = $event` : `null`
|
|
|
|
assignmentExp = createCompoundExpression([
|
|
|
|
`${eventArg} => (${context.helperString(IS_REF)}(${rawExp}) ? `,
|
|
|
|
createSimpleExpression(rawExp, false, exp.loc),
|
|
|
|
`.value = $event : ${altAssignment})`
|
|
|
|
])
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assignmentExp = createCompoundExpression([
|
|
|
|
`${eventArg} => (`,
|
|
|
|
exp,
|
|
|
|
` = $event)`
|
|
|
|
])
|
|
|
|
}
|
2020-11-17 17:42:58 +00:00
|
|
|
|
2019-10-10 22:02:51 +00:00
|
|
|
const props = [
|
2019-10-16 18:18:29 +00:00
|
|
|
// modelValue: foo
|
2019-10-10 14:33:58 +00:00
|
|
|
createObjectProperty(propName, dir.exp!),
|
2019-10-16 18:18:29 +00:00
|
|
|
// "onUpdate:modelValue": $event => (foo = $event)
|
2020-11-19 00:38:18 +00:00
|
|
|
createObjectProperty(eventName, assignmentExp)
|
2019-10-10 22:02:51 +00:00
|
|
|
]
|
|
|
|
|
2019-10-19 01:51:34 +00:00
|
|
|
// cache v-model handler if applicable (when it doesn't refer any scope vars)
|
|
|
|
if (
|
|
|
|
!__BROWSER__ &&
|
|
|
|
context.prefixIdentifiers &&
|
2019-10-23 21:57:40 +00:00
|
|
|
context.cacheHandlers &&
|
2019-10-19 01:51:34 +00:00
|
|
|
!hasScopeRef(exp, context.identifiers)
|
|
|
|
) {
|
|
|
|
props[1].value = context.cache(props[1].value)
|
|
|
|
}
|
|
|
|
|
2019-10-16 18:18:29 +00:00
|
|
|
// modelModifiers: { foo: true, "bar-baz": true }
|
|
|
|
if (dir.modifiers.length && node.tagType === ElementTypes.COMPONENT) {
|
|
|
|
const modifiers = dir.modifiers
|
|
|
|
.map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`)
|
|
|
|
.join(`, `)
|
2019-11-07 14:40:34 +00:00
|
|
|
const modifiersKey = arg
|
2020-07-13 20:48:16 +00:00
|
|
|
? isStaticExp(arg)
|
2019-11-07 14:40:34 +00:00
|
|
|
? `${arg.content}Modifiers`
|
2020-02-05 19:23:03 +00:00
|
|
|
: createCompoundExpression([arg, ' + "Modifiers"'])
|
2019-11-07 14:40:34 +00:00
|
|
|
: `modelModifiers`
|
2019-10-16 18:18:29 +00:00
|
|
|
props.push(
|
|
|
|
createObjectProperty(
|
2019-11-07 14:40:34 +00:00
|
|
|
modifiersKey,
|
2020-11-21 00:26:07 +00:00
|
|
|
createSimpleExpression(
|
|
|
|
`{ ${modifiers} }`,
|
|
|
|
false,
|
|
|
|
dir.loc,
|
|
|
|
ConstantTypes.CAN_HOIST
|
|
|
|
)
|
2019-10-16 18:18:29 +00:00
|
|
|
)
|
|
|
|
)
|
2019-10-10 22:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return createTransformProps(props)
|
2019-10-10 14:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function createTransformProps(props: Property[] = []) {
|
2020-02-04 17:20:51 +00:00
|
|
|
return { props }
|
2019-10-10 14:33:58 +00:00
|
|
|
}
|