diff --git a/src/execute-mezzurite-framework-rules.ts b/src/execute-mezzurite-framework-rules.ts new file mode 100644 index 0000000..f1426b1 --- /dev/null +++ b/src/execute-mezzurite-framework-rules.ts @@ -0,0 +1,31 @@ +import {ExtensionConstants} from './extension-constants'; +import {MezzuriteAngularV1} from './mezzurite-angular-version1'; + +export class ExecuteMezzuriteFrameworkRules { + private frameworkName: string; + private frameworkversion: number; + + constructor(name: string, health: number) { + this.frameworkName = name; + this.frameworkversion = health; + } + + async executeRules() { + let mezzuriteFramework: any; + switch(this.frameworkName){ + case ExtensionConstants.mezzuriteAngularJs: + break; + case ExtensionConstants.mezzuriteAngular: + mezzuriteFramework = new MezzuriteAngularV1(); + break; + case ExtensionConstants.mezzuriteReact: + break; + default: console.log('Mezzurite framework name '+ this.frameworkName + ' or version '+ this.frameworkversion +' is invalid!'); + } + return await mezzuriteFramework.executeFrameworkSpecificRules(); + } + } + + export function ValidateRules(name: string, version: number) { + return new ExecuteMezzuriteFrameworkRules(name, version); + } \ No newline at end of file diff --git a/src/extension-constants.ts b/src/extension-constants.ts index 79391f9..345f634 100644 --- a/src/extension-constants.ts +++ b/src/extension-constants.ts @@ -1,12 +1,22 @@ const ExtensionConstants = { + + mezzuritePath : '/node_modules/@microsoft/', + mezzuriteDirectories : ["mezzurite-angular", "mezzurite-react", "mezzurite-angularjs"], + mezzuriteFrameworks : ["@microsoft/mezzurite-angular", "@microsoft/mezzurite-react", "@microsoft/mezzurite-angularjs"], + pathForAppsPackageJson : "**/package.json", + pathForNodeModules : "**/node_modules/**", titleForWelcomePage : "Mezzurite Extension", placeholderForStyleTag : "##StyleLink##", webviewStyleName : "style.css", webviewHtmlFileName : "landingPage.html", clientFolderName : "client", validateMezzuriteCommand : "extension.validateMezzurite", - displayLandingPageCommand : "extension.displayLandingPage" + displayLandingPageCommand : "extension.displayLandingPage", + + mezzuriteAngularJs:"@microsoft/mezzurite-angularjs", + mezzuriteAngular:"@microsoft/mezzurite-angular", + mezzuriteReact:"@microsoft/mezzurite-react", } export { ExtensionConstants }; \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 2208f95..e4fb18e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,6 +2,8 @@ import * as vscode from 'vscode'; import { window, commands} from 'vscode'; import {LandingPage} from './landing-page'; +import {MezzuriteDependency} from './verify-mezzurite-dependency'; +import {ExecuteMezzuriteFrameworkRules} from './execute-mezzurite-framework-rules'; import {ExtensionConstants} from './extension-constants'; // this method is called when your extension is activated @@ -14,9 +16,12 @@ export async function activate(context: vscode.ExtensionContext) { // Check if mezzurite dependency is found or not // This will be done by parsing the application's package.json file or searching for mezzuite-framework in node_modules folder - var mezzuriteFound = mezzuriteExtension.verifyMezzurite(); - if(mezzuriteFound){ + var mezzuriteDependency: any = await mezzuriteExtension.verifyMezzurite(); + if(mezzuriteDependency){ mezzuriteExtension.displayLandingPage(context); + let validateMezzuriteFramework = new ExecuteMezzuriteFrameworkRules(mezzuriteDependency.name, mezzuriteDependency.version); + let ruleResults = await validateMezzuriteFramework.executeRules(); + console.log(ruleResults); } // Command for validate mezzurite on current workspace @@ -62,9 +67,8 @@ class MezzuriteExtension{ * * @return true if found */ - public verifyMezzurite(){ - // This is just to test the base extension - console.log('Mezzurite framework found!'); - return true; + public async verifyMezzurite(){ + let mezzuriteDependency = new MezzuriteDependency(); + return await mezzuriteDependency.verifyMezzuriteDependency(); } } \ No newline at end of file diff --git a/src/landing-page.ts b/src/landing-page.ts index a3b06ad..a833d8f 100644 --- a/src/landing-page.ts +++ b/src/landing-page.ts @@ -74,8 +74,8 @@ export class LandingPage { * Returns the absolute path to a file located in our misc folder. * * @param file: The base file name. - * @param asResource: a boolean flag to know whether its html or css file and to add the vscode-resource scheme. - * vscode-resource: loads a resource at a given absolute path from the disk. + * @param asResource: a boolean flag to know whether its html or css file and to add the 'vscode-resource' scheme. + * vscode-resource: loads a resource at a given absolute path from the disk. */ public getMiscPath(file: string, asResource: boolean): string { if (asResource) { diff --git a/src/mezzurite-angular-version1.ts b/src/mezzurite-angular-version1.ts new file mode 100644 index 0000000..f3cd6d9 --- /dev/null +++ b/src/mezzurite-angular-version1.ts @@ -0,0 +1,114 @@ +import {workspace} from 'vscode'; +import ts = require('typescript'); +import 'reflect-metadata'; +import {MezzuriteUtils} from './mezzurite-utils'; + +export class MezzuriteAngularV1{ + + constructor(){ + + } + + async executeFrameworkSpecificRules(){ + // Read the .js and .ts files from the work space + // Get the contents + // Look for @Component keyword + // If found, get that object + // Check property templateUrl and template + // If templateUrl found store that file name as html + // If template found, mark that as component and check for mezzurite and component title in that html string + let files: any = await MezzuriteUtils.searchWorkspace(workspace, "**/*.ts", "**/node_modules/**"); + let data: string; + let htmlFiles: any = []; + let output : any = []; + for(const index in files){ + data = MezzuriteUtils.readFileFromWorkspace(files[index].fsPath, 'utf8'); + if(data.indexOf('@NgModule') > -1){ + console.log("This is a angular module:-"+ files[index].fsPath); + console.log("You should have import and router.start() here"); + } + if(data.indexOf('@Component') > -1){ + + let outputObject: any = { + componentName: "", + filePath: "", + status: "Unmarked", + template: "" + }; + // Add the file path + outputObject.filePath = files[index].fsPath; + + const parsedData = ts.createSourceFile(files[index].fsPath, data, ts.ScriptTarget.Latest, true); + var componentFound = false; + + for(var i = 0;i < parsedData.statements.length; i++){ + var nodeObj: any = ts.getParseTreeNode(parsedData.statements[i]); + if(nodeObj.decorators && ts.isDecorator(nodeObj.decorators[0])){ + // Add the componentName + outputObject.componentName = nodeObj.name.text; + + // Get the decorator properties + var expObj = ts.getParseTreeNode(nodeObj.decorators[0].expression); + if(expObj.expression.text !== "Component"){ + continue; + } + + var properties; + if(expObj && expObj.arguments){ + properties = ts.getParseTreeNode(expObj.arguments[0]).properties; + componentFound = true; + } + + for(var j = 0; j < properties.length; j++){ + var element = properties[j]; + if(element.name.text === "templateUrl"){ + htmlFiles.push(element.initializer.text); + outputObject.template = element.initializer.text; + if(element.initializer.text !== ""){ + var found = await MezzuriteAngularV1.parseHTMLFile(element.initializer.text); + if(found){ + outputObject.status = "Marked"; + } + } + } + if(element.name.text === "template"){ + outputObject.template = "Html template provided"; + if(MezzuriteAngularV1.verifyComponentMarking(element.initializer.text)){ + outputObject.status = "Marked"; + } + } + }; + } + } + + if(componentFound){ + output.push(outputObject); + } + } + + } + + // Display output + for(var component = 0;component < output.length; component++){ + console.log(output[component]); + } + } + + static async parseHTMLFile(filePath: string){ + var lastIndex = filePath.lastIndexOf('/') > -1? filePath.lastIndexOf('/') : filePath.lastIndexOf('\\'); + var includePattern = "**/" + filePath.substring(lastIndex + 1, filePath.length); + + // Get the html file and parse its contents for mezzurite markings + let files: any = await MezzuriteUtils.searchWorkspace(workspace, includePattern, "**/node_modules/**"); + var templateString = MezzuriteUtils.readFileFromWorkspace(files[0].fsPath, 'utf8'); + + return MezzuriteAngularV1.verifyComponentMarking(templateString); + } + + static verifyComponentMarking(htmlString: string){ + if(htmlString.indexOf('mezzurite') > -1 && htmlString.indexOf('component-title')> -1){ + return true; + } + return false; + } +} \ No newline at end of file diff --git a/src/mezzurite-utils.ts b/src/mezzurite-utils.ts new file mode 100644 index 0000000..ca0b5ba --- /dev/null +++ b/src/mezzurite-utils.ts @@ -0,0 +1,45 @@ +import * as fs from "fs"; + +export class MezzuriteUtils { + + constructor( + ) { } + + /** + * This method search for Mezzurite-framework dependency in node_modules/mezzurite-framework's Package.json file + * @param workspace is the current workspace in the vs code editor + * @param includePatterns is the path pattern which needs to searched + * @param excludePattern is the path pattern which should be excluded from search + * @return Return the arrays of files found in the current workspace + */ + static async searchWorkspace(workspace: any, includePatterns: any, excludePattern: any){ + try{ + return await workspace.findFiles(includePatterns, excludePattern); + }catch(err){ + console.log(err); + throw err; + } + } + + /** + * This method reads file contents, provided the filePath + * @param filePath is the path to the file + * @param encodingType is the character encoding type + * @return Returns the file contents + */ + static readFileFromWorkspace(filePath: string, encodingType: string){ + let data: any; + try{ + data = fs.readFileSync(filePath, encodingType); + } + catch(err) + { + if (err){ + console.log('File not found at the following path:-' + filePath); + throw err; + } + } + return data; + } + +} \ No newline at end of file diff --git a/src/verify-mezzurite-dependency.ts b/src/verify-mezzurite-dependency.ts new file mode 100644 index 0000000..0d025b7 --- /dev/null +++ b/src/verify-mezzurite-dependency.ts @@ -0,0 +1,151 @@ +import {window, workspace} from 'vscode'; +import * as fs from "fs"; +import {ExtensionConstants} from './extension-constants'; +import {MezzuriteUtils} from './mezzurite-utils'; + +export class MezzuriteDependency { + + constructor( + ) { } + + /** + * This method verifies whether Mezzurite-framework dependency is present in the current workspace or not. + * @return If found, returns the mezzurite framework name and version in an object, otherwise, undefined. + */ + public async verifyMezzuriteDependency(){ + // Parse application's package.json file + var dependencyFound= await MezzuriteDependency.searchInPackageJsonFile(); + if(dependencyFound === undefined){ + // If Mezzurite framework dependency is not found in application's package.json file + // then, search into node modules directory for @microsoft/mezzurite-(frameworkName) + // frameworkName can be angularjs, angular or react + dependencyFound = await MezzuriteDependency.searchNodeDirectory(); + } + return dependencyFound; + } + + /** + * This method search for Mezzurite-framework dependency in application's Package.json file + * @return If found, returns the mezzurite framework name and version in an object, otherwise, undefined. + */ + static async searchInPackageJsonFile(){ + var packageJsonFile = await MezzuriteUtils.searchWorkspace(workspace, ExtensionConstants.pathForAppsPackageJson, ExtensionConstants.pathForNodeModules); + if(packageJsonFile.length < 1){ + console.log('Applications package.json file not found in the current workspace.'); + return undefined; + } + return MezzuriteDependency.parsePackageJsonContents(packageJsonFile); + } + + /** + * This method is used to parse application's Package.json file + * @param packageJsonFile.json file path object + * @return Returns the mezzurite framework name and version in an object, otherwise, undefined. + */ + static parsePackageJsonContents(packageJsonFile: any){ + let mezzuriteDependency: any = undefined; + + // read application's package.json contents + let data: any = MezzuriteUtils.readFileFromWorkspace(packageJsonFile[0].fsPath, 'utf8'); + + // Get the package.json Object + let packageJsonObj = JSON.parse(data); + // Search in dependencies object in package.json file + mezzuriteDependency = this.getMezzuriteDependency(packageJsonObj.dependencies); + + if(mezzuriteDependency === undefined){ + + // Search in devDependencies object in package.json file + mezzuriteDependency = this.getMezzuriteDependency(packageJsonObj.devDependencies); + + if(mezzuriteDependency === undefined){ + return mezzuriteDependency; // Mezzurite framework dependency is not found in package.json file + } + } + + window.showInformationMessage('Mezzurite framework configured is '+ mezzuriteDependency.name + ' and version is '+ mezzuriteDependency.version); + return mezzuriteDependency; + } + + /** + * This method is used to parse dependencies and devDependencies Object's in application's Package.json file + * @param dependancyObject is the dependency object from package.json file + * @return Returns the mezzurite framework name and version in an object, otherwise, undefined. + */ + static getMezzuriteDependency(dependancyObject: any){ + let mezzuriteDependency: any = undefined; + for(var dependency in dependancyObject){ + // if there's a match with any of our framework + if(ExtensionConstants.mezzuriteFrameworks.indexOf(dependency) > -1){ + mezzuriteDependency = this.getDependencyDetails(dependency, dependancyObject[dependency]); + break; + } + } + + return mezzuriteDependency; + } + + /** + * This method is used to create mezzurite framework name and version object + * @param dependencyName is the mezzurite framework name + * @param dependencyVersion is the mezzurite framework version + * @return Returns the object + */ + static getDependencyDetails(dependencyName: string, dependencyVersion: number){ + return { + name: dependencyName, + version: dependencyVersion + }; + } + + /** + * This method search for Mezzurite-framework dependency in node_modules directory + * @return If found, returns the mezzurite framework name and version in an object, otherwise, undefined. + */ + static async searchNodeDirectory(){ + var mezzuriteLibs; + var mezzuFrameworkName: any = undefined; + + try{ + // Get all the folders in nodemodules/@microsoft directory + mezzuriteLibs = fs.readdirSync(workspace.rootPath + ExtensionConstants.mezzuritePath); + }catch(err){ + console.log('Mezzurite frameworks directory not found'); + throw err; + } + + // Search if mezzurite framework's folder exists or not + if(mezzuriteLibs.length > 0){ + for(var lib in mezzuriteLibs){ + if(ExtensionConstants.mezzuriteDirectories.indexOf(mezzuriteLibs[lib]) > -1){ + mezzuFrameworkName = mezzuriteLibs[lib]; + break; + } + } + } + + // If mezzurite dependency found, then get the mezzurite-frameworkName and version + if(mezzuFrameworkName !== undefined){ + + var mzzFrameworksPackageJsonPath = '**'+ ExtensionConstants.mezzuritePath + mezzuFrameworkName +'/package.json'; + + // If mezzurite framework found inside node modules directory + // then, parse mezzurite framework's package.json file and get the version + // This will help to identify the which version of mezzurite-frameworkName is used by the application + // It can be:- 1. angularjs, 2. angular (version = 1.0.x for Angular 2-5 and version = 2.0.x for Angular 6) or 3. react + let files: any = await MezzuriteUtils.searchWorkspace(workspace, mzzFrameworksPackageJsonPath, ''); + + // read framework's package.json contents + let data: any = MezzuriteUtils.readFileFromWorkspace(files[0].fsPath, 'utf8'); + + let obj = JSON.parse(data); + + // @TODO:Shud be removed before final checkin + window.showInformationMessage('Mezzurite framework configured is '+ obj.name + ' and version is '+ obj.version); + return this.getDependencyDetails(obj.name, obj.version); + } + + return undefined; + } + +} \ No newline at end of file