feat(compiler-core/v-model): error when v-model is used on scope variable

This commit is contained in:
Evan You 2019-10-16 14:05:18 -04:00
parent 5481f76ce8
commit 25dd507f71
4 changed files with 39 additions and 5 deletions

View File

@ -361,7 +361,7 @@ describe('compiler: transform v-model', () => {
test('should mark update handler dynamic if it refers slot scope variables', () => { test('should mark update handler dynamic if it refers slot scope variables', () => {
const root = parseWithVModel( const root = parseWithVModel(
'<Comp v-slot="{ foo }"><input v-model="foo"/></Comp>', '<Comp v-slot="{ foo }"><input v-model="foo.bar"/></Comp>',
{ {
prefixIdentifiers: true prefixIdentifiers: true
} }
@ -407,5 +407,20 @@ describe('compiler: transform v-model', () => {
}) })
) )
}) })
test('used on scope variable', () => {
const onError = jest.fn()
parseWithVModel('<span v-for="i in list" v-model="i" />', {
onError,
prefixIdentifiers: true
})
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE
})
)
})
}) })
}) })

View File

@ -81,6 +81,7 @@ export const enum ErrorCodes {
X_V_SLOT_MISPLACED, X_V_SLOT_MISPLACED,
X_V_MODEL_NO_EXPRESSION, X_V_MODEL_NO_EXPRESSION,
X_V_MODEL_MALFORMED_EXPRESSION, X_V_MODEL_MALFORMED_EXPRESSION,
X_V_MODEL_ON_SCOPE_VARIABLE,
// generic errors // generic errors
X_PREFIX_ID_NOT_SUPPORTED, X_PREFIX_ID_NOT_SUPPORTED,
@ -171,6 +172,7 @@ export const errorMessages: { [code: number]: string } = {
[ErrorCodes.X_V_SLOT_MISPLACED]: `v-slot can only be used on components or <template> tags.`, [ErrorCodes.X_V_SLOT_MISPLACED]: `v-slot can only be used on components or <template> tags.`,
[ErrorCodes.X_V_MODEL_NO_EXPRESSION]: `v-model is missing expression.`, [ErrorCodes.X_V_MODEL_NO_EXPRESSION]: `v-model is missing expression.`,
[ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION]: `v-model value must be a valid JavaScript member expression.`, [ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION]: `v-model value must be a valid JavaScript member expression.`,
[ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE]: `v-model cannot be used on v-for or v-slot scope variables because they are not writable.`,
// generic errors // generic errors
[ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler.`, [ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler.`,

View File

@ -9,7 +9,7 @@ import {
createInterpolation createInterpolation
} from '../ast' } from '../ast'
import { createCompilerError, ErrorCodes } from '../errors' import { createCompilerError, ErrorCodes } from '../errors'
import { isMemberExpression } from '../utils' import { isMemberExpression, isSimpleIdentifier } from '../utils'
import { isObject } from '@vue/shared' import { isObject } from '@vue/shared'
export const transformModel: DirectiveTransform = (dir, node, context) => { export const transformModel: DirectiveTransform = (dir, node, context) => {
@ -30,6 +30,18 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
return createTransformProps() 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 propName = arg ? arg : createSimpleExpression('modelValue', true)
const eventName = arg const eventName = arg
? arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic ? arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic

View File

@ -15,7 +15,12 @@ import {
} from '../runtimeHelpers' } from '../runtimeHelpers'
export const transformModel: DirectiveTransform = (dir, node, context) => { export const transformModel: DirectiveTransform = (dir, node, context) => {
const res = baseTransform(dir, node, context) const baseResult = baseTransform(dir, node, context)
// base transform has errors
if (!baseResult.props.length) {
return baseResult
}
const { tag, tagType } = node const { tag, tagType } = node
if (tagType === ElementTypes.ELEMENT) { if (tagType === ElementTypes.ELEMENT) {
if (dir.arg) { if (dir.arg) {
@ -63,7 +68,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
// by returning the helper symbol via needRuntime // by returning the helper symbol via needRuntime
// the import will replaced a resovleDirective call. // the import will replaced a resovleDirective call.
if (!isInvalidType) { if (!isInvalidType) {
res.needRuntime = context.helper(directiveToUse) baseResult.needRuntime = context.helper(directiveToUse)
} }
} else { } else {
context.onError( context.onError(
@ -74,5 +79,5 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
) )
} }
} }
return res return baseResult
} }