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

fix https://github.com/vuejs/core/issues/10280
This commit is contained in:
三咲智子 Kevin Deng 2024-02-07 22:18:01 +08:00
parent 5e52ac9ab4
commit 3957dabb8c
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
4 changed files with 49 additions and 13 deletions

View File

@ -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()

View File

@ -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', () => {

View File

@ -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) : '""'
}

View File

@ -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 {