Skip to content

Commit

Permalink
Merge pull request #29 from oslabs-beta/ast-implementation
Browse files Browse the repository at this point in the history
early implementation for lazy-loading import statements
  • Loading branch information
yujinkay authored Sep 30, 2019
2 parents 36dfdd2 + 307981d commit fde1d3a
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 76 deletions.
60 changes: 31 additions & 29 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 43 additions & 24 deletions package/astParser.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,53 @@
const acorn = require('acorn');
const jsx = require('acorn-jsx');
const JSXParser = acorn.Parser.extend(jsx());

// Helper function to recursively traverse through the user's codebase
// INSERT HERE
const JSXParser = acorn.Parser.extend(jsx());

module.exports = file => {
// Helper function to recursively traverse AST of a specified component for all hook declarations
function getHookNames(ast) {
// Initialize empty object to store the setters and getter
const hookState = {};
const ast = JSXParser.parse(file).body;
// Iterate through AST of every function declaration
// Check within each function declaration if there are hook declarations
ast.forEach(func => {
const { body } = func.body;
const statements = [];
// Traverse through the function's funcDecs and Expression Statements
body.forEach(program => {
if (program.type === 'VariableDeclaration') {
program.declarations.forEach(dec => {
statements.push(dec.id.name);
});
// All module exports will always start off as a single 'FunctionDeclaration' type
while (Object.hasOwnProperty.call(ast, 'body')) {
// Traverse down .body once before invoking parsing logic and will loop through any .body after
ast = ast.body;
// Iterate through AST of every function declaration
// Check within each function declaration if there are hook declarations
ast.forEach(functionDec => {
const { body } = functionDec.body;
const statements = [];
// Traverse through the function's funcDecs and Expression Statements
body.forEach(program => {
// Hook Declarations will only be under 'VariableDeclaration' type
if (program.type === 'VariableDeclaration') {
program.declarations.forEach(dec => {
statements.push(dec.id.name);
});
}
});
// Iterate through the array and determine getter/setters based on pattern
for (let i = 0; i < statements.length; i += 1) {
if (statements[i].match(/_use/)) {
hookState[statements[i]] = statements[i + 2];
}
}
});
// Iterate through the array and determine getter/setters based on pattern
for (let i = 0; i < statements.length; i += 1) {
if (statements[i].match(/_use/)) {
hookState[statements[i]] = statements[i + 2];
}
}
});
// Return the object with setters and getters
}
return hookState;
}

module.exports = file => {
// Create an empty object to allow all invocations of getHookNames to consolidate
let allHookNames = {};
const ast = JSXParser.parse(file);
// console.log('Original File', file.toString());
// console.log('Original AST', ast);
// Upsert any new/updated {_hookType#: hookName} pairs
allHookNames = {
...allHookNames,
...getHookNames(ast),
};

// Return the object with setters and getters
return allHookNames;
};
49 changes: 31 additions & 18 deletions package/linkFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
/* eslint-disable no-param-reassign */
// links component state tree to library
// changes the setState method to also update our snapshot

// import loadable from '@loadable/component';

const Tree = require('./tree');
const astParser = require('./astParser');
const { saveState } = require('./masterState');
const astParser = require('./astParser');
const { saveState } = require('./masterState');

module.exports = (snap, mode) => {
let fiberRoot = null;
Expand Down Expand Up @@ -46,13 +49,13 @@ module.exports = (snap, mode) => {

function changeUseState(component) {
if (component.queue.dispatch.linkFiberChanged) return;
// store the original dispatch function definition
// store the original dispatch function definition
const oldDispatch = component.queue.dispatch.bind(component.queue);
// redefine the dispatch function so we can inject our code
component.queue.dispatch = (fiber, queue, action) => {
// don't do anything if state is locked
if (mode.locked && !mode.jumping) return;
//oldDispatch(fiber, queue, action);
if (mode.locked && !mode.jumping) return;
// oldDispatch(fiber, queue, action);
setTimeout(() => {
oldDispatch(fiber, queue, action);
updateSnapShotTree();
Expand All @@ -67,17 +70,17 @@ module.exports = (snap, mode) => {
function traverseHooks(memoizedState) {
// Declare variables and assigned to 0th index and an empty object, respectively
const memoized = {};
let index = 0;
astHooks = Object.values(astHooks);
let index = 0;
astHooks = Object.values(astHooks);
// while memoizedState is truthy, save the value to the object
while (memoizedState) {
changeUseState(memoizedState);
//memoized[astHooks[index]] = memoizedState.memoizedState;
memoized[astHooks[index]] = memoizedState.memoizedState;
// memoized[astHooks[index]] = memoizedState.memoizedState;
memoized[astHooks[index]] = memoizedState.memoizedState;
// Reassign memoizedState to its next value
memoizedState = memoizedState.next;
// Increment the index by 2
index += 2;
index += 2;
}
return memoized;
}
Expand All @@ -101,8 +104,8 @@ module.exports = (snap, mode) => {
changeSetState(stateNode);
}
// Check if the component uses hooks
if (memoizedState && memoizedState.hasOwnProperty('baseState')) {
// Add a traversed property and initialize to the evaluated result
if (memoizedState && Object.hasOwnProperty.call(memoizedState, 'baseState')) {
// Add a traversed property and initialize to the evaluated result
// of invoking traverseHooks, and reassign nextTree
memoizedState.traversed = traverseHooks(memoizedState);
nextTree = tree.appendChild(memoizedState);
Expand All @@ -114,8 +117,8 @@ module.exports = (snap, mode) => {

return tree;
}
// runs when page initially loads
// but skips 1st hook click
// runs when page initially loads
// but skips 1st hook click
function updateSnapShotTree() {
const { current } = fiberRoot;
snap.tree = createTree(current);
Expand All @@ -128,16 +131,26 @@ module.exports = (snap, mode) => {
} = container;
// only assign internal rootp if it actually exists
fiberRoot = _internalRoot || _reactRootContainer;
// If hooks are implemented, traverse through the source code
// If hooks are implemented, traverse through the source code
// Save the getter/setter combo for timeJump
if (entryFile) {
astHooks = astParser(entryFile);
saveState(astHooks);
// console.log('Ast Hooks', astHooks);
saveState(astHooks);
}
updateSnapShotTree();
updateSnapShotTree();
// send the initial snapshot once the content script has started up
window.addEventListener('message', ({ data: { action } }) => {
if (action === 'contentScriptStarted') sendSnapshot();
});
}
// Testing sending back a function def to client
// function getNextImport(filePath) {
// return loadable(() => import(`${filePath}`))
// Got relative file path to return back to client code
// return (`myTestString${filePath}`);
}
// return getNextImport('./UseStateHook');
// return 'Testing outside';
};
};
// const OtherComponent = loadable(() => import('./OtherComponent'))
6 changes: 4 additions & 2 deletions package/masterState.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable guard-for-in */
/* eslint-disable no-restricted-syntax */
// Export two functions that either saves the AST state object into an array
// or returns the array for use
const masterState = [];
Expand All @@ -7,7 +9,7 @@ module.exports = {
for (const key in state) {
masterState.push(state[key]);
}
return masterState;
return masterState;
},
returnState: () => masterState
returnState: () => masterState,
};
35 changes: 35 additions & 0 deletions package/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package/timeJump.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-param-reassign */
// traverses given tree by accessing children through coords array
const { returnState } = require('./masterState');
const { returnState } = require('./masterState');

function traverseTree(tree, coords) {
let curr = tree;
Expand All @@ -16,6 +16,7 @@ module.exports = (origin, mode) => {
const originNode = traverseTree(origin.tree, coords);
// set the state of the origin tree if the component is stateful
if (originNode.component.setState) {
console.log('if(originNode.component.setState):', originNode.component);
originNode.component.setState(target.state, () => {
// iterate through new children once state has been set
target.children.forEach((child, i) => {
Expand All @@ -26,8 +27,8 @@ module.exports = (origin, mode) => {
// if component uses hooks, traverse through the memoize tree
let current = originNode.component;
let index = 0;
const hooks = returnState();
// Iterate through the memoize tree
const hooks = returnState();
// while loop through the memoize tree
while (current) {
current.queue.dispatch(target.state[hooks[index]]);
// Reassign the current value
Expand Down

0 comments on commit fde1d3a

Please sign in to comment.