| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- import {
- transformModel as baseTransform,
- DirectiveTransform,
- ElementTypes,
- findProp,
- NodeTypes,
- hasDynamicKeyVBind
- } from '@vue/compiler-core'
- import { createDOMCompilerError, DOMErrorCodes } from '../errors'
- import {
- V_MODEL_CHECKBOX,
- V_MODEL_RADIO,
- V_MODEL_SELECT,
- V_MODEL_TEXT,
- V_MODEL_DYNAMIC,
- V_MODEL_DETAILS,
- V_MODEL_DIALOG
- } from '../runtimeHelpers'
- export const transformModel: DirectiveTransform = (dir, node, context) => {
- const baseResult = baseTransform(dir, node, context)
- // base transform has errors OR component v-model (only need props)
- if (!baseResult.props.length || node.tagType === ElementTypes.COMPONENT) {
- return baseResult
- }
- if (dir.arg) {
- context.onError(
- createDOMCompilerError(
- DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
- dir.arg.loc
- )
- )
- }
- function checkDuplicatedValue() {
- const value = findProp(node, 'value')
- if (value) {
- context.onError(
- createDOMCompilerError(
- DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE,
- value.loc
- )
- )
- }
- }
- const { tag } = node
- const isCustomElement = context.isCustomElement(tag)
- if (
- tag === 'input' ||
- tag === 'textarea' ||
- tag === 'select' ||
- tag === 'details' ||
- tag === 'dialog' ||
- isCustomElement
- ) {
- let directiveToUse = V_MODEL_TEXT
- let isInvalidType = false
- if (tag === 'input' || isCustomElement) {
- const type = findProp(node, `type`)
- if (type) {
- if (type.type === NodeTypes.DIRECTIVE) {
- // :type="foo"
- directiveToUse = V_MODEL_DYNAMIC
- } else if (type.value) {
- switch (type.value.content) {
- case 'radio':
- directiveToUse = V_MODEL_RADIO
- break
- case 'checkbox':
- directiveToUse = V_MODEL_CHECKBOX
- break
- case 'file':
- isInvalidType = true
- context.onError(
- createDOMCompilerError(
- DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT,
- dir.loc
- )
- )
- break
- default:
- // text type
- __DEV__ && checkDuplicatedValue()
- break
- }
- }
- } else if (hasDynamicKeyVBind(node)) {
- // element has bindings with dynamic keys, which can possibly contain
- // "type".
- directiveToUse = V_MODEL_DYNAMIC
- } else {
- // text type
- __DEV__ && checkDuplicatedValue()
- }
- } else if (tag === 'select') {
- directiveToUse = V_MODEL_SELECT
- } else if (tag === 'dialog') {
- directiveToUse = V_MODEL_DIALOG
- } else if (tag === 'details') {
- directiveToUse = V_MODEL_DETAILS
- } else {
- // textarea
- __DEV__ && checkDuplicatedValue()
- }
- // inject runtime directive
- // by returning the helper symbol via needRuntime
- // the import will replaced a resolveDirective call.
- if (!isInvalidType) {
- baseResult.needRuntime = context.helper(directiveToUse)
- }
- } else {
- context.onError(
- createDOMCompilerError(
- DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
- dir.loc
- )
- )
- }
- // native vmodel doesn't need the `modelValue` props since they are also
- // passed to the runtime as `binding.value`. removing it reduces code size.
- baseResult.props = baseResult.props.filter(
- p =>
- !(
- p.key.type === NodeTypes.SIMPLE_EXPRESSION &&
- p.key.content === 'modelValue'
- )
- )
- return baseResult
- }
|