mirror of https://github.com/vuejs/core.git
fix(compiler-core): properly handle for loop variable declarations in expression transforms
ref https://github.com/vuejs/core/pull/11467#issuecomment-2263069794
This commit is contained in:
parent
f3efff1909
commit
67bb820904
|
@ -14,6 +14,21 @@ return function render(_ctx, _cache, $props, $setup, $data, $options) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: expression transform > should allow leak of var declarations in for loop 1`] = `
|
||||||
|
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
return (_openBlock(), _createElementBlock("div", {
|
||||||
|
onClick: () => {
|
||||||
|
for (var i = 0; i < _ctx.list.length; i++) {
|
||||||
|
_ctx.log(i)
|
||||||
|
}
|
||||||
|
_ctx.error(i)
|
||||||
|
}
|
||||||
|
}, null, 8 /* PROPS */, ["onClick"]))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: expression transform > should not prefix catch block param 1`] = `
|
exports[`compiler: expression transform > should not prefix catch block param 1`] = `
|
||||||
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
|
@ -53,6 +68,7 @@ return function render(_ctx, _cache) {
|
||||||
for (let i = 0; i < _ctx.list.length; i++) {
|
for (let i = 0; i < _ctx.list.length; i++) {
|
||||||
_ctx.log(i)
|
_ctx.log(i)
|
||||||
}
|
}
|
||||||
|
_ctx.error(_ctx.i)
|
||||||
}
|
}
|
||||||
}, null, 8 /* PROPS */, ["onClick"]))
|
}, null, 8 /* PROPS */, ["onClick"]))
|
||||||
}"
|
}"
|
||||||
|
@ -67,6 +83,7 @@ return function render(_ctx, _cache) {
|
||||||
for (const x in _ctx.list) {
|
for (const x in _ctx.list) {
|
||||||
_ctx.log(x)
|
_ctx.log(x)
|
||||||
}
|
}
|
||||||
|
_ctx.error(_ctx.x)
|
||||||
}
|
}
|
||||||
}, null, 8 /* PROPS */, ["onClick"]))
|
}, null, 8 /* PROPS */, ["onClick"]))
|
||||||
}"
|
}"
|
||||||
|
@ -81,6 +98,7 @@ return function render(_ctx, _cache) {
|
||||||
for (const x of _ctx.list) {
|
for (const x of _ctx.list) {
|
||||||
_ctx.log(x)
|
_ctx.log(x)
|
||||||
}
|
}
|
||||||
|
_ctx.error(_ctx.x)
|
||||||
}
|
}
|
||||||
}, null, 8 /* PROPS */, ["onClick"]))
|
}, null, 8 /* PROPS */, ["onClick"]))
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -468,9 +468,11 @@ describe('compiler: expression transform', () => {
|
||||||
for (const x in list) {
|
for (const x in list) {
|
||||||
log(x)
|
log(x)
|
||||||
}
|
}
|
||||||
|
error(x)
|
||||||
}"/>`,
|
}"/>`,
|
||||||
)
|
)
|
||||||
expect(code).not.toMatch(`_ctx.x`)
|
expect(code).not.toMatch(`log(_ctx.x)`)
|
||||||
|
expect(code).toMatch(`error(_ctx.x)`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -480,9 +482,11 @@ describe('compiler: expression transform', () => {
|
||||||
for (const x of list) {
|
for (const x of list) {
|
||||||
log(x)
|
log(x)
|
||||||
}
|
}
|
||||||
|
error(x)
|
||||||
}"/>`,
|
}"/>`,
|
||||||
)
|
)
|
||||||
expect(code).not.toMatch(`_ctx.x`)
|
expect(code).not.toMatch(`log(_ctx.x)`)
|
||||||
|
expect(code).toMatch(`error(_ctx.x)`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -492,9 +496,25 @@ describe('compiler: expression transform', () => {
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
log(i)
|
log(i)
|
||||||
}
|
}
|
||||||
|
error(i)
|
||||||
}"/>`,
|
}"/>`,
|
||||||
)
|
)
|
||||||
expect(code).not.toMatch(`_ctx.i`)
|
expect(code).not.toMatch(`log(_ctx.i)`)
|
||||||
|
expect(code).toMatch(`error(_ctx.i)`)
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should allow leak of var declarations in for loop', () => {
|
||||||
|
const { code } = compile(
|
||||||
|
`<div @click="() => {
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
log(i)
|
||||||
|
}
|
||||||
|
error(i)
|
||||||
|
}"/>`,
|
||||||
|
)
|
||||||
|
expect(code).not.toMatch(`log(_ctx.i)`)
|
||||||
|
expect(code).not.toMatch(`error(_ctx.i)`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
// do not import runtime methods
|
// do not import runtime methods
|
||||||
import type {
|
import type {
|
||||||
BlockStatement,
|
BlockStatement,
|
||||||
|
ForInStatement,
|
||||||
|
ForOfStatement,
|
||||||
|
ForStatement,
|
||||||
Function,
|
Function,
|
||||||
Identifier,
|
Identifier,
|
||||||
Node,
|
Node,
|
||||||
|
@ -81,6 +84,10 @@ export function walkIdentifiers(
|
||||||
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)) {
|
||||||
|
walkForStatement(node, false, id =>
|
||||||
|
markScopeIdentifier(node, id, knownIds),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
|
leave(node: Node & { scopeIds?: Set<string> }, parent: Node | null) {
|
||||||
|
@ -196,21 +203,39 @@ export function walkBlockDeclarations(
|
||||||
) {
|
) {
|
||||||
if (stmt.declare || !stmt.id) continue
|
if (stmt.declare || !stmt.id) continue
|
||||||
onIdent(stmt.id)
|
onIdent(stmt.id)
|
||||||
} else if (
|
} else if (isForStatement(stmt)) {
|
||||||
|
walkForStatement(stmt, true, onIdent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isForStatement(
|
||||||
|
stmt: Node,
|
||||||
|
): stmt is ForStatement | ForOfStatement | ForInStatement {
|
||||||
|
return (
|
||||||
stmt.type === 'ForOfStatement' ||
|
stmt.type === 'ForOfStatement' ||
|
||||||
stmt.type === 'ForInStatement' ||
|
stmt.type === 'ForInStatement' ||
|
||||||
stmt.type === 'ForStatement'
|
stmt.type === 'ForStatement'
|
||||||
) {
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function walkForStatement(
|
||||||
|
stmt: ForStatement | ForOfStatement | ForInStatement,
|
||||||
|
isVar: boolean,
|
||||||
|
onIdent: (id: Identifier) => void,
|
||||||
|
) {
|
||||||
const variable = stmt.type === 'ForStatement' ? stmt.init : stmt.left
|
const variable = stmt.type === 'ForStatement' ? stmt.init : stmt.left
|
||||||
if (variable && variable.type === 'VariableDeclaration') {
|
if (
|
||||||
|
variable &&
|
||||||
|
variable.type === 'VariableDeclaration' &&
|
||||||
|
(variable.kind === 'var' ? isVar : !isVar)
|
||||||
|
) {
|
||||||
for (const decl of variable.declarations) {
|
for (const decl of variable.declarations) {
|
||||||
for (const id of extractIdentifiers(decl.id)) {
|
for (const id of extractIdentifiers(decl.id)) {
|
||||||
onIdent(id)
|
onIdent(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractIdentifiers(
|
export function extractIdentifiers(
|
||||||
|
|
Loading…
Reference in New Issue