@@ -3,10 +3,44 @@ import { addListener } from './listener.js';
3
3
// import { profiler } from './profiler.js';
4
4
import { getNode } from './svelte.js' ;
5
5
6
+ const propClones = new Map ( ) ;
7
+
8
+ /**
9
+ * @param {* } orig
10
+ * @param {* } value
11
+ * @returns {any }
12
+ */
13
+ function updateProp ( orig , value , seen = new Map ( ) ) {
14
+ switch ( typeof value ) {
15
+ case 'object' : {
16
+ if ( value === window || value === null ) return null ;
17
+ if ( Array . isArray ( value ) ) return value . map ( ( o , index ) => updateProp ( orig [ index ] , o , seen ) ) ;
18
+ if ( seen . has ( value ) ) return seen . get ( value ) ;
19
+
20
+ /** @type {Record<string, any> } */
21
+ const o = { } ;
22
+ seen . set ( value , o ) ;
23
+ for ( const [ key , v ] of Object . entries ( value ) ) {
24
+ orig [ key ] = updateProp ( orig [ key ] , v , seen ) ;
25
+ }
26
+
27
+ return orig ;
28
+ }
29
+ default :
30
+ return value ;
31
+ }
32
+ }
33
+
6
34
// @ts -ignore - possibly find an alternative
7
35
window . __svelte_devtools_inject_state = function ( id , key , value ) {
8
36
const { detail : component } = getNode ( id ) || { } ;
9
- component && component . $inject_state ( { [ key ] : value } ) ;
37
+ if ( component ) {
38
+ const clone = updateProp ( propClones . get ( id ) [ key ] , value ) ;
39
+
40
+ component . $inject_state ( {
41
+ [ key ] : clone ,
42
+ } ) ;
43
+ }
10
44
} ;
11
45
12
46
// @ts -ignore - possibly find an alternative
@@ -131,19 +165,38 @@ function serialize(node) {
131
165
switch ( node . type ) {
132
166
case 'component' : {
133
167
const { $$ : internal = { } } = node . detail ;
134
- const ctx = clone ( node . detail . $capture_state ?. ( ) || { } ) ;
168
+ const nodeState = node . detail . $capture_state ?. ( ) || { } ;
135
169
const bindings = Object . values ( internal . bound || { } ) . map (
136
170
/** @param {Function } f */ ( f ) => f . name ,
137
171
) ;
172
+
173
+ /** @type {Record<string, any> } */
174
+ // clone original prop objects for update
175
+ const _propClones = { } ;
138
176
const props = Object . keys ( internal . props || { } ) . flatMap ( ( key ) => {
139
- const value = ctx [ key ] ;
140
- delete ctx [ key ] ; // deduplicate for ctx
177
+ const prop = nodeState [ key ] ;
178
+
179
+ if ( prop ) {
180
+ const prototypeDescriptors = Object . getOwnPropertyDescriptors (
181
+ Object . getPrototypeOf ( nodeState [ key ] ) ,
182
+ ) ;
183
+ const protoClone = Object . create ( null , prototypeDescriptors ) ;
184
+ const clone = Object . create ( protoClone , Object . getOwnPropertyDescriptors ( prop ) ) ;
185
+ _propClones [ key ] = clone ;
186
+ }
187
+
188
+ const value = clone ( prop ) ;
189
+ delete nodeState [ key ] ; // deduplicate for ctx
141
190
if ( value === undefined ) return [ ] ;
142
191
143
192
const bounded = bindings . some ( ( f ) => f . includes ( key ) ) ;
144
193
return { key, value, bounded } ;
145
194
} ) ;
146
195
196
+ propClones . set ( res . id , _propClones ) ;
197
+
198
+ const ctx = clone ( nodeState ) ;
199
+
147
200
res . detail = {
148
201
attributes : props ,
149
202
listeners : Object . entries ( internal . callbacks || { } ) . flatMap ( ( [ event , value ] ) =>
0 commit comments