Skip to content

Commit 6151e7e

Browse files
committed
Merge with dev branch
2 parents 421f2c7 + 8188481 commit 6151e7e

File tree

7 files changed

+212
-32
lines changed

7 files changed

+212
-32
lines changed

demo-app/src/client/Components/Nav.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ function Nav() {
1313
<Link className='link' to='/buttons'>
1414
Counter
1515
</Link>
16-
<Link className='link' to='/test'>
16+
{/* <Link className='link' to='/test'>
1717
Test
18-
</Link>
18+
</Link> */}
1919
</div>
2020
);
2121
}

src/backend/controllers/timeJump.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ async function initiateJump(target, mode): Promise<void> {
7272
document.body.onmouseover = () => {
7373
console.log('STOP JUMPING');
7474
mode.jumping = false;
75+
console.log('mouseover');
7576
};
7677
});
7778
}

src/backend/models/masterState.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,38 @@
33
/* eslint-disable no-plusplus */
44
/* eslint-disable guard-for-in */
55
/* eslint-disable no-restricted-syntax */
6+
/**
7+
* @type ComponentAction - an array of actions that can be performed on a component
8+
*/
69
type ComponentAction = {
710
[url: string]: any[];
811
};
912
type ComponentActionRecord = ComponentAction[];
1013

11-
// HookState is an array that contains a "component" for
12-
// every single state change that occurs in the app
14+
// The HookState data structure is an array that holds the current value of a hook's state, as well as a dispatch function that is used to update that state.
1315
// Information on these components include ComponentData as well as state
1416
// For class components, there will be one "component" for each snapshot
1517
// For functional components that utilize Hooks, there will be one "component"
1618
// for each setter/getter every time we have a new snapshot
1719
let componentActionsRecord: ComponentActionRecord = [];
20+
// index keeps track of the current position in the array
1821
let index: number;
1922
index = 0;
2023

