1+ /**
2+ * This file contains core module functionality.
3+ *
4+ * It exports an anonymous
5+ * @function
6+ * that is invoked on
7+ * @param snap --> Current snapshot
8+ * @param mode --> Current mode (jumping i.e. time-traveling, locked, or paused)
9+ * and @returns a function to be invoked on the rootContainer HTMLElement
10+ *
11+ * @function updateSnapShotTree
12+ * --> Middleware #1: Updates snap object with latest snapshot
13+ *
14+ * @function sendSnapshot
15+ * --> Middleware #2: Gets a copy of the current snap.tree and posts a message to the window
16+ *
17+ * @function changeSetState
18+ * @param component : stateNode property on a stateful class component's FiberNode object
19+ * --> Binds class component setState method to the component
20+ * --> Injects middleware into class component's setState method
21+ *
22+ * @function changeUseState
23+ * @param component : memoizedState property on a stateful functional component's FiberNode object
24+ * --> Binds functional component dispatch method to the component
25+ * --> Injects middleware into component's dispatch method
26+ * Note: dispatch is hook equivalent to setState()
27+ *
28+ * @function traverseHooks
29+ * @param memoizedState : memoizedState property on a stateful fctnl component's FiberNode object
30+ * --> Helper function to traverse through memoizedState
31+ * --> Invokes @changeUseState on each stateful functional component
32+ *
33+ * @function createTree
34+ * @param currentFiber : a FiberNode object
35+ * --> Recursive function to traverse from FiberRootNode and create
36+ * an instance of custom Tree class and build up state snapshot
37+ */
38+
139/* eslint-disable no-underscore-dangle */
240/* eslint-disable func-names */
341/* eslint-disable no-use-before-define */
442/* eslint-disable no-param-reassign */
5- // links component state tree to library
6- // changes the setState method to also update our snapshot
43+
744const Tree = require ( './tree' ) ;
845const astParser = require ( './astParser' ) ;
946const { saveState } = require ( './masterState' ) ;
@@ -14,80 +51,80 @@ module.exports = (snap, mode) => {
1451 let concurrent = false ; // flag to check if we are in concurrent mode
1552
1653 function sendSnapshot ( ) {
17- // don 't send messages while jumping or while paused
54+ // Don 't send messages while jumping or while paused
1855 // DEV: So that when we are jumping to an old snapshot it
19- // wouldn't think we want to create new snapshots
2056 if ( mode . jumping || mode . paused ) return ;
2157 const payload = snap . tree . getCopy ( ) ;
22- // console.log('payload', payload);
2358 window . postMessage ( {
2459 action : 'recordSnap' ,
2560 payload,
2661 } ) ;
2762 }
2863
2964 function changeSetState ( component ) {
30- // check that setState hasn't been changed yet
3165 if ( component . setState . linkFiberChanged ) return ;
32- // make a copy of setState
66+
67+ // Persist the old setState and bind to component so we can continue to setState({})
3368 const oldSetState = component . setState . bind ( component ) ;
34- // replace component's setState so developer doesn't change syntax
35- // component.setState = newSetState.bind(component);
69+
3670 component . setState = ( state , callback = ( ) => { } ) => {
37- // don't do anything if state is locked
38- // UNLESS we are currently jumping through time
71+ // Don't do anything if state is locked UNLESS we are currently jumping through time
3972 if ( mode . locked && ! mode . jumping ) return ;
40- // continue normal setState functionality, except add sending message middleware
73+ // Continue normal setState functionality, with middleware in callback
4174 oldSetState ( state , ( ) => {
4275 updateSnapShotTree ( ) ;
4376 sendSnapshot ( ) ;
4477 callback . bind ( component ) ( ) ;
4578 } ) ;
4679 } ;
80+ // Set a custom property to ensure we don't change this method again
4781 component . setState . linkFiberChanged = true ;
4882 }
4983
5084 function changeUseState ( component ) {
5185 if ( component . queue . dispatch . linkFiberChanged ) return ;
52- // store the original dispatch function definition
86+
87+ // Persist the old dispatch and bind to component so we can continue to dispatch()
5388 const oldDispatch = component . queue . dispatch . bind ( component . queue ) ;
54- // redefine the dispatch function so we can inject our code
89+
5590 component . queue . dispatch = ( fiber , queue , action ) => {
56- // don't do anything if state is locked
5791 if ( mode . locked && ! mode . jumping ) return ;
5892 oldDispatch ( fiber , queue , action ) ;
93+ // * Uncomment setTimeout to prevent snapshot lag-effect
94+ // * (i.e. getting the prior snapshot on each state change)
5995 // setTimeout(() => {
6096 updateSnapShotTree ( ) ;
6197 sendSnapshot ( ) ;
6298 // }, 100);
6399 } ;
100+ // Set a custom property to ensure we don't change this method again
64101 component . queue . dispatch . linkFiberChanged = true ;
65102 }
66103
67- // Helper function to traverse through the memoized state
68104 // TODO: WE NEED TO CLEAN IT UP A BIT
69105 function traverseHooks ( memoizedState ) {
70106 // Declare variables and assigned to 0th index and an empty object, respectively
71107 const memoized = { } ;
72108 let index = 0 ;
73109 astHooks = Object . values ( astHooks ) ;
74- // while memoizedState is truthy, save the value to the object
110+ // While memoizedState is truthy, save the value to the object
75111 while ( memoizedState && memoizedState . queue ) {
76- // prevents useEffect from crashing on load
112+ // // prevents useEffect from crashing on load
77113 // if (memoizedState.next.queue === null) { // prevents double pushing snapshot updates
78114 changeUseState ( memoizedState ) ;
79115 // }
80116 // memoized[astHooks[index]] = memoizedState.memoizedState;
81117 memoized [ astHooks [ index ] ] = memoizedState . memoizedState ;
82118 // Reassign memoizedState to its next value
83119 memoizedState = memoizedState . next ;
84- // Increment the index by 2
120+ // See astParser.js for explanation of this increment
85121 index += 2 ;
86122 }
87123 return memoized ;
88124 }
89125
90126 function createTree ( currentFiber , tree = new Tree ( 'root' ) ) {
127+ // Base case: child or sibling pointed to null
91128 if ( ! currentFiber ) return tree ;
92129
93130 const {
@@ -99,19 +136,17 @@ module.exports = (snap, mode) => {
99136 } = currentFiber ;
100137
101138 let nextTree = tree ;
102- // check if stateful component
139+
140+ // Check if stateful component
103141 if ( stateNode && stateNode . state ) {
104- // add component to tree
105- nextTree = tree . appendChild ( stateNode ) ;
106- // change setState functionality
107- changeSetState ( stateNode ) ;
142+ nextTree = tree . appendChild ( stateNode ) ; // Add component to tree
143+ changeSetState ( stateNode ) ; // Change setState functionality
108144 }
109- // Check if the component uses hooks
110- // console.log("memoizedState", memoizedState);
111145
146+ // Check if the component uses hooks
112147 if (
113- memoizedState &&
114- Object . hasOwnProperty . call ( memoizedState , 'baseState' )
148+ memoizedState
149+ && Object . hasOwnProperty . call ( memoizedState , 'baseState' )
115150 ) {
116151 // 'catch-all' for suspense elements (experimental)
117152 if ( typeof elementType . $$typeof === 'symbol' ) return ;
@@ -123,18 +158,19 @@ module.exports = (snap, mode) => {
123158 memoizedState . traversed = traverseHooks ( memoizedState ) ;
124159 nextTree = tree . appendChild ( memoizedState ) ;
125160 }
126- // iterate through siblings
161+
162+ // Recurse on siblings
127163 createTree ( sibling , tree ) ;
128- // iterate through children
164+ // Recurse on children
129165 createTree ( child , nextTree ) ;
130166
131167 return tree ;
132168 }
133- // runs when page initially loads
134- // but skips 1st hook click
169+
170+ // ! BUG: skips 1st hook click
135171 async function updateSnapShotTree ( ) {
136172 let current ;
137- // if concurrent mode, grab current.child'
173+ // If concurrent mode, grab current.child
138174 if ( concurrent ) {
139175 // we need a way to wait for current child to populate
140176 const promise = new Promise ( ( resolve , reject ) => {
@@ -152,6 +188,7 @@ module.exports = (snap, mode) => {
152188 }
153189
154190 return async container => {
191+ // Point fiberRoot to FiberRootNode
155192 if ( container . _internalRoot ) {
156193 fiberRoot = container . _internalRoot ;
157194 concurrent = true ;
@@ -160,12 +197,13 @@ module.exports = (snap, mode) => {
160197 _reactRootContainer : { _internalRoot } ,
161198 _reactRootContainer,
162199 } = container ;
163- // only assign internal root if it actually exists
200+ // Only assign internal root if it actually exists
164201 fiberRoot = _internalRoot || _reactRootContainer ;
165202 }
166203
167204 await updateSnapShotTree ( ) ;
168- // send the initial snapshot once the content script has started up
205+ // Send the initial snapshot once the content script has started up
206+ // This message is sent from contentScript.js in chrome extension bundles
169207 window . addEventListener ( 'message' , ( { data : { action } } ) => {
170208 if ( action === 'contentScriptStarted' ) sendSnapshot ( ) ;
171209 } ) ;
0 commit comments