}"
`;
+exports[`sfc reactive props destructure > for-of loop variable shadowing 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+interface Props {
+ msg: string;
+ input: string[];
+ }
+
+export default /*@__PURE__*/_defineComponent({
+ props: {
+ msg: { type: String, required: true },
+ input: { type: Array, required: true }
+ },
+ setup(__props: any) {
+
+
+ for (const msg of __props.input) {
+ console.log('MESSAGE', msg);
+ }
+ console.log('NOT FAIL', { msg: __props.msg });
+
+return () => {}
+}
+
+})"
+`;
+
exports[`sfc reactive props destructure > handle function parameters with same name as destructured props 1`] = `
"
export default {
}"
`;
+exports[`sfc reactive props destructure > regular for loop variable shadowing 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*@__PURE__*/_defineComponent({
+ props: {
+ i: { type: Number, required: true },
+ len: { type: Number, required: true }
+ },
+ setup(__props: any) {
+
+
+ for (let i = 0; i < __props.len; i++) {
+ console.log('INDEX', i);
+ }
+ console.log('AFTER', { i: __props.i });
+
+return () => {}
+}
+
+})"
+`;
+
exports[`sfc reactive props destructure > rest spread 1`] = `
"import { createPropsRestProxy as _createPropsRestProxy } from 'vue'
})
})
+ test('for-of loop variable shadowing', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ interface Props {
+ msg: string;
+ input: string[];
+ }
+ const { msg, input } = defineProps<Props>();
+ for (const msg of input) {
+ console.log('MESSAGE', msg);
+ }
+ console.log('NOT FAIL', { msg });
+ </script>
+ `)
+ // inside loop: should use local variable
+ expect(content).toMatch(`for (const msg of __props.input)`)
+ expect(content).toMatch(`console.log('MESSAGE', msg)`)
+ // after loop: should restore to prop reference
+ expect(content).toMatch(`console.log('NOT FAIL', { msg: __props.msg })`)
+ assertCode(content)
+ })
+
+ test('regular for loop variable shadowing', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ const { i, len } = defineProps<{ i: number; len: number }>();
+ for (let i = 0; i < len; i++) {
+ console.log('INDEX', i);
+ }
+ console.log('AFTER', { i });
+ </script>
+ `)
+ // inside loop: should use local variable
+ expect(content).toMatch(`for (let i = 0; i < __props.len; i++)`)
+ expect(content).toMatch(`console.log('INDEX', i)`)
+ // after loop: should restore to prop reference
+ expect(content).toMatch(`console.log('AFTER', { i: __props.i })`)
+ assertCode(content)
+ })
+
test('default values w/ array runtime declaration', () => {
const { content } = compile(`
<script setup>
) {
if (stmt.declare || !stmt.id) continue
registerLocalBinding(stmt.id)
- } else if (
- (stmt.type === 'ForOfStatement' || stmt.type === 'ForInStatement') &&
- stmt.left.type === 'VariableDeclaration'
- ) {
- walkVariableDeclaration(stmt.left)
} else if (
stmt.type === 'ExportNamedDeclaration' &&
stmt.declaration &&
return
}
+ // for loops: loop variable should be scoped to the loop
+ if (
+ node.type === 'ForOfStatement' ||
+ node.type === 'ForInStatement' ||
+ node.type === 'ForStatement'
+ ) {
+ pushScope()
+ const varDecl = node.type === 'ForStatement' ? node.init : node.left
+ if (varDecl && varDecl.type === 'VariableDeclaration') {
+ walkVariableDeclaration(varDecl)
+ }
+ if (node.body.type === 'BlockStatement') {
+ walkScope(node.body)
+ }
+ return
+ }
+
// non-function block scopes
if (node.type === 'BlockStatement' && !isFunctionType(parent!)) {
pushScope()
if (
(node.type === 'BlockStatement' && !isFunctionType(parent!)) ||
isFunctionType(node) ||
- node.type === 'CatchClause'
+ node.type === 'CatchClause' ||
+ node.type === 'ForOfStatement' ||
+ node.type === 'ForInStatement' ||
+ node.type === 'ForStatement'
) {
popScope()
}