fix: handle `$$Props` interface during migration (#13305)

fixes #13178
pull/13311/head
Simon H 12 months ago committed by GitHub
parent d338e8083f
commit b23516121b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: handle `$$Props` interface during migration

@ -335,7 +335,8 @@ 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(
@ -343,9 +344,21 @@ const instance_script = {
);
}
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)
)
: '';
prop.bindable = binding.updated;
prop.exported = binding.prop_alias || name;
} else {
state.props.push({
local: declarator.id.name,
exported: binding.prop_alias ? binding.prop_alias : declarator.id.name,
local: name,
exported: binding.prop_alias ? binding.prop_alias : name,
init: declarator.init
? state.str.original.substring(
/** @type {number} */ (declarator.init.start),
@ -356,6 +369,8 @@ const instance_script = {
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),
@ -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);
}
}
}
}

@ -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() }]);
}
},

@ -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>

@ -0,0 +1,13 @@
<script lang="ts">
interface Props {
/** foo */
foo: string;
bar: boolean;
}
let { foo = $bindable(), bar = true }: Props = $props();
foo = '';
</script>
Loading…
Cancel
Save