@@ -3,6 +3,8 @@ import { addListener } from './listener.js';
33// import { profiler } from './profiler.js';
44import { nodes } from './svelte.js' ;
55
6+ const propClones = new Map ( ) ;
7+
68// @ts -ignore - for the app to call with `eval`
79window [ '#SvelteDevTools' ] = {
810 /**
@@ -12,10 +14,43 @@ window['#SvelteDevTools'] = {
1214 */
1315 inject ( id , key , value ) {
1416 const { detail : component } = nodes . map . get ( id ) || { } ;
15- component && component . $inject_state ( { [ key ] : value } ) ;
17+
18+ if ( component ) {
19+ const clone = updateProp ( propClones . get ( id ) [ key ] , value ) ;
20+
21+ component . $inject_state ( {
22+ [ key ] : clone ,
23+ } ) ;
24+ }
1625 } ,
1726} ;
1827
28+ /**
29+ * @param {* } orig
30+ * @param {* } value
31+ * @returns {any }
32+ */
33+ function updateProp ( orig , value , seen = new Map ( ) ) {
34+ switch ( typeof value ) {
35+ case 'object' : {
36+ if ( value === window || value === null ) return null ;
37+ if ( Array . isArray ( value ) ) return value . map ( ( o , index ) => updateProp ( orig [ index ] , o , seen ) ) ;
38+ if ( seen . has ( value ) ) return seen . get ( value ) ;
39+
40+ /** @type {Record<string, any> } */
41+ const o = { } ;
42+ seen . set ( value , o ) ;
43+ for ( const [ key , v ] of Object . entries ( value ) ) {
44+ orig [ key ] = updateProp ( orig [ key ] , v , seen ) ;
45+ }
46+
47+ return orig ;
48+ }
49+ default :
50+ return value ;
51+ }
52+ }
53+
1954const previous = {
2055 /** @type {HTMLElement | null } */
2156 target : null ,
@@ -132,19 +167,38 @@ function serialize(node) {
132167 switch ( node . type ) {
133168 case 'component' : {
134169 const { $$ : internal = { } } = node . detail ;
135- const ctx = clone ( node . detail . $capture_state ?. ( ) || { } ) ;
170+ const nodeState = node . detail . $capture_state ?. ( ) || { } ;
136171 const bindings = Object . values ( internal . bound || { } ) . map (
137172 /** @param {Function } f */ ( f ) => f . name ,
138173 ) ;
174+
175+ /** @type {Record<string, any> } */
176+ // clone original prop objects for update
177+ const _propClones = { } ;
139178 const props = Object . keys ( internal . props || { } ) . flatMap ( ( key ) => {
140- const value = ctx [ key ] ;
141- delete ctx [ key ] ; // deduplicate for ctx
179+ const prop = nodeState [ key ] ;
180+
181+ if ( prop ) {
182+ const prototypeDescriptors = Object . getOwnPropertyDescriptors (
183+ Object . getPrototypeOf ( nodeState [ key ] ) ,
184+ ) ;
185+ const protoClone = Object . create ( null , prototypeDescriptors ) ;
186+ const clone = Object . create ( protoClone , Object . getOwnPropertyDescriptors ( prop ) ) ;
187+ _propClones [ key ] = clone ;
188+ }
189+
190+ const value = clone ( prop ) ;
191+ delete nodeState [ key ] ; // deduplicate for ctx
142192 if ( value === undefined ) return [ ] ;
143193
144194 const bounded = bindings . some ( ( f ) => f . includes ( key ) ) ;
145195 return { key, value, bounded } ;
146196 } ) ;
147197
198+ propClones . set ( res . id , _propClones ) ;
199+
200+ const ctx = clone ( nodeState ) ;
201+
148202 res . detail = {
149203 attributes : props ,
150204 listeners : Object . entries ( internal . callbacks || { } ) . flatMap ( ( [ event , value ] ) =>
0 commit comments