Skip to content

Commit c2a7dd2

Browse files
committed
added logic for parser directives component type, fixed syntax for comments to make it uniform, moved getNonce into a util folder, changed property in .eslintrc.json to remove non-dangerous warnings when running tests
1 parent b5c1f52 commit c2a7dd2

File tree

15 files changed

+54
-84
lines changed

15 files changed

+54
-84
lines changed

.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"no-this-before-super": "warn",
1919
"no-undef": "warn",
2020
"no-unreachable": "warn",
21-
"no-unused-vars": "warn",
21+
"no-unused-vars": "off",
2222
"constructor-super": "warn",
2323
"valid-typeof": "warn"
2424
}

package-lock.json

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

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function activate(context: vscode.ExtensionContext) {
3838

3939
// Check if panel currently has a webview, if it does dispose of it and create another with updated root file selected.
4040
// Otherwise create a new webview to display root file selected.
41-
if(!panel) {
41+
if (!panel) {
4242
panel = createPanel(context, data, columnToShowIn);
4343
} else {
4444
panel.dispose()

src/panel.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import * as vscode from 'vscode';
2-
import { getNonce } from './getNonce';
2+
import { getNonce } from './utils/getNonce';
33
import { Tree } from './types/tree';
44

5-
let panel: vscode.WebviewPanel | undefined = undefined
5+
let panel: vscode.WebviewPanel | undefined = undefined;
66

77
export function createPanel(context: vscode.ExtensionContext, data: Tree, columnToShowIn: vscode.ViewColumn) {
8-
9-
// utilize method on vscode.window object to create webview
8+
// Utilize method on vscode.window object to create webview
109
panel = vscode.window.createWebviewPanel(
1110
'reactLabyrinth',
1211
'React Labyrinth',
13-
// create one new tab
12+
// Create one tab
1413
vscode.ViewColumn.One,
1514
{
1615
enableScripts: true,
@@ -24,10 +23,10 @@ export function createPanel(context: vscode.ExtensionContext, data: Tree, column
2423
// Set URI to be the path to bundle
2524
const bundlePath: vscode.Uri = vscode.Uri.joinPath(context.extensionUri, 'build', 'bundle.js');
2625

27-
// set webview URI to pass into html script
26+
// Set webview URI to pass into html script
2827
const bundleURI: vscode.Uri = panel.webview.asWebviewUri(bundlePath);
2928

30-
// render html of webview here
29+
// Render html of webview here
3130
panel.webview.html = createWebviewHTML(bundleURI, data);
3231

3332
// Sends data to Flow.tsx to be displayed after parsed data is received
@@ -37,7 +36,6 @@ export function createPanel(context: vscode.ExtensionContext, data: Tree, column
3736
case 'onData':
3837
if (!msg.value) break;
3938
context.workspaceState.update('reactLabyrinth', msg.value);
40-
4139
panel.webview.postMessage(
4240
{
4341
type: 'parsed-data',
@@ -54,10 +52,10 @@ export function createPanel(context: vscode.ExtensionContext, data: Tree, column
5452
return panel
5553
};
5654

57-
// getNonce generates a new random string each time ext is used to prevent external injection of foreign code into the html
55+
// getNonce generates a new random string to prevent external injection of foreign code into the HTML
5856
const nonce: string = getNonce();
5957

60-
// function to create the HTML page for webview
58+
// Creates the HTML page for webview
6159
function createWebviewHTML(URI: vscode.Uri, initialData: Tree) : string {
6260
return (
6361
`
@@ -83,5 +81,5 @@ function createWebviewHTML(URI: vscode.Uri, initialData: Tree) : string {
8381
</body>
8482
</html>
8583
`
86-
)
84+
);
8785
}

src/parser.ts

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,11 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
33
import * as babel from '@babel/parser';
4-
import { getNonce } from './getNonce';
4+
import { getNonce } from './utils/getNonce';
55
import { ImportObj } from './types/ImportObj';
66
import { Tree } from "./types/tree";
77
import { File } from '@babel/types';
88

9-
// // function to determine server or client component (can look for 'use client' and 'hooks')
10-
// // input: ast node (object)
11-
// // output: boolean
12-
// checkForClientString(node) {
13-
// if (node.type === 'Directive') {
14-
// console.log('node', node);
15-
// // access the value property of the Directive node
16-
// console.log('Directive Value:', node.value);
17-
// // check if the node.value is a 'DirectiveLiteral' node
18-
// if (node.value && node.value.type === 'DirectiveLiteral') {
19-
// // check the value to see if it is 'use client'
20-
// if (typeof node.value.value === 'string' && node.value.value.trim() === 'use client') {
21-
// // access the value property of the 'DirectiveLiteral' node
22-
// console.log('DirectiveLiteral Value:', node.value.value);
23-
// // might need to do something else here to make it known as client type
24-
// return true;
25-
// }
26-
// }
27-
// }
28-
// return false;
29-
// }
30-
319
export class Parser {
3210
entryFile: string;
3311
tree: Tree | undefined;
@@ -86,7 +64,7 @@ export class Parser {
8664
return this.tree;
8765
}
8866

89-
// Set Sapling Parser with a specific Data Tree (from workspace state)
67+
// Set entryFile property with the result of Parser (from workspace state)
9068
public setTree(tree: Tree) {
9169
this.entryFile = tree.filePath;
9270
this.tree = tree;
@@ -131,7 +109,7 @@ export class Parser {
131109
return this.tree!;
132110
}
133111

134-
// Traverses the tree and changes expanded property of node whose id matches provided id
112+
// Traverses the tree and changes expanded property of node whose ID matches provided ID
135113
public toggleNode(id: string, expanded: boolean): Tree{
136114
const callback = (node: { id: string; expanded: boolean }) => {
137115
if (node.id === id) {
@@ -204,14 +182,13 @@ export class Parser {
204182
// Find imports in the current file, then find child components in the current file
205183
const imports = this.getImports(ast.program.body);
206184

207-
if (this.getCallee(ast.program.body)) {
185+
// Set value of isClientComponent property
186+
if (this.getComponentType(ast.program.directives, ast.program.body)) {
208187
componentTree.isClientComponent = true;
209188
} else {
210189
componentTree.isClientComponent = false;
211190
}
212191

213-
// console.log('componentTree.isClientComponent', componentTree.isClientComponent);
214-
// console.log('--------------------------------')
215192
// Get any JSX Children of current file:
216193
if (ast.tokens) {
217194
componentTree.children = this.getJSXChildren(
@@ -247,10 +224,8 @@ export class Parser {
247224
}
248225

249226
// Extracts Imports from current file
250-
// const Page1 = lazy(() => import('./page1')); -> is parsed as 'ImportDeclaration'
251-
// import Page2 from './page2'; -> is parsed as 'VariableDeclaration'
252-
// input: array of objects: ast.program.body
253-
// output: object of imoprts
227+
// const App1 = lazy(() => import('./App1')); => is parsed as 'ImportDeclaration'
228+
// import App2 from './App2'; => is parsed as 'VariableDeclaration'
254229
private getImports(body: { [key: string]: any }[]): ImportObj {
255230
const bodyImports = body.filter((item) => item.type === 'ImportDeclaration' || 'VariableDeclaration');
256231

@@ -278,7 +253,7 @@ export class Parser {
278253
}
279254

280255
private findVarDecImports(ast: { [key: string]: any }): string | boolean {
281-
// find import path in variable declaration and return it,
256+
// Find import path in variable declaration and return it,
282257
if (ast.hasOwnProperty('callee') && ast.callee.type === 'Import') {
283258
return ast.arguments[0].value;
284259
}
@@ -294,23 +269,32 @@ export class Parser {
294269
return false;
295270
}
296271

297-
// helper function to determine component type (client)
298-
// input: ast.program.body
299-
// output: boolean
300-
private getCallee(body: { [key: string]: any }[]): boolean {
301-
const defaultErr = (err,) => {
272+
// Determines server or client component type (looks for use of 'use client' and react/redux state hooks)
273+
private getComponentType(directive: { [key: string]: any }[], body: { [key: string]: any }[]): boolean {
274+
const defaultErr = (err) => {
302275
return {
303276
method: 'Error in getCallee method of Parser:',
304277
log: err,
305278
}
306279
};
307280

308-
// if statement to first check if component has a directive that is strictly equal to 'use client' or 'use server'
309-
// if there is no directive, continue down the chain of logic below
281+
console.log('directive: ', directive);
282+
// Initial check for use of directives (ex: 'use client', 'use server', 'use strict')
283+
// Accounts for more than one directive
284+
for (let i = 0; i < directive.length; i++) {
285+
if (directive[i].type === 'Directive') {
286+
if (typeof directive[i].value.value === 'string' && directive[i].value.value.trim() === 'use client') {
287+
return true;
288+
}
289+
}
290+
break;
291+
}
310292

293+
// Second check for use of React/Redux hooks
311294
const bodyCallee = body.filter((item) => item.type === 'VariableDeclaration');
312295
if (bodyCallee.length === 0) return false;
313296

297+
// Helper function
314298
const calleeHelper = (item) => {
315299
const hooksObj = {
316300
useState: 0,
@@ -423,7 +407,7 @@ export class Parser {
423407
childNodes,
424408
);
425409

426-
// Case for finding components passed in as props e.g. <Route component={App} />
410+
// Case for finding components passed in as props e.g. <Route Component={App} />
427411
} else if (
428412
astTokens[i].type.label === 'jsxName' &&
429413
(astTokens[i].value === 'Component' ||
@@ -476,7 +460,6 @@ export class Parser {
476460
props: props,
477461
children: [],
478462
parent: parent.id,
479-
// consider adding the id to the parentList array somehow for D3 integration...
480463
parentList: [parent.filePath].concat(parent.parentList),
481464
error: '',
482465
isClientComponent: false
@@ -504,7 +487,7 @@ export class Parser {
504487

505488
// Checks if current Node is connected to React-Redux Store
506489
private checkForRedux(astTokens: any[], importsObj: ImportObj): boolean {
507-
// Check that react-redux is imported in this file (and we have a connect method or otherwise)
490+
// Check that React-Redux is imported in this file (and we have a connect method or otherwise)
508491
let reduxImported = false;
509492
let connectAlias;
510493
Object.keys(importsObj).forEach((key) => {

src/test/runTest.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@ import { runTests } from '@vscode/test-electron';
44
async function main() {
55
console.log('made it through the line before try block');
66
try {
7-
console.log('inside try block');
87
// The folder containing the Extension Manifest package.json
98
// Passed to `--extensionDevelopmentPath`
109
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
1110

12-
console.log('inside try block after first var declare');
13-
1411
// The path to the extension test script
1512
// Passed to --extensionTestsPath
1613
const extensionTestsPath = path.resolve(__dirname, './suite/index');
1714

18-
console.log('inside try block after second var declare');
15+
console.log('inside try block after var declarations');
1916

2017
// Download VS Code, unzip it and run the integration test
2118
await runTests({

src/test/suite/parser.test.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// import * as assert from 'assert' -- this one is from node
21
import { Parser } from '../../parser';
32
import * as path from 'path';
43
import { beforeEach, expect, test } from '@jest/globals';
@@ -14,7 +13,7 @@ describe('Parser Test Suite', () => {
1413
// UNPARSED TREE TEST
1514
describe('It initializes correctly', () => {
1615
beforeEach(() => {
17-
// declare var and assign it to a test file and make new instance of Parser
16+
// Assign the test file and make new instance of Parser
1817
file = path.join(__dirname, '../test_cases/tc_0/index.js');
1918
// file = path.join(__dirname, '../../../src/test/test_apps/test_0/index.js');
2019
parser = new Parser(file);
@@ -32,7 +31,7 @@ describe('Parser Test Suite', () => {
3231

3332
// TEST 0: ONE CHILD
3433
describe('It works for simple apps', () => {
35-
before(() => {
34+
beforeEach(() => {
3635
file = path.join(__dirname, '');
3736
parser = new Parser(file);
3837
tree = parser.parse();
@@ -43,9 +42,9 @@ describe('Parser Test Suite', () => {
4342
//expect(tree).toMatchObject()
4443
});
4544

46-
test('Parsed tree has a property called name with value index and one child with name App', () => {
45+
// test('Parsed tree has a property called name with value index and one child with name App', () => {
4746

48-
});
47+
// });
4948
});
5049

5150
// these are the 14 tests we need to test for
@@ -63,7 +62,7 @@ describe('Parser Test Suite', () => {
6362
// TEST 11: PARSER DOESN'T BREAK UPON RECURSIVE COMPONENTS
6463
// TEST 12: NEXT.JS APPS (pages version & app router version)
6564
// TEST 13: Variable Declaration Imports and React.lazy Imports
66-
// TEST 14: CHECK IF COMPONENT IS CLIENT OR SERVER (USING HOOKS) => RENDERS A CERTAIN COLOR (priority)
65+
// TEST 14: CHECK IF COMPONENT IS CLIENT OR SERVER (USING HOOKS & DIRECTIVES) => BOOLEAN (priority)
6766

6867
// LOU is doing EXTENSION TEST in extension.test.ts
6968
});
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
// import React from "react";
21
export default function App() {
32
return (
43
<div>This is the App.</div>
54
)
6-
}
5+
};

src/test/test_cases/tc_0/index.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
// what we are building to test for
2-
// we will point to index.js and call new instance of parser passing in file
3-
4-
// expecting:
5-
// if the value of new instance is an obj
6-
// tree is undefined with a proper file
7-
8-
// test case 0 - simple react app with one app component
1+
// Test Case 0 - Simple react app with one app component
92

103
import React from 'react';
114
import { createRoot } from 'react-dom/client';

src/test/vscode-environment.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const { TestEnvironment } = require('jest-environment-node');
22
const vscode = require('vscode');
33

4+
// Allows for VSCode Envionrment to be extended to Jest Environment
45
class VsCodeEnvironment extends TestEnvironment {
56
async setup() {
67
await super.setup();

0 commit comments

Comments
 (0)