From: Tony Wang <100271394+wngtk@users.noreply.github.com> Date: Wed, 24 Sep 2025 13:33:48 +0000 (+0800) Subject: fix(compiler-core): identifiers in switch-case should not be inferred as references... X-Git-Tag: v3.5.22~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5953c9ff90090e128372f645d377bd99137a5fb4;p=thirdparty%2Fvuejs%2Fcore.git fix(compiler-core): identifiers in switch-case should not be inferred as references (#13923) --- diff --git a/packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts b/packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts index c92814089..2f1e6eb64 100644 --- a/packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts @@ -716,4 +716,42 @@ describe('compiler: expression transform', () => { }) }) }) + + describe('switch case variable declarations', () => { + test('should handle const declarations in switch case without braces', () => { + const { code } = compile( + `{{ (() => { switch (1) { case 1: const foo = "bar"; return \`\${foo}\`; } })() }}`, + ) + + expect(code).toMatch(`const foo = "bar";`) + expect(code).toMatch(`return \`\${foo}\`;`) + expect(code).not.toMatch(`_ctx.foo`) + }) + + test('should handle const declarations in switch case with braces (existing behavior)', () => { + const { code } = compile( + `{{ (() => { + switch (true) { + case true: { + const foo = "bar"; + return \`\${foo}\`; + } + } + })() }}`, + ) + + expect(code).toMatch(`const foo = "bar";`) + expect(code).toMatch(`return \`\${foo}\`;`) + expect(code).not.toMatch(`_ctx.foo`) + }) + + test('should parse switch case test as local scoped variables', () => { + const { code } = compile( + `{{ (() => { switch (foo) { case bar: return \`\${bar}\`; } })() }}`, + ) + + expect(code).toMatch('_ctx.foo') + expect(code).toMatch(`_ctx.bar`) + }) + }) }) diff --git a/packages/compiler-core/src/babelUtils.ts b/packages/compiler-core/src/babelUtils.ts index 51614612b..0ce257ca5 100644 --- a/packages/compiler-core/src/babelUtils.ts +++ b/packages/compiler-core/src/babelUtils.ts @@ -10,6 +10,8 @@ import type { Node, ObjectProperty, Program, + SwitchCase, + SwitchStatement, } from '@babel/types' import { walk } from 'estree-walker' @@ -80,14 +82,31 @@ export function walkIdentifiers( markScopeIdentifier(node, id, knownIds), ) } + } else if (node.type === 'SwitchStatement') { + if (node.scopeIds) { + node.scopeIds.forEach(id => markKnownIds(id, knownIds)) + } else { + // record switch case block-level local variables + walkSwitchStatement(node, false, id => + markScopeIdentifier(node, id, knownIds), + ) + } } else if (node.type === 'CatchClause' && node.param) { - for (const id of extractIdentifiers(node.param)) { - markScopeIdentifier(node, id, knownIds) + if (node.scopeIds) { + node.scopeIds.forEach(id => markKnownIds(id, knownIds)) + } else { + for (const id of extractIdentifiers(node.param)) { + markScopeIdentifier(node, id, knownIds) + } } } else if (isForStatement(node)) { - walkForStatement(node, false, id => - markScopeIdentifier(node, id, knownIds), - ) + if (node.scopeIds) { + node.scopeIds.forEach(id => markKnownIds(id, knownIds)) + } else { + walkForStatement(node, false, id => + markScopeIdentifier(node, id, knownIds), + ) + } } }, leave(node: Node & { scopeIds?: Set }, parent: Node | null) { @@ -187,10 +206,11 @@ export function walkFunctionParams( } export function walkBlockDeclarations( - block: BlockStatement | Program, + block: BlockStatement | SwitchCase | Program, onIdent: (node: Identifier) => void, ): void { - for (const stmt of block.body) { + const body = block.type === 'SwitchCase' ? block.consequent : block.body + for (const stmt of body) { if (stmt.type === 'VariableDeclaration') { if (stmt.declare) continue for (const decl of stmt.declarations) { @@ -206,6 +226,8 @@ export function walkBlockDeclarations( onIdent(stmt.id) } else if (isForStatement(stmt)) { walkForStatement(stmt, true, onIdent) + } else if (stmt.type === 'SwitchStatement') { + walkSwitchStatement(stmt, true, onIdent) } } } @@ -239,6 +261,28 @@ function walkForStatement( } } +function walkSwitchStatement( + stmt: SwitchStatement, + isVar: boolean, + onIdent: (id: Identifier) => void, +) { + for (const cs of stmt.cases) { + for (const stmt of cs.consequent) { + if ( + stmt.type === 'VariableDeclaration' && + (stmt.kind === 'var' ? isVar : !isVar) + ) { + for (const decl of stmt.declarations) { + for (const id of extractIdentifiers(decl.id)) { + onIdent(id) + } + } + } + } + walkBlockDeclarations(cs, onIdent) + } +} + export function extractIdentifiers( param: Node, nodes: Identifier[] = [],