Skip to content

Commit

Permalink
fix: handle $$Props interface during migration
Browse files Browse the repository at this point in the history
fixes #13178
  • Loading branch information
dummdidumm committed Sep 18, 2024
1 parent b441738 commit 91d2659
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/lucky-drinks-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: handle `$$Props` interface during migration
77 changes: 67 additions & 10 deletions packages/svelte/src/compiler/migrate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,27 +335,42 @@ const instance_script = {
// }
}

const binding = /** @type {Binding} */ (state.scope.get(declarator.id.name));
const name = declarator.id.name;
const binding = /** @type {Binding} */ (state.scope.get(name));

if (state.analysis.uses_props && (declarator.init || binding.updated)) {
throw new Error(
'$$props is used together with named props in a way that cannot be automatically migrated.'
);
}

state.props.push({
local: declarator.id.name,
exported: binding.prop_alias ? binding.prop_alias : declarator.id.name,
init: declarator.init
const prop = state.props.find((prop) => prop.exported === (binding.prop_alias || name));
if (prop) {
// $$Props type was used
prop.init = declarator.init
? state.str.original.substring(
/** @type {number} */ (declarator.init.start),
/** @type {number} */ (declarator.init.end)
)
: '',
optional: !!declarator.init,
bindable: binding.updated,
...extract_type_and_comment(declarator, state.str, path)
});
: '';
prop.bindable = binding.updated;
prop.exported = binding.prop_alias || name;
} else {
state.props.push({
local: name,
exported: binding.prop_alias ? binding.prop_alias : name,
init: declarator.init
? state.str.original.substring(
/** @type {number} */ (declarator.init.start),
/** @type {number} */ (declarator.init.end)
)
: '',
optional: !!declarator.init,
bindable: binding.updated,
...extract_type_and_comment(declarator, state.str, path)
});
}

state.props_insertion_point = /** @type {number} */ (declarator.end);
state.str.update(
/** @type {number} */ (declarator.start),
Expand Down Expand Up @@ -944,6 +959,48 @@ function handle_identifier(node, state, path) {
}
}
// else passed as identifier, we don't know what to do here, so let it error
} else if (
parent?.type === 'TSInterfaceDeclaration' ||
parent?.type === 'TSTypeAliasDeclaration'
) {
const members =
parent.type === 'TSInterfaceDeclaration' ? parent.body.body : parent.typeAnnotation?.members;
if (Array.isArray(members)) {
if (node.name === '$$Props') {
for (const member of members) {
const prop = state.props.find((prop) => prop.exported === member.key.name);

const type = state.str.original.substring(
member.typeAnnotation.typeAnnotation.start,
member.typeAnnotation.typeAnnotation.end
);

let comment;
const comment_node = member.leadingComments?.at(-1);
if (comment_node?.type === 'Block') {
comment = state.str.original.substring(comment_node.start, comment_node.end);
}

if (prop) {
prop.type = type;
prop.optional = member.optional;
prop.comment = comment ?? prop.comment;
} else {
state.props.push({
local: member.key.name,
exported: member.key.name,
init: '',
bindable: false,
optional: member.optional,
type,
comment
});
}
}

state.str.remove(parent.start, parent.end);
}
}
}
}

Expand Down
9 changes: 8 additions & 1 deletion packages/svelte/src/compiler/phases/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,14 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
// references
Identifier(node, { path, state }) {
const parent = path.at(-1);
if (parent && is_reference(node, /** @type {Node} */ (parent))) {
if (
parent &&
is_reference(node, /** @type {Node} */ (parent)) &&
// TSTypeAnnotation, TSInterfaceDeclaration etc - these are normally already filtered out,
// but for the migration they aren't, so we need to filter them out here
// -> once migration script is gone we can remove this check
!parent.type.startsWith('TS')
) {
references.push([state.scope, { node, path: path.slice() }]);
}
},
Expand Down
12 changes: 12 additions & 0 deletions packages/svelte/tests/migrate/samples/props-interface/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script lang="ts">
interface $$Props {
/** foo */
foo: string;
bar: boolean;
}
export let foo: $$Props['foo'];
export let bar = true;
foo = '';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script lang="ts">
interface Props {
/** foo */
foo: string;
bar: boolean;
}
let { foo = $bindable(), bar = true }: Props = $props();
foo = '';
</script>

0 comments on commit 91d2659

Please sign in to comment.