diff --git a/extension.js b/extension.js
index ad435a8..20a3008 100644
--- a/extension.js
+++ b/extension.js
@@ -21,7 +21,8 @@ function activate(context) {
const fileArray = await vscode.window.showOpenDialog({ canSelectFolders: false, canSelectFiles: true, canSelectMany: false });
const tree = new Parser(fileArray[0].path);
tree.parse();
- console.log('tree instance', tree);
+ const data = tree.getTree();
+ console.log('Data sent back: ', data)
});
context.subscriptions.push(disposable, result);
diff --git a/src/parser.js b/src/parser.js
index ba8fa3f..d64ba47 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -2,118 +2,27 @@ const fs = require('fs')
const path = require('path')
const babel = require('@babel/parser');
const { getNonce } = require('./getNonce.js');
-// const { Tree } = require('./treeTemplates/tree.js')
-
-// Parser2 is our old code
-// class Parser2 {
-// constructor() {
-// this.ast = undefined;
-// this.entryFile = undefined;
-// this.arrList = [];
-// this.parentDirectoryPath = undefined;
-// }
-
-// async grabFile(file) {
-// try {
-// if (!file) {
-// console.error('Invalid file parameter. Cannot process undefined.');
-// return;
-// }
-
-// if (typeof file !== 'string') {
-// file = path.resolve(file[0].fsPath);
-// }
-
-// const fileContent = fs.readFileSync(file, 'utf-8');
-// this.ast = babel.parse(fileContent, {
-// sourceType: 'module',
-// tokens: true,
-// plugins: ['jsx', 'typescript'],
-// });
-// await this.traverseAST(this.ast);
-// console.log('Result of arrList: ', this.arrList);
-// } catch (error) {
-// console.error(`Error processing file: ${error}`)
-// }
-// }
-
-// // traverse the ast nodes, passing in node
-// // input: ast node (object)
-// // output ?
-// traverseAST(node) {
-// if (node.type === 'ImportDeclaration') {
-// // extract file name path
-// const elementName = node.source.value;
-// if (elementName.startsWith('./') || elementName.startsWith('../')) {
-// console.log('file path:', elementName)
-// console.log('node import: ', node);
-// // now with this list, we can call a func to determine if node is a client component?
-// this.arrList.push(elementName);
-// return this.grabFile(elementName);
-// };
-
-// const result = getImports(node.program.body);
-// console.log(result, 'result');
-
-// /* this code only works for JSXElement types: has prop of .children, but not the one above
-// if (node.children) {
-// // if node children exist, then recursively call the child nodes with this func
-// for (const child of node.children) {
-// await traverseAST(child);
-// }
-// }*/
-// } else {
-// // recursively iterate through the other non-jsx types if the jsx node children doesnt exist
-// for (const key in node) {
-// if (node[key] && typeof node[key] === 'object' && key !== 'tokens') {
-// this.traverseAST(node[key]);
-// }
-// }
-// }
-// }
// // function to determine server or client component (can look for 'use client' and 'hooks')
// // input: ast node (object)
// // output: boolean
-// checkForClientString(node) {
-// if (node.type === 'Directive') {
-// console.log('node', node);
-// // access the value property of the Directive node
-// console.log('Directive Value:', node.value);
-// // check if the node.value is a 'DirectiveLiteral' node
-// if (node.value && node.value.type === 'DirectiveLiteral') {
-// // check the value to see if it is 'use client'
-// if (typeof node.value.value === 'string' && node.value.value.trim() === 'use client') {
-// // access the value property of the 'DirectiveLiteral' node
-// console.log('DirectiveLiteral Value:', node.value.value);
-// // might need to do something else here to make it known as client type
-// return true;
-// }
-// }
-// }
-// return false;
-// }
-
-// // function to determine if file uses react hooks (startswith 'use')
-// // input: ast node (object)
-// // output: boolean
-// checkReactHooks(node) {
-// // for just the mvp, look up for the FIRST client component and make every child as a client component
-// // function to determine if component uses react hooks (checks if its BEING CALLED IN COMPONENT)
-// if (node.type === 'CallExpression') {
-// console.log('nodeCall', node)
-// if (node.callee && node.callee.name) {
-// // to be more specific, we might want to consider declaring an array of hooks and write logic to iterate and checks if the name includes any of the elements, then return true
-// if (node.callee.name.startsWith('use')) {
-// // if the node.type is CallExpression (dealing with function or method call) (callee is prop on callexpression - an identifier), return true
-// console.log('node.callee', node.callee);
-// console.log('Node with Hook', node.callee.name);
-// return true;
-// }
+// checkForClientString(node) {
+// if (node.type === 'Directive') {
+// console.log('node', node);
+// // access the value property of the Directive node
+// console.log('Directive Value:', node.value);
+// // check if the node.value is a 'DirectiveLiteral' node
+// if (node.value && node.value.type === 'DirectiveLiteral') {
+// // check the value to see if it is 'use client'
+// if (typeof node.value.value === 'string' && node.value.value.trim() === 'use client') {
+// // access the value property of the 'DirectiveLiteral' node
+// console.log('DirectiveLiteral Value:', node.value.value);
+// // might need to do something else here to make it known as client type
+// return true;
// }
// }
-// return false;
// }
+// return false;
// }
class Parser {
@@ -136,7 +45,6 @@ class Parser {
filePath.split(path.win32.sep).slice(1).join(path.posix.sep)
);
}
-
this.tree = undefined;
// Break down and reasemble given filePath safely for any OS using path?
}
@@ -160,8 +68,8 @@ class Parser {
parentList: [],
props: {},
error: '',
+ isClientComponent: false,
};
-
this.tree = root;
this.parser(root);
return this.tree;
@@ -243,7 +151,7 @@ class Parser {
// Recursively builds the React component tree structure starting from root node
parser(componentTree) {
- console.log(componentTree);
+ console.log('componentTree:', componentTree);
// If import is a node module, do not parse any deeper
if (!['\\', '/', '.'].includes(componentTree.importPath[0])) {
componentTree.thirdParty = true;
@@ -287,12 +195,20 @@ class Parser {
// Find imports in the current file, then find child components in the current file
const imports = this.getImports(ast.program.body);
+ if (this.getCallee(ast.program.body)) {
+ componentTree.isClientComponent = true;
+ } else {
+ componentTree.isClientComponent = false;
+ }
+
+ console.log('componentTree.isClientComponent', componentTree.isClientComponent);
+ console.log('--------------------------------')
// Get any JSX Children of current file:
if (ast.tokens) {
componentTree.children = this.getJSXChildren(
ast.tokens,
imports,
- componentTree
+ componentTree,
);
}
@@ -328,10 +244,8 @@ class Parser {
// output: object of imoprts
getImports(body) {
const bodyImports = body.filter((item) => item.type === 'ImportDeclaration' || 'VariableDeclaration');
- console.log('body imports', bodyImports);
return bodyImports.reduce((accum, curr) => {
- // also determine if component is client or server
if (curr.type === 'ImportDeclaration') {
curr.specifiers.forEach(({ local, imported }) => {
accum[local.name] = {
@@ -355,8 +269,6 @@ class Parser {
}
findVarDecImports(ast) {
- // also determine if component is client or server
-
// find import path in variable declaration and return it,
if (ast.hasOwnProperty('callee') && ast.callee.type === 'Import') {
return ast.arguments[0].value;
@@ -373,6 +285,33 @@ class Parser {
return false;
}
+ // helper function to determine component type (client)
+ // input: ast.program.body
+ // output: boolean
+ getCallee(body) {
+ // does useStore count as a client component functionality?
+ const hooksArray = ['useState', 'useContext', 'useRef', 'useImperativeHandle', 'useNavigate', 'useLayoutEffect', 'useInsertionEffect', 'useMemo', 'useCallback', 'useTransition', 'useDeferredValue', 'useEffect', 'useReducer', 'useDispatch', 'useActions', 'useSelector', 'bindActionCreators'];
+
+ //! console.log('ast.program.body', body);
+ const bodyCallee = body.filter((item) => item.type === 'VariableDeclaration');
+ const calleeArr = bodyCallee[0].declarations[0].init.body.body // gives us an array of callee nodes
+
+ console.log('calleArr:', calleeArr);
+ for (let i = 0; i < calleeArr.length; i++) {
+ if (calleeArr[i].type === 'VariableDeclaration') {
+ if (hooksArray.includes(calleeArr[i].declarations[0].init.callee.name) || calleeArr[i].declarations[0].init.callee.name.startsWith('use')) {
+ return true;
+ }
+ }
+ if (calleeArr[i].type === 'ExpressionStatement') {
+ if (hooksArray.includes(calleeArr[i].expression.callee.name) || calleeArr[i].expression.callee.name.startsWith('use')) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
// Finds JSX React Components in current file
getJSXChildren(astTokens, importsObj, parentNode) {
let childNodes = {};
@@ -380,6 +319,7 @@ class Parser {
let token;
for (let i = 0; i < astTokens.length; i++) {
+
// Case for finding JSX tags eg
if (
astTokens[i].type.label === 'jsxTagStart' &&
@@ -393,7 +333,7 @@ class Parser {
token,
props,
parentNode,
- childNodes
+ childNodes,
);
// Case for finding components passed in as props e.g.
@@ -409,7 +349,7 @@ class Parser {
token,
props,
parentNode,
- childNodes
+ childNodes,
);
}
}
@@ -421,7 +361,7 @@ class Parser {
astToken,
props,
parent,
- children
+ children,
) {
if (children[astToken.value]) {
children[astToken.value].count += 1;
@@ -450,9 +390,9 @@ class Parser {
children: [],
parentList: [parent.filePath].concat(parent.parentList),
error: '',
+ isClientComponent: false
};
}
-
return children;
}
@@ -504,8 +444,4 @@ class Parser {
}
}
-// function to determine if the client component imports server components or call server hooks/utils, if it does, then return 'is not valid client comp'
-
-// function to determine if the component is server
-
module.exports = { Parser };
\ No newline at end of file