Skip to content

Commit

Permalink
fix(compiler-core): fix :key shorthand on v-for (#10942)
Browse files Browse the repository at this point in the history
close #10882
close #10939
  • Loading branch information
quiteeasy committed Jun 4, 2024
1 parent f94568b commit 29425df
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 11 deletions.
30 changes: 29 additions & 1 deletion packages/compiler-core/__tests__/transforms/vFor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { ErrorCodes } from '../../src/errors'
import { type CompilerOptions, generate } from '../../src'
import { FRAGMENT, RENDER_LIST, RENDER_SLOT } from '../../src/runtimeHelpers'
import { PatchFlags } from '@vue/shared'
import { PatchFlagNames, PatchFlags } from '@vue/shared'
import { createObjectMatcher, genFlagText } from '../testUtils'

export function parseWithForTransform(
Expand Down Expand Up @@ -1043,5 +1043,33 @@ describe('compiler: v-for', () => {
})
expect(generate(root).code).toMatchSnapshot()
})

test('template v-for key w/ :key shorthand on div', () => {
const {
node: { codegenNode },
} = parseWithForTransform('<div v-for="key in keys" :key>test</div>')
expect(codegenNode.patchFlag).toBe(
`${PatchFlags.KEYED_FRAGMENT} /* ${PatchFlagNames[PatchFlags.KEYED_FRAGMENT]} */`,
)
})

test('template v-for key w/ :key shorthand on template injected to the child', () => {
const {
node: { codegenNode },
} = parseWithForTransform(
'<template v-for="key in keys" :key><div>test</div></template>',
)
expect(assertSharedCodegen(codegenNode, true)).toMatchObject({
source: { content: `keys` },
params: [{ content: `key` }],
innerVNodeCall: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`,
props: createObjectMatcher({
key: '[key]',
}),
},
})
})
})
})
23 changes: 17 additions & 6 deletions packages/compiler-core/src/transforms/vBind.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { DirectiveTransform } from '../transform'
import type { DirectiveTransform, TransformContext } from '../transform'
import {
type DirectiveNode,
type ExpressionNode,
NodeTypes,
type SimpleExpressionNode,
Expand Down Expand Up @@ -56,11 +57,8 @@ export const transformBind: DirectiveTransform = (dir, _node, context) => {
}
}

const propName = camelize((arg as SimpleExpressionNode).content)
exp = dir.exp = createSimpleExpression(propName, false, arg.loc)
if (!__BROWSER__) {
exp = dir.exp = processExpression(exp, context)
}
transformBindShorthand(dir, context)
exp = dir.exp!
}

if (arg.type !== NodeTypes.SIMPLE_EXPRESSION) {
Expand Down Expand Up @@ -98,6 +96,19 @@ export const transformBind: DirectiveTransform = (dir, _node, context) => {
}
}

export const transformBindShorthand = (
dir: DirectiveNode,
context: TransformContext,
) => {
const arg = dir.arg!

const propName = camelize((arg as SimpleExpressionNode).content)
dir.exp = createSimpleExpression(propName, false, arg.loc)
if (!__BROWSER__) {
dir.exp = processExpression(dir.exp, context)
}
}

const injectPrefix = (arg: ExpressionNode, prefix: string) => {
if (arg.type === NodeTypes.SIMPLE_EXPRESSION) {
if (arg.isStatic) {
Expand Down
16 changes: 12 additions & 4 deletions packages/compiler-core/src/transforms/vFor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
import { processExpression } from './transformExpression'
import { validateBrowserExpression } from '../validateExpression'
import { PatchFlagNames, PatchFlags } from '@vue/shared'
import { transformBindShorthand } from './vBind'

export const transformFor = createStructuralDirectiveTransform(
'for',
Expand All @@ -60,13 +61,20 @@ export const transformFor = createStructuralDirectiveTransform(
]) as ForRenderListExpression
const isTemplate = isTemplateNode(node)
const memo = findDir(node, 'memo')
const keyProp = findProp(node, `key`)
const keyProp = findProp(node, `key`, false, true)
if (keyProp && keyProp.type === NodeTypes.DIRECTIVE && !keyProp.exp) {
// resolve :key shorthand #10882
transformBindShorthand(keyProp, context)
}
const keyExp =
keyProp &&
(keyProp.type === NodeTypes.ATTRIBUTE
? createSimpleExpression(keyProp.value!.content, true)
: keyProp.exp!)
const keyProperty = keyProp ? createObjectProperty(`key`, keyExp!) : null
? keyProp.value
? createSimpleExpression(keyProp.value.content, true)
: undefined
: keyProp.exp)
const keyProperty =
keyProp && keyExp ? createObjectProperty(`key`, keyExp) : null

if (!__BROWSER__ && isTemplate) {
// #2085 / #5288 process :key and v-memo expressions need to be
Expand Down

0 comments on commit 29425df

Please sign in to comment.