mirror of https://github.com/vuejs/core.git
fix(compiler-core): identifiers in switch-case should not be inferred as references (#13923)
This commit is contained in:
parent
565741a9b2
commit
5953c9ff90
|
@ -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`)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -10,6 +10,8 @@ import type {
|
||||||
Node,
|
Node,
|
||||||
ObjectProperty,
|
ObjectProperty,
|
||||||
Program,
|
Program,
|
||||||
|
SwitchCase,
|
||||||
|
SwitchStatement,
|
||||||
} from '@babel/types'
|
} from '@babel/types'
|
||||||
import { walk } from 'estree-walker'
|
import { walk } from 'estree-walker'
|
||||||
|
|
||||||
|
@ -80,15 +82,32 @@ export function walkIdentifiers(
|
||||||
markScopeIdentifier(node, id, knownIds),
|
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) {
|
} else if (node.type === 'CatchClause' && node.param) {
|
||||||
|
if (node.scopeIds) {
|
||||||
|
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||||
|
} else {
|
||||||
for (const id of extractIdentifiers(node.param)) {
|
for (const id of extractIdentifiers(node.param)) {
|
||||||
markScopeIdentifier(node, id, knownIds)
|
markScopeIdentifier(node, id, knownIds)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (isForStatement(node)) {
|
} else if (isForStatement(node)) {
|
||||||
|
if (node.scopeIds) {
|
||||||
|
node.scopeIds.forEach(id => markKnownIds(id, knownIds))
|
||||||
|
} else {
|
||||||
walkForStatement(node, false, id =>
|
walkForStatement(node, false, id =>
|
||||||
markScopeIdentifier(node, id, knownIds),
|
markScopeIdentifier(node, id, knownIds),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
|
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
|
||||||
parent && parentStack.pop()
|
parent && parentStack.pop()
|
||||||
|
@ -187,10 +206,11 @@ export function walkFunctionParams(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function walkBlockDeclarations(
|
export function walkBlockDeclarations(
|
||||||
block: BlockStatement | Program,
|
block: BlockStatement | SwitchCase | Program,
|
||||||
onIdent: (node: Identifier) => void,
|
onIdent: (node: Identifier) => void,
|
||||||
): 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.type === 'VariableDeclaration') {
|
||||||
if (stmt.declare) continue
|
if (stmt.declare) continue
|
||||||
for (const decl of stmt.declarations) {
|
for (const decl of stmt.declarations) {
|
||||||
|
@ -206,6 +226,8 @@ export function walkBlockDeclarations(
|
||||||
onIdent(stmt.id)
|
onIdent(stmt.id)
|
||||||
} else if (isForStatement(stmt)) {
|
} else if (isForStatement(stmt)) {
|
||||||
walkForStatement(stmt, true, onIdent)
|
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(
|
export function extractIdentifiers(
|
||||||
param: Node,
|
param: Node,
|
||||||
nodes: Identifier[] = [],
|
nodes: Identifier[] = [],
|
||||||
|
|
Loading…
Reference in New Issue