fix: place `let:` declarations before `{@const}` declarations (#16985)

* fix: place `let:` declarations before `{@const}` declarations

* lint

* fix
pull/16984/head
ComputerGuy 1 week ago committed by GitHub
parent c8ef540985
commit 9a488d6b25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: place `let:` declarations before `{@const}` declarations

@ -172,6 +172,7 @@ export function client_component(analysis, options) {
// these are set inside the `Fragment` visitor, and cannot be used until then // these are set inside the `Fragment` visitor, and cannot be used until then
init: /** @type {any} */ (null), init: /** @type {any} */ (null),
consts: /** @type {any} */ (null), consts: /** @type {any} */ (null),
let_directives: /** @type {any} */ (null),
update: /** @type {any} */ (null), update: /** @type {any} */ (null),
after_update: /** @type {any} */ (null), after_update: /** @type {any} */ (null),
template: /** @type {any} */ (null), template: /** @type {any} */ (null),

@ -54,6 +54,8 @@ export interface ComponentClientTransformState extends ClientTransformState {
readonly after_update: Statement[]; readonly after_update: Statement[];
/** Transformed `{@const }` declarations */ /** Transformed `{@const }` declarations */
readonly consts: Statement[]; readonly consts: Statement[];
/** Transformed `let:` directives */
readonly let_directives: Statement[];
/** Memoized expressions */ /** Memoized expressions */
readonly memoizer: Memoizer; readonly memoizer: Memoizer;
/** The HTML template string */ /** The HTML template string */

@ -63,6 +63,7 @@ export function Fragment(node, context) {
...context.state, ...context.state,
init: [], init: [],
consts: [], consts: [],
let_directives: [],
update: [], update: [],
after_update: [], after_update: [],
memoizer: new Memoizer(), memoizer: new Memoizer(),
@ -150,7 +151,7 @@ export function Fragment(node, context) {
} }
} }
body.push(...state.consts); body.push(...state.let_directives, ...state.consts);
if (has_await) { if (has_await) {
body.push(b.if(b.call('$.aborted'), b.return())); body.push(b.if(b.call('$.aborted'), b.return()));

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

@ -106,7 +106,7 @@ export function RegularElement(node, context) {
case 'LetDirective': case 'LetDirective':
// visit let directives before everything else, to set state // 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; break;
case 'OnDirective': case 'OnDirective':

@ -49,7 +49,7 @@ export function SlotElement(node, context) {
} }
} }
} else if (attribute.type === 'LetDirective') { } else if (attribute.type === 'LetDirective') {
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute))); context.visit(attribute, { ...context.state, let_directives: lets });
} }
} }

@ -9,7 +9,7 @@
export function SvelteFragment(node, context) { export function SvelteFragment(node, context) {
for (const attribute of node.attributes) { for (const attribute of node.attributes) {
if (attribute.type === 'LetDirective') { if (attribute.type === 'LetDirective') {
context.state.init.push(/** @type {ExpressionStatement} */ (context.visit(attribute))); context.visit(attribute);
} }
} }

@ -101,7 +101,7 @@ export function build_component(node, component_name, context) {
if (slot_scope_applies_to_itself) { if (slot_scope_applies_to_itself) {
for (const attribute of node.attributes) { for (const attribute of node.attributes) {
if (attribute.type === 'LetDirective') { if (attribute.type === 'LetDirective') {
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute))); context.visit(attribute, { ...context.state, let_directives: lets });
} }
} }
} }
@ -109,7 +109,7 @@ export function build_component(node, component_name, context) {
for (const attribute of node.attributes) { for (const attribute of node.attributes) {
if (attribute.type === 'LetDirective') { if (attribute.type === 'LetDirective') {
if (!slot_scope_applies_to_itself) { 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') { } else if (attribute.type === 'OnDirective') {
if (!attribute.expression) { if (!attribute.expression) {

@ -0,0 +1,5 @@
import { test } from '../../test';
export default test({
html: 'foo'
});

@ -0,0 +1,7 @@
<script>
import Component from './component.svelte';
</script>
<Component let:data>
{@const thing = data}
{thing}
</Component>
Loading…
Cancel
Save