Skip to content

Commit 5696f60

Browse files
authored
Merge pull request #35 from oslabs-beta/AL/directives
AL/directives
2 parents 8244259 + 20a38b7 commit 5696f60

File tree

18 files changed

+92
-141
lines changed

18 files changed

+92
-141
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.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"scripts": {
7171
"lint": "eslint .",
7272
"pretest": "npm run lint",
73-
"test": "node ./build/src/test/runTest.js",
73+
"test": "npx tsc ; node ./build/src/test/runTest.js",
7474
"dev": "webpack --watch",
7575
"webpack": "webpack"
7676
},

src/extension.ts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Parser } from './parser';
44
import { Tree } from './types/tree';
55

66
let tree: Parser | undefined = undefined;
7-
let panel: vscode.WebviewPanel | undefined = undefined
7+
let panel: vscode.WebviewPanel | undefined = undefined;
88

99
// This method is called when your extension is activated
1010
// Your extension is activated the very first time the command is executed
@@ -14,37 +14,31 @@ function activate(context: vscode.ExtensionContext) {
1414
let columnToShowIn : vscode.ViewColumn | undefined = vscode.window.activeTextEditor
1515
? vscode.window.activeTextEditor.viewColumn
1616
: undefined;
17-
1817

1918
// Command that allows for User to select the root file of their React application.
2019
const pickFile: vscode.Disposable = vscode.commands.registerCommand('myExtension.pickFile', async () => {
21-
2220
// Check if there is an existing webview panel, if so display it.
23-
if(panel) {
24-
panel.reveal(columnToShowIn)
21+
if (panel) {
22+
panel.reveal(columnToShowIn);
2523
}
2624

27-
2825
// Opens window for the User to select the root file of React application
2926
const fileArray: vscode.Uri[] = await vscode.window.showOpenDialog({ canSelectFolders: false, canSelectFiles: true, canSelectMany: false });
30-
3127

3228
// Throw error message if no file was selected
3329
if (!fileArray || fileArray.length === 0) {
3430
vscode.window.showErrorMessage('No file selected');
3531
return;
3632
}
37-
3833

3934
// Create Tree to be inserted into returned HTML
4035
tree = new Parser(fileArray[0].path);
4136
tree.parse();
4237
const data: Tree = tree.getTree();
4338

44-
4539
// Check if panel currently has a webview, if it does dispose of it and create another with updated root file selected.
4640
// Otherwise create a new webview to display root file selected.
47-
if(!panel) {
41+
if (!panel) {
4842
panel = createPanel(context, data, columnToShowIn);
4943
} else {
5044
panel.dispose()
@@ -54,23 +48,19 @@ function activate(context: vscode.ExtensionContext) {
5448
// Listens for when webview is closed and disposes of webview resources
5549
panel.onDidDispose(
5650
() => {
57-
console.log("Before: ", panel)
58-
panel.dispose()
51+
panel.dispose();
5952
panel = undefined;
6053
columnToShowIn = undefined;
61-
console.log("After: ", panel)
6254
},
6355
null,
6456
context.subscriptions
65-
);
57+
);
6658
});
6759

68-
6960
// Command to show panel if it is hidden
7061
const showPanel: vscode.Disposable = vscode.commands.registerCommand('myExtension.showPanel', () => {
71-
panel.reveal(columnToShowIn)
72-
});
73-
62+
panel.reveal(columnToShowIn);
63+
});
7464

7565
context.subscriptions.push(pickFile, showPanel);
7666
}

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: 27 additions & 41 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,20 +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

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+
}
292+
293+
// Second check for use of React/Redux hooks
308294
const bodyCallee = body.filter((item) => item.type === 'VariableDeclaration');
309295
if (bodyCallee.length === 0) return false;
310296

297+
// Helper function
311298
const calleeHelper = (item) => {
312299
const hooksObj = {
313300
useState: 0,
@@ -420,7 +407,7 @@ export class Parser {
420407
childNodes,
421408
);
422409

423-
// 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} />
424411
} else if (
425412
astTokens[i].type.label === 'jsxName' &&
426413
(astTokens[i].value === 'Component' ||
@@ -473,7 +460,6 @@ export class Parser {
473460
props: props,
474461
children: [],
475462
parent: parent.id,
476-
// consider adding the id to the parentList array somehow for D3 integration...
477463
parentList: [parent.filePath].concat(parent.parentList),
478464
error: '',
479465
isClientComponent: false
@@ -501,7 +487,7 @@ export class Parser {
501487

502488
// Checks if current Node is connected to React-Redux Store
503489
private checkForRedux(astTokens: any[], importsObj: ImportObj): boolean {
504-
// 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)
505491
let reduxImported = false;
506492
let connectAlias;
507493
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/extension.test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ import * as vscode from 'vscode'
66
// we can either use test() or it() -- matter of style for team/project convention
77

88
describe('Extension Test Suite', () => {
9-
// beforeEach(() => {
10-
// vscode.window.showInformationMessage('Start all tests.');
11-
// });
129

1310
it('Sample test', () => {
1411
expect([1, 2, 3].indexOf(5)).toBe(-1);

0 commit comments

Comments
 (0)