refactor(compiler-core): emit error on v-if key usage

This commit is contained in:
Evan You 2020-07-28 15:18:41 -04:00
parent 355c052622
commit 58b4a382f9
4 changed files with 23 additions and 32 deletions

View File

@ -145,17 +145,3 @@ return function render(_ctx, _cache) {
} }
}" }"
`; `;
exports[`compiler: v-if codegen v-if with key 1`] = `
"const _Vue = Vue
return function render(_ctx, _cache) {
with (_ctx) {
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
return ok
? (_openBlock(), _createBlock(\\"div\\", { key: \\"some-key\\" }))
: _createCommentVNode(\\"v-if\\", true)
}
}"
`;

View File

@ -282,6 +282,16 @@ describe('compiler: v-if', () => {
} }
]) ])
}) })
test('error on user key', () => {
const onError = jest.fn()
parseWithIfTransform(`<div v-if="ok" :key="1" />`, { onError })
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_V_IF_KEY
}
])
})
}) })
describe('codegen', () => { describe('codegen', () => {
@ -581,18 +591,6 @@ describe('compiler: v-if', () => {
expect(branch1.props).toMatchObject(createObjectMatcher({ key: `[0]` })) expect(branch1.props).toMatchObject(createObjectMatcher({ key: `[0]` }))
}) })
test('v-if with key', () => {
const {
root,
node: { codegenNode }
} = parseWithIfTransform(`<div v-if="ok" key="some-key"/>`)
expect(codegenNode.consequent).toMatchObject({
tag: `"div"`,
props: createObjectMatcher({ key: 'some-key' })
})
expect(generate(root).code).toMatchSnapshot()
})
test('with comments', () => { test('with comments', () => {
const { node } = parseWithIfTransform(` const { node } = parseWithIfTransform(`
<template v-if="ok"> <template v-if="ok">

View File

@ -63,6 +63,7 @@ export const enum ErrorCodes {
// transform errors // transform errors
X_V_IF_NO_EXPRESSION, X_V_IF_NO_EXPRESSION,
X_V_IF_KEY,
X_V_ELSE_NO_ADJACENT_IF, X_V_ELSE_NO_ADJACENT_IF,
X_V_FOR_NO_EXPRESSION, X_V_FOR_NO_EXPRESSION,
X_V_FOR_MALFORMED_EXPRESSION, X_V_FOR_MALFORMED_EXPRESSION,
@ -135,6 +136,7 @@ export const errorMessages: { [code: number]: string } = {
// transform errors // transform errors
[ErrorCodes.X_V_IF_NO_EXPRESSION]: `v-if/v-else-if is missing expression.`, [ErrorCodes.X_V_IF_NO_EXPRESSION]: `v-if/v-else-if is missing expression.`,
[ErrorCodes.X_V_IF_KEY]: `v-if branches must use compiler generated keys.`,
[ErrorCodes.X_V_ELSE_NO_ADJACENT_IF]: `v-else/v-else-if has no adjacent v-if.`, [ErrorCodes.X_V_ELSE_NO_ADJACENT_IF]: `v-else/v-else-if has no adjacent v-if.`,
[ErrorCodes.X_V_FOR_NO_EXPRESSION]: `v-for is missing expression.`, [ErrorCodes.X_V_FOR_NO_EXPRESSION]: `v-for is missing expression.`,
[ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION]: `v-for has invalid expression.`, [ErrorCodes.X_V_FOR_MALFORMED_EXPRESSION]: `v-for has invalid expression.`,

View File

@ -30,7 +30,7 @@ import {
OPEN_BLOCK, OPEN_BLOCK,
TELEPORT TELEPORT
} from '../runtimeHelpers' } from '../runtimeHelpers'
import { injectProp, findDir } from '../utils' import { injectProp, findDir, findProp } from '../utils'
import { PatchFlags, PatchFlagNames } from '@vue/shared' import { PatchFlags, PatchFlagNames } from '@vue/shared'
export const transformIf = createStructuralDirectiveTransform( export const transformIf = createStructuralDirectiveTransform(
@ -111,6 +111,11 @@ export function processIf(
validateBrowserExpression(dir.exp as SimpleExpressionNode, context) validateBrowserExpression(dir.exp as SimpleExpressionNode, context)
} }
const userKey = /*#__PURE__*/ findProp(node, 'key')
if (userKey) {
context.onError(createCompilerError(ErrorCodes.X_V_IF_KEY, userKey.loc))
}
if (dir.name === 'if') { if (dir.name === 'if') {
const branch = createIfBranch(node, dir) const branch = createIfBranch(node, dir)
const ifNode: IfNode = { const ifNode: IfNode = {
@ -175,13 +180,13 @@ function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
function createCodegenNodeForBranch( function createCodegenNodeForBranch(
branch: IfBranchNode, branch: IfBranchNode,
index: number, keyIndex: number,
context: TransformContext context: TransformContext
): IfConditionalExpression | BlockCodegenNode { ): IfConditionalExpression | BlockCodegenNode {
if (branch.condition) { if (branch.condition) {
return createConditionalExpression( return createConditionalExpression(
branch.condition, branch.condition,
createChildrenCodegenNode(branch, index, context), createChildrenCodegenNode(branch, keyIndex, context),
// make sure to pass in asBlock: true so that the comment node call // make sure to pass in asBlock: true so that the comment node call
// closes the current block. // closes the current block.
createCallExpression(context.helper(CREATE_COMMENT), [ createCallExpression(context.helper(CREATE_COMMENT), [
@ -190,19 +195,19 @@ function createCodegenNodeForBranch(
]) ])
) as IfConditionalExpression ) as IfConditionalExpression
} else { } else {
return createChildrenCodegenNode(branch, index, context) return createChildrenCodegenNode(branch, keyIndex, context)
} }
} }
function createChildrenCodegenNode( function createChildrenCodegenNode(
branch: IfBranchNode, branch: IfBranchNode,
index: number, keyIndex: number,
context: TransformContext context: TransformContext
): BlockCodegenNode { ): BlockCodegenNode {
const { helper } = context const { helper } = context
const keyProperty = createObjectProperty( const keyProperty = createObjectProperty(
`key`, `key`,
createSimpleExpression(index + '', false) createSimpleExpression(`${keyIndex}`, false)
) )
const { children } = branch const { children } = branch
const firstChild = children[0] const firstChild = children[0]