@@ -2,118 +2,27 @@ const fs = require('fs')
22const path = require ( 'path' )
33const babel = require ( '@babel/parser' ) ;
44const { getNonce } = require ( './getNonce.js' ) ;
5- // const { Tree } = require('./treeTemplates/tree.js')
6-
7- // Parser2 is our old code
8- // class Parser2 {
9- // constructor() {
10- // this.ast = undefined;
11- // this.entryFile = undefined;
12- // this.arrList = [];
13- // this.parentDirectoryPath = undefined;
14- // }
15-
16- // async grabFile(file) {
17- // try {
18- // if (!file) {
19- // console.error('Invalid file parameter. Cannot process undefined.');
20- // return;
21- // }
22-
23- // if (typeof file !== 'string') {
24- // file = path.resolve(file[0].fsPath);
25- // }
26-
27- // const fileContent = fs.readFileSync(file, 'utf-8');
28- // this.ast = babel.parse(fileContent, {
29- // sourceType: 'module',
30- // tokens: true,
31- // plugins: ['jsx', 'typescript'],
32- // });
33- // await this.traverseAST(this.ast);
34- // console.log('Result of arrList: ', this.arrList);
35- // } catch (error) {
36- // console.error(`Error processing file: ${error}`)
37- // }
38- // }
39-
40- // // traverse the ast nodes, passing in node
41- // // input: ast node (object)
42- // // output ?
43- // traverseAST(node) {
44- // if (node.type === 'ImportDeclaration') {
45- // // extract file name path
46- // const elementName = node.source.value;
47- // if (elementName.startsWith('./') || elementName.startsWith('../')) {
48- // console.log('file path:', elementName)
49- // console.log('node import: ', node);
50- // // now with this list, we can call a func to determine if node is a client component?
51- // this.arrList.push(elementName);
52- // return this.grabFile(elementName);
53- // };
54-
55- // const result = getImports(node.program.body);
56- // console.log(result, 'result');
57-
58- // /* this code only works for JSXElement types: has prop of .children, but not the one above
59- // if (node.children) {
60- // // if node children exist, then recursively call the child nodes with this func
61- // for (const child of node.children) {
62- // await traverseAST(child);
63- // }
64- // }*/
65- // } else {
66- // // recursively iterate through the other non-jsx types if the jsx node children doesnt exist
67- // for (const key in node) {
68- // if (node[key] && typeof node[key] === 'object' && key !== 'tokens') {
69- // this.traverseAST(node[key]);
70- // }
71- // }
72- // }
73- // }
745
756// // function to determine server or client component (can look for 'use client' and 'hooks')
767// // input: ast node (object)
778// // output: boolean
78- // checkForClientString(node) {
79- // if (node.type === 'Directive') {
80- // console.log('node', node);
81- // // access the value property of the Directive node
82- // console.log('Directive Value:', node.value);
83- // // check if the node.value is a 'DirectiveLiteral' node
84- // if (node.value && node.value.type === 'DirectiveLiteral') {
85- // // check the value to see if it is 'use client'
86- // if (typeof node.value.value === 'string' && node.value.value.trim() === 'use client') {
87- // // access the value property of the 'DirectiveLiteral' node
88- // console.log('DirectiveLiteral Value:', node.value.value);
89- // // might need to do something else here to make it known as client type
90- // return true;
91- // }
92- // }
93- // }
94- // return false;
95- // }
96-
97- // // function to determine if file uses react hooks (startswith 'use')
98- // // input: ast node (object)
99- // // output: boolean
100- // checkReactHooks(node) {
101- // // for just the mvp, look up for the FIRST client component and make every child as a client component
102- // // function to determine if component uses react hooks (checks if its BEING CALLED IN COMPONENT)
103- // if (node.type === 'CallExpression') {
104- // console.log('nodeCall', node)
105- // if (node.callee && node.callee.name) {
106- // // 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
107- // if (node.callee.name.startsWith('use')) {
108- // // if the node.type is CallExpression (dealing with function or method call) (callee is prop on callexpression - an identifier), return true
109- // console.log('node.callee', node.callee);
110- // console.log('Node with Hook', node.callee.name);
111- // return true;
112- // }
9+ // checkForClientString(node) {
10+ // if (node.type === 'Directive') {
11+ // console.log('node', node);
12+ // // access the value property of the Directive node
13+ // console.log('Directive Value:', node.value);
14+ // // check if the node.value is a 'DirectiveLiteral' node
15+ // if (node.value && node.value.type === 'DirectiveLiteral') {
16+ // // check the value to see if it is 'use client'
17+ // if (typeof node.value.value === 'string' && node.value.value.trim() === 'use client') {
18+ // // access the value property of the 'DirectiveLiteral' node
19+ // console.log('DirectiveLiteral Value:', node.value.value);
20+ // // might need to do something else here to make it known as client type
21+ // return true;
11322// }
11423// }
115- // return false;
11624// }
25+ // return false;
11726// }
11827
11928class Parser {
@@ -136,7 +45,6 @@ class Parser {
13645 filePath . split ( path . win32 . sep ) . slice ( 1 ) . join ( path . posix . sep )
13746 ) ;
13847 }
139-
14048 this . tree = undefined ;
14149 // Break down and reasemble given filePath safely for any OS using path?
14250 }
@@ -160,8 +68,8 @@ class Parser {
16068 parentList : [ ] ,
16169 props : { } ,
16270 error : '' ,
71+ isClientComponent : false ,
16372 } ;
164-
16573 this . tree = root ;
16674 this . parser ( root ) ;
16775 return this . tree ;
@@ -243,7 +151,7 @@ class Parser {
243151
244152 // Recursively builds the React component tree structure starting from root node
245153 parser ( componentTree ) {
246- console . log ( componentTree ) ;
154+ console . log ( 'componentTree:' , componentTree ) ;
247155 // If import is a node module, do not parse any deeper
248156 if ( ! [ '\\' , '/' , '.' ] . includes ( componentTree . importPath [ 0 ] ) ) {
249157 componentTree . thirdParty = true ;
@@ -287,12 +195,20 @@ class Parser {
287195 // Find imports in the current file, then find child components in the current file
288196 const imports = this . getImports ( ast . program . body ) ;
289197
198+ if ( this . getCallee ( ast . program . body ) ) {
199+ componentTree . isClientComponent = true ;
200+ } else {
201+ componentTree . isClientComponent = false ;
202+ }
203+
204+ console . log ( 'componentTree.isClientComponent' , componentTree . isClientComponent ) ;
205+ console . log ( '--------------------------------' )
290206 // Get any JSX Children of current file:
291207 if ( ast . tokens ) {
292208 componentTree . children = this . getJSXChildren (
293209 ast . tokens ,
294210 imports ,
295- componentTree
211+ componentTree ,
296212 ) ;
297213 }
298214
@@ -328,10 +244,8 @@ class Parser {
328244 // output: object of imoprts
329245 getImports ( body ) {
330246 const bodyImports = body . filter ( ( item ) => item . type === 'ImportDeclaration' || 'VariableDeclaration' ) ;
331- console . log ( 'body imports' , bodyImports ) ;
332247
333248 return bodyImports . reduce ( ( accum , curr ) => {
334- // also determine if component is client or server
335249 if ( curr . type === 'ImportDeclaration' ) {
336250 curr . specifiers . forEach ( ( { local, imported } ) => {
337251 accum [ local . name ] = {
@@ -355,8 +269,6 @@ class Parser {
355269 }
356270
357271 findVarDecImports ( ast ) {
358- // also determine if component is client or server
359-
360272 // find import path in variable declaration and return it,
361273 if ( ast . hasOwnProperty ( 'callee' ) && ast . callee . type === 'Import' ) {
362274 return ast . arguments [ 0 ] . value ;
@@ -373,13 +285,41 @@ class Parser {
373285 return false ;
374286 }
375287
288+ // helper function to determine component type (client)
289+ // input: ast.program.body
290+ // output: boolean
291+ getCallee ( body ) {
292+ // does useStore count as a client component functionality?
293+ const hooksArray = [ 'useState' , 'useContext' , 'useRef' , 'useImperativeHandle' , 'useNavigate' , 'useLayoutEffect' , 'useInsertionEffect' , 'useMemo' , 'useCallback' , 'useTransition' , 'useDeferredValue' , 'useEffect' , 'useReducer' , 'useDispatch' , 'useActions' , 'useSelector' , 'bindActionCreators' ] ;
294+
295+ //! console.log('ast.program.body', body);
296+ const bodyCallee = body . filter ( ( item ) => item . type === 'VariableDeclaration' ) ;
297+ const calleeArr = bodyCallee [ 0 ] . declarations [ 0 ] . init . body . body // gives us an array of callee nodes
298+
299+ console . log ( 'calleArr:' , calleeArr ) ;
300+ for ( let i = 0 ; i < calleeArr . length ; i ++ ) {
301+ if ( calleeArr [ i ] . type === 'VariableDeclaration' ) {
302+ if ( hooksArray . includes ( calleeArr [ i ] . declarations [ 0 ] . init . callee . name ) || calleeArr [ i ] . declarations [ 0 ] . init . callee . name . startsWith ( 'use' ) ) {
303+ return true ;
304+ }
305+ }
306+ if ( calleeArr [ i ] . type === 'ExpressionStatement' ) {
307+ if ( hooksArray . includes ( calleeArr [ i ] . expression . callee . name ) || calleeArr [ i ] . expression . callee . name . startsWith ( 'use' ) ) {
308+ return true ;
309+ }
310+ }
311+ }
312+ return false ;
313+ }
314+
376315 // Finds JSX React Components in current file
377316 getJSXChildren ( astTokens , importsObj , parentNode ) {
378317 let childNodes = { } ;
379318 let props = { } ;
380319 let token ;
381320
382321 for ( let i = 0 ; i < astTokens . length ; i ++ ) {
322+
383323 // Case for finding JSX tags eg <App .../>
384324 if (
385325 astTokens [ i ] . type . label === 'jsxTagStart' &&
@@ -393,7 +333,7 @@ class Parser {
393333 token ,
394334 props ,
395335 parentNode ,
396- childNodes
336+ childNodes ,
397337 ) ;
398338
399339 // Case for finding components passed in as props e.g. <Route component={App} />
@@ -409,7 +349,7 @@ class Parser {
409349 token ,
410350 props ,
411351 parentNode ,
412- childNodes
352+ childNodes ,
413353 ) ;
414354 }
415355 }
@@ -421,7 +361,7 @@ class Parser {
421361 astToken ,
422362 props ,
423363 parent ,
424- children
364+ children ,
425365 ) {
426366 if ( children [ astToken . value ] ) {
427367 children [ astToken . value ] . count += 1 ;
@@ -450,9 +390,9 @@ class Parser {
450390 children : [ ] ,
451391 parentList : [ parent . filePath ] . concat ( parent . parentList ) ,
452392 error : '' ,
393+ isClientComponent : false
453394 } ;
454395 }
455-
456396 return children ;
457397 }
458398
@@ -504,8 +444,4 @@ class Parser {
504444 }
505445}
506446
507- // 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'
508-
509- // function to determine if the component is server
510-
511447module . exports = { Parser } ;
0 commit comments