Skip to content

Commit 323f2c7

Browse files
committed
handeled the errors
2 parents 39869f3 + e64fc61 commit 323f2c7

File tree

5 files changed

+125
-50
lines changed

5 files changed

+125
-50
lines changed

package/astParser.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
/* eslint-disable no-inner-declarations */
2-
const acorn = require('acorn'); // javascript parser
1+
/* eslint-disable no-inner-declarations, no-loop-func */
32
// eslint-disable-next-line import/newline-after-import
3+
const acorn = require('acorn'); // javascript parser
44
const jsx = require('acorn-jsx');
5+
56
const JSXParser = acorn.Parser.extend(jsx());
67

78
// Helper function to grab the getters/setters from `elementType`
@@ -11,6 +12,7 @@ module.exports = elementType => {
1112
const hookState = {};
1213

1314
while (Object.hasOwnProperty.call(ast, 'body')) {
15+
let tsCount = 0; // Counter for the number of TypeScript hooks seen (to distinguish in masterState)
1416
ast = ast.body;
1517
const statements = [];
1618

@@ -26,7 +28,19 @@ module.exports = elementType => {
2628
body.forEach(elem => {
2729
if (elem.type === 'VariableDeclaration') {
2830
elem.declarations.forEach(hook => {
29-
statements.push(hook.id.name);
31+
// * TypeScript hooks appear to have no "VariableDeclarator"
32+
// * with id.name of _useState, _useState2, etc...
33+
// * hook.id.type relevant for TypeScript applications
34+
// *
35+
// * Works for useState hooks
36+
if (hook.id.type === 'ArrayPattern') {
37+
hook.id.elements.forEach(hook => {
38+
statements.push(hook.name);
39+
// * Unshift a wildcard name to achieve similar functionality as before
40+
statements.unshift(`_useWildcard${tsCount}`);
41+
tsCount += 1;
42+
});
43+
} else statements.push(hook.id.name);
3044
});
3145
}
3246
});

package/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* 'reactime' module has a single export
3+
* @function linkFiber
4+
*/
5+
6+
// * State snapshot object initialized here
17
const snapShot = { tree: null };
28

39
const mode = {
@@ -21,10 +27,11 @@ function getRouteURL(node) {
2127
}
2228
}
2329

24-
window.addEventListener('message', ({ data: { action, payload } }) => { // runs automatically twice per second with inspectedElement
30+
// * Event listener for time-travel actions
31+
window.addEventListener('message', ({ data: { action, payload } }) => {
2532
switch (action) {
2633
case 'jumpToSnap':
27-
timeJump(payload);
34+
timeJump(payload); // * This sets state with given payload
2835
// Get the pathname from payload and add new entry to browser history
2936
// MORE: https://developer.mozilla.org/en-US/docs/Web/API/History/pushState
3037
window.history.pushState('', '', getRouteURL(payload));

package/linkFiber.js

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,46 @@
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+
744
const Tree = require('./tree');
845
const astParser = require('./astParser');
946
const { 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
});

package/timeJump.js

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1+
/**
2+
* This file contains necessary functionality for time-travel feature
3+
*
4+
* It exports an anonymous
5+
* @function
6+
* that is invoked on
7+
* @param target --> a target snapshot portraying some past state
8+
* and recursively sets state for any stateful components.
9+
*
10+
*/
11+
112
/* eslint-disable no-param-reassign */
2-
// traverses given tree by accessing children through coords array
13+
314
const { returnState } = require('./masterState');
415

16+
// Traverses given tree by accessing children through coords array
517
function traverseTree(tree, coords) {
618
let curr = tree;
719
coords.forEach(coord => {
@@ -11,30 +23,33 @@ function traverseTree(tree, coords) {
1123
}
1224

1325
module.exports = (origin, mode) => {
14-
// recursively change state of tree
26+
// Recursively change state of tree
1527
function jump(target, coords = []) {
1628
const originNode = traverseTree(origin.tree, coords);
17-
// set the state of the origin tree if the component is stateful
29+
30+
// Set the state of the origin tree if the component is stateful
1831
if (originNode.component.setState) {
19-
originNode.component.setState((prevState) => {
20-
Object.keys(prevState).forEach((key) => {
32+
// * Use the function argument when setting state to account for any state properties
33+
// * that may not have existed in the past
34+
originNode.component.setState(prevState => {
35+
Object.keys(prevState).forEach(key => {
2136
if (target.state[key] === undefined) {
2237
target.state[key] = undefined;
2338
}
24-
})
39+
});
2540
return target.state;
2641
}, () => {
27-
// iterate through new children once state has been set
42+
// Iterate through new children once state has been set
2843
target.children.forEach((child, i) => {
2944
jump(child, coords.concat(i));
3045
});
3146
});
3247
} else {
33-
// if component uses hooks, traverse through the memoize tree
48+
// If component uses hooks, traverse through the memoize tree
3449
let current = originNode.component;
3550
let index = 0;
3651
const hooks = returnState();
37-
// while loop through the memoize tree
52+
// While loop through the memoize tree
3853
while (current && current.queue) { // allows time travel with useEffect
3954
current.queue.dispatch(target.state[hooks[index]]);
4055
// Reassign the current value
@@ -45,7 +60,7 @@ module.exports = (origin, mode) => {
4560
}
4661

4762
return target => {
48-
// setting mode disables setState from posting messages to window
63+
// * Setting mode disables setState from posting messages to window
4964
mode.jumping = true;
5065
jump(target);
5166
setTimeout(() => {

src/app/containers/ActionContainer.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ function ActionContainer() {
2121
if (snapshots.length > 0) {
2222
// breadth first function - take in an delta obj
2323
function breadthFirst(delta) {
24+
if (delta === undefined) return '';
2425
// aux array = current and one called next
2526
let current = Object.values(delta.children); // Object.keys(delta.children);
2627
let next = [];

0 commit comments

Comments
 (0)