Skip to content

Commit eac4218

Browse files
fix: possible name clash in hoisted functions (#11237)
* fix: possible name clash in hoisted functions * chore: add test
1 parent cca67bb commit eac4218

File tree

4 files changed

+41
-6
lines changed

4 files changed

+41
-6
lines changed

.changeset/stupid-parents-crash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: possible name clash in hoisted functions

packages/svelte/src/compiler/phases/3-transform/client/utils.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -455,18 +455,28 @@ export const function_visitor = (node, context) => {
455455
function get_hoistable_params(node, context) {
456456
const scope = context.state.scope;
457457

458-
/** @type {import('estree').Pattern[]} */
458+
/** @type {import('estree').Identifier[]} */
459459
const params = [];
460460
let added_props = false;
461461

462+
/**
463+
* we only want to push if it's not already present to avoid name clashing
464+
* @param {import('estree').Identifier} id
465+
*/
466+
function safe_push(id) {
467+
if (!params.find((param) => param.name === id.name)) {
468+
params.push(id);
469+
}
470+
}
471+
462472
for (const [reference] of scope.references) {
463473
const binding = scope.get(reference);
464474

465475
if (binding !== null && !scope.declarations.has(reference) && binding.initial !== node) {
466476
if (binding.kind === 'store_sub') {
467477
// We need both the subscription for getting the value and the store for updating
468-
params.push(b.id(binding.node.name.slice(1)));
469-
params.push(b.id(binding.node.name));
478+
safe_push(b.id(binding.node.name.slice(1)));
479+
safe_push(b.id(binding.node.name));
470480
} else if (
471481
// If it's a destructured derived binding, then we can extract the derived signal reference and use that.
472482
binding.expression !== null &&
@@ -477,7 +487,7 @@ function get_hoistable_params(node, context) {
477487
binding.expression.object.callee.name === '$.get' &&
478488
binding.expression.object.arguments[0].type === 'Identifier'
479489
) {
480-
params.push(b.id(binding.expression.object.arguments[0].name));
490+
safe_push(b.id(binding.expression.object.arguments[0].name));
481491
} else if (
482492
// If we are referencing a simple $$props value, then we need to reference the object property instead
483493
(binding.kind === 'prop' || binding.kind === 'bindable_prop') &&
@@ -488,11 +498,11 @@ function get_hoistable_params(node, context) {
488498
// Handle $$props.something use-cases
489499
if (!added_props) {
490500
added_props = true;
491-
params.push(b.id('$$props'));
501+
safe_push(b.id('$$props'));
492502
}
493503
} else {
494504
// create a copy to remove start/end tags which would mess up source maps
495-
params.push(b.id(binding.node.name));
505+
safe_push(b.id(binding.node.name));
496506
}
497507
}
498508
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
compileOptions: {
5+
dev: true
6+
},
7+
recover: true,
8+
mode: ['client']
9+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script lang="ts">
2+
import { writable } from 'svelte/store';
3+
const store = writable(0);
4+
5+
async function logStore() {
6+
console.log($store)
7+
store.set(100);
8+
}
9+
</script>
10+
11+
<button onclick={logStore}>Click me</button>

0 commit comments

Comments
 (0)