Skip to content

Commit 438de04

Browse files
fix: add migration task when there's a variable named that would conflict with a rune (#14216)
Closes #14215
1 parent 870745f commit 438de04

File tree

29 files changed

+266
-0
lines changed

29 files changed

+266
-0
lines changed

.changeset/chatty-gorillas-poke.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: add migration task when there's a variable named that would conflict with a rune

packages/svelte/src/compiler/migrate/index.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,18 @@ export function migrate(source, { filename, use_ts } = {}) {
239239

240240
insertion_point = state.props_insertion_point;
241241

242+
/**
243+
* @param {"derived"|"props"|"bindable"} rune
244+
*/
245+
function check_rune_binding(rune) {
246+
const has_rune_binding = !!state.scope.get(rune);
247+
if (has_rune_binding) {
248+
throw new MigrationError(
249+
`migrating this component would require adding a \`$${rune}\` rune but there's already a variable named ${rune}.\n Rename the variable and try again or migrate by hand.`
250+
);
251+
}
252+
}
253+
242254
if (state.props.length > 0 || analysis.uses_rest_props || analysis.uses_props) {
243255
const has_many_props = state.props.length > 3;
244256
const newline_separator = `\n${indent}${indent}`;
@@ -253,6 +265,7 @@ export function migrate(source, { filename, use_ts } = {}) {
253265
let prop_str =
254266
prop.local === prop.exported ? prop.local : `${prop.exported}: ${prop.local}`;
255267
if (prop.bindable) {
268+
check_rune_binding('bindable');
256269
prop_str += ` = $bindable(${prop.init})`;
257270
} else if (prop.init) {
258271
prop_str += ` = ${prop.init}`;
@@ -300,11 +313,13 @@ export function migrate(source, { filename, use_ts } = {}) {
300313
if (type) {
301314
props_declaration = `${type}\n\n${indent}${props_declaration}`;
302315
}
316+
check_rune_binding('props');
303317
props_declaration = `${props_declaration}${type ? `: ${type_name}` : ''} = $props();`;
304318
} else {
305319
if (type) {
306320
props_declaration = `${state.props.length > 0 ? `${type}\n\n${indent}` : ''}/** @type {${state.props.length > 0 ? type_name : ''}${analysis.uses_props || analysis.uses_rest_props ? `${state.props.length > 0 ? ' & ' : ''}{ [key: string]: any }` : ''}} */\n${indent}${props_declaration}`;
307321
}
322+
check_rune_binding('props');
308323
props_declaration = `${props_declaration} = $props();`;
309324
}
310325

@@ -361,13 +376,15 @@ export function migrate(source, { filename, use_ts } = {}) {
361376
: insertion_point;
362377

363378
if (state.derived_components.size > 0) {
379+
check_rune_binding('derived');
364380
str.appendRight(
365381
insertion_point,
366382
`\n${indent}${[...state.derived_components.entries()].map(([init, name]) => `const ${name} = $derived(${init});`).join(`\n${indent}`)}\n`
367383
);
368384
}
369385

370386
if (state.derived_conflicting_slots.size > 0) {
387+
check_rune_binding('derived');
371388
str.appendRight(
372389
insertion_point,
373390
`\n${indent}${[...state.derived_conflicting_slots.entries()].map(([name, init]) => `const ${name} = $derived(${init});`).join(`\n${indent}`)}\n`
@@ -652,6 +669,18 @@ const instance_script = {
652669
continue;
653670
}
654671

672+
/**
673+
* @param {"state"|"derived"} rune
674+
*/
675+
function check_rune_binding(rune) {
676+
const has_rune_binding = !!state.scope.get(rune);
677+
if (has_rune_binding) {
678+
throw new MigrationError(
679+
`can't migrate \`${state.str.original.substring(/** @type {number} */ (node.start), node.end)}\` to \`$${rune}\` because there's a variable named ${rune}.\n Rename the variable and try again or migrate by hand.`
680+
);
681+
}
682+
}
683+
655684
// state
656685
if (declarator.init) {
657686
let { start, end } = /** @type {{ start: number, end: number }} */ (declarator.init);
@@ -661,6 +690,8 @@ const instance_script = {
661690
while (state.str.original[end - 1] !== ')') end += 1;
662691
}
663692

693+
check_rune_binding('state');
694+
664695
state.str.prependLeft(start, '$state(');
665696
state.str.appendRight(end, ')');
666697
} else {
@@ -755,6 +786,8 @@ const instance_script = {
755786
}
756787
}
757788

789+
check_rune_binding('derived');
790+
758791
// Someone wrote a `$: { ... }` statement which we can turn into a `$derived`
759792
state.str.appendRight(
760793
/** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),
@@ -795,6 +828,8 @@ const instance_script = {
795828
}
796829
}
797830
} else {
831+
check_rune_binding('state');
832+
798833
state.str.prependLeft(
799834
/** @type {number} */ (declarator.id.typeAnnotation?.end ?? declarator.id.end),
800835
' = $state('
@@ -858,6 +893,18 @@ const instance_script = {
858893

859894
next();
860895

896+
/**
897+
* @param {"state"|"derived"} rune
898+
*/
899+
function check_rune_binding(rune) {
900+
const has_rune_binding = state.scope.get(rune);
901+
if (has_rune_binding) {
902+
throw new MigrationError(
903+
`can't migrate \`$: ${state.str.original.substring(/** @type {number} */ (node.body.start), node.body.end)}\` to \`$${rune}\` because there's a variable named ${rune}.\n Rename the variable and try again or migrate by hand.`
904+
);
905+
}
906+
}
907+
861908
if (
862909
node.body.type === 'ExpressionStatement' &&
863910
node.body.expression.type === 'AssignmentExpression'
@@ -878,6 +925,8 @@ const instance_script = {
878925
node.body.expression.right
879926
);
880927

928+
check_rune_binding('derived');
929+
881930
// $derived
882931
state.str.update(
883932
/** @type {number} */ (node.start),
@@ -902,6 +951,7 @@ const instance_script = {
902951
} else {
903952
for (const binding of reassigned_bindings) {
904953
if (binding && (ids.includes(binding.node) || expression_ids.length === 0)) {
954+
check_rune_binding('state');
905955
const init =
906956
binding.kind === 'state'
907957
? ' = $state()'
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let bindable;
3+
export let something;
4+
</script>
5+
6+
<input bind:value={something} />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!-- @migration-task Error while migrating Svelte code: migrating this component would require adding a `$bindable` rune but there's already a variable named bindable.
2+
Rename the variable and try again or migrate by hand. -->
3+
<script>
4+
let bindable;
5+
export let something;
6+
</script>
7+
8+
<input bind:value={something} />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
let name = 'world';
3+
4+
let derived;
5+
6+
$: other = name;
7+
</script>
8+
9+
<input bind:value={name} />
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!-- @migration-task Error while migrating Svelte code: can't migrate `$: other = name;` to `$derived` because there's a variable named derived.
2+
Rename the variable and try again or migrate by hand. -->
3+
<script>
4+
let name = 'world';
5+
6+
let derived;
7+
8+
$: other = name;
9+
</script>
10+
11+
<input bind:value={name} />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
let derived;
3+
</script>
4+
5+
<svelte:component this={derived} />
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!-- @migration-task Error while migrating Svelte code: migrating this component would require adding a `$derived` rune but there's already a variable named derived.
2+
Rename the variable and try again or migrate by hand. -->
3+
<script>
4+
let derived;
5+
</script>
6+
7+
<svelte:component this={derived} />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
let derived;
3+
</script>
4+
<Component>
5+
<slot name="derived" slot="derived" />
6+
</Component>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<!-- @migration-task Error while migrating Svelte code: This migration would change the name of a slot making the component unusable -->
2+
<script>
3+
let derived;
4+
</script>
5+
<Component>
6+
<slot name="derived" slot="derived" />
7+
</Component>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
let name = 'world';
3+
4+
let derived;
5+
6+
let other;
7+
$: other = name;
8+
</script>
9+
10+
<input bind:value={name} />
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!-- @migration-task Error while migrating Svelte code: can't migrate `let other;` to `$derived` because there's a variable named derived.
2+
Rename the variable and try again or migrate by hand. -->
3+
<script>
4+
let name = 'world';
5+
6+
let derived;
7+
8+
let other;
9+
$: other = name;
10+
</script>
11+
12+
<input bind:value={name} />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<script>
2+
let props;
3+
export let something;
4+
</script>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!-- @migration-task Error while migrating Svelte code: migrating this component would require adding a `$props` rune but there's already a variable named props.
2+
Rename the variable and try again or migrate by hand. -->
3+
<script>
4+
let props;
5+
export let something;
6+
</script>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let state = 'world';
3+
4+
let other;
5+
</script>
6+
7+
<input bind:value={other} />
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!-- @migration-task Error while migrating Svelte code: can't migrate `let other;` to `$state` because there's a variable named state.
2+
Rename the variable and try again or migrate by hand. -->
3+
<script>
4+
let state = 'world';
5+
6+
let other;
7+
</script>
8+
9+
<input bind:value={other} />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let state = 'world';
3+
4+
let other = 42;
5+
</script>
6+
7+
<input bind:value={other} />
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!-- @migration-task Error while migrating Svelte code: can't migrate `let other = 42;` to `$state` because there's a variable named state.
2+
Rename the variable and try again or migrate by hand. -->
3+
<script>
4+
let state = 'world';
5+
6+
let other = 42;
7+
</script>
8+
9+
<input bind:value={other} />
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
logs: [
5+
'One or more `@migration-task` comments were added to `output.svelte`, please check them and complete the migration manually.'
6+
],
7+
errors: []
8+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let state = 'world';
3+
4+
$: other = 42;
5+
</script>
6+
7+
<input bind:value={other} />
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!-- @migration-task Error while migrating Svelte code: can't migrate `$: other = 42;` to `$state` because there's a variable named state.
2+
Rename the variable and try again or migrate by hand. -->
3+
<script>
4+
let state = 'world';
5+
6+
$: other = 42;
7+
</script>
8+
9+
<input bind:value={other} />

0 commit comments

Comments
 (0)