11/** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, Pattern, Property, SequenceExpression, Statement } from 'estree' */
22/** @import { AST } from '#compiler' */
3- /** @import { ComponentContext } from '../../types.js' */
3+ /** @import { ComponentContext, MemoizedExpression } from '../../types.js' */
44import { dev , is_ignored } from '../../../../../state.js' ;
55import { get_attribute_chunks , object } from '../../../../../utils/ast.js' ;
66import * as b from '../../../../../utils/builders.js' ;
7- import { build_bind_this , memoize_expression , validate_binding } from '../shared/utils.js' ;
7+ import {
8+ build_bind_this ,
9+ get_expression_id ,
10+ memoize_expression ,
11+ validate_binding
12+ } from '../shared/utils.js' ;
813import { build_attribute_value } from '../shared/element.js' ;
914import { build_event_handler } from './events.js' ;
1015import { determine_slot } from '../../../../../utils/slot.js' ;
16+ import { create_derived } from '../../utils.js' ;
1117
1218/**
1319 * @param {AST.Component | AST.SvelteComponent | AST.SvelteSelf } node
@@ -40,6 +46,12 @@ export function build_component(node, component_name, context, anchor = context.
4046 /** @type {Record<string, Expression[]> } */
4147 const events = { } ;
4248
49+ /** @type {MemoizedExpression[] } */
50+ const expressions = [ ] ;
51+
52+ /** @type {MemoizedExpression[] } */
53+ const async_expressions = [ ] ;
54+
4355 /** @type {Property[] } */
4456 const custom_css_props = [ ] ;
4557
@@ -115,16 +127,21 @@ export function build_component(node, component_name, context, anchor = context.
115127 ( events [ attribute . name ] ||= [ ] ) . push ( handler ) ;
116128 } else if ( attribute . type === 'SpreadAttribute' ) {
117129 const expression = /** @type {Expression } */ ( context . visit ( attribute ) ) ;
118- if ( attribute . metadata . expression . has_state ) {
119- let value = expression ;
120130
121- if ( attribute . metadata . expression . has_call ) {
122- const id = b . id ( context . state . scope . generate ( 'spread_element' ) ) ;
123- context . state . init . push ( b . var ( id , b . call ( '$.derived' , b . thunk ( value ) ) ) ) ;
124- value = b . call ( '$.get' , id ) ;
125- }
126-
127- props_and_spreads . push ( b . thunk ( value ) ) ;
131+ if ( attribute . metadata . expression . has_state ) {
132+ props_and_spreads . push (
133+ b . thunk (
134+ attribute . metadata . expression . is_async || attribute . metadata . expression . has_call
135+ ? b . call (
136+ '$.get' ,
137+ get_expression_id (
138+ attribute . metadata . expression . is_async ? async_expressions : expressions ,
139+ expression
140+ )
141+ )
142+ : expression
143+ )
144+ ) ;
128145 } else {
129146 props_and_spreads . push ( expression ) ;
130147 }
@@ -133,10 +150,15 @@ export function build_component(node, component_name, context, anchor = context.
133150 custom_css_props . push (
134151 b . init (
135152 attribute . name ,
136- build_attribute_value ( attribute . value , context , ( value , metadata ) =>
153+ build_attribute_value ( attribute . value , context , ( value , metadata ) => {
137154 // TODO put the derived in the local block
138- metadata . has_call ? memoize_expression ( context . state , value ) : value
139- ) . value
155+ return metadata . has_call || metadata . is_async
156+ ? b . call (
157+ '$.get' ,
158+ get_expression_id ( metadata . is_async ? async_expressions : expressions , value )
159+ )
160+ : value ;
161+ } ) . value
140162 )
141163 ) ;
142164 continue ;
@@ -154,7 +176,7 @@ export function build_component(node, component_name, context, anchor = context.
154176 attribute . value ,
155177 context ,
156178 ( value , metadata ) => {
157- if ( ! metadata . has_state ) return value ;
179+ if ( ! metadata . has_state && ! metadata . is_async ) return value ;
158180
159181 // When we have a non-simple computation, anything other than an Identifier or Member expression,
160182 // then there's a good chance it needs to be memoized to avoid over-firing when read within the
@@ -167,7 +189,12 @@ export function build_component(node, component_name, context, anchor = context.
167189 ) ;
168190 } ) ;
169191
170- return should_wrap_in_derived ? memoize_expression ( context . state , value ) : value ;
192+ return should_wrap_in_derived
193+ ? b . call (
194+ '$.get' ,
195+ get_expression_id ( metadata . is_async ? async_expressions : expressions , value )
196+ )
197+ : value ;
171198 }
172199 ) ;
173200
@@ -420,7 +447,12 @@ export function build_component(node, component_name, context, anchor = context.
420447 } ;
421448 }
422449
423- const statements = [ ...snippet_declarations ] ;
450+ const statements = [
451+ ...snippet_declarations ,
452+ ...expressions . map ( ( memo ) =>
453+ b . let ( memo . id , create_derived ( context . state , b . thunk ( memo . expression ) ) )
454+ )
455+ ] ;
424456
425457 if ( node . type === 'SvelteComponent' ) {
426458 const prev = fn ;
@@ -457,5 +489,20 @@ export function build_component(node, component_name, context, anchor = context.
457489 statements . push ( b . stmt ( fn ( anchor ) ) ) ;
458490 }
459491
492+ [ ...async_expressions , ...expressions ] . forEach ( ( memo , i ) => {
493+ memo . id . name = `$${ i } ` ;
494+ } ) ;
495+
496+ if ( async_expressions . length > 0 ) {
497+ return b . stmt (
498+ b . call (
499+ '$.async' ,
500+ anchor ,
501+ b . array ( async_expressions . map ( ( { expression } ) => b . thunk ( expression , true ) ) ) ,
502+ b . arrow ( [ b . id ( '$$anchor' ) , ...async_expressions . map ( ( { id } ) => id ) ] , b . block ( statements ) )
503+ )
504+ ) ;
505+ }
506+
460507 return statements . length > 1 ? b . block ( statements ) : statements [ 0 ] ;
461508}
0 commit comments