Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/brown-insects-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: place `let:` declarations before `{@const}` declarations
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ export function client_component(analysis, options) {
// these are set inside the `Fragment` visitor, and cannot be used until then
init: /** @type {any} */ (null),
consts: /** @type {any} */ (null),
let_directives: /** @type {any} */ (null),
update: /** @type {any} */ (null),
after_update: /** @type {any} */ (null),
template: /** @type {any} */ (null),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export interface ComponentClientTransformState extends ClientTransformState {
readonly after_update: Statement[];
/** Transformed `{@const }` declarations */
readonly consts: Statement[];
/** Transformed `let:` directives */
readonly let_directives: Statement[];
/** Memoized expressions */
readonly memoizer: Memoizer;
/** The HTML template string */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export function Fragment(node, context) {
...context.state,
init: [],
consts: [],
let_directives: [],
update: [],
after_update: [],
memoizer: new Memoizer(),
Expand Down Expand Up @@ -150,7 +151,7 @@ export function Fragment(node, context) {
}
}

body.push(...state.consts);
body.push(...state.let_directives, ...state.consts);

if (has_await) {
body.push(b.if(b.call('$.aborted'), b.return()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,24 @@ export function LetDirective(node, context) {
};
}

return b.const(
name,
b.call(
'$.derived',
b.thunk(
b.block([
b.let(
/** @type {Expression} */ (node.expression).type === 'ObjectExpression'
? // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
b.object_pattern(node.expression.properties)
: // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
b.array_pattern(node.expression.elements),
b.member(b.id('$$slotProps'), node.name)
),
b.return(b.object(bindings.map((binding) => b.init(binding.node.name, binding.node))))
])
context.state.let_directives.push(
b.const(
name,
b.call(
'$.derived',
b.thunk(
b.block([
b.let(
/** @type {Expression} */ (node.expression).type === 'ObjectExpression'
? // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
b.object_pattern(node.expression.properties)
: // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
b.array_pattern(node.expression.elements),
b.member(b.id('$$slotProps'), node.name)
),
b.return(b.object(bindings.map((binding) => b.init(binding.node.name, binding.node))))
])
)
)
)
);
Expand All @@ -46,6 +48,8 @@ export function LetDirective(node, context) {
read: (node) => b.call('$.get', node)
};

return b.const(name, create_derived(context.state, b.member(b.id('$$slotProps'), node.name)));
context.state.let_directives.push(
b.const(name, create_derived(context.state, b.member(b.id('$$slotProps'), node.name)))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export function RegularElement(node, context) {

case 'LetDirective':
// visit let directives before everything else, to set state
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute)));
context.visit(attribute, { ...context.state, let_directives: lets });
break;

case 'OnDirective':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function SlotElement(node, context) {
}
}
} else if (attribute.type === 'LetDirective') {
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute)));
context.visit(attribute, { ...context.state, let_directives: lets });
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
export function SvelteFragment(node, context) {
for (const attribute of node.attributes) {
if (attribute.type === 'LetDirective') {
context.state.init.push(/** @type {ExpressionStatement} */ (context.visit(attribute)));
context.visit(attribute);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,15 @@ export function build_component(node, component_name, context) {
if (slot_scope_applies_to_itself) {
for (const attribute of node.attributes) {
if (attribute.type === 'LetDirective') {
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute)));
context.visit(attribute, { ...context.state, let_directives: lets });
}
}
}

for (const attribute of node.attributes) {
if (attribute.type === 'LetDirective') {
if (!slot_scope_applies_to_itself) {
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute, states.default)));
context.visit(attribute, { ...states.default, let_directives: lets });
}
} else if (attribute.type === 'OnDirective') {
if (!attribute.expression) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test } from '../../test';

export default test({
html: 'foo'
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<slot data='foo'></slot>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
import Component from './component.svelte';
</script>
<Component let:data>
{@const thing = data}
{thing}
</Component>
Loading