Explorar el Código

fix(compiler-vapor): handle same-name shorthand edge case for in-DOM templates

fix https://github.com/vuejs/core/issues/10280
三咲智子 Kevin Deng hace 2 años
padre
commit
3957dabb8c

+ 1 - 1
packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap

@@ -183,7 +183,7 @@ export function render(_ctx) {
 
 exports[`compiler v-bind > should error if empty expression 1`] = `
 "import { template as _template } from 'vue/vapor';
-const t0 = _template("<div arg=\\"\\"></div>")
+const t0 = _template("<div arg></div>")
 
 export function render(_ctx) {
   const n0 = t0()

+ 20 - 2
packages/compiler-vapor/__tests__/transforms/vBind.spec.ts

@@ -245,11 +245,29 @@ describe('compiler v-bind', () => {
     })
     expect(ir.template[0]).toMatchObject({
       type: IRNodeTypes.TEMPLATE_FACTORY,
-      template: '<div arg=""></div>',
+      template: '<div arg></div>',
     })
 
     expect(code).matchSnapshot()
-    expect(code).contains(JSON.stringify('<div arg=""></div>'))
+    expect(code).contains(JSON.stringify('<div arg></div>'))
+  })
+
+  test('error on invalid argument for same-name shorthand', () => {
+    const onError = vi.fn()
+    compileWithVBind(`<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,
+        },
+      },
+    })
   })
 
   test('.camel modifier', () => {

+ 1 - 1
packages/compiler-vapor/src/transforms/transformRef.ts

@@ -17,7 +17,7 @@ export const transformRef: NodeTransform = (node, context) => {
   if (dir.type === NodeTypes.DIRECTIVE) {
     value =
       (dir.exp as SimpleExpressionNode | undefined) ||
-      normalizeBindShorthand(dir.arg as SimpleExpressionNode)
+      normalizeBindShorthand(dir.arg as SimpleExpressionNode, context)
   } else {
     value = dir.value ? JSON.stringify(dir.value.content) : '""'
   }

+ 27 - 9
packages/compiler-vapor/src/transforms/vBind.ts

@@ -1,16 +1,29 @@
 import {
   ErrorCodes,
+  NodeTypes,
   type SimpleExpressionNode,
   createCompilerError,
   createSimpleExpression,
 } from '@vue/compiler-dom'
 import { camelize, isReservedProp } from '@vue/shared'
-import type { DirectiveTransform } from '../transform'
+import type { DirectiveTransform, TransformContext } from '../transform'
 
+// same-name shorthand - :arg is expanded to :arg="arg"
 export function normalizeBindShorthand(
   arg: SimpleExpressionNode,
+  context: TransformContext,
 ): SimpleExpressionNode {
-  // shorthand syntax https://github.com/vuejs/core/pull/9451
+  if (arg.type !== NodeTypes.SIMPLE_EXPRESSION || !arg.isStatic) {
+    // only simple expression is allowed for same-name shorthand
+    context.options.onError(
+      createCompilerError(
+        ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
+        arg.loc,
+      ),
+    )
+    return createSimpleExpression('', true, arg.loc)
+  }
+
   const propName = camelize(arg.content)
   const exp = createSimpleExpression(propName, false, arg.loc)
   exp.ast = null
@@ -18,12 +31,13 @@ export function normalizeBindShorthand(
 }
 
 export const transformVBind: DirectiveTransform = (dir, node, context) => {
-  let { exp, loc, modifiers } = dir
+  const { loc, modifiers } = dir
+  let { exp } = dir
   const arg = dir.arg!
 
   if (arg.isStatic && isReservedProp(arg.content)) return
 
-  if (!exp) exp = normalizeBindShorthand(arg)
+  if (!exp) exp = normalizeBindShorthand(arg, context)
 
   let camel = false
   if (modifiers.includes('camel')) {
@@ -35,11 +49,15 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
   }
 
   if (!exp.content.trim()) {
-    context.options.onError(
-      createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
-    )
-    context.template += ` ${arg.content}=""`
-    return
+    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.options.onError(
+        createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
+      )
+    }
+    exp = createSimpleExpression('', true, loc)
   }
 
   return {