]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-core): handle same-name shorthand edge case for in-DOM templates
authorEvan You <yyx990803@gmail.com>
Wed, 7 Feb 2024 04:15:39 +0000 (12:15 +0800)
committerEvan You <yyx990803@gmail.com>
Wed, 7 Feb 2024 04:15:39 +0000 (12:15 +0800)
Also add error for invalid arguments for same-name shorthand.

close #10280

packages/compiler-core/__tests__/transforms/vBind.spec.ts
packages/compiler-core/src/errors.ts
packages/compiler-core/src/transforms/vBind.ts

index 84b9ee8ca47c8ce1bd0017f7ad91627a097ba222..be063b8a9d5c630fd21ef463b98e8a652cc05a4d 100644 (file)
@@ -408,4 +408,22 @@ describe('compiler: transform v-bind', () => {
       },
     })
   })
+
+  test('error on invalid argument for same-name shorthand', () => {
+    const onError = vi.fn()
+    parseWithVBind(`<div v-bind:[arg] />`, { onError })
+    expect(onError.mock.calls[0][0]).toMatchObject({
+      code: ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
+      loc: {
+        start: {
+          line: 1,
+          column: 13,
+        },
+        end: {
+          line: 1,
+          column: 18,
+        },
+      },
+    })
+  })
 })
index 6728a80d44a94c8c2755ee4524eb6cb60978c2d6..cd6a443c5cf94bd648542271d45dadb87d23a283 100644 (file)
@@ -78,6 +78,7 @@ export enum ErrorCodes {
   X_V_FOR_MALFORMED_EXPRESSION,
   X_V_FOR_TEMPLATE_KEY_PLACEMENT,
   X_V_BIND_NO_EXPRESSION,
+  X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
   X_V_ON_NO_EXPRESSION,
   X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
   X_V_SLOT_MIXED_SLOT_USAGE,
@@ -156,6 +157,7 @@ export const errorMessages: Record<ErrorCodes, string> = {
   [ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION]: `v-for has invalid expression.`,
   [ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT]: `<template v-for> key should be placed on the <template> tag.`,
   [ErrorCodes.X_V_BIND_NO_EXPRESSION]: `v-bind is missing expression.`,
+  [ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT]: `v-bind with same-name shorthand only allows static argument.`,
   [ErrorCodes.X_V_ON_NO_EXPRESSION]: `v-on is missing expression.`,
   [ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET]: `Unexpected custom directive on <slot> outlet.`,
   [ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE]:
index d121775497a73688f57283d8a1abd147fe73f146..234cf1fbc3060dec73648b881e9da0f43e33f4f1 100644 (file)
@@ -2,6 +2,7 @@ import type { DirectiveTransform } from '../transform'
 import {
   type ExpressionNode,
   NodeTypes,
+  type SimpleExpressionNode,
   createObjectProperty,
   createSimpleExpression,
 } from '../ast'
@@ -17,10 +18,45 @@ export const transformBind: DirectiveTransform = (dir, _node, context) => {
   const { modifiers, loc } = dir
   const arg = dir.arg!
 
-  // :arg is replaced by :arg="arg"
   let { exp } = dir
-  if (!exp && arg.type === NodeTypes.SIMPLE_EXPRESSION) {
-    const propName = camelize(arg.content)
+
+  // handle empty expression
+  if (exp && exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim()) {
+    if (!__BROWSER__) {
+      // #10280 only error against empty expression in non-browser build
+      // because :foo in in-DOM templates will be parsed into :foo="" by the
+      // browser
+      context.onError(
+        createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
+      )
+      return {
+        props: [
+          createObjectProperty(arg, createSimpleExpression('', true, loc)),
+        ],
+      }
+    } else {
+      exp = undefined
+    }
+  }
+
+  // same-name shorthand - :arg is expanded to :arg="arg"
+  if (!exp) {
+    if (arg.type !== NodeTypes.SIMPLE_EXPRESSION || !arg.isStatic) {
+      // only simple expression is allowed for same-name shorthand
+      context.onError(
+        createCompilerError(
+          ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
+          arg.loc,
+        ),
+      )
+      return {
+        props: [
+          createObjectProperty(arg, createSimpleExpression('', true, loc)),
+        ],
+      }
+    }
+
+    const propName = camelize((arg as SimpleExpressionNode).content)
     exp = dir.exp = createSimpleExpression(propName, false, arg.loc)
     if (!__BROWSER__) {
       exp = dir.exp = processExpression(exp, context)
@@ -57,16 +93,6 @@ export const transformBind: DirectiveTransform = (dir, _node, context) => {
     }
   }
 
-  if (
-    !exp ||
-    (exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim())
-  ) {
-    context.onError(createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc))
-    return {
-      props: [createObjectProperty(arg, createSimpleExpression('', true, loc))],
-    }
-  }
-
   return {
     props: [createObjectProperty(arg, exp)],
   }