1
- /** @import { VariableDeclaration, VariableDeclarator, Expression, CallExpression, Pattern, Identifier } from 'estree' */
1
+ /** @import { VariableDeclaration, VariableDeclarator, Expression, CallExpression, Pattern, Identifier, ObjectPattern, ArrayPattern, Property } from 'estree' */
2
2
/** @import { Binding } from '#compiler' */
3
3
/** @import { Context } from '../types.js' */
4
4
/** @import { Scope } from '../../../scope.js' */
5
- import { build_fallback , extract_paths } from '../../../../utils/ast.js' ;
5
+ import { walk } from 'zimmerframe' ;
6
+ import { build_fallback , extract_identifiers , extract_paths } from '../../../../utils/ast.js' ;
6
7
import * as b from '../../../../utils/builders.js' ;
7
8
import { get_rune } from '../../../scope.js' ;
8
- import { walk } from 'zimmerframe' ;
9
9
10
10
/**
11
11
* @param {VariableDeclaration } node
@@ -16,6 +16,9 @@ export function VariableDeclaration(node, context) {
16
16
const declarations = [ ] ;
17
17
18
18
if ( context . state . analysis . runes ) {
19
+ /** @type {VariableDeclarator[] } */
20
+ const destructured_reassigns = [ ] ;
21
+
19
22
for ( const declarator of node . declarations ) {
20
23
const init = declarator . init ;
21
24
const rune = get_rune ( init , context . state . scope ) ;
@@ -73,27 +76,72 @@ export function VariableDeclaration(node, context) {
73
76
const value =
74
77
args . length === 0 ? b . id ( 'undefined' ) : /** @type {Expression } */ ( context . visit ( args [ 0 ] ) ) ;
75
78
79
+ const is_destructuring =
80
+ declarator . id . type === 'ObjectPattern' || declarator . id . type === 'ArrayPattern' ;
81
+
82
+ /**
83
+ *
84
+ * @param {()=>Expression } get_generated_init
85
+ */
86
+ function add_destructured_reassign ( get_generated_init ) {
87
+ // to keep everything that the user destructure as a function we need to change the original
88
+ // assignment to a generated value and then reassign a variable with the original name
89
+ if ( declarator . id . type === 'ObjectPattern' || declarator . id . type === 'ArrayPattern' ) {
90
+ const id = /** @type {ObjectPattern | ArrayPattern } */ ( context . visit ( declarator . id ) ) ;
91
+ const modified = walk (
92
+ /**@type {Identifier|Property }*/ ( /**@type {unknown }*/ ( id ) ) ,
93
+ { } ,
94
+ {
95
+ Identifier ( id , { path } ) {
96
+ const parent = path . at ( - 1 ) ;
97
+ // we only want the identifiers for the value
98
+ if ( parent ?. type === 'Property' && parent . value !== id ) return ;
99
+ const generated = context . state . scope . generate ( id . name ) ;
100
+ destructured_reassigns . push ( b . declarator ( b . id ( id . name ) , b . thunk ( b . id ( generated ) ) ) ) ;
101
+ return b . id ( generated ) ;
102
+ }
103
+ }
104
+ ) ;
105
+ declarations . push ( b . declarator ( /**@type {Pattern }*/ ( modified ) , get_generated_init ( ) ) ) ;
106
+ }
107
+ }
108
+
76
109
if ( rune === '$derived.by' ) {
110
+ if ( is_destructuring ) {
111
+ add_destructured_reassign ( ( ) => b . call ( value ) ) ;
112
+ continue ;
113
+ }
77
114
declarations . push (
78
- b . declarator ( /** @type {Pattern } */ ( context . visit ( declarator . id ) ) , b . call ( value ) )
115
+ b . declarator ( /** @type {Pattern } */ ( context . visit ( declarator . id ) ) , value )
79
116
) ;
80
117
continue ;
81
118
}
82
119
83
120
if ( declarator . id . type === 'Identifier' ) {
84
- declarations . push ( b . declarator ( declarator . id , value ) ) ;
121
+ if ( is_destructuring && rune === '$derived' ) {
122
+ add_destructured_reassign ( ( ) => value ) ;
123
+ continue ;
124
+ }
125
+ declarations . push (
126
+ b . declarator ( declarator . id , rune === '$derived' ? b . thunk ( value ) : value )
127
+ ) ;
85
128
continue ;
86
129
}
87
130
88
131
if ( rune === '$derived' ) {
132
+ if ( is_destructuring ) {
133
+ add_destructured_reassign ( ( ) => value ) ;
134
+ continue ;
135
+ }
89
136
declarations . push (
90
- b . declarator ( /** @type {Pattern } */ ( context . visit ( declarator . id ) ) , value )
137
+ b . declarator ( /** @type {Pattern } */ ( context . visit ( declarator . id ) ) , b . thunk ( value ) )
91
138
) ;
92
139
continue ;
93
140
}
94
141
95
142
declarations . push ( ...create_state_declarators ( declarator , context . state . scope , value ) ) ;
96
143
}
144
+ declarations . push ( ...destructured_reassigns ) ;
97
145
} else {
98
146
for ( const declarator of node . declarations ) {
99
147
const bindings = /** @type {Binding[] } */ ( context . state . scope . get_bindings ( declarator ) ) ;
0 commit comments