Skip to content

Commit 9fa1626

Browse files
authored
Merge branch 'main' into fix-slots-with-bracket-notation
2 parents 6bb4179 + dfe0138 commit 9fa1626

File tree

13 files changed

+247
-16
lines changed

13 files changed

+247
-16
lines changed

.changeset/funny-houses-kick.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: migrate `$$Props` without creating non existent props

.changeset/many-fishes-warn.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: move labeled statements that need reordering after props insertion point

.changeset/real-camels-pay.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+
feat: support migration of self closing tags

.changeset/real-timers-complain.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: various `svelte:component` migration bugs

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

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { extract_identifiers } from '../utils/ast.js';
1414
import { migrate_svelte_ignore } from '../utils/extract_svelte_ignore.js';
1515
import { determine_slot } from '../utils/slot.js';
1616
import { validate_component_options } from '../validate-options.js';
17+
import { is_svg, is_void } from '../../utils.js';
1718

1819
const regex_style_tags = /(<style[^>]+>)([\S\s]*?)(<\/style>)/g;
1920
const style_placeholder = '/*$$__STYLE_CONTENT__$$*/';
@@ -150,6 +151,7 @@ export function migrate(source) {
150151
props = `...${state.names.props}`;
151152
} else {
152153
props = state.props
154+
.filter((prop) => !prop.type_only)
153155
.map((prop) => {
154156
let prop_str =
155157
prop.local === prop.exported ? prop.local : `${prop.exported}: ${prop.local}`;
@@ -236,7 +238,9 @@ export function migrate(source) {
236238
dependencies.some(
237239
(dep) =>
238240
!ids.includes(dep) &&
239-
/** @type {number} */ (dep.node.start) > /** @type {number} */ (node.start)
241+
(dep.kind === 'prop' || dep.kind === 'bindable_prop'
242+
? state.props_insertion_point
243+
: /** @type {number} */ (dep.node.start)) > /** @type {number} */ (node.start)
240244
)
241245
) {
242246
needs_reordering = true;
@@ -282,7 +286,7 @@ export function migrate(source) {
282286
* str: MagicString;
283287
* analysis: ComponentAnalysis;
284288
* indent: string;
285-
* props: Array<{ local: string; exported: string; init: string; bindable: boolean; slot_name?: string; optional: boolean; type: string; comment?: string; needs_refine_type?: boolean; }>;
289+
* props: Array<{ local: string; exported: string; init: string; bindable: boolean; slot_name?: string; optional: boolean; type: string; comment?: string; type_only?: boolean; needs_refine_type?: boolean; }>;
286290
* props_insertion_point: number;
287291
* has_props_rune: boolean;
288292
* end: number;
@@ -419,6 +423,7 @@ const instance_script = {
419423
: '';
420424
prop.bindable = binding.updated;
421425
prop.exported = binding.prop_alias || name;
426+
prop.type_only = false;
422427
} else {
423428
state.props.push({
424429
local: name,
@@ -576,6 +581,15 @@ const template = {
576581
},
577582
RegularElement(node, { state, next }) {
578583
handle_events(node, state);
584+
// Strip off any namespace from the beginning of the node name.
585+
const node_name = node.name.replace(/[a-zA-Z-]*:/g, '');
586+
587+
if (state.analysis.source[node.end - 2] === '/' && !is_void(node_name) && !is_svg(node_name)) {
588+
let trimmed_position = node.end - 2;
589+
while (state.str.original.charAt(trimmed_position - 1) === ' ') trimmed_position--;
590+
state.str.remove(trimmed_position, node.end - 1);
591+
state.str.appendRight(node.end, `</${node.name}>`);
592+
}
579593
next();
580594
},
581595
SvelteElement(node, { state, next }) {
@@ -625,21 +639,30 @@ const template = {
625639
part.type === 'EachBlock' ||
626640
part.type === 'AwaitBlock' ||
627641
part.type === 'IfBlock' ||
628-
part.type === 'KeyBlock' ||
629642
part.type === 'SnippetBlock' ||
630643
part.type === 'Component' ||
631644
part.type === 'SvelteComponent'
632645
) {
646+
let position = node.start;
647+
if (i !== path.length - 1) {
648+
for (let modifier = 1; modifier < path.length - i; modifier++) {
649+
const path_part = path[i + modifier];
650+
if ('start' in path_part) {
651+
position = /** @type {number} */ (path_part.start);
652+
break;
653+
}
654+
}
655+
}
633656
const indent = state.str.original.substring(
634-
state.str.original.lastIndexOf('\n', node.start) + 1,
635-
node.start
657+
state.str.original.lastIndexOf('\n', position) + 1,
658+
position
636659
);
637660
state.str.prependLeft(
638-
node.start,
661+
position,
639662
`{@const ${expression} = ${current_expression}}\n${indent}`
640663
);
641664
needs_derived = false;
642-
continue;
665+
break;
643666
}
644667
}
645668
if (needs_derived) {
@@ -1037,7 +1060,8 @@ function handle_identifier(node, state, path) {
10371060
bindable: false,
10381061
optional: member.optional,
10391062
type,
1040-
comment
1063+
comment,
1064+
type_only: true
10411065
});
10421066
}
10431067
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
export let readonly;
3+
$: writable = !readonly;
4+
export let optional = 'foo';
5+
</script>
6+
7+
{readonly} {optional} {writable}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
/** @type {{readonly: any, optional?: string}} */
3+
let { readonly, optional = 'foo' } = $props();
4+
let writable = $derived(!readonly);
5+
</script>
6+
7+
{readonly} {optional} {writable}

packages/svelte/tests/migrate/samples/props-interface/input.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
/** foo */
44
foo: string;
55
bar: boolean;
6+
/** should not create a prop */
7+
type_only: boolean;
68
}
79
810
export let foo: $$Props['foo'];

packages/svelte/tests/migrate/samples/props-interface/output.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
/** foo */
66
foo: string;
77
bar: boolean;
8+
/** should not create a prop */
9+
type_only: boolean;
810
}
911
1012
let { foo = $bindable(), bar = true }: Props = $props();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div />
2+
<div title="preserve" />
3+
<input type="text" />
4+
<hr />
5+
<f:table />
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div></div>
2+
<div title="preserve"></div>
3+
<input type="text" />
4+
<hr />
5+
<f:table></f:table>

packages/svelte/tests/migrate/samples/svelte-component/input.svelte

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,78 @@
122122
<svelte:component this={Something} />
123123
{:catch Error}
124124
<svelte:component this={Error} />
125-
{/await}
125+
{/await}
126+
127+
<Component>
128+
{@const stuff = true}
129+
<div>
130+
<p>
131+
<svelte:component this={stuff && Component} />
132+
</p>
133+
</div>
134+
</Component>
135+
136+
<svelte:component this={Component}>
137+
{@const stuff = true}
138+
<div>
139+
<p>
140+
<svelte:component this={stuff && Component} />
141+
</p>
142+
</div>
143+
</svelte:component>
144+
145+
{#each [] as i}
146+
{@const stuff = true}
147+
<li>
148+
<svelte:component this={stuff && Component} />
149+
</li>
150+
{/each}
151+
152+
{#await stuff}
153+
{@const stuff = true}
154+
<li>
155+
<svelte:component this={stuff && Component} />
156+
</li>
157+
{:then x}
158+
{@const stuff = true}
159+
<li>
160+
<svelte:component this={stuff && Component} />
161+
</li>
162+
{:catch e}
163+
{@const stuff = true}
164+
<li>
165+
<svelte:component this={stuff && Component} />
166+
</li>
167+
{/await}
168+
169+
{#await stuff then x}
170+
{@const stuff = true}
171+
<li>
172+
<svelte:component this={stuff && Component} />
173+
</li>
174+
{:catch e}
175+
{@const stuff = true}
176+
<li>
177+
<svelte:component this={stuff && Component} />
178+
</li>
179+
{/await}
180+
181+
{#if true}
182+
{@const stuff = true}
183+
<li>
184+
<svelte:component this={stuff && Component} />
185+
</li>
186+
{/if}
187+
188+
{#snippet test()}
189+
{@const stuff = true}
190+
<li>
191+
<svelte:component this={stuff && Component} />
192+
</li>
193+
{/snippet}
194+
195+
<Component>
196+
<Nested>
197+
<svelte:component this={stuff && Component} />
198+
</Nested>
199+
</Component>

0 commit comments

Comments
 (0)