]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(vModel): warn if v-model is used on file input (#295)
authorCr <631807682@qq.com>
Tue, 15 Oct 2019 16:23:38 +0000 (00:23 +0800)
committerEvan You <yyx990803@gmail.com>
Tue, 15 Oct 2019 16:23:38 +0000 (12:23 -0400)
packages/compiler-dom/__tests__/transforms/vModel.spec.ts [new file with mode: 0644]
packages/compiler-dom/src/errors.ts
packages/compiler-dom/src/transforms/vModel.ts

diff --git a/packages/compiler-dom/__tests__/transforms/vModel.spec.ts b/packages/compiler-dom/__tests__/transforms/vModel.spec.ts
new file mode 100644 (file)
index 0000000..2ed1528
--- /dev/null
@@ -0,0 +1,28 @@
+import { parse, transform, CompilerOptions } from '@vue/compiler-core'
+import { transformModel } from '../../src/transforms/vModel'
+import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
+import { DOMErrorCodes } from '../../src/errors'
+
+function transformWithModel(template: string, options: CompilerOptions = {}) {
+  const ast = parse(template)
+  transform(ast, {
+    nodeTransforms: [transformElement],
+    directiveTransforms: {
+      model: transformModel
+    },
+    ...options
+  })
+  return ast
+}
+
+describe('compiler: v-model transform', () => {
+  it('should raise error if used file input element', () => {
+    const onError = jest.fn()
+    transformWithModel(`<input type="file" v-model="test"></input>`, {
+      onError
+    })
+    expect(onError.mock.calls).toMatchObject([
+      [{ code: DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT }]
+    ])
+  })
+})
index efe55715b6dc7de9d1be8b6ed23421cfb38ea176..b59ee0c02e5a168880119fde1da87805e874d892 100644 (file)
@@ -26,7 +26,8 @@ export const enum DOMErrorCodes {
   X_V_TEXT_NO_EXPRESSION,
   X_V_TEXT_WITH_CHILDREN,
   X_V_MODEL_ON_INVALID_ELEMENT,
-  X_V_MODEL_ARG_ON_ELEMENT
+  X_V_MODEL_ARG_ON_ELEMENT,
+  X_V_MODEL_ON_FILE_INPUT_ELEMENT
 }
 
 export const DOMErrorMessages: { [code: number]: string } = {
@@ -35,5 +36,6 @@ export const DOMErrorMessages: { [code: number]: string } = {
   [DOMErrorCodes.X_V_TEXT_NO_EXPRESSION]: `v-text is missing expression.`,
   [DOMErrorCodes.X_V_TEXT_WITH_CHILDREN]: `v-text will override element children.`,
   [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_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.`
 }
index 9212e2d05e7eda38877dc513d66e657b2605021e..9cc60f49340309b52cb1325ba279044642f1274d 100644 (file)
@@ -29,6 +29,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
 
     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) {
@@ -43,6 +44,15 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
               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
             }
           }
         }
@@ -51,8 +61,10 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
       }
       // inject runtime directive
       // by returning the helper symbol via needRuntime
-      // the import will replace the resovleDirective call.
-      res.needRuntime = context.helper(directiveToUse)
+      // the import will replaced a resovleDirective call.
+      if (!isInvalidType) {
+        res.needRuntime = context.helper(directiveToUse)
+      }
     } else {
       context.onError(
         createDOMCompilerError(