| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- import { DirectiveTransform } from '../transform'
- import {
- createSimpleExpression,
- createObjectProperty,
- createCompoundExpression,
- NodeTypes,
- Property,
- ElementTypes,
- ExpressionNode,
- ConstantTypes
- } from '../ast'
- import { createCompilerError, ErrorCodes } from '../errors'
- import {
- isMemberExpression,
- isSimpleIdentifier,
- hasScopeRef,
- isStaticExp
- } from '../utils'
- import { IS_REF } from '../runtimeHelpers'
- import { BindingTypes } from '../options'
- export const transformModel: DirectiveTransform = (dir, node, context) => {
- const { exp, arg } = dir
- if (!exp) {
- context.onError(
- createCompilerError(ErrorCodes.X_V_MODEL_NO_EXPRESSION, dir.loc)
- )
- return createTransformProps()
- }
- const rawExp = exp.loc.source
- const expString =
- exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : rawExp
- // im SFC <script setup> inline mode, the exp may have been transformed into
- // _unref(exp)
- const bindingType = context.bindingMetadata[rawExp]
- const maybeRef =
- !__BROWSER__ &&
- context.inline &&
- bindingType &&
- bindingType !== BindingTypes.SETUP_CONST
- if (!expString.trim() || (!isMemberExpression(expString) && !maybeRef)) {
- context.onError(
- createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc)
- )
- return createTransformProps()
- }
- if (
- !__BROWSER__ &&
- context.prefixIdentifiers &&
- isSimpleIdentifier(expString) &&
- context.identifiers[expString]
- ) {
- context.onError(
- createCompilerError(ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE, exp.loc)
- )
- return createTransformProps()
- }
- const propName = arg ? arg : createSimpleExpression('modelValue', true)
- const eventName = arg
- ? isStaticExp(arg)
- ? `onUpdate:${arg.content}`
- : createCompoundExpression(['"onUpdate:" + ', arg])
- : `onUpdate:modelValue`
- 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.
- // the assignment needs to check whether the binding is actually a ref.
- 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)`
- ])
- }
- const props = [
- // modelValue: foo
- createObjectProperty(propName, dir.exp!),
- // "onUpdate:modelValue": $event => (foo = $event)
- createObjectProperty(eventName, assignmentExp)
- ]
- // cache v-model handler if applicable (when it doesn't refer any scope vars)
- if (
- !__BROWSER__ &&
- context.prefixIdentifiers &&
- context.cacheHandlers &&
- !hasScopeRef(exp, context.identifiers)
- ) {
- props[1].value = context.cache(props[1].value)
- }
- // 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(`, `)
- const modifiersKey = arg
- ? isStaticExp(arg)
- ? `${arg.content}Modifiers`
- : createCompoundExpression([arg, ' + "Modifiers"'])
- : `modelModifiers`
- props.push(
- createObjectProperty(
- modifiersKey,
- createSimpleExpression(
- `{ ${modifiers} }`,
- false,
- dir.loc,
- ConstantTypes.CAN_HOIST
- )
- )
- )
- }
- return createTransformProps(props)
- }
- function createTransformProps(props: Property[] = []) {
- return { props }
- }
|