2124
export default {
25+
/**
26+
* @function clear - Clears componentActionsRecord
27+
*/
2228
clear: () => {
2329
componentActionsRecord[window.location.href] = [];
2430
index = 0;
2531
},
26-
// Adds new component to ComponentActionsRecord
32+
33+
/**
34+
* @function saveNew - Adds a new component to the componentActionsRecord array and returns its index.
35+
* @param component
36+
* @returns number
37+
*/
2738
saveNew: (component): number => {
2839
componentActionsRecord[window.location.href].push(component);
2940
// componentActionsRecord[index] = component;
@@ -34,7 +45,7 @@ export default {
3445
},
3546
// ----------------------------CLASS COMPONENT--------------------------------
3647
/**
37-
* This function is used for stateful Class Component to retrieve an object that has the bound setState method
48+
* @function getComponentByIndex - This function is used for stateful Class Component to retrieve an object that has the bound setState method
3849
* @param inputIndex - index of component inside `componentActionsRecord` coming from `timeJump.ts`
3950
* @returns - an object containing the bound setState method
4051
*/
@@ -43,15 +54,15 @@ export default {
4354

4455
//---------------------------FUNCTIONAL COMPONENT-----------------------------
4556
/**
46-
* This function is used for Functional Component to retrieve an array of objects that have the bound dispatch methods.
57+
* @function getComponentByIndexHooks - This function is used for Functional Component to retrieve an array of objects that have the bound dispatch methods.
4758
* @param inputIndex - index of component inside `componentActionsRecord` coming from `timeJump.ts`
4859
* @returns - an array of objects containing the bound dispatch methods
4960
*/
5061
getComponentByIndexHooks: (inputIndex: Array<number> = []): any[] | undefined =>
5162
inputIndex.map((index) => componentActionsRecord[window.location.href][index]),
5263
// ----------------------------------DEBUGGING--------------------------------
5364
/**
54-
* This method is used for debugging purpose to access the array of setState/dispatch methods
65+
* @function getAllComponents - This method is used for debugging purpose to access the array of setState/dispatch methods
5566
* @returns - an array of objects containing the bound methods for updating state
5667
*/
5768
getAllComponents: (): any[] => componentActionsRecord[window.location.href],

src/backend/models/tree.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
/* eslint-disable no-param-reassign */
88
import { Route } from './routes';
99

10-
let copyInstances = 0; // Tells you if we have already made a copy of current tree??
11-
const circularComponentTable = new Set<Tree>(); // Keeps track of the nodes added to the tree
12-
let componentNames = {}; // {componentName: frequency of use} => component name as a key and it's frequency of use as its value
10+
// The circularComponentTable is used to handle circular references in the state object. It keeps tracks of the components that have already been serialized. When a component is encountered for the first time, it is added to the table along with a unique identifier. If the same component is encountered again, the identifier is used to reference the previously serialized component in the output instead of serializing it again, thus avoiding the infinite loop.
11+
const circularComponentTable = new Set<Tree>();
12+
// Used to keep track of which objects have already been copied during the serialization process. This is necessary to handle circular references correctly. When an object is serialized, all its properties are copied to the serialized object. If an object property is an object itself, it needs to be serialized recursively. However, if the object being serialized has already been serialized before, it should not be serialized again to prevent an infinite loop.
13+
let copyInstances = 0;
14+
// ComponentNames is used to store a mapping between a component's unique identifier and its name. This mapping is used to reconstruct the component instances during deserialization.
15+
let componentNames = {};
1316

1417
// Functions dont serialize properly so we need to scrub for that
1518
export function scrubUnserializableMembers(tree: Tree): Tree {
@@ -20,6 +23,11 @@ export function scrubUnserializableMembers(tree: Tree): Tree {
2023
}
2124

2225
// Making a deep clone of state becuase we want to make a copy
26+
/**
27+
* @function serializeState - In the context of React, state is often used to store data that determines the behavior and appearance of a component. By serializing the state, we can preserve the component's data across page refreshes, server-side rendering, and other transitions. Additionally, by serializing the state and passing it to a child component, we can create a deep clone of the state, which allows the child component to manipulate the state without affecting the original component. This is useful in situations where we want to keep the state of the parent component immutable, but still allow child components to modify a copy of the state.
28+
* @param state - Object that contains the current state of the application or system that needs to be serialized.
29+
* @returns
30+
*/
2331
export function serializeState(state) {
2432
try {
2533
// makes a deep clone
@@ -33,15 +41,14 @@ export function serializeState(state) {
3341
/**
3442
* This is the current snapshot that is being sent to the snapshots array.
3543
* Creates a Tree
36-
* @param state - {string| {}} - the tree's current state
37-
* @param name - {string} - the tree's name
38-
* @param componentData - {props: {}} - Data in the component tree
39-
* @param chilren - {(Tree | string)[]} - An array of children nodes
40-
* @param parent - {Tree} - the parent node
41-
* @param isExpanded - {boolean}
42-
* @param rtid - {any}
43-
* @param route -
44-
* @parent generates a new tree (recursive call)
44+
* @param state - the current state of the component represented by this node.
45+
* @param name - the name of the component represented by this node.
46+
* @param componentData - an object containing the props of the component represented by this node.
47+
* @param chilren - an array of child nodes.
48+
* @param parent - a reference to the parent node.
49+
* @param isExpanded - a boolean value indicating whether the node is expanded in the UI.
50+
* @param rtid - a unique identifier for the node.
51+
* @param route - an object representing the route associated with the node.
4552
*/
4653
class Tree {
4754
state: string | {};
@@ -87,6 +94,11 @@ class Tree {
8794
}
8895

8996
// Returns a unique name ready to be used for when new components gets added to the tree
97+
/**
98+
* @function checkForDuplicates - Generates a unique name for a component that is being added to the component tree
99+
* @param name
100+
* @returns
101+
*/
90102
checkForDuplicates(name: string): string {
91103
// check for empty name
92104
if (name === '' && typeof this.rtid === 'string') {
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/**
2+
* @type
3+
* @member type - The type of the element. Can be a string (for HTML/SVG tags), a function component (a function that returns a React element), or a class component (a class that extends React.Component and has a render() method).
4+
* @member props - An object containing the properties passed to the element. These are the properties that are specified in JSX
5+
* @member key - An optional key that can be used to identify an element in a list. This helps React determine which elements have changed when rendering a list.
6+
* @member ref - An optional ref that can be used to get a reference to the element's underlying DOM node. This is useful for imperatively manipulating the DOM
7+
* @member _owner - A reference to the component that created this element. This property is used for debugging purposes only and is not meant to be used in production code.
8+
*/
9+
10+
interface ReactElement {
11+
type: string | Function;
12+
props: {
13+
[key: string]: any;
14+
children: ReactElement[];
15+
};
16+
key: string | null;
17+
ref: any;
18+
_owner: FiberNode | null;
19+
}
20+
21+
/**
22+
* @type
23+
* @member element - This property holds the current element that the fiber represents in the render tree.
24+
* @member parent - This property holds a reference to the parent fiber of the current fiber.
25+
* @member child - This property holds a reference to the first child fiber of the current fiber.
26+
* @member sibling - This property holds a reference to the next sibling fiber of the current fiber.
27+
* @member alternate - This property holds a reference to the corresponding fiber in the previous render (i.e. the "old" fiber).
28+
* @member effectTag - This property is used to describe the type of update that needs to be made to the DOM when the fiber is committed. It can be one of three values: "PLACEMENT" (for new elements), "UPDATE" (for updates to existing elements), or "DELETION" (for elements that need to be removed from the DOM).
29+
* @member effects - This property is used to keep track of all the fibers that need to be updated, added, or removed from the DOM during the current commit phase. It is an array of fibers that have been marked with an effectTag other than null.
30+
*/
31+
32+
interface FiberNode {
33+
element: ReactElement | null;
34+
parent: FiberNode | null;
35+
child: FiberNode | null;
36+
sibling: FiberNode | null;
37+
alternate: FiberNode | null;
38+
effectTag: string | null;
39+
effects?: FiberNode[];
40+
stateNode: any;
41+
}
42+
43+
/**
44+
* @function createFiberNode - Responsible for creating a new Fiber Node. A Fiber node is an object that represents a React element in the reconciliation process. It contains information about the element, its parent, and its children as well other data
45+
* @param element - React element that represents the component or DOM node that the fiber will represent. It is an object that contains information about the type of element, its props, its children, etc.
46+
* @param parent - The fiber node that represents the parent component of the element. It is used to link the new fiber node to the fiber tree by setting its parent property to the parent fiber node
47+
* @returns
48+
*/
49+
const createFiberNode = (element: ReactElement, parent: FiberNode | null): FiberNode => {
50+
return {
51+
element,
52+
parent,
53+
child: null,
54+
sibling: null,
55+
alternate: null,
56+
effectTag: null,
57+
stateNode: null,
58+
};
59+
};
60+
61+
/**
62+
* @function reconcile - The purpose of the reconcile function is to reconcile the children array with the parentFiber node. In other words, it creates a fiber tree that reflects the current state of the React element tree
63+
* @param parentFiber - The fiber node of the parent element in the tree
64+
* @param children - An array of child elements (React elements) that belong to the parent element
65+
*/
66+
const reconcile = (parentFiber: FiberNode, children: any[]): void => {
67+
// checks to see if the parent fiber has an alternate fiber and if it does, it sets oldFiber to its child
68+
// If there is an alternate fiber for the parent fiber, it means that there was a previous version of the fiber tree that was reconciled, and oldFiber is set to its child fiber so that it can compared to the new children in the current version of the tree
69+
let oldFiber = parentFiber.alternate && parentFiber.alternate.child;
70+
let newFiber: FiberNode | null = null;
71+
let index = 0; // used to keep track of the current index in the children array that is being processed
72+
let prevFiber: FiberNode | null = null; // used to keep track of the last fiber that was process in the loop
73+
74+
while (index < children.length || !oldFiber) {
75+
const reactElement = children[index];
76+
// see if same type
77+
let sameType = oldFiber && reactElement && reactElement.type === oldFiber.element.type;
78+
// if same type is found, create a newFiber
79+
if (sameType) {
80+
newFiber = {
81+
element: reactElement,
82+
child: null,
83+
sibling: null,
84+
parent: parentFiber,
85+
alternate: oldFiber,
86+
effectTag: 'UPDATE',
87+
stateNode: oldFiber.stateNode,
88+
};
89+
} else {
90+
if (reactElement) {
91+
newFiber = createFiberNode(reactElement, parentFiber);
92+
newFiber.effectTag = 'PLACEMENT';
93+
94+
if (typeof reactElement.type === 'function') {
95+
newFiber.stateNode = new (reactElement.type as any)(reactElement.props);
96+
} else {
97+
newFiber.stateNode = document.createElement(reactElement.type as string);
98+
}
99+
}
100+
101+
if (oldFiber) {
102+
oldFiber.effectTag = 'DELETION';
103+
parentFiber.effects = parentFiber.effects || [];
104+
parentFiber.effects.push(oldFiber);
105+
}
106+
}
107+
108+
oldFiber === null ? null : oldFiber.sibling;
109+
// this block of code if responsible for creating a singly linked list of child nodes for the parent element, where each node has a child property pointing to its first child node and a sibling property pointing to its next sibling
110+
if (index === 0) {
111+
parentFiber.child = newFiber;
112+
} else if (reactElement) {
113+
prevFiber!.sibling = newFiber;
114+
}
115+
116+
prevFiber = newFiber;
117+
index++;
118+
}
119+
};
120+
121+
/**
122+
* @function commitRoot - Responsible for committing the changes made to the DOM during the reconcilation phase
123+
* @param rootFiber - Root of the fiber tree. It contains information about the element and changes that need to be made to the DOM
124+
*/
125+
const commitRoot = (rootFiber: FiberNode) => {
126+
if (!rootFiber) return;
127+
rootFiber.effects?.forEach((fiber) => {
128+
if (fiber.effectTag === 'PLACEMENT') {
129+
// place existing element
130+
} else if (fiber.effectTag === 'UPDATE') {
131+
// update existing element
132+
} else if (fiber.effectTag === 'DELETION') {
133+
// remove element from DOM
134+
}
135+
});
136+
};
137+
138+
/**
139+
* @function render - Creates a root fiber which is the top-level fiber that represents the root of the React element ree.
140+
* @param element - The react element that you want to render into the container. It represents the root of your component tree
141+
* @param container - The DOM element that you want to render your React element into. It is typically a <div>
142+
*/
143+
const render = (element: ReactElement, container: HTMLElement) => {
144+
const rootFiber: FiberNode = createFiberNode(element, null);
145+
rootFiber.element = container as any as ReactElement; // cast container to ReactElement
146+
const workInProgressRootFiber: FiberNode = {
147+
...rootFiber,
148+
alternate: rootFiber,
149+
};
150+
reconcile(workInProgressRootFiber, element.props.children);
151+
commitRoot(workInProgressRootFiber);
152+
};

src/backend/routers/linkFiber.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ declare global {
3939
}
4040

4141
/**
42-
* linkFiber contains core module functionality, exported as an anonymous function, perform the following logic:
42+
* @function linkFiber - linkFiber contains core module functionality, exported as an anonymous function, perform the following logic:
4343
* 1. Check if React Dev Tool is installed.
4444
* 2. Check if the target application (on the browser) is a valid react application.
4545
* 3. Initiate a event listener for visibility update of the target React Applicaiton.
46-
* 4. Obtain the initial fiberRootNode, which is the root node of a tree of React component.
47-
* 5. Initialize the tree snapShot on Chrome Extension.
46+
* 4. Obtain the initial fiberRootNode, which is the root node of the fiber tree
47+
* 5. Initialize the fiber tree snapShot on Chrome Extension.
4848
* 6. Monkey patching the onCommitFiberRoot from REACT DEV TOOL to obtain updated data after React Applicaiton is re-rendered.
49-
* @param snapShot The current snapshot
49+
* @param snapShot The current snapshot (i.e fiber tree)
5050
* @param mode The current mode (i.e. jumping, time-traveling, or paused)
5151
* @return a function to be invoked by index.js that initiates snapshot monitoring
5252
*/
@@ -56,8 +56,9 @@ export default function linkFiber(snapShot: Snapshot, mode: Status): () => void
5656
*/
5757
let isVisible: boolean = true;
5858
/**
59-
* The `fiberRootNode`, which is the root node of a tree of React component.
60-
* The `current` property of `fiberRoot` has data structure of a Tree, which can be used to traverse and obtain all child component data.
59+
* Every React application has one or more DOM elements that act as containers. React creates a fiber root object for each of those containers.
60+
* This fiber root is where React holds reference to a fiber tree
61+
* The `fiberRootNode`, which is the root node of the fiber tree is stored in the current property of the fiber root object
6162
*/
6263
let fiberRoot: FiberRoot;
6364
/**
@@ -95,6 +96,8 @@ export default function linkFiber(snapShot: Snapshot, mode: Status): () => void
9596
// react devtools global hook is a global object that was injected by the React Devtools content script, allows access to fiber nodes and react version
9697
// Obtain React Devtools Object:
9798
const devTools = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
99+
const { onCommitFiberRoot } = devTools;
100+
console.log('onCommit..', onCommitFiberRoot);
98101
// If React Devtools is not installed, object will be undefined.
99102
if (!devTools) {
100103
return;

0 commit comments

Comments
 (0)