fix(compiler/v-model): catch incorrect v-model usage on prop bindings

close #5584
This commit is contained in:
Evan You 2022-11-10 10:42:27 +08:00
parent ec795bfc51
commit 001184e6bb
3 changed files with 31 additions and 1 deletions

View File

@ -10,7 +10,8 @@ import {
ComponentNode,
NodeTypes,
VNodeCall,
NORMALIZE_PROPS
NORMALIZE_PROPS,
BindingTypes
} from '../../src'
import { ErrorCodes } from '../../src/errors'
import { transformModel } from '../../src/transforms/vModel'
@ -561,5 +562,22 @@ describe('compiler: transform v-model', () => {
})
)
})
test('used on props', () => {
const onError = jest.fn()
parseWithVModel('<div v-model="p" />', {
onError,
bindingMetadata: {
p: BindingTypes.PROPS
}
})
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: ErrorCodes.X_V_MODEL_ON_SCOPE_VARIABLE
})
)
})
})
})

View File

@ -87,6 +87,7 @@ export const enum ErrorCodes {
X_V_MODEL_NO_EXPRESSION,
X_V_MODEL_MALFORMED_EXPRESSION,
X_V_MODEL_ON_SCOPE_VARIABLE,
X_V_MODEL_ON_PROPS,
X_INVALID_EXPRESSION,
X_KEEP_ALIVE_INVALID_CHILDREN,
@ -168,6 +169,7 @@ export const errorMessages: Record<ErrorCodes, string> = {
[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_ON_SCOPE_VARIABLE]: `v-model cannot be used on v-for or v-slot scope variables because they are not writable.`,
[ErrorCodes.X_V_MODEL_ON_PROPS]: `v-model cannot be used on a prop, because local prop bindings are not writable.\nUse a v-bind binding combined with a v-on listener that emits update:x event instead.`,
[ErrorCodes.X_INVALID_EXPRESSION]: `Error parsing JavaScript expression: `,
[ErrorCodes.X_KEEP_ALIVE_INVALID_CHILDREN]: `<KeepAlive> expects exactly one child component.`,

View File

@ -35,6 +35,16 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
// im SFC <script setup> inline mode, the exp may have been transformed into
// _unref(exp)
const bindingType = context.bindingMetadata[rawExp]
// check props
if (
bindingType === BindingTypes.PROPS ||
bindingType === BindingTypes.PROPS_ALIASED
) {
context.onError(createCompilerError(ErrorCodes.X_V_MODEL_ON_PROPS, exp.loc))
return createTransformProps()
}
const maybeRef =
!__BROWSER__ &&
context.inline &&