Skip to content

Commit 3957dab

Browse files
committed
fix(compiler-vapor): handle same-name shorthand edge case for in-DOM templates
fix vuejs/core#10280
1 parent 5e52ac9 commit 3957dab

File tree

4 files changed

+49
-13
lines changed

4 files changed

+49
-13
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export function render(_ctx) {
183183
184184
exports[`compiler v-bind > should error if empty expression 1`] = `
185185
"import { template as _template } from 'vue/vapor';
186-
const t0 = _template("<div arg=\\"\\"></div>")
186+
const t0 = _template("<div arg></div>")
187187
188188
export function render(_ctx) {
189189
const n0 = t0()

packages/compiler-vapor/__tests__/transforms/vBind.spec.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,29 @@ describe('compiler v-bind', () => {
245245
})
246246
expect(ir.template[0]).toMatchObject({
247247
type: IRNodeTypes.TEMPLATE_FACTORY,
248-
template: '<div arg=""></div>',
248+
template: '<div arg></div>',
249249
})
250250

251251
expect(code).matchSnapshot()
252-
expect(code).contains(JSON.stringify('<div arg=""></div>'))
252+
expect(code).contains(JSON.stringify('<div arg></div>'))
253+
})
254+
255+
test('error on invalid argument for same-name shorthand', () => {
256+
const onError = vi.fn()
257+
compileWithVBind(`<div v-bind:[arg] />`, { onError })
258+
expect(onError.mock.calls[0][0]).toMatchObject({
259+
code: ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
260+
loc: {
261+
start: {
262+
line: 1,
263+
column: 13,
264+
},
265+
end: {
266+
line: 1,
267+
column: 18,
268+
},
269+
},
270+
})
253271
})
254272

255273
test('.camel modifier', () => {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const transformRef: NodeTransform = (node, context) => {
1717
if (dir.type === NodeTypes.DIRECTIVE) {
1818
value =
1919
(dir.exp as SimpleExpressionNode | undefined) ||
20-
normalizeBindShorthand(dir.arg as SimpleExpressionNode)
20+
normalizeBindShorthand(dir.arg as SimpleExpressionNode, context)
2121
} else {
2222
value = dir.value ? JSON.stringify(dir.value.content) : '""'
2323
}

packages/compiler-vapor/src/transforms/vBind.ts

+27-9
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,43 @@
11
import {
22
ErrorCodes,
3+
NodeTypes,
34
type SimpleExpressionNode,
45
createCompilerError,
56
createSimpleExpression,
67
} from '@vue/compiler-dom'
78
import { camelize, isReservedProp } from '@vue/shared'
8-
import type { DirectiveTransform } from '../transform'
9+
import type { DirectiveTransform, TransformContext } from '../transform'
910

11+
// same-name shorthand - :arg is expanded to :arg="arg"
1012
export function normalizeBindShorthand(
1113
arg: SimpleExpressionNode,
14+
context: TransformContext,
1215
): SimpleExpressionNode {
13-
// shorthand syntax https://github.com/vuejs/core/pull/9451
16+
if (arg.type !== NodeTypes.SIMPLE_EXPRESSION || !arg.isStatic) {
17+
// only simple expression is allowed for same-name shorthand
18+
context.options.onError(
19+
createCompilerError(
20+
ErrorCodes.X_V_BIND_INVALID_SAME_NAME_ARGUMENT,
21+
arg.loc,
22+
),
23+
)
24+
return createSimpleExpression('', true, arg.loc)
25+
}
26+
1427
const propName = camelize(arg.content)
1528
const exp = createSimpleExpression(propName, false, arg.loc)
1629
exp.ast = null
1730
return exp
1831
}
1932

2033
export const transformVBind: DirectiveTransform = (dir, node, context) => {
21-
let { exp, loc, modifiers } = dir
34+
const { loc, modifiers } = dir
35+
let { exp } = dir
2236
const arg = dir.arg!
2337

2438
if (arg.isStatic && isReservedProp(arg.content)) return
2539

26-
if (!exp) exp = normalizeBindShorthand(arg)
40+
if (!exp) exp = normalizeBindShorthand(arg, context)
2741

2842
let camel = false
2943
if (modifiers.includes('camel')) {
@@ -35,11 +49,15 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
3549
}
3650

3751
if (!exp.content.trim()) {
38-
context.options.onError(
39-
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
40-
)
41-
context.template += ` ${arg.content}=""`
42-
return
52+
if (!__BROWSER__) {
53+
// #10280 only error against empty expression in non-browser build
54+
// because :foo in in-DOM templates will be parsed into :foo="" by the
55+
// browser
56+
context.options.onError(
57+
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc),
58+
)
59+
}
60+
exp = createSimpleExpression('', true, loc)
4361
}
4462

4563
return {

0 commit comments

Comments
 (0)