fix(compiler-vapor): treat attribute as dynamic if has dynamic key prop

This commit is contained in:
三咲智子 Kevin Deng 2024-02-05 03:11:37 +08:00
parent 6d098b6871
commit 2229d3ce20
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
4 changed files with 96 additions and 12 deletions

View File

@ -169,6 +169,20 @@ export function render(_ctx) {
}"
`;
exports[`compiler v-bind > dynamic arg w/ static attribute 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_renderEffect(() => {
_setDynamicProps(n1, { [_ctx.id]: _ctx.id, foo: "bar", checked: "" })
})
return n0
}"
`;
exports[`compiler v-bind > no expression (shorthand) 1`] = `
"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';

View File

@ -167,6 +167,55 @@ describe('compiler v-bind', () => {
)
})
test('dynamic arg w/ static attribute', () => {
const { ir, code } = compileWithVBind(
`<div v-bind:[id]="id" foo="bar" checked />`,
)
expect(code).matchSnapshot()
expect(ir.effect[0].operations[0]).toMatchObject({
type: IRNodeTypes.SET_DYNAMIC_PROPS,
element: 1,
props: [
[
{
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'id',
isStatic: false,
},
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'id',
isStatic: false,
},
},
{
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'foo',
isStatic: true,
},
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'bar',
isStatic: true,
},
},
{
key: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: 'checked',
isStatic: true,
},
},
],
],
})
expect(code).contains(
'_setDynamicProps(n1, { [_ctx.id]: _ctx.id, foo: "bar", checked: "" })',
)
})
test('should error if empty expression', () => {
const onError = vi.fn()
const { ir, code } = compileWithVBind(`<div v-bind:arg="" />`, {

View File

@ -10,7 +10,6 @@ import {
type ParentNode,
type RootNode,
type SimpleExpressionNode,
type SourceLocation,
type TemplateChildNode,
type TemplateNode,
defaultOnError,
@ -46,7 +45,6 @@ export type DirectiveTransform = (
export interface DirectiveTransformResult {
key: SimpleExpressionNode
value: SimpleExpressionNode
loc: SourceLocation
modifier?: '.' | '^'
runtimeCamelize?: boolean
}

View File

@ -6,6 +6,7 @@ import {
NodeTypes,
type SimpleExpressionNode,
createCompilerError,
createSimpleExpression,
} from '@vue/compiler-dom'
import { isBuiltInDirective, isReservedProp, isVoidTag } from '@vue/shared'
import type {
@ -57,16 +58,18 @@ export const transformElement: NodeTransform = (node, context) => {
function buildProps(
node: ElementNode,
context: TransformContext<ElementNode>,
props: ElementNode['props'] = node.props,
props: (VaporDirectiveNode | AttributeNode)[] = node.props as any,
isComponent: boolean,
) {
const dynamicArgs: PropsExpression[] = []
const dynamicExpr: SimpleExpressionNode[] = []
let results: DirectiveTransformResult[] = []
function pushExpressions(...exprs: SimpleExpressionNode[]) {
function pushDynamicExpressions(
...exprs: (SimpleExpressionNode | undefined)[]
) {
for (const expr of exprs) {
if (!expr.isStatic) dynamicExpr.push(expr)
if (expr && !expr.isStatic) dynamicExpr.push(expr)
}
}
@ -77,14 +80,22 @@ function buildProps(
}
}
for (const prop of props as (VaporDirectiveNode | AttributeNode)[]) {
// treat all props as dynamic key
const asDynamic = props.some(
prop =>
prop.type === NodeTypes.DIRECTIVE &&
prop.name === 'bind' &&
(!prop.arg || !prop.arg.isStatic),
)
for (const prop of props) {
if (
prop.type === NodeTypes.DIRECTIVE &&
prop.name === 'bind' &&
!prop.arg
) {
if (prop.exp) {
pushExpressions(prop.exp)
pushDynamicExpressions(prop.exp)
pushMergeArg()
dynamicArgs.push(prop.exp)
} else {
@ -95,10 +106,10 @@ function buildProps(
continue
}
const result = transformProp(prop, node, context)
const result = transformProp(prop, node, context, asDynamic)
if (result) {
results.push(result)
pushExpressions(result.key, result.value)
asDynamic && pushDynamicExpressions(result.key, result.value)
}
}
@ -136,14 +147,26 @@ function transformProp(
prop: VaporDirectiveNode | AttributeNode,
node: ElementNode,
context: TransformContext<ElementNode>,
asDynamic: boolean,
): DirectiveTransformResult | void {
const { name } = prop
if (isReservedProp(name)) return
if (prop.type === NodeTypes.ATTRIBUTE) {
context.template += ` ${name}`
if (prop.value) context.template += `="${prop.value.content}"`
return
if (asDynamic) {
return {
key: createSimpleExpression(prop.name, true, prop.nameLoc),
value: createSimpleExpression(
prop.value ? prop.value.content : '',
true,
prop.value && prop.value.loc,
),
}
} else {
context.template += ` ${name}`
if (prop.value) context.template += `="${prop.value.content}"`
return
}
}
const directiveTransform = context.options.directiveTransforms[name]