-
-
Notifications
You must be signed in to change notification settings - Fork 8.5k
/
Copy pathvModel.ts
127 lines (121 loc) · 3.36 KB
/
vModel.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import {
type DirectiveTransform,
ElementTypes,
NodeTypes,
transformModel as baseTransform,
findDir,
findProp,
hasDynamicKeyVBind,
isStaticArgOf,
} from '@vue/compiler-core'
import { DOMErrorCodes, createDOMCompilerError } from '../errors'
import {
V_MODEL_CHECKBOX,
V_MODEL_DYNAMIC,
V_MODEL_RADIO,
V_MODEL_SELECT,
V_MODEL_TEXT,
} 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 = findDir(node, 'bind')
if (value && isStaticArgOf(value.arg, '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' ||
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 {
// 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
}