wip(compiler-ssr): v-model static types + textarea

This commit is contained in:
Evan You
2020-02-05 14:23:03 -05:00
parent fd470e0b1a
commit c952321fcf
15 changed files with 328 additions and 114 deletions

View File

@@ -28,6 +28,7 @@ export const enum DOMErrorCodes {
X_V_MODEL_ON_INVALID_ELEMENT,
X_V_MODEL_ARG_ON_ELEMENT,
X_V_MODEL_ON_FILE_INPUT_ELEMENT,
X_V_MODEL_UNNECESSARY_VALUE,
X_V_SHOW_NO_EXPRESSION,
__EXTEND_POINT__
}
@@ -40,5 +41,6 @@ export const DOMErrorMessages: { [code: number]: string } = {
[DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT]: `v-model can only be used on <input>, <textarea> and <select> elements.`,
[DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT]: `v-model argument is not supported on plain elements.`,
[DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT]: `v-model cannot used on file inputs since they are read-only. Use a v-on:change listener instead.`,
[DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE]: `Unnecessary value binding used alongside v-model. It will interfere with v-model's behavior.`,
[DOMErrorCodes.X_V_SHOW_NO_EXPRESSION]: `v-show is missing expression.`
}

View File

@@ -57,5 +57,5 @@ export function parse(template: string, options: ParserOptions = {}): RootNode {
}
export { transformStyle } from './transforms/transformStyle'
export { DOMErrorCodes } from './errors'
export { createDOMCompilerError, DOMErrorCodes } from './errors'
export * from '@vue/compiler-core'

View File

@@ -16,68 +16,88 @@ import {
export const transformModel: DirectiveTransform = (dir, node, context) => {
const baseResult = baseTransform(dir, node, context)
// base transform has errors
if (!baseResult.props.length) {
// base transform has errors OR component v-model (only need props)
if (!baseResult.props.length || node.tagType === ElementTypes.COMPONENT) {
return baseResult
}
const { tag, tagType } = node
if (tagType === ElementTypes.ELEMENT) {
if (dir.arg) {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
dir.arg.loc
)
if (dir.arg) {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
dir.arg.loc
)
}
)
}
if (tag === 'input' || tag === 'textarea' || tag === 'select') {
let directiveToUse = V_MODEL_TEXT
let isInvalidType = false
if (tag === 'input') {
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
}
}
}
} else if (tag === 'select') {
directiveToUse = V_MODEL_SELECT
}
// 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 {
function checkDuplicatedValue() {
const value = findProp(node, 'value')
if (value) {
context.onError(
createDOMCompilerError(
DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
dir.loc
DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE,
value.loc
)
)
}
}
const { tag } = node
if (tag === 'input' || tag === 'textarea' || tag === 'select') {
let directiveToUse = V_MODEL_TEXT
let isInvalidType = false
if (tag === 'input') {
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 {
// text type
__DEV__ && checkDuplicatedValue()
}
} else if (tag === 'select') {
directiveToUse = V_MODEL_SELECT
} else if (tag === '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
)
)
}
return baseResult
}