Răsfoiți Sursa

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

close #5584
Evan You 3 ani în urmă
părinte
comite
001184e6bb

+ 19 - 1
packages/compiler-core/__tests__/transforms/vModel.spec.ts

@@ -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
+        })
+      )
+    })
   })
 })

+ 2 - 0
packages/compiler-core/src/errors.ts

@@ -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.`,
 

+ 10 - 0
packages/compiler-core/src/transforms/vModel.ts

@@ -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 &&