├── mockData
├── treeGraph.js
├── tinyFlameGraph.js
├── fiber.js
├── ticTacToe.js
├── devToolData.js
└── ticTacToeFiberRoot.js
├── .gitignore
├── src
├── assets
│ ├── rm-icon16.png
│ ├── readmeDemo.gif
│ ├── rm-icon-128.png
│ ├── rm-icon-48.png
│ ├── play-button-svgrepo-com.svg
│ ├── pause-svgrepo-com.svg
│ └── reload-svgrepo-com.svg
├── extension
│ ├── devtools.js
│ ├── devtools.html
│ ├── manifest.json
│ ├── contentScript.js
│ └── backgroundScript.js
└── app
│ ├── index.html
│ ├── components
│ ├── timeTravel.js
│ ├── record.js
│ ├── mainContainer.js
│ ├── stateChange.js
│ ├── componentsList.js
│ ├── flameChart.js
│ ├── stateAndProps.js
│ ├── playButton.js
│ ├── helperFunctions.js
│ └── d3tree.js
│ ├── App.js
│ └── style.scss
├── package
├── sendContentScript.js
├── deleteParent.js
├── containerWrapper.js
├── JSONStringify.js
├── makeTreeCreator.test.js
├── ReactWorkTags.js
├── createTree.js
├── treeGraphFactory.test.js
├── deleteParent.test.js
├── makeTreeCreator.js
├── newNode.js
├── package.json
├── compareStateAndProps.js
├── README.md
└── treeGraphFactory.js
├── uml
├── highLevelDiagram.plantuml
├── devtools.plantuml
└── treeCreator.plantuml
├── __test__
├── stateChange.test.js
├── record.test.js
├── stateAndProps.test.js
├── componentsList.test.js
├── playButton.test.js
├── timeTravel.test.js
└── helperFunctions.test.js
├── LICENSE
├── webpack.config.js
├── package.json
└── README.md
/mockData/treeGraph.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | /dist
3 | .vscode/
--------------------------------------------------------------------------------
/src/assets/rm-icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactMonitor/HEAD/src/assets/rm-icon16.png
--------------------------------------------------------------------------------
/src/assets/readmeDemo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactMonitor/HEAD/src/assets/readmeDemo.gif
--------------------------------------------------------------------------------
/src/assets/rm-icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactMonitor/HEAD/src/assets/rm-icon-128.png
--------------------------------------------------------------------------------
/src/assets/rm-icon-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/ReactMonitor/HEAD/src/assets/rm-icon-48.png
--------------------------------------------------------------------------------
/src/extension/devtools.js:
--------------------------------------------------------------------------------
1 | chrome.devtools.panels.create(
2 | 'React Monitor', // panel title
3 | './assets/rm-icon-128.png', // logo path
4 | 'index.html', // initial HTML page for the dev panel
5 | null
6 | );
7 |
--------------------------------------------------------------------------------
/package/sendContentScript.js:
--------------------------------------------------------------------------------
1 | module.exports = function(treeCreator, prevTree, currentTree)
2 | {
3 | const treeGraph = treeCreator(currentTree);
4 | window.postMessage({ action: 'npmToContent', payload: treeGraph });
5 | }
6 |
--------------------------------------------------------------------------------
/package/deleteParent.js:
--------------------------------------------------------------------------------
1 |
2 | function deleteParent(root){
3 |
4 | if (root.parent) {
5 | delete root.parent;
6 | }
7 | if (root.children) {
8 | root.children.forEach((child) => deleteParent(child));
9 | }
10 |
11 | }
12 |
13 |
14 |
15 | module.exports = deleteParent;
--------------------------------------------------------------------------------
/src/extension/devtools.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React Monitor
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | React Monitor
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/mockData/tinyFlameGraph.js:
--------------------------------------------------------------------------------
1 | const flameGraphData = {
2 | "children": [
3 | {
4 | "name": "genunix`syscall_mstate",
5 | "value": 89
6 | },
7 | {
8 | "children": [
9 | {
10 | "name": "unix`page_lookup_create",
11 | "value": 1
12 | }
13 | ],
14 | "name": "america",
15 | "value": 99
16 | }],
17 | "name": "codesmith",
18 | "value": 56
19 | }
20 |
21 | export default flameGraphData;
--------------------------------------------------------------------------------
/package/containerWrapper.js:
--------------------------------------------------------------------------------
1 | const reactMonitor = require("./createTree.js");
2 |
3 | //grabbing the Dom element that has the property of react_RootContiner
4 | function get_fiber_root(document_children) {
5 | for (let ele of document_children) {
6 | if (ele.hasOwnProperty("_reactRootContainer")) return ele;
7 | }
8 | }
9 |
10 | const container = get_fiber_root(document.body.children);
11 |
12 | //invoking the createTree function by passing the DOM element that contain the property of react_RootContainer
13 | reactMonitor(container);
14 |
--------------------------------------------------------------------------------
/package/JSONStringify.js:
--------------------------------------------------------------------------------
1 | module.exports = function (object){
2 |
3 | let cache = [];
4 | const string = JSON.stringify(
5 | object,
6 | // custom replacer - gets around "TypeError: Converting circular structure to JSON"
7 | (key, value) => {
8 | if (typeof value === 'object' && value !== null) {
9 | if (cache.indexOf(value) !== -1) {
10 | // Circular reference found, discard key
11 | return;
12 | }
13 | // Store value in collection
14 | cache.push(value);
15 | }
16 | return value;
17 | },
18 | 4
19 | );
20 | cache = null; // garbage collection
21 | return string;
22 | }
--------------------------------------------------------------------------------
/package/makeTreeCreator.test.js:
--------------------------------------------------------------------------------
1 | const makeTreeCreator = require('./makeTreeCreator');
2 | const fiber = require('../mockData/fiber');
3 |
4 |
5 | describe('test makeTreeCreator', () => {
6 |
7 |
8 | it('test makeTreeCreator returns a function', () => {
9 |
10 | const treeCreator = makeTreeCreator();
11 | const treeGraph = treeCreator(fiber);
12 |
13 | expect( treeCreator ).toBeInstanceOf( Function )
14 | expect( treeGraph.name ).toBe('div');
15 | });
16 |
17 | it('test makeTreeCreator has valid value', () => {
18 |
19 | const treeCreator = makeTreeCreator();
20 | const treeGraph = treeCreator(fiber);
21 |
22 | expect( treeGraph.name ).toBe('div');
23 | });
24 |
25 |
26 | });
27 |
--------------------------------------------------------------------------------
/uml/highLevelDiagram.plantuml:
--------------------------------------------------------------------------------
1 | @startuml windowUML
2 |
3 | boundary App
4 | boundary Container
5 | control Window
6 | control TreeCreator
7 | entity D3Tree
8 | entity D3Tree
9 |
10 | App -> Container : setState is called
11 | Container -> Container : render method called \nfiberRoot = container._reactRootContainer._internalRoot
12 | Container -> Window: check every 20ms \nif Virtual DOM has changed.
13 | Window -> TreeCreator : treeCreator(fiberTree)
14 | Window <- TreeCreator : returns treeGraph
15 | Window -> Container: sends treeGraph
16 | Container -> D3Tree: recieves treeGraph
17 | D3Tree -> D3Tree: present tree using \nD3Tree or D3Flame visual.
18 |
19 | @enduml
--------------------------------------------------------------------------------
/__test__/stateChange.test.js:
--------------------------------------------------------------------------------
1 | import StateChange from '../src/app/components/stateChange'
2 | import React from 'react'
3 | import { configure, shallow, mount } from 'enzyme';
4 | import Adapter from 'enzyme-adapter-react-16';
5 | configure({ adapter: new Adapter() });
6 |
7 | describe(' StateChanges component rendered correctly ', () => {
8 | let wrapper;
9 | let props = {
10 | currentState: [{}],
11 | index: 0,
12 | }
13 | wrapper = shallow()
14 | it(' Record rendered correctly ', () => {
15 | expect(wrapper.type()).toEqual('div')
16 | expect(wrapper.find('h2').text()).toEqual('State Diff')
17 | expect(wrapper.find('ComponentsList2')).not.toEqual(undefined)
18 | })
19 | })
--------------------------------------------------------------------------------
/mockData/fiber.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | type: {
3 | name: "h1"
4 | },
5 | tag: 5,
6 | effectTag: 1,
7 | actualDuration: 9.00,
8 | actualStartTime: 400,
9 | memorizedProps: {},
10 | memorizedState: null,
11 | child: {
12 | type: { name: "div"},
13 | tag: 1,
14 | effectTag: 2,
15 | actualDuration: 8.00,
16 | actualStartTime: 300,
17 | memorizedProps: {},
18 | memorizedState: null,
19 | child: {
20 | type: "div",
21 | tag: 1,
22 | effectTag: 2,
23 | actualDuration: 8.00,
24 | actualStartTime: 300,
25 | memorizedProps: {},
26 | memorizedState: null,
27 | }
28 | },
29 | }
30 |
--------------------------------------------------------------------------------
/package/ReactWorkTags.js:
--------------------------------------------------------------------------------
1 | export const FunctionComponent = 0;
2 | export const ClassComponent = 1;
3 | export const IndeterminateComponent = 2; // Before we know whether it is function or class
4 | export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
5 | export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
6 | export const HostComponent = 5;
7 | export const HostText = 6;
8 | export const Fragment = 7;
9 | export const Mode = 8;
10 | export const ContextConsumer = 9;
11 | export const ContextProvider = 10;
12 | export const ForwardRef = 11;
13 | export const Profiler = 12;
14 | export const SuspenseComponent = 13;
15 | export const MemoComponent = 14;
16 | export const SimpleMemoComponent = 15;
17 | export const LazyComponent = 16;
--------------------------------------------------------------------------------
/package/createTree.js:
--------------------------------------------------------------------------------
1 | const sendContentScript = require("./sendContentScript");
2 |
3 | //this function will be invoked in containerWrapper.js
4 |
5 | module.exports = function (container) {
6 | const fiberRoot = container._reactRootContainer._internalRoot;
7 | let hostRoot = fiberRoot.current;
8 | const treeCreator = require("./makeTreeCreator")();
9 | let time_last = -Infinity;
10 | // console.log("[info] actualStartTime:", hostRoot);
11 |
12 | setInterval( function() {
13 | hostRoot = fiberRoot.current;
14 | if (hostRoot.actualStartTime !== time_last) {
15 | sendContentScript( treeCreator, undefined, hostRoot);
16 | time_last = hostRoot.actualStartTime;
17 | console.log("[2] actualStartTime:", time_last);
18 | console.log("[2] actualStartTime:", hostRoot.actualStartTime);
19 | }
20 | }, 100 );
21 |
22 | };
23 |
--------------------------------------------------------------------------------
/package/treeGraphFactory.test.js:
--------------------------------------------------------------------------------
1 | const fiber = require('../mockData/fiber');
2 | const treeGraphFactory = require('./treeGraphFactory');
3 |
4 |
5 | describe('test treeGraphFactory', () => {
6 |
7 | it('test treeGraph was created properly', () => {
8 |
9 | const treeGraph = treeGraphFactory(fiber);
10 | expect(treeGraph.name).toBe('h1');
11 | expect(treeGraph.value).toBe(9);
12 | expect(treeGraph.tag).toBe(5);
13 | expect(treeGraph.stats.effectTag).toBe(1);
14 | expect(treeGraph.stats.renderStart).toBe('400.00');
15 | expect(treeGraph.stats.renderTotal).toBe('9.00');
16 | expect(treeGraph.children[0].name).toBe('div');
17 | expect(treeGraph.children[0].value).toBe(8);
18 | expect(treeGraph.children[0].tag).toBe(1);
19 | expect(treeGraph.children[0].stats.effectTag).toBe(2)
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/src/extension/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "React Monitor",
4 | "version": "0.0.0.1",
5 | "devtools_page": "devtools.html",
6 | "permissions": ["activeTab", "contextMenus", ""],
7 | "content_scripts": [
8 | {
9 | "matches": [""],
10 | "js": ["contentScript.js"]
11 | }
12 | ],
13 | "background": {
14 | "scripts": ["backgroundScript.js"],
15 | "persistent": false
16 | },
17 | "icons": {
18 | "16": "./assets/rm-icon16.png",
19 | "48": "./assets/rm-icon-48.png",
20 | "128": "./assets/rm-icon-128.png"
21 | },
22 | "externally_connectable": {
23 | "ids": ["*"]
24 | },
25 | "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
26 | "web_accessible_resources": ["/containerWrapper.js", "/fiberTreeAnalyzer.js"]
27 | }
28 |
--------------------------------------------------------------------------------
/__test__/record.test.js:
--------------------------------------------------------------------------------
1 | import Record from '../src/app/components/record'
2 | import React from 'react'
3 | import { configure, shallow, mount } from 'enzyme';
4 | import Adapter from 'enzyme-adapter-react-16';
5 | configure({ adapter: new Adapter() });
6 |
7 | describe(' Record component rendered correctly ', () => {
8 | let wrapper;
9 | let props = {
10 | logofTime: [1],
11 | index: 0,
12 | }
13 | wrapper = shallow()
17 | it(' Record rendered correctly ', () => {
18 | expect(wrapper.type()).toEqual('div')
19 | expect(wrapper.find('h2').text()).toEqual('Time')
20 | expect(wrapper.find('ul')).not.toEqual(undefined)
21 | expect(wrapper.find('span')).not.toEqual(undefined)
22 | expect(wrapper.find('li')).not.toEqual(undefined)
23 | })
24 | })
--------------------------------------------------------------------------------
/__test__/stateAndProps.test.js:
--------------------------------------------------------------------------------
1 | import StateAndProps from '../src/app/components/stateAndProps'
2 | import React from 'react'
3 | import { configure, shallow, mount } from 'enzyme';
4 | import Adapter from 'enzyme-adapter-react-16';
5 | configure({ adapter: new Adapter() });
6 |
7 | describe(' StateAndProps component rendered correctly ', () => {
8 | let wrapper;
9 | let props = {
10 | state: [],
11 | props: [],
12 | selected:[],
13 | label:'',
14 | onChange:() => true
15 | }
16 | wrapper = shallow()
17 | it(' StateAndProps component rendered correctly ', () => {
18 | expect(wrapper.type()).toEqual('div')
19 | expect(wrapper.find('li')).not.toEqual(undefined)
20 | expect(wrapper.find('span').at(0).text()).toEqual(' State ')
21 | expect(wrapper.find('span').at(1).text()).toEqual(' Props ')
22 | })
23 | })
--------------------------------------------------------------------------------
/__test__/componentsList.test.js:
--------------------------------------------------------------------------------
1 | import ComponentsList from '../src/app/components/componentsList'
2 | import React from 'react'
3 | import { configure, shallow, mount } from 'enzyme';
4 | import Adapter from 'enzyme-adapter-react-16';
5 | configure({ adapter: new Adapter() });
6 |
7 | describe(' ComponentsList component rendered correctly ', () => {
8 | let wrapper;
9 | let props = {
10 | components: [{children:[]}],
11 | onChange: () => true,
12 | selectedComponents: 0,
13 | isFirst:true
14 | }
15 | wrapper = shallow()
16 | it(' ComponentsList Component rendered correctly ', () => {
17 | expect(wrapper.type()).toEqual('div')
18 | expect(wrapper.find('StateAndProps')).not.toEqual(undefined)
19 | expect(wrapper.find('ComponentsList')).not.toEqual(undefined)
20 | expect(wrapper.find('ul')).not.toEqual(undefined)
21 | })
22 | })
--------------------------------------------------------------------------------
/uml/devtools.plantuml:
--------------------------------------------------------------------------------
1 | @startuml devtools
2 | entity npmPackage
3 | boundary Window
4 | control contentScript
5 | boundary Chrome
6 | boundary ChromePort
7 |
8 | control backgroundScript
9 | control MainContainer
10 | control D3Tree
11 |
12 |
13 | backgroundScript -> ChromePort : chrome.runtime.onConnect.\naddListener((port));
14 | contentScript -> Window : window.\naddEventListener('message');
15 |
16 | npmPackage -> Window : 1.) postMessage({action:'NpmToContent', \npayload: treeGraph})
17 | Window <- contentScript : 2.) receives Window action \n'NpmToContent'
18 | contentScript -> Chrome : 3.) chrome.runtime.sendMessage
19 | Chrome <- backgroundScript : 4.) receives Chrome Message \nvia chrome.runtime.onMessage.\naddListener
20 | backgroundScript -> ChromePort : 5.) post message to ChromePort.
21 | ChromePort <- MainContainer : 6.) receives message.
22 | MainContainer -> D3Tree : 7.) get treeGraph and \npresent information on D3Tree
23 |
24 | @enduml
--------------------------------------------------------------------------------
/package/deleteParent.test.js:
--------------------------------------------------------------------------------
1 | const treeGraph = require('../mockData/treeGraph');
2 | const deleteParent = require('./deleteParent');
3 |
4 |
5 | describe('test deleteParent', () => {
6 |
7 |
8 | xit('test deleteParent deletes Parents', () => {
9 |
10 | const prunedTreeGraph = deleteParent(treeGraph);
11 |
12 | console.log("prunedTreeGraph -", prunedTreeGraph);
13 | expect(prunedTreeGraph.name).toBe('h1');
14 | expect(prunedTreeGraph.value).toBe(9);
15 | expect(prunedTreeGraph.tag).toBe(5);
16 | expect(prunedTreeGraph.stats.effectTag).toBe(1);
17 | expect(prunedTreeGraph.stats.renderStart).toBe('400.00');
18 | expect(prunedTreeGraph.stats.renderTotal).toBe('9.00');
19 | expect(prunedTreeGraph.children[0].name).toBe('div');
20 | expect(prunedTreeGraph.children[0].value).toBe(8);
21 | expect(prunedTreeGraph.children[0].tag).toBe(1);
22 | expect(prunedTreeGraph.children[0].stats.effectTag).toBe(2)
23 | });
24 |
25 |
26 | });
27 |
--------------------------------------------------------------------------------
/src/app/components/timeTravel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import Playbutton from './playButton'
3 | import Record from './record'
4 | import Statechange from './stateChange'
5 |
6 | export default class timeTravel extends Component {
7 | constructor(props) {
8 | super(props);
9 | }
10 | render() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | )
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/components/record.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 |
3 | export default class record extends Component {
4 | constructor(props){
5 | super(props)
6 | }
7 | render() {
8 | if(this.props.logofTime){
9 | return (
10 |
11 |
Time
12 |
13 | {this.props.logofTime.map((elem,i) =>{
14 | if(this.props.index===i){
15 | return - Name:{elem[0]} Time:{elem[1]}
16 | }else{
17 | return - Name:{elem[0]} Time:{elem[1]}
18 | }
19 | })}
20 |
21 |
22 | )
23 | }else{
24 | return (
25 |
26 | )
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/__test__/playButton.test.js:
--------------------------------------------------------------------------------
1 | import PlayButton from '../src/app/components/playButton'
2 | import React from 'react'
3 | import { configure, shallow, mount } from 'enzyme';
4 | import Adapter from 'enzyme-adapter-react-16';
5 | configure({ adapter: new Adapter() });
6 |
7 | describe(' PlayButton rendering correctly', () => {
8 | let wrapper;
9 | let props = {
10 | logOfTime: 1,
11 | index: 0,
12 | handelPlay: () => true,
13 | }
14 | beforeAll(() => {
15 | wrapper = shallow()
20 | })
21 | it(' PlayButton rendered correctly ', () => {
22 | const label = ['Play','Pause','Reset']
23 | expect(wrapper.type()).toEqual('div')
24 | expect(wrapper.find('button')).toHaveLength(3)
25 | for(let i=0; i<3;i+=1){
26 | expect(wrapper.find('button').at(i).text()).toEqual(label[i])
27 | }
28 | })
29 | })
--------------------------------------------------------------------------------
/src/app/components/mainContainer.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
4 | import D3Tree from './d3tree';
5 | import FlameChart from './flameChart'
6 |
7 | export default class MainContainer extends Component {
8 | constructor(props) {
9 | super(props);
10 | }
11 | render() {
12 | return (
13 |
14 |
15 |
16 |
Tree
17 | Chart
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 OSLabs Beta
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/__test__/timeTravel.test.js:
--------------------------------------------------------------------------------
1 |
2 | import TimeTravel from '../src/app/components/timeTravel'
3 | import React from 'react'
4 | import { configure, shallow, mount } from 'enzyme';
5 | import Adapter from 'enzyme-adapter-react-16';
6 | configure({ adapter: new Adapter() });
7 |
8 | describe('Time travel rendered correctly', () => {
9 | let wrapper
10 | let props = {
11 | currentState:[{}],
12 | handelPlay : () => 'hello world',
13 | logofTime: [['App',1.5]],
14 | index:0
15 | }
16 | beforeAll(() => {
17 | wrapper = shallow()
23 | })
24 | it('Timetravel rendered correctly', () => {
25 | expect(wrapper.type()).toEqual('div')
26 | expect(wrapper.find('Playbutton')).toEqual({})
27 | expect(wrapper.find('Record')).toEqual({})
28 | expect(wrapper.find('Statechange')).toEqual({})
29 | expect(wrapper.find('Playbutton')).toEqual({})
30 | })
31 | })
--------------------------------------------------------------------------------
/package/makeTreeCreator.js:
--------------------------------------------------------------------------------
1 | const treeGraphFactory = require('./treeGraphFactory');
2 | const deleteParent = require('./deleteParent');
3 | const compareStateAndProps = require('./compareStateAndProps');
4 |
5 |
6 | module.exports = function (){
7 |
8 | // first time load these closure variables
9 | // need to be initialized accordingly.
10 | let wasMounted = false;
11 | let prevTreeGraph = null;
12 |
13 | function treeCreator(hostRoot, treeGraph = null) {
14 |
15 | // 1.) create treeGraph
16 | if (hostRoot.child) {
17 | // recursively traverse App Fiber Tree and create treeGraph
18 | treeGraph = treeGraphFactory(hostRoot.child);
19 | }
20 |
21 | // 2.) prune treeGraph
22 | deleteParent(treeGraph);
23 | delete treeGraph.parent;
24 |
25 | // 3.) enhance treeGraph
26 | // by comparing state and props in prevTreeGraph and treeGraph(current)
27 | const tempTreeGraph = JSON.parse(JSON.stringify(treeGraph));
28 | compareStateAndProps(wasMounted, treeGraph, prevTreeGraph, null);
29 | prevTreeGraph = tempTreeGraph;
30 | wasMounted = true;
31 |
32 |
33 | return treeGraph;
34 |
35 | }
36 | return treeCreator;
37 | }
38 |
--------------------------------------------------------------------------------
/src/assets/play-button-svgrepo-com.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
43 |
--------------------------------------------------------------------------------
/package/newNode.js:
--------------------------------------------------------------------------------
1 | const JSONStringify = require('./JSONStringify');
2 |
3 | function Node(name, parent, children, fiber) {
4 | console.log(' fiber.actualDuration hi',fiber.actualDuration)
5 | console.log(' fiber.actualStartTime hi',fiber.actualStartTime)
6 | this.name = name;
7 | this.parent = parent;
8 | this.value = Number(fiber.actualDuration.toFixed(2));
9 | this.children = children;
10 | this.stats = {
11 | state: JSON.stringify((fiber.memoizedState)?( (fiber.memoizedState.memoizedState)?fiber.memoizedState.memoizedState: fiber.memoizedState):fiber.memoizedState ),
12 | props: JSONStringify(fiber.memoizedProps),
13 | effectTag: fiber.effectTag,
14 | type: typeof fiber.type,
15 | renderStart: fiber.actualStartTime.toFixed(2),
16 | renderTotal: fiber.actualDuration.toFixed(2),
17 | };
18 | this.nodeSvgShape = {
19 | shape: 'ellipse',
20 | shapeProps: {
21 | rx: 10,
22 | ry: 10,
23 | fill: 'lightgreen',
24 | },
25 | };
26 | if (typeof this.type === "string") {
27 | this.type = fiber.type;
28 | }
29 | this.tag = fiber.tag;
30 |
31 | }
32 |
33 | module.exports = {
34 | Node: Node
35 | }
36 |
--------------------------------------------------------------------------------
/uml/treeCreator.plantuml:
--------------------------------------------------------------------------------
1 | @startuml treeCreatorUML
2 |
3 | control MakeTreeCreator
4 | control TreeCreator
5 | control TreeGraphFactory
6 | entity Node
7 | control helper
8 | entity deleteParent
9 | entity compareStateAndProps
10 | entity Window
11 |
12 | MakeTreeCreator -> TreeCreator : closed over \nwasMounted, prevTreeGraph, \nreturns function
13 | TreeCreator -> TreeGraphFactory : treeGraphFactor(fiberRoot);
14 | TreeGraphFactory -> Node : treeGraph = new Node(name, null, [], fiber);
15 | TreeGraphFactory -> helper: helper(fiber, treeGraph)
16 | helper -> helper: recursively reads Fiber child, sibling \nand creates array of children, parent.children
17 | TreeCreator <- TreeGraphFactory: return treeGraph
18 | TreeCreator -> deleteParent: delete parents from treeGraph
19 | TreeCreator <- deleteParent: return pruned treeGraph
20 | TreeCreator -> compareStateAndProps: compareStateAndProps(treeGraph, prevTreeGraph, null)
21 | compareStateAndProps -> compareStateAndProps: update node colors based on \n1.)initial load \n2.) when nodes diff \n3.)no prevNode
22 | TreeCreator <- compareStateAndProps: return TreeGraph with colored nodes
23 | TreeCreator -> TreeCreator: prevTreeGraph = tempTreeGraph \nwasMounted = true;
24 | TreeCreator -> Window: send TreeGraph
25 | @enduml
--------------------------------------------------------------------------------
/mockData/ticTacToe.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function TicTacToe() {
4 | return (
5 |
6 |
Tic Tac Toe
7 |
8 |
9 |
12 |
15 |
18 |
19 |
20 |
23 |
26 |
29 |
30 |
31 |
34 |
37 |
40 |
41 |
42 |
43 | );
44 | }
45 |
46 | export default TicTacToe;
47 |
--------------------------------------------------------------------------------
/src/app/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { render } from 'react-dom';
3 | import MainContainer from './components/mainContainer';
4 | import './style.scss';
5 |
6 | let port;
7 |
8 | export default class App extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | name: '',
13 | children: [],
14 | stats: '',
15 | value: 0,
16 | oldState:[]
17 | };
18 | }
19 |
20 | componentDidMount() {
21 | if (!port) port = chrome.runtime.connect();
22 |
23 | port.onMessage.addListener((message) => {
24 | let array=this.state.oldState
25 | array.push(message.payload.payload)
26 | this.setState({
27 | value: message.payload.payload.value,
28 | name: message.payload.payload.name,
29 | children: message.payload.payload.children,
30 | stats: message.payload.payload.stats,
31 | oldstate:array
32 | });
33 | });
34 | }
35 |
36 | render() {
37 |
38 | return (
39 |
40 |
47 |
48 | );
49 | }
50 | }
51 |
52 | render(, document.getElementById('app'));
53 |
--------------------------------------------------------------------------------
/src/assets/pause-svgrepo-com.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
47 |
--------------------------------------------------------------------------------
/src/extension/contentScript.js:
--------------------------------------------------------------------------------
1 | // listen for message from npm package
2 | window.addEventListener("message", (msg) => {
3 | // filter the incoming msg.data
4 | if (msg.data.action === "npmToContent") {
5 | // send the message to the chrome - backgroundScript
6 | chrome.runtime.sendMessage({
7 | action: "ContentToBackground",
8 | payload: msg.data,
9 | });
10 | }
11 | });
12 |
13 | function injectScript(file, node) {
14 | // test - inject javascript, access fibergraph
15 | const body0 = document.getElementsByTagName(node)[0];
16 |
17 | // iterating the file from web accessible resources
18 | for (let i = 0; i < file.length; i++) {
19 | const s0 = document.createElement("script"); //
20 |
21 | s0.setAttribute("type", "text/javascript");
22 |
23 | //built in chrome method to get the path of the file to be injected to the user's app
24 | s0.setAttribute("src", chrome.extension.getURL(file[i]));
25 | // console.log(chrome.extension.getURL(file[0]), "injectedfile");
26 | body0.appendChild(s0);
27 | }
28 | }
29 | /*
30 | ... this will inject the following HTML tags into index.html:
31 |
32 |