Skip to content

Commit 17d6de9

Browse files
committed
submitting new additions of traverseAST with client conditional functionality
1 parent 0e360a0 commit 17d6de9

File tree

5 files changed

+151
-34
lines changed

5 files changed

+151
-34
lines changed

extension.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const vscode = require('vscode');
2-
const {createPanel, grabFile} = require('./src/panel');
2+
const { createPanel } = require('./src/panel');
3+
const { grabFile } = require('./src/parser');
34

45
// This method is called when your extension is activated
56
// Your extension is activated the very first time the command is executed
@@ -16,9 +17,9 @@ function activate(context) {
1617
createPanel(context);
1718
});
1819

19-
let file = vscode.commands.registerCommand('myExtension.pickFile', () => {
20-
grabFile(context);
21-
})
20+
vscode.commands.registerCommand('myExtension.pickFile', () => {
21+
grabFile();
22+
});
2223

2324
context.subscriptions.push(disposable, result);
2425
}

package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
"@types/node": "18.x",
7070
"@types/vscode": "^1.84.0",
7171
"@vscode/test-electron": "^2.3.6",
72-
"eslint": "^8.52.0",
72+
"eslint": "^8.54.0",
7373
"glob": "^10.3.10",
7474
"mocha": "^10.2.0",
7575
"typescript": "^5.2.2",

src/panel.js

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
const vscode = require('vscode');
2-
const fs = require('fs');
3-
const path = require('path');
4-
const babel = require('@babel/parser');
52

63
function createPanel(context) {
74
// utilize method on vscode.window object to create webview
@@ -48,21 +45,4 @@ function createWebviewHTML(URI) {
4845
)
4946
}
5047

51-
let ast;
52-
async function grabFile() {
53-
54-
const file = await vscode.window.showOpenDialog({canSelectFolders: true, canSelectFiles: true, canSelectMany: true})
55-
.then(async (data) => {
56-
ast = await babel.parse(
57-
fs.readFileSync(path.resolve(data[0].path), 'utf-8'),
58-
{
59-
sourceType: 'module',
60-
tokens: true,
61-
plugins: ['jsx', 'typescript'],
62-
}
63-
);
64-
console.log(ast)
65-
})
66-
}
67-
68-
module.exports = {createPanel, grabFile};
48+
module.exports = {createPanel};

src/parser.js

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
const vscode = require('vscode');
2+
const fs = require('fs');
3+
const path = require('path');
4+
const babel = require('@babel/parser');
5+
6+
let ast;
7+
async function grabFile() {
8+
try {
9+
const file = await vscode.window.showOpenDialog({ canSelectFolders: true, canSelectFiles: true, canSelectMany: true });
10+
console.log('file path', file[0].path);
11+
const name = path.basename(file[0].path);
12+
console.log('name of file', name);
13+
ast = await babel.parse(
14+
fs.readFileSync(path.resolve(file[0].path), 'utf-8'),
15+
{
16+
sourceType: 'module',
17+
tokens: true,
18+
plugins: ['jsx', 'typescript'],
19+
});
20+
// console.log('ast', ast);
21+
const result = await traverseAST(ast);
22+
console.log('res', result);
23+
} catch (error) {
24+
console.error(`Error processing file: ${error}`)
25+
}
26+
}
27+
28+
// create a set to reduce redundancy in console logs during recursive call
29+
const processedNodes = new Set();
30+
31+
// traverse the ast nodes, passing in node
32+
async function traverseAST(node) {
33+
// identify which are jsx elements type and then extract info about them (like the component name) and store it in var
34+
if (node.type === 'JSXElement' && !processedNodes.has(node)) {
35+
processedNodes.add(node);
36+
// console.log('JSX Node', node);
37+
38+
// im guessing that jsx elements will never contain the use client or hook declaration, so i wouldnt need to call the functions here
39+
40+
// property on node to obtain component name (could be tag or component name)
41+
const elementName = node.openingElement.name.name;
42+
// console.log('JSX Name', elementName);
43+
44+
if (node.children) {
45+
// if node children exist, then recursively call the child nodes with this func
46+
for (const child of node.children) {
47+
await traverseAST(child);
48+
}
49+
}
50+
} else if (!processedNodes.has(node)) {
51+
processedNodes.add(node);
52+
53+
// call the function to determine if it is a client component and store it in var
54+
const isClientComp = await checkForClientString(node);
55+
const isReactHook = await checkReactHooks(node);
56+
57+
// recursively iterate through the other non-jsx types if the jsx node children doesnt exist
58+
for (const key in node) {
59+
if (node[key] && typeof node[key] === 'object' && key !== 'tokens') {
60+
await traverseAST(node[key]);
61+
}
62+
}
63+
}
64+
return processedNodes;
65+
}
66+
67+
// function to determine server or client component (can look for 'use client' and 'hooks')
68+
69+
// also might want to consider functionality for child components of the current node to be classifed as client component (except for server clients rendered tree)
70+
71+
function checkForClientString(node) {
72+
if (node.type === 'Directive') {
73+
console.log('node', node);
74+
75+
// access the value property of the Directive node
76+
console.log('Directive Value:', node.value);
77+
78+
// check if the node.value is a 'DirectiveLiteral' node
79+
if (node.value && node.value.type === 'DirectiveLiteral') {
80+
81+
// check the value to see if it is 'use client'
82+
if (typeof node.value.value === 'string' && node.value.value.trim() === 'use client') {
83+
// access the value property of the 'DirectiveLiteral' node
84+
console.log('DirectiveLiteral Value:', node.value.value);
85+
86+
// might need to do something else here to make it known as client type
87+
console.log(`this node above has 'use client': `, true);
88+
return true;
89+
}
90+
}
91+
}
92+
return false;
93+
}
94+
95+
function checkReactHooks(node) {
96+
// for just the mvp, look up for the FIRST client component and make every child as a client component
97+
98+
// function to determine if component uses react hooks (this only checks if its BEING CALLED IN COMPONENT, not IMPORTED)
99+
// console.log('node', node);
100+
if (node.type === 'CallExpression') {
101+
console.log('nodeCall', node)
102+
if (node.callee && node.callee.name) {
103+
if (node.callee.name.startsWith('use')) {
104+
// if the node.type is CallExpression (dealing with function or method call) (callee is prop on callexpression - an identifier), return true
105+
console.log('node.callee', node.callee);
106+
console.log('Node with Hook', node.callee.name);
107+
console.log(`this node above uses hooks: `, true);
108+
return true;
109+
}
110+
}
111+
}
112+
113+
// function to determine if hooks are being IMPORTED
114+
// if (node.type === 'ImportDeclaration') {
115+
// console.log('node import', node);
116+
// if (node.specifiers) {
117+
// // filter through the array to see which ones uses hooks
118+
// const clientNodes = node.specifiers.filter((nodeImport) => {
119+
// return nodeImport.type === 'ImportSpecifier' && nodeImport.imported.name.startsWith('use');
120+
// });
121+
// // mapped over to console log the name of hook
122+
// clientNodes.map((nodeImport) => console.log('Names of Hooks', nodeImport.imported.name));
123+
// console.log(clientNodes);
124+
// // we'll wanna change this to use it somehow
125+
// return clientNodes;
126+
// }
127+
return false;
128+
}
129+
130+
// 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'
131+
132+
// function to determine if the component is server
133+
134+
// render component tree using react flow, passing in node and recursvely call on child nodes
135+
136+
module.exports = { grabFile };

0 commit comments

Comments
 (0)