diff --git a/packages/compiler-core/__tests__/transforms/vBind.spec.ts b/packages/compiler-core/__tests__/transforms/vBind.spec.ts
index 84b9ee8ca47..be063b8a9d5 100644
--- a/packages/compiler-core/__tests__/transforms/vBind.spec.ts
+++ b/packages/compiler-core/__tests__/transforms/vBind.spec.ts
@@ -408,4 +408,22 @@ describe('compiler: transform v-bind', () => {
},
})
})
+
+ test('error on invalid argument for same-name shorthand', () => {
+ const onError = vi.fn()
+ parseWithVBind(`
`, { 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,
+ },
+ },
+ })
+ })
})
diff --git a/packages/compiler-core/src/errors.ts b/packages/compiler-core/src/errors.ts
index 6728a80d44a..cd6a443c5cf 100644
--- a/packages/compiler-core/src/errors.ts
+++ b/packages/compiler-core/src/errors.ts
@@ -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.X_V_FOR_MALFORMED_EXPRESSION]: `v-for has invalid expression.`,
[ErrorCodes.X_V_FOR_TEMPLATE_KEY_PLACEMENT]: ` key should be placed on the 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 outlet.`,
[ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE]:
diff --git a/packages/compiler-core/src/transforms/vBind.ts b/packages/compiler-core/src/transforms/vBind.ts
index d121775497a..234cf1fbc30 100644
--- a/packages/compiler-core/src/transforms/vBind.ts
+++ b/packages/compiler-core/src/transforms/vBind.ts
@@ -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)],
}