44
44
/* eslint-disable no-use-before-define */
45
45
/* eslint-disable no-param-reassign */
46
46
47
+ < << << << HEAD
47
48
const { Tree , UnfilteredTreeNode } = require ( './tree' ) ;
48
49
const astParser = require ( './astParser' ) ;
49
50
const { saveState } = require ( './masterState' ) ;
50
51
// import * as reactWorkTags from './reactWorkTags';
52
+ = === ===
53
+ const Tree = require ( './tree' ) ;
54
+ const componentActionsRecord = require ( './masterState' ) ;
55
+ > >>> >>> 8e774670 f36699322d70300c6382bcdcc7b349e0
51
56
52
57
module . exports = ( snap , mode ) => {
53
58
let fiberRoot = null ;
@@ -64,109 +69,93 @@ module.exports = (snap, mode) => {
64
69
] ;
65
70
66
71
67
- function sendSnapshot ( ) {
72
+ async function sendSnapshot ( ) {
68
73
// Don't send messages while jumping or while paused
69
- // DEV: So that when we are jumping to an old snapshot it
70
74
if ( mode . jumping || mode . paused ) return ;
71
- const payload = snap . tree . getCopy ( ) ;
72
- window . postMessage ( {
73
- action : 'recordSnap' ,
74
- payload,
75
- } ) ;
76
- }
77
-
78
- function changeSetState ( component ) {
79
- if ( component . setState . linkFiberChanged ) return ;
80
-
81
- // Persist the old setState and bind to component so we can continue to setState({})
82
- const oldSetState = component . setState . bind ( component ) ;
83
-
84
- component . setState = ( state , callback = ( ) => { } ) => {
85
- // Don't do anything if state is locked UNLESS we are currently jumping through time
86
- if ( mode . locked && ! mode . jumping ) return ;
87
- // Continue normal setState functionality, with middleware in callback
88
- oldSetState ( state , ( ) => {
89
- updateSnapShotTree ( ) ;
90
- sendSnapshot ( ) ;
91
- callback . bind ( component ) ( ) ;
75
+ // console.log('PAYLOAD: before cleaning', snap.tree);
76
+ const payload = snap . tree . cleanTreeCopy ( ) ; // snap.tree.getCopy();
77
+ // console.log('PAYLOAD: after cleaning', payload);
78
+ try {
79
+ await window . postMessage ( {
80
+ action : 'recordSnap' ,
81
+ payload,
92
82
} ) ;
93
- } ;
94
- // Set a custom property to ensure we don't change this method again
95
- component . setState . linkFiberChanged = true ;
96
- }
97
-
98
- function changeUseState ( component ) {
99
- if ( component . queue . dispatch . linkFiberChanged ) return ;
100
-
101
- // Persist the old dispatch and bind to component so we can continue to dispatch()
102
- const oldDispatch = component . queue . dispatch . bind ( component . queue ) ;
103
-
104
- component . queue . dispatch = ( fiber , queue , action ) => {
105
- if ( mode . locked && ! mode . jumping ) return ;
106
- oldDispatch ( fiber , queue , action ) ;
107
- // * Uncomment setTimeout to prevent snapshot lag-effect
108
- // * (i.e. getting the prior snapshot on each state change)
109
- // setTimeout(() => {
110
- updateSnapShotTree ( ) ;
111
- sendSnapshot ( ) ;
112
- // }, 100);
113
- } ;
114
- // Set a custom property to ensure we don't change this method again
115
- component . queue . dispatch . linkFiberChanged = true ;
83
+ } catch ( e ) {
84
+ console . log ( 'failed to send postMessage:' , e ) ;
85
+ }
116
86
}
117
87
118
- // TODO: WE NEED TO CLEAN IT UP A BIT
88
+ // Carlos: Injects instrumentation to update our state tree every time
89
+ // a hooks component changes state
119
90
function traverseHooks ( memoizedState ) {
120
- // Declare variables and assigned to 0th index and an empty object, respectively
121
- const memoized = { } ;
122
- let index = 0 ;
123
- astHooks = Object . values ( astHooks ) ;
124
- // While memoizedState is truthy, save the value to the object
91
+ const hooksComponents = [ ] ;
125
92
while ( memoizedState && memoizedState . queue ) {
126
- // // prevents useEffect from crashing on load
93
+ // Carlos: these two are legacy comments, we should look into them later
94
+ // prevents useEffect from crashing on load
127
95
// if (memoizedState.next.queue === null) { // prevents double pushing snapshot updates
128
- changeUseState ( memoizedState ) ;
129
- // }
130
- // memoized[astHooks[index]] = memoizedState.memoizedState;
131
- memoized [ astHooks [ index ] ] = memoizedState . memoizedState ;
132
- // Reassign memoizedState to its next value
133
- memoizedState = memoizedState . next ;
134
- // See astParser.js for explanation of this increment
135
- index += 2 ;
96
+ if ( memoizedState . memoizedState ) {
97
+ console . log ( 'memoizedState in traverseHooks is:' , memoizedState ) ;
98
+ hooksComponents . push ( {
99
+ component : memoizedState . queue ,
100
+ state : memoizedState . memoizedState ,
101
+ } ) ;
102
+ }
103
+ // console.log('GOT STATE', memoizedState.memoizedState);
104
+ memoizedState = memoizedState . next !== memoizedState
105
+ ? memoizedState . next : null ;
136
106
}
137
- return memoized ;
107
+ return hooksComponents ;
138
108
}
139
109
140
-
141
- function createTree ( curFiber , parentNode ) {
142
- // on call from updateSnapShot, no parentNode provided, so create a root node
143
- if ( ! parentNode ) parentNode = new Tree ( 'root' ) ;
144
-
145
- // Base case: parentNode's child or sibling pointed to null
146
- if ( ! curFiber ) return parentNode ;
147
-
148
- let newChildNode = null ;
149
-
150
- // If stateful, add to parentNode's children array, then inject new setState into fiber node
151
- if ( curFiber . stateNode && curFiber . stateNode . state ) {
152
- newChildNode = parentNode . appendChild ( curFiber . stateNode ) ;
153
- changeSetState ( curFiber . stateNode ) ;
154
-
155
- // newChildNode.isStateful = true;
156
- newChildNode . tagLabel = reactWorkTags [ curFiber . tag ] ;
157
- newChildNode . actualDuration = curFiber . actualDuration ;
158
- // newChildNode.actualStartTime = curFiber.actualStartTime;
159
- // newChildNode.selfBaseDuration = curFiber.selfBaseDuration;
160
- // newChildNode.treeBaseDuration = curFiber.treeBaseDuration;
110
+ // Carlos: This runs after EVERY Fiber commit. It creates a new snapshot,
111
+ //
112
+ function createTree ( currentFiber , tree = new Tree ( 'root' ) ) {
113
+ // Base case: child or sibling pointed to null
114
+ if ( ! currentFiber ) return tree ;
115
+
116
+ // These have the newest state. We update state and then
117
+ // called updateSnapshotTree()
118
+ const {
119
+ sibling,
120
+ stateNode,
121
+ child,
122
+ memoizedState,
123
+ elementType,
124
+ tag,
125
+ } = currentFiber ;
126
+
127
+ let index ;
128
+ // Check if node is a stateful component
129
+ if ( stateNode && stateNode . state && ( tag === 0 || tag === 1 ) ) {
130
+ // Save component's state and setState() function to our record for future
131
+ // time-travel state changing. Add record index to snapshot so we can retrieve.
132
+ index = componentActionsRecord . saveNew ( stateNode . state , stateNode ) ;
133
+ tree . appendChild ( stateNode . state , elementType . name , index ) ; // Add component to tree
134
+ } else {
135
+ // grab stateless components here
161
136
}
162
137
163
- // Recurse to sibling; siblings that have state should be added to our parentNode
164
- createTree ( curFiber . sibling , parentNode ) ;
138
+ // Check if node is a hooks function
139
+ if ( memoizedState && ( tag === 0 || tag === 1 || tag === 10 ) ) {
140
+ if ( memoizedState . queue ) {
141
+ const hooksComponents = traverseHooks ( memoizedState ) ;
142
+ hooksComponents . forEach ( c => {
143
+ if ( elementType . name ) {
144
+ index = componentActionsRecord . saveNew ( c . state , c . component ) ;
145
+ tree . appendChild ( c . state , elementType . name ? elementType . name : 'nameless' , index ) ;
146
+ }
147
+ } ) ;
148
+ }
149
+ }
165
150
166
- // Recurse to child; If this fiber was stateful, then we added a newChildNode here, and we want
167
- // to attach further children to that. If this fiber wasn't stateful, we want to attach any
168
- // children to our existing parentNode.
169
- createTree ( curFiber . child , newChildNode || parentNode ) ;
151
+ // Recurse on siblings
152
+ createTree ( sibling , tree ) ;
153
+ // Recurse on children
154
+ if ( tree . children . length > 0 ) {
155
+ createTree ( child , tree . children [ 0 ] ) ;
156
+ } else {
157
+ createTree ( child , tree ) ;
158
+ }
170
159
171
160
return parentNode ;
172
161
}
@@ -204,26 +193,31 @@ module.exports = (snap, mode) => {
204
193
205
194
206
195
// ! BUG: skips 1st hook click
207
- async function updateSnapShotTree ( ) {
208
- let current ;
196
+ function updateSnapShotTree ( ) {
197
+ /* let current;
209
198
// If concurrent mode, grab current.child
210
199
if (concurrent) {
211
200
// we need a way to wait for current child to populate
212
201
const promise = new Promise((resolve, reject) => {
213
202
setTimeout(() => resolve(fiberRoot.current.child), 400);
214
203
});
215
-
216
204
current = await promise;
217
-
218
205
current = fiberRoot.current.child;
219
206
} else {
220
207
current = fiberRoot.current;
221
- }
208
+ } */
209
+ const { current } = fiberRoot ; // Carlos: get rid of concurrent mode for now
222
210
211
+ < << << << HEAD
223
212
snap . tree = createTree ( current ) ;
224
213
console . log ( "updateSnapShotTree -> snap.tree" , snap . tree )
225
214
// snap.unfilteredTree = createUnfilteredTree(current);
226
215
// console.log("updateSnapShotTree -> snap.unfilteredTree", snap.unfilteredTree)
216
+ === = ===
217
+ // console.log('FIBER COMMITTED, new fiber is:', util.inspect(current, false, 4));
218
+ // fs.appendFile('fiberlog.txt', util.inspect(current, false, 10));
219
+ snap . tree = createTree ( current ) ; // Carlos: pass new hooks state here?
220
+ > >>> >>> 8e774670 f36699322d70300c6382bcdcc7b349e0
227
221
}
228
222
229
223
return async container => {
@@ -238,15 +232,30 @@ module.exports = (snap, mode) => {
238
232
} = container ;
239
233
// Only assign internal root if it actually exists
240
234
fiberRoot = _internalRoot || _reactRootContainer ;
241
- console . log ( 'linkFiber.js, fiberRoot:' , fiberRoot ) ;
235
+ // console.log('_reactRootContainer is:', _reactRootContainer);
236
+ // console.log('linkFiber.js, fiberRoot:', fiberRoot);
242
237
}
243
-
244
- await updateSnapShotTree ( ) ;
238
+ const devTools = window . __REACT_DEVTOOLS_GLOBAL_HOOK__ ;
239
+ const reactInstance = devTools ? devTools . renderers . get ( 1 ) : null ;
240
+ const overrideHookState = reactInstance ? reactInstance . overrideHookState : null ;
241
+ console . log ( 'DEVTOOLS:' , devTools ) ;
242
+ console . log ( 'roots:' , reactInstance . getCurrentFiber ( ) )
243
+
244
+ if ( reactInstance && reactInstance . version ) {
245
+ devTools . onCommitFiberRoot = ( function ( original ) {
246
+ return function ( ...args ) {
247
+ fiberRoot = args [ 1 ] ;
248
+ updateSnapShotTree ( ) ;
249
+ sendSnapshot ( ) ;
250
+ return original ( ...args ) ;
251
+ } ;
252
+ } ( devTools . onCommitFiberRoot ) ) ;
253
+ }
254
+ updateSnapShotTree ( ) ;
245
255
// Send the initial snapshot once the content script has started up
246
256
// This message is sent from contentScript.js in chrome extension bundles
247
257
window . addEventListener ( 'message' , ( { data : { action } } ) => {
248
258
if ( action === 'contentScriptStarted' ) {
249
- console . log ( 'linkFiber.js received contentScriptStarted message, sending snapshot' ) ;
250
259
sendSnapshot ( ) ;
251
260
}
252
261
} ) ;
0 commit comments