2
2
/** @import { Binding } from '#compiler' */
3
3
/** @import { ComponentClientTransformState, ComponentContext } from '../types' */
4
4
import { dev } from '../../../../state.js' ;
5
- import { build_pattern , extract_paths } from '../../../../utils/ast.js' ;
5
+ import { extract_paths } from '../../../../utils/ast.js' ;
6
6
import * as b from '#compiler/builders' ;
7
7
import * as assert from '../../../../utils/assert.js' ;
8
8
import { get_rune } from '../../../scope.js' ;
9
9
import { get_prop_source , is_prop_source , is_state_source , should_proxy } from '../utils.js' ;
10
10
import { is_hoisted_function } from '../../utils.js' ;
11
+ import { get_value } from './shared/declarations.js' ;
11
12
12
13
/**
13
14
* @param {VariableDeclaration } node
@@ -116,7 +117,7 @@ export function VariableDeclaration(node, context) {
116
117
}
117
118
118
119
const args = /** @type {CallExpression } */ ( init ) . arguments ;
119
- const value = args . length > 0 ? /** @type {Expression } */ ( context . visit ( args [ 0 ] ) ) : b . void0 ;
120
+ const value = /** @type {Expression } */ ( args [ 0 ] ) ?? b . void0 ; // TODO do we need the void 0? can we just omit it altogether?
120
121
121
122
if ( rune === '$state' || rune === '$state.raw' ) {
122
123
/**
@@ -137,24 +138,34 @@ export function VariableDeclaration(node, context) {
137
138
} ;
138
139
139
140
if ( declarator . id . type === 'Identifier' ) {
141
+ const expression = /** @type {Expression } */ ( context . visit ( value ) ) ;
142
+
140
143
declarations . push (
141
- b . declarator ( declarator . id , create_state_declarator ( declarator . id , value ) )
144
+ b . declarator ( declarator . id , create_state_declarator ( declarator . id , expression ) )
142
145
) ;
143
146
} else {
144
- const [ pattern , replacements ] = build_pattern ( declarator . id , context . state . scope ) ;
147
+ const tmp = b . id ( context . state . scope . generate ( 'tmp' ) ) ;
148
+ const { inserts, paths } = extract_paths ( declarator . id , tmp ) ;
149
+
145
150
declarations . push (
146
- b . declarator ( pattern , value ) ,
147
- .../** @type {[Identifier, Identifier][] } */ ( [ ...replacements ] ) . map (
148
- ( [ original , replacement ] ) => {
149
- const binding = context . state . scope . get ( original . name ) ;
150
- return b . declarator (
151
- original ,
152
- binding ?. kind === 'state' || binding ?. kind === 'raw_state'
153
- ? create_state_declarator ( binding . node , replacement )
154
- : replacement
155
- ) ;
156
- }
157
- )
151
+ b . declarator ( tmp , value ) ,
152
+ ...inserts . map ( ( { id, value } ) => {
153
+ id . name = context . state . scope . generate ( '$$array' ) ;
154
+ context . state . transform [ id . name ] = { read : get_value } ;
155
+
156
+ const expression = /** @type {Expression } */ ( context . visit ( b . thunk ( value ) ) ) ;
157
+ return b . declarator ( id , b . call ( '$.derived' , expression ) ) ;
158
+ } ) ,
159
+ ...paths . map ( ( path ) => {
160
+ const value = /** @type {Expression } */ ( context . visit ( path . expression ) ) ;
161
+ const binding = context . state . scope . get ( /** @type {Identifier } */ ( path . node ) . name ) ;
162
+ return b . declarator (
163
+ path . node ,
164
+ binding ?. kind === 'state' || binding ?. kind === 'raw_state'
165
+ ? create_state_declarator ( binding . node , value )
166
+ : value
167
+ ) ;
168
+ } )
158
169
) ;
159
170
}
160
171
@@ -163,44 +174,41 @@ export function VariableDeclaration(node, context) {
163
174
164
175
if ( rune === '$derived' || rune === '$derived.by' ) {
165
176
if ( declarator . id . type === 'Identifier' ) {
166
- declarations . push (
167
- b . declarator (
168
- declarator . id ,
169
- b . call ( '$.derived' , rune === '$derived.by' ? value : b . thunk ( value ) )
170
- )
171
- ) ;
177
+ let expression = /** @type {Expression } */ ( context . visit ( value ) ) ;
178
+ if ( rune === '$derived' ) expression = b . thunk ( expression ) ;
179
+
180
+ declarations . push ( b . declarator ( declarator . id , b . call ( '$.derived' , expression ) ) ) ;
172
181
} else {
173
- const [ pattern , replacements ] = build_pattern ( declarator . id , context . state . scope ) ;
174
182
const init = /** @type {CallExpression } */ ( declarator . init ) ;
175
183
176
- /** @type {Identifier } */
177
- let id ;
178
184
let rhs = value ;
179
185
180
- if ( rune === '$derived' && init . arguments [ 0 ] . type === 'Identifier' ) {
181
- id = init . arguments [ 0 ] ;
182
- } else {
183
- id = b . id ( context . state . scope . generate ( '$$d' ) ) ;
186
+ if ( rune !== '$derived' || init . arguments [ 0 ] . type !== 'Identifier' ) {
187
+ const id = b . id ( context . state . scope . generate ( '$$d' ) ) ;
184
188
rhs = b . call ( '$.get' , id ) ;
185
189
186
- declarations . push (
187
- b . declarator ( id , b . call ( '$.derived' , rune === '$derived.by' ? value : b . thunk ( value ) ) )
188
- ) ;
190
+ let expression = /** @type {Expression } */ ( context . visit ( value ) ) ;
191
+ if ( rune === '$derived' ) expression = b . thunk ( expression ) ;
192
+
193
+ declarations . push ( b . declarator ( id , b . call ( '$.derived' , expression ) ) ) ;
189
194
}
190
195
191
- for ( let i = 0 ; i < replacements . size ; i ++ ) {
192
- const [ original , replacement ] = [ ...replacements ] [ i ] ;
193
- declarations . push (
194
- b . declarator (
195
- original ,
196
- b . call (
197
- '$.derived' ,
198
- b . arrow ( [ ] , b . block ( [ b . let ( pattern , rhs ) , b . return ( replacement ) ] ) )
199
- )
200
- )
201
- ) ;
196
+ const { inserts, paths } = extract_paths ( declarator . id , rhs ) ;
197
+
198
+ for ( const { id, value } of inserts ) {
199
+ id . name = context . state . scope . generate ( '$$array' ) ;
200
+ context . state . transform [ id . name ] = { read : get_value } ;
201
+
202
+ const expression = /** @type {Expression } */ ( context . visit ( b . thunk ( value ) ) ) ;
203
+ declarations . push ( b . declarator ( id , b . call ( '$.derived' , expression ) ) ) ;
204
+ }
205
+
206
+ for ( const path of paths ) {
207
+ const expression = /** @type {Expression } */ ( context . visit ( path . expression ) ) ;
208
+ declarations . push ( b . declarator ( path . node , b . call ( '$.derived' , b . thunk ( expression ) ) ) ) ;
202
209
}
203
210
}
211
+
204
212
continue ;
205
213
}
206
214
}
@@ -229,20 +237,29 @@ export function VariableDeclaration(node, context) {
229
237
if ( declarator . id . type !== 'Identifier' ) {
230
238
// Turn export let into props. It's really really weird because export let { x: foo, z: [bar]} = ..
231
239
// means that foo and bar are the props (i.e. the leafs are the prop names), not x and z.
232
- const tmp = context . state . scope . generate ( 'tmp' ) ;
233
- const paths = extract_paths ( declarator . id ) ;
240
+ const tmp = b . id ( context . state . scope . generate ( 'tmp' ) ) ;
241
+ const { inserts , paths } = extract_paths ( declarator . id , tmp ) ;
234
242
235
243
declarations . push (
236
244
b . declarator (
237
- b . id ( tmp ) ,
245
+ tmp ,
238
246
/** @type {Expression } */ ( context . visit ( /** @type {Expression } */ ( declarator . init ) ) )
239
247
)
240
248
) ;
241
249
250
+ for ( const { id, value } of inserts ) {
251
+ id . name = context . state . scope . generate ( '$$array' ) ;
252
+ context . state . transform [ id . name ] = { read : get_value } ;
253
+
254
+ const expression = /** @type {Expression } */ ( context . visit ( b . thunk ( value ) ) ) ;
255
+ declarations . push ( b . declarator ( id , b . call ( '$.derived' , expression ) ) ) ;
256
+ }
257
+
242
258
for ( const path of paths ) {
243
259
const name = /** @type {Identifier } */ ( path . node ) . name ;
244
260
const binding = /** @type {Binding } */ ( context . state . scope . get ( name ) ) ;
245
- const value = path . expression ?. ( b . id ( tmp ) ) ;
261
+ const value = /** @type {Expression } */ ( context . visit ( path . expression ) ) ;
262
+
246
263
declarations . push (
247
264
b . declarator (
248
265
path . node ,
@@ -276,7 +293,7 @@ export function VariableDeclaration(node, context) {
276
293
declarations . push (
277
294
...create_state_declarators (
278
295
declarator ,
279
- context . state ,
296
+ context ,
280
297
/** @type {Expression } */ ( declarator . init && context . visit ( declarator . init ) )
281
298
)
282
299
) ;
@@ -296,32 +313,41 @@ export function VariableDeclaration(node, context) {
296
313
/**
297
314
* Creates the output for a state declaration in legacy mode.
298
315
* @param {VariableDeclarator } declarator
299
- * @param {ComponentClientTransformState } scope
316
+ * @param {ComponentContext } context
300
317
* @param {Expression } value
301
318
*/
302
- function create_state_declarators ( declarator , { scope , analysis } , value ) {
319
+ function create_state_declarators ( declarator , context , value ) {
303
320
if ( declarator . id . type === 'Identifier' ) {
304
321
return [
305
322
b . declarator (
306
323
declarator . id ,
307
- b . call ( '$.mutable_source' , value , analysis . immutable ? b . true : undefined )
324
+ b . call ( '$.mutable_source' , value , context . state . analysis . immutable ? b . true : undefined )
308
325
)
309
326
] ;
310
327
}
311
328
312
- const [ pattern , replacements ] = build_pattern ( declarator . id , scope ) ;
329
+ const tmp = b . id ( context . state . scope . generate ( 'tmp' ) ) ;
330
+ const { inserts, paths } = extract_paths ( declarator . id , tmp ) ;
331
+
313
332
return [
314
- b . declarator ( pattern , value ) ,
315
- .../** @type {[Identifier, Identifier][] } */ ( [ ...replacements ] ) . map (
316
- ( [ original , replacement ] ) => {
317
- const binding = scope . get ( original . name ) ;
318
- return b . declarator (
319
- original ,
320
- binding ?. kind === 'state'
321
- ? b . call ( '$.mutable_source' , replacement , analysis . immutable ? b . true : undefined )
322
- : replacement
323
- ) ;
324
- }
325
- )
333
+ b . declarator ( tmp , value ) ,
334
+ ...inserts . map ( ( { id, value } ) => {
335
+ id . name = context . state . scope . generate ( '$$array' ) ;
336
+ context . state . transform [ id . name ] = { read : get_value } ;
337
+
338
+ const expression = /** @type {Expression } */ ( context . visit ( b . thunk ( value ) ) ) ;
339
+ return b . declarator ( id , b . call ( '$.derived' , expression ) ) ;
340
+ } ) ,
341
+ ...paths . map ( ( path ) => {
342
+ const value = /** @type {Expression } */ ( context . visit ( path . expression ) ) ;
343
+ const binding = context . state . scope . get ( /** @type {Identifier } */ ( path . node ) . name ) ;
344
+
345
+ return b . declarator (
346
+ path . node ,
347
+ binding ?. kind === 'state'
348
+ ? b . call ( '$.mutable_source' , value , context . state . analysis . immutable ? b . true : undefined )
349
+ : value
350
+ ) ;
351
+ } )
326
352
] ;
327
353
}
0 commit comments