diff --git a/packages/compiler-core/__tests__/transforms/vFor.spec.ts b/packages/compiler-core/__tests__/transforms/vFor.spec.ts index fead2476a..b80bd9c20 100644 --- a/packages/compiler-core/__tests__/transforms/vFor.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vFor.spec.ts @@ -17,7 +17,7 @@ import { type SimpleExpressionNode, } from '../../src/ast' import { ErrorCodes } from '../../src/errors' -import { type CompilerOptions, generate } from '../../src' +import { BindingTypes, type CompilerOptions, generate } from '../../src' import { FRAGMENT, RENDER_LIST, RENDER_SLOT } from '../../src/runtimeHelpers' import { PatchFlags } from '@vue/shared' import { createObjectMatcher } from '../testUtils' @@ -320,6 +320,51 @@ describe('compiler: v-for', () => { ) expect(onError).toHaveBeenCalledTimes(1) }) + + test('v-for + the parameter name is the same as the component name.', () => { + const onError1 = vi.fn() + parseWithForTransform('', { + onError: onError1, + bindingMetadata: { + Comp: BindingTypes.SETUP_CONST, + }, + }) + expect(onError1).toHaveBeenCalledTimes(1) + expect(onError1).toHaveBeenCalledWith( + expect.objectContaining({ + code: ErrorCodes.X_INVALID_PARAMETER_NAME, + }), + ) + + const onError2 = vi.fn() + parseWithForTransform('', { + onError: onError2, + }) + expect(onError2).toHaveBeenCalledTimes(1) + expect(onError2).toHaveBeenCalledWith( + expect.objectContaining({ + code: ErrorCodes.X_INVALID_PARAMETER_NAME, + }), + ) + + const onError3 = vi.fn() + parseWithForTransform( + `
+
+ {{ Comp }} +
+
`, + { + onError: onError3, + }, + ) + expect(onError3).toHaveBeenCalledTimes(1) + expect(onError3).toHaveBeenCalledWith( + expect.objectContaining({ + code: ErrorCodes.X_INVALID_PARAMETER_NAME, + }), + ) + }) }) describe('source location', () => { diff --git a/packages/compiler-core/__tests__/transforms/vSlot.spec.ts b/packages/compiler-core/__tests__/transforms/vSlot.spec.ts index 4766c2ca9..c02e81686 100644 --- a/packages/compiler-core/__tests__/transforms/vSlot.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vSlot.spec.ts @@ -928,6 +928,45 @@ describe('compiler: transform component slots', () => { }, }) }) + + test('v-slot + the parameter name is the same as the component name.', () => { + const onError1 = vi.fn() + parseWithSlots( + ` + + `, + { + onError: onError1, + }, + ) + expect(onError1).toHaveBeenCalledTimes(1) + expect(onError1).toHaveBeenCalledWith( + expect.objectContaining({ + code: ErrorCodes.X_INVALID_PARAMETER_NAME, + }), + ) + + const onError2 = vi.fn() + parseWithSlots( + ` + + `, + { + onError: onError2, + prefixIdentifiers: true, + }, + ) + expect(onError2).toHaveBeenCalledTimes(1) + expect(onError2).toHaveBeenCalledWith( + expect.objectContaining({ + code: ErrorCodes.X_INVALID_PARAMETER_NAME, + }), + ) + }) }) describe(`with whitespace: 'preserve'`, () => { diff --git a/packages/compiler-core/src/errors.ts b/packages/compiler-core/src/errors.ts index 58e113ab1..1c60dfe42 100644 --- a/packages/compiler-core/src/errors.ts +++ b/packages/compiler-core/src/errors.ts @@ -69,6 +69,7 @@ export enum ErrorCodes { X_MISSING_INTERPOLATION_END, X_MISSING_DIRECTIVE_NAME, X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END, + X_INVALID_PARAMETER_NAME, // transform errors X_V_IF_NO_EXPRESSION, @@ -151,6 +152,7 @@ export const errorMessages: Record = { 'End bracket for dynamic directive argument was not found. ' + 'Note that dynamic directive argument cannot contain spaces.', [ErrorCodes.X_MISSING_DIRECTIVE_NAME]: 'Legal directive name was expected.', + [ErrorCodes.X_INVALID_PARAMETER_NAME]: `avoid using component name as parameter name.`, // transform errors [ErrorCodes.X_V_IF_NO_EXPRESSION]: `v-if/v-else-if is missing expression.`, diff --git a/packages/compiler-core/src/transforms/vFor.ts b/packages/compiler-core/src/transforms/vFor.ts index 0dca0ba9a..c82f45370 100644 --- a/packages/compiler-core/src/transforms/vFor.ts +++ b/packages/compiler-core/src/transforms/vFor.ts @@ -33,6 +33,7 @@ import { } from '../ast' import { ErrorCodes, createCompilerError } from '../errors' import { + checkParameterName, findDir, findProp, injectProp, @@ -217,6 +218,14 @@ export const transformFor: NodeTransform = createStructuralDirectiveTransform( } } + if (__DEV__ || !__BROWSER__) { + checkParameterName( + forNode.parseResult.value, + childBlock as VNodeCall, + context, + ) + } + if (memo) { const loop = createFunctionExpression( createForLoopParams(forNode.parseResult, [ diff --git a/packages/compiler-core/src/transforms/vSlot.ts b/packages/compiler-core/src/transforms/vSlot.ts index 28625439a..8549d87fd 100644 --- a/packages/compiler-core/src/transforms/vSlot.ts +++ b/packages/compiler-core/src/transforms/vSlot.ts @@ -24,6 +24,7 @@ import type { NodeTransform, TransformContext } from '../transform' import { ErrorCodes, createCompilerError } from '../errors' import { assert, + checkParameterName, findDir, hasScopeRef, isStaticExp, @@ -175,6 +176,10 @@ export function buildSlots( continue } + if (__DEV__ || !__BROWSER__) { + checkParameterName(slotDir.exp, slotElement, context) + } + if (onComponentSlot) { // already has on-component slot - this is incorrect usage. context.onError( diff --git a/packages/compiler-core/src/utils.ts b/packages/compiler-core/src/utils.ts index b49d70bb2..2ca6cdf32 100644 --- a/packages/compiler-core/src/utils.ts +++ b/packages/compiler-core/src/utils.ts @@ -2,6 +2,7 @@ import { type BlockCodegenNode, type CacheExpression, type CallExpression, + type CompoundExpressionNode, type DirectiveNode, type ElementNode, ElementTypes, @@ -42,6 +43,7 @@ import type { PropsExpression } from './transforms/transformElement' import { parseExpression } from '@babel/parser' import type { Expression, Node } from '@babel/types' import { unwrapTSNode } from './babelUtils' +import { ErrorCodes, createCompilerError } from './errors' export const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode => p.type === NodeTypes.SIMPLE_EXPRESSION && p.isStatic @@ -564,3 +566,51 @@ export function getMemoedVNodeCall( } export const forAliasRE: RegExp = /([\s\S]*?)\s+(?:in|of)\s+(\S[\s\S]*)/ + +export function findComponentTagNode( + node: VNodeCall | ElementNode, + name: string, +): VNodeCall | ElementNode | undefined { + if ( + node.tag === name || + node.tag === `$setup["${name}"]` || + node.tag === `_component_${name}` + ) + return node + if (node.children) { + const children = node.children as TemplateChildNode[] + for (let i = 0; i < children.length; i++) { + const child = children[i] + if ((child as ElementNode).tag) { + const targetTag = findComponentTagNode(child as ElementNode, name) + if (targetTag) return targetTag + } + } + } +} + +export function checkParameterName( + exp: ExpressionNode | undefined, + blockNode: VNodeCall | ElementNode, + context: TransformContext, +): void { + if ( + exp && + findComponentTagNode(blockNode, (exp as SimpleExpressionNode).content) + ) { + context.onError( + createCompilerError(ErrorCodes.X_INVALID_PARAMETER_NAME, exp.loc), + ) + } + + let identifiers: CompoundExpressionNode['identifiers'] = [] + if (exp && (exp as CompoundExpressionNode).identifiers) { + identifiers = (exp as CompoundExpressionNode).identifiers + } + + if (identifiers!.some(i => !!findComponentTagNode(blockNode, i))) { + context.onError( + createCompilerError(ErrorCodes.X_INVALID_PARAMETER_NAME, exp!.loc), + ) + } +} diff --git a/packages/compiler-dom/src/errors.ts b/packages/compiler-dom/src/errors.ts index b47624840..5bffa4e53 100644 --- a/packages/compiler-dom/src/errors.ts +++ b/packages/compiler-dom/src/errors.ts @@ -21,7 +21,7 @@ export function createDOMCompilerError( } export enum DOMErrorCodes { - X_V_HTML_NO_EXPRESSION = 53 /* ErrorCodes.__EXTEND_POINT__ */, + X_V_HTML_NO_EXPRESSION = 54 /* ErrorCodes.__EXTEND_POINT__ */, X_V_HTML_WITH_CHILDREN, X_V_TEXT_NO_EXPRESSION, X_V_TEXT_WITH_CHILDREN,