]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-core): identifiers in switch-case should not be inferred as references...
authorTony Wang <100271394+wngtk@users.noreply.github.com>
Wed, 24 Sep 2025 13:33:48 +0000 (21:33 +0800)
committerGitHub <noreply@github.com>
Wed, 24 Sep 2025 13:33:48 +0000 (21:33 +0800)
packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts
packages/compiler-core/src/babelUtils.ts

index c92814089ef8fd4758f2b91040629b76984105c2..2f1e6eb64122c29ed7408c345dccb70322e6b9ff 100644 (file)
@@ -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`)
+    })
+  })
 })
index 51614612b1015b6a099419a6d96cbd330b92559b..0ce257ca53f4182fb5d2c6e87ef219e21546bd1d 100644 (file)
@@ -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<string> }, 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[] = [],