From 5665ca9104e5b1a00fe9652fc8644861931355ad Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Thu, 12 Dec 2019 13:26:58 +0200 Subject: [PATCH 01/19] small code refactoring --- .vscode/launch.json | 4 ++-- backend/.nycrc.json | 7 +++---- backend/src/yeomanui.ts | 45 +++++++++++++++++------------------------ 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 67274da94..bdc0e7333 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,7 +18,7 @@ { "type": "node", "request": "launch", - "name": "Mocha Tests", + "name": "backend unit tests", "program": "${workspaceFolder}/backend/node_modules/mocha/bin/mocha", "args": [ "-r", @@ -74,7 +74,7 @@ ] }, { - "name": "Test frontend", + "name": "frontend unit tests", "type": "node", "request": "launch", "runtimeArgs": [ diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 383d51c2a..93d67c486 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -1,7 +1,6 @@ { "require": ["ts-node/register/transpile-only"], "include": ["src/**/*.ts"], - "exclude": ["src/run-configuration*", "src/cfView.ts", "src/cfViewCommands.ts", "src/sql-tools.ts"], "reporter": ["lcov", "text"], "extension": [".ts"], "all": true, @@ -9,7 +8,7 @@ "report-dir": "./reports/coverage", "check-coverage": true, "branches": 0, - "lines": 24, - "functions": 17, - "statements": 25 + "lines": 25, + "functions": 18, + "statements": 26 } diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index 4485d7f49..19c4c4041 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -93,13 +93,13 @@ export class YeomanUI { const env: Environment = Environment.createEnv(undefined, {}, this.youiAdapter); try { - const meta: Environment.GeneratorMeta = this.genMeta[`${generatorName}:app`]; + const meta: Environment.GeneratorMeta = this.getGenMetadata(generatorName); // TODO: support sub-generators env.register(meta.resolved); const gen: any = env.create(`${generatorName}:app`, {}); // check if generator defined a helper function called getPrompts() - if ((gen as any)["getPrompts"] !== undefined) { - const promptNames: any[] = (gen as any)["getPrompts"](); + if (gen["getPrompts"] !== undefined) { + const promptNames: any[] = gen["getPrompts"](); const prompts: IPrompt[] = promptNames.map((value) => { return _.assign({ questions: [], name: "" }, value); }); @@ -107,7 +107,7 @@ export class YeomanUI { } if ((gen as any)["getImage"] !== undefined) { - const image: string | Promise | undefined = (gen as any)["getImage"](); + const image: string | Promise | undefined = gen["getImage"](); if ((image as any)["then"]) { (image as any)["then"]((contents: string) => { console.log(`image contents: ${contents}`); @@ -142,11 +142,7 @@ export class YeomanUI { } public doGeneratorDone(success: boolean, message: string): Promise { - if (this.rpc) { - return this.rpc.invoke("generatorDone", [true, message]); - } - - return Promise.resolve(); + return this.rpc ? this.rpc.invoke("generatorDone", [true, message]) : Promise.resolve(); } /** @@ -175,10 +171,7 @@ export class YeomanUI { } public toggleLog(): boolean { - if (this.rpc) { - return this.logger.showLog(); - } - return false; + return this.rpc ? this.logger.showLog() : false; } public async showPrompt(questions: Environment.Adapter.Questions): Promise { @@ -191,9 +184,9 @@ export class YeomanUI { } const mappedQuestions: Environment.Adapter.Questions = this.normalizeFunctions(questions); return this.rpc.invoke("showPrompt", [mappedQuestions, promptName]); - } else { - return Promise.resolve({}); - } + } + + return Promise.resolve({}); } private async onEnvLookup(env: Environment.Options, resolve: any, type?: Type) { @@ -214,7 +207,7 @@ export class YeomanUI { } private async createGeneratorChoice(genName: string, type?: Type): Promise { - const genPackagePath = this.getGenPackagePath(genName); + const genPackagePath = this.getGenMetaPackagePath(genName); let genImageUrl; let genMessage; @@ -239,12 +232,16 @@ export class YeomanUI { } private async getGenPackageJson(genPackagePath: string): Promise { - const packageJsonString: string = await fsextra.readFile(path.join(genPackagePath, "package.json"), "utf8"); - return JSON.parse(packageJsonString); + const packageJsonString: string = await fsextra.readFile(path.join(genPackagePath, "package.json"), "utf8"); + return JSON.parse(packageJsonString); + } + + private getGenMetaPackagePath(genName: string): string { + return _.get(this.getGenMetadata(genName), "packagePath"); } - private getGenPackagePath(genName: string): string { - return _.get(this, ["genMeta", `${genName}:app`, "packagePath"]); + private getGenMetadata(genName: string): Environment.GeneratorMeta { + return _.get(this, ["genMeta", `${genName}:app`]); } /** @@ -260,10 +257,6 @@ export class YeomanUI { } private setPrompts(prompts: IPrompt[]): Promise { - if (this.rpc) { - return this.rpc.invoke("setPrompts", [prompts]); - } - - return Promise.resolve(); + return this.rpc ? this.rpc.invoke("setPrompts", [prompts]) : Promise.resolve(); } } From 614e13be8805e766858e08877db9e7ec8d46c4e6 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Thu, 12 Dec 2019 13:37:59 +0200 Subject: [PATCH 02/19] code improvement --- backend/src/yeomanui.ts | 14 ++++++++------ backend/tests/yeomanui.spec.ts | 11 +++-------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index 19c4c4041..2ee159425 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -98,16 +98,18 @@ export class YeomanUI { env.register(meta.resolved); const gen: any = env.create(`${generatorName}:app`, {}); // check if generator defined a helper function called getPrompts() - if (gen["getPrompts"] !== undefined) { - const promptNames: any[] = gen["getPrompts"](); + const genGetPrompts = _.get(gen, "getPromts"); + if (genGetPrompts) { + const promptNames: any[] = genGetPrompts(); const prompts: IPrompt[] = promptNames.map((value) => { return _.assign({ questions: [], name: "" }, value); }); this.setPrompts(prompts); } - if ((gen as any)["getImage"] !== undefined) { - const image: string | Promise | undefined = gen["getImage"](); + const genGetImage = _.get(gen, "getImage"); + if (genGetImage) { + const image: string | Promise | undefined = genGetImage(); if ((image as any)["then"]) { (image as any)["then"]((contents: string) => { console.log(`image contents: ${contents}`); @@ -152,8 +154,8 @@ export class YeomanUI { */ public evaluateMethod(params: any[], questionName: string, methodName: string): any { if (this.currentQuestions) { - const relevantQuestion: any = (this.currentQuestions as any[]).find((question) => { - return (question.name === questionName); + const relevantQuestion: any = _.find(this.currentQuestions, question => { + return (_.get(question, "name") === questionName); }); if (relevantQuestion) { return relevantQuestion[methodName].apply(this.gen, params); diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index b50abcd05..86cad9346 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -155,24 +155,19 @@ describe('yeomanui unit test', () => { }, }); envMock.expects("getGeneratorNames").returns(["test1", "test3"]); - fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test1Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).throws(new Error("description_error")); fsExtraMock.expects("readFile").withExactArgs(path.join("test3Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test3Description"}`); datauriMock.expects("promise").withExactArgs(path.join("test1Path", YEOMAN_PNG)).resolves("yeomanPngData"); - datauriMock.expects("promise").withExactArgs(path.join("test3Path", YEOMAN_PNG)).throws(new Error("testError")); + datauriMock.expects("promise").withExactArgs(path.join("test3Path", YEOMAN_PNG)).throws(new Error("yeomanpng_error")); const result = await yeomanUi.getGenerators(); const test1Choice = result.questions[0].choices[0]; expect(test1Choice.name).to.be.equal("test1"); - expect(test1Choice.message).to.be.equal("test1Description"); + expect(test1Choice.message).to.be.equal(choiceMessage); expect(test1Choice.imageUrl).to.be.equal("yeomanPngData"); - // const test2Choice = result.questions[0].choices[1]; - // expect(test2Choice.name).to.be.equal("test2"); - // expect(test2Choice.message).to.be.equal(choiceMessage); - // expect(test2Choice.imageUrl).to.be.equal(defaultImage.default); - const test3Choice = result.questions[0].choices[1]; expect(test3Choice.name).to.be.equal("test3"); expect(test3Choice.message).to.be.equal("test3Description"); From 811b62473e3afcbf78221bc8bb2a8bcfd9ed40b1 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Thu, 12 Dec 2019 15:14:52 +0200 Subject: [PATCH 03/19] add tests --- backend/src/yeomanui.ts | 37 ++++++++----- backend/tests/yeomanui.spec.ts | 97 +++++++++++++++++++++++++++++----- 2 files changed, 109 insertions(+), 25 deletions(-) diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index 2ee159425..7c59637b7 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -195,7 +195,7 @@ export class YeomanUI { this.genMeta = env.getGeneratorsMeta(); const generatorNames: string[] = env.getGeneratorNames(); const generatorChoicePromises = _.map(generatorNames, genName => { - return this.createGeneratorChoice(genName, type); + return this.getGeneratorChoice(genName, type); }); const generatorChoices = await Promise.all(generatorChoicePromises); @@ -203,28 +203,41 @@ export class YeomanUI { type: "generators", name: "name", message: "name", - choices: generatorChoices + choices: _.compact(generatorChoices) }; resolve({ name: "Choose Generator", questions: [generatorQuestion] }); } - private async createGeneratorChoice(genName: string, type?: Type): Promise { + private async getGeneratorChoice(genName: string, type?: Type): Promise { + let packageJson: any; + const genPackagePath = this.getGenMetaPackagePath(genName); + try { + packageJson = await this.getGenPackageJson(genPackagePath); + } catch (error) { + return; + } + + if (type) { + const genType: string = _.get(packageJson, ["generator-filter", "type"]); + if (type === genType) { + return this.createGeneratorChoice(genName, genPackagePath, packageJson); + } + } else { + return this.createGeneratorChoice(genName, genPackagePath, packageJson); + } + } + + private async createGeneratorChoice(genName: string, genPackagePath: string, packageJson: any): Promise { let genImageUrl; - let genMessage; - + try { genImageUrl = await datauri.promise(path.join(genPackagePath, YeomanUI.YEOMAN_PNG)); - } catch (err) { + } catch (error) { genImageUrl = defaultImage.default; } - try { - const packageJson: any = await this.getGenPackageJson(genPackagePath); - genMessage = _.get(packageJson, "description", YeomanUI.defaultMessage); - } catch (err) { - genMessage = YeomanUI.defaultMessage; - } + const genMessage = _.get(packageJson, "description", YeomanUI.defaultMessage); return { name: genName, diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index 86cad9346..e6df97df6 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -10,6 +10,7 @@ import * as defaultImage from "../src/defaultImage"; import * as yeomanEnv from "yeoman-environment"; import { YouiLog } from "../src/youi-log"; import { IMethod, IPromiseCallbacks, IRpc } from "@sap-devx/webview-rpc/out.ext/rpc-common"; +import { Type } from "../src/filter"; describe('yeomanui unit test', () => { let sandbox: any; @@ -142,36 +143,106 @@ describe('yeomanui unit test', () => { expect(result).to.be.deep.equal({ name: "Choose Generator", questions: [generatorQuestion] }); }); - it("there are generators", async () => { + it("get generators with type project", async () => { envMock.expects("getGeneratorsMeta").returns({ "test1:app": { packagePath: "test1Path" }, - "test2:app2": { + "test2:app": { packagePath: "test2Path" }, "test3:app": { packagePath: "test3Path" }, + "test4:app": { + packagePath: "test4Path" + }, + "test5:app": { + packagePath: "test5Path" + } }); - envMock.expects("getGeneratorNames").returns(["test1", "test3"]); - fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).throws(new Error("description_error")); - fsExtraMock.expects("readFile").withExactArgs(path.join("test3Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test3Description"}`); + envMock.expects("getGeneratorNames").returns(["test1", "test2", "test3", "test4", "test5"]); - datauriMock.expects("promise").withExactArgs(path.join("test1Path", YEOMAN_PNG)).resolves("yeomanPngData"); - datauriMock.expects("promise").withExactArgs(path.join("test3Path", YEOMAN_PNG)).throws(new Error("yeomanpng_error")); + fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test1Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test2Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project_test"}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test3Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "module"}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); - const result = await yeomanUi.getGenerators(); + const result = await yeomanUi.getGenerators(Type.project); + expect(result.questions[0].choices).to.have.lengthOf(2); const test1Choice = result.questions[0].choices[0]; + const test2Choice = result.questions[0].choices[1]; expect(test1Choice.name).to.be.equal("test1"); + expect(test1Choice.message).to.be.equal("test1Description"); + expect(test2Choice.name).to.be.equal("test4"); + expect(test2Choice.message).to.be.equal("test4Description"); + }); + + it("get generators with type module", async () => { + envMock.expects("getGeneratorsMeta").returns({ + "test1:app": { + packagePath: "test1Path" + }, + "test2:app": { + packagePath: "test2Path" + }, + "test3:app": { + packagePath: "test3Path" + }, + "test4:app": { + packagePath: "test4Path" + }, + "test5:app": { + packagePath: "test5Path" + } + }); + envMock.expects("getGeneratorNames").returns(["test1", "test2", "test3", "test4", "test5"]); + + fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test1Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test2Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project_test"}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test3Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "module"}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); + + const result = await yeomanUi.getGenerators(Type.module); + + expect(result.questions[0].choices).to.have.lengthOf(1); + const test1Choice = result.questions[0].choices[0]; + expect(test1Choice.name).to.be.equal("test3"); expect(test1Choice.message).to.be.equal(choiceMessage); - expect(test1Choice.imageUrl).to.be.equal("yeomanPngData"); + }); + + it("get generators all generators", async () => { + envMock.expects("getGeneratorsMeta").returns({ + "test1:app": { + packagePath: "test1Path" + }, + "test2:app": { + packagePath: "test2Path" + }, + "test3:app": { + packagePath: "test3Path" + }, + "test4:app": { + packagePath: "test4Path" + }, + "test5:app": { + packagePath: "test5Path" + } + }); + envMock.expects("getGeneratorNames").returns(["test1", "test2", "test3", "test4", "test5"]); + + fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test1Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test2Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project_test"}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test3Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "module"}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); + + const result = await yeomanUi.getGenerators(); - const test3Choice = result.questions[0].choices[1]; - expect(test3Choice.name).to.be.equal("test3"); - expect(test3Choice.message).to.be.equal("test3Description"); - expect(test3Choice.imageUrl).to.be.equal(defaultImage.default); + expect(result.questions[0].choices).to.have.lengthOf(5); }); }); }); From f3f1ad6171fac1ba70fcb805dca080b18516ca48 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Thu, 12 Dec 2019 15:15:49 +0200 Subject: [PATCH 04/19] update coverage --- backend/.nycrc.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 93d67c486..11fc0c8d0 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -7,8 +7,8 @@ "temp-dir": "./reports/.nyc_output", "report-dir": "./reports/coverage", "check-coverage": true, - "branches": 0, - "lines": 25, - "functions": 18, - "statements": 26 + "branches": 9, + "lines": 28, + "functions": 20, + "statements": 28 } From b9bc05a607d8855d5c622abe2d64844f58ff59b0 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Sun, 15 Dec 2019 07:06:15 +0200 Subject: [PATCH 05/19] add test --- backend/tests/yeomanui.spec.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index e6df97df6..e775cb5de 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -244,5 +244,36 @@ describe('yeomanui unit test', () => { expect(result.questions[0].choices).to.have.lengthOf(5); }); + + it("get generators with accessible package.json", async () => { + envMock.expects("getGeneratorsMeta").returns({ + "test1:app": { + packagePath: "test1Path" + }, + "test2:app": { + packagePath: "test2Path" + }, + "test3:app": { + packagePath: "test3Path" + }, + "test4:app": { + packagePath: "test4Path" + }, + "test5:app": { + packagePath: "test5Path" + } + }); + envMock.expects("getGeneratorNames").returns(["test1", "test2", "test3", "test4", "test5"]); + + fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).throws(new Error("test1Error")); + fsExtraMock.expects("readFile").withExactArgs(path.join("test2Path", PACKAGE_JSON), UTF8).throws(new Error("test2Error")); + fsExtraMock.expects("readFile").withExactArgs(path.join("test3Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "module"}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); + + const result = await yeomanUi.getGenerators(); + + expect(result.questions[0].choices).to.have.lengthOf(3); + }); }); }); From 5de1fdf34f4d9a9941e7c2ec559ca86433e1c78c Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Sun, 15 Dec 2019 07:20:57 +0200 Subject: [PATCH 06/19] add filter --- backend/.nycrc.json | 4 ++-- backend/src/filter.ts | 9 +++++++-- backend/src/yeomanui.ts | 21 +++++++++++---------- backend/tests/yeomanui.spec.ts | 10 +++++++--- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 11fc0c8d0..31c4898ce 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -8,7 +8,7 @@ "report-dir": "./reports/coverage", "check-coverage": true, "branches": 9, - "lines": 28, + "lines": 29, "functions": 20, - "statements": 28 + "statements": 29 } diff --git a/backend/src/filter.ts b/backend/src/filter.ts index 14853be98..721193ad6 100644 --- a/backend/src/filter.ts +++ b/backend/src/filter.ts @@ -1,4 +1,9 @@ -export enum Type { +export enum GeneratorType { project = "project", module = "module" -} \ No newline at end of file +} + +export class GeneratorFilter { + type?: GeneratorType; + category?: string[]; +} diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index 7c59637b7..600dc13e3 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -11,7 +11,7 @@ import { YouiAdapter } from "./youi-adapter"; import { YouiLog } from "./youi-log"; import { IRpc } from "@sap-devx/webview-rpc/out.ext/rpc-common"; import Generator = require("yeoman-generator"); -import { Type } from "./filter"; +import { GeneratorType, GeneratorFilter } from "./filter"; export interface IGeneratorChoice { name: string; @@ -63,13 +63,13 @@ export class YeomanUI { this.currentQuestions = {}; } - public async getGenerators(type?: Type): Promise { + public async getGenerators(filter?: GeneratorFilter): Promise { // optimization: looking up generators takes a long time, so if generators are already loaded don't bother // on the other hand, we never look for newly installed generators... const promise: Promise = new Promise(resolve => { const env: Environment.Options = Environment.createEnv(); - env.lookup(async () => this.onEnvLookup(env, resolve, type)); + env.lookup(async () => this.onEnvLookup(env, resolve, filter)); }); return promise; @@ -163,10 +163,10 @@ export class YeomanUI { } } - public async receiveIsWebviewReady(type?: Type) { + public async receiveIsWebviewReady(filter?: GeneratorFilter) { // TODO: loading generators takes a long time; consider prefetching list of generators if (this.rpc) { - const generators: IPrompt = await this.getGenerators(type); + const generators: IPrompt = await this.getGenerators(filter); const response: any = await this.rpc.invoke("showPrompt", [generators.questions, generators.name]); this.runGenerator(response.name); } @@ -191,11 +191,11 @@ export class YeomanUI { return Promise.resolve({}); } - private async onEnvLookup(env: Environment.Options, resolve: any, type?: Type) { + private async onEnvLookup(env: Environment.Options, resolve: any, filter?: GeneratorFilter) { this.genMeta = env.getGeneratorsMeta(); const generatorNames: string[] = env.getGeneratorNames(); const generatorChoicePromises = _.map(generatorNames, genName => { - return this.getGeneratorChoice(genName, type); + return this.getGeneratorChoice(genName, filter); }); const generatorChoices = await Promise.all(generatorChoicePromises); @@ -208,7 +208,7 @@ export class YeomanUI { resolve({ name: "Choose Generator", questions: [generatorQuestion] }); } - private async getGeneratorChoice(genName: string, type?: Type): Promise { + private async getGeneratorChoice(genName: string, filter?: GeneratorFilter): Promise { let packageJson: any; const genPackagePath = this.getGenMetaPackagePath(genName); @@ -218,9 +218,10 @@ export class YeomanUI { return; } - if (type) { + const filterType = _.get(filter, "type"); + if (filterType) { const genType: string = _.get(packageJson, ["generator-filter", "type"]); - if (type === genType) { + if (filterType === genType) { return this.createGeneratorChoice(genName, genPackagePath, packageJson); } } else { diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index e775cb5de..013590163 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -10,7 +10,7 @@ import * as defaultImage from "../src/defaultImage"; import * as yeomanEnv from "yeoman-environment"; import { YouiLog } from "../src/youi-log"; import { IMethod, IPromiseCallbacks, IRpc } from "@sap-devx/webview-rpc/out.ext/rpc-common"; -import { Type } from "../src/filter"; +import { GeneratorType, GeneratorFilter } from "../src/filter"; describe('yeomanui unit test', () => { let sandbox: any; @@ -169,7 +169,9 @@ describe('yeomanui unit test', () => { fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); - const result = await yeomanUi.getGenerators(Type.project); + const genFilter = new GeneratorFilter(); + genFilter.type = GeneratorType.project; + const result = await yeomanUi.getGenerators(genFilter); expect(result.questions[0].choices).to.have.lengthOf(2); const test1Choice = result.questions[0].choices[0]; @@ -206,7 +208,9 @@ describe('yeomanui unit test', () => { fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); - const result = await yeomanUi.getGenerators(Type.module); + const genFilter = new GeneratorFilter(); + genFilter.type = GeneratorType.module; + const result = await yeomanUi.getGenerators(genFilter); expect(result.questions[0].choices).to.have.lengthOf(1); const test1Choice = result.questions[0].choices[0]; From 6deac22852b8878d736488652d0484c93d196ae8 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Sun, 15 Dec 2019 07:39:40 +0200 Subject: [PATCH 07/19] update dependencies --- backend/.nycrc.json | 2 +- backend/src/datauri.ts | 1 - backend/src/yeomanui.ts | 20 +++++++++++++------- backend/tests/yeomanui.spec.ts | 4 +--- 4 files changed, 15 insertions(+), 12 deletions(-) delete mode 100644 backend/src/datauri.ts diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 31c4898ce..bf977ef63 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -9,6 +9,6 @@ "check-coverage": true, "branches": 9, "lines": 29, - "functions": 20, + "functions": 21, "statements": 29 } diff --git a/backend/src/datauri.ts b/backend/src/datauri.ts deleted file mode 100644 index 6172e48a8..000000000 --- a/backend/src/datauri.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'datauri'; \ No newline at end of file diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index 600dc13e3..28f60977c 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -5,7 +5,7 @@ import * as fsextra from "fs-extra"; import * as _ from "lodash"; import * as Environment from "yeoman-environment"; import * as inquirer from "inquirer"; -import * as datauri from "datauri"; +const datauri = require("datauri"); import * as defaultImage from "./defaultImage"; import { YouiAdapter } from "./youi-adapter"; import { YouiLog } from "./youi-log"; @@ -96,12 +96,13 @@ export class YeomanUI { const meta: Environment.GeneratorMeta = this.getGenMetadata(generatorName); // TODO: support sub-generators env.register(meta.resolved); - const gen: any = env.create(`${generatorName}:app`, {}); + const getGenMetadataName = this.getGenMetaName(generatorName); + const gen: any = env.create(getGenMetadataName, {}); // check if generator defined a helper function called getPrompts() const genGetPrompts = _.get(gen, "getPromts"); if (genGetPrompts) { const promptNames: any[] = genGetPrompts(); - const prompts: IPrompt[] = promptNames.map((value) => { + const prompts: IPrompt[] = promptNames.map(value => { return _.assign({ questions: [], name: "" }, value); }); this.setPrompts(prompts); @@ -109,9 +110,9 @@ export class YeomanUI { const genGetImage = _.get(gen, "getImage"); if (genGetImage) { - const image: string | Promise | undefined = genGetImage(); - if ((image as any)["then"]) { - (image as any)["then"]((contents: string) => { + const image: any = genGetImage(); + if (image.then) { + image.then((contents: string) => { console.log(`image contents: ${contents}`); }); } else if (image !== undefined) { @@ -257,7 +258,12 @@ export class YeomanUI { } private getGenMetadata(genName: string): Environment.GeneratorMeta { - return _.get(this, ["genMeta", `${genName}:app`]); + const metadataName: string = this.getGenMetaName(genName); + return _.get(this, ["genMeta", metadataName]); + } + + private getGenMetaName(genName: string): string { + return `${genName}:app`; } /** diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index 013590163..49e073b72 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -1,12 +1,10 @@ import * as sinon from "sinon"; -import * as mocha from "mocha"; -import * as datauri from "datauri"; +const datauri = require("datauri"); import * as fsextra from "fs-extra"; import { expect } from "chai"; import * as _ from "lodash"; import * as path from "path"; import {YeomanUI, IGeneratorQuestion} from "../src/yeomanui"; -import * as defaultImage from "../src/defaultImage"; import * as yeomanEnv from "yeoman-environment"; import { YouiLog } from "../src/youi-log"; import { IMethod, IPromiseCallbacks, IRpc } from "@sap-devx/webview-rpc/out.ext/rpc-common"; From f2663647925a6f8b524205fc927936e03a0a0074 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Sun, 15 Dec 2019 13:33:26 +0200 Subject: [PATCH 08/19] set filter --- backend/.nycrc.json | 8 ++++---- backend/package.json | 6 +++--- backend/src/extension.ts | 37 ++++++++++++++++++++-------------- backend/src/filter.ts | 4 ++-- backend/src/yeomanui.ts | 17 ++++++++++------ backend/src/youi-adapter.ts | 9 +++++---- backend/tests/yeomanui.spec.ts | 13 ++++++------ generator-foodq/package.json | 3 +++ 8 files changed, 57 insertions(+), 40 deletions(-) diff --git a/backend/.nycrc.json b/backend/.nycrc.json index bf977ef63..44583638b 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -7,8 +7,8 @@ "temp-dir": "./reports/.nyc_output", "report-dir": "./reports/coverage", "check-coverage": true, - "branches": 9, - "lines": 29, - "functions": 21, - "statements": 29 + "branches": 11, + "lines": 30, + "functions": 23, + "statements": 30 } diff --git a/backend/package.json b/backend/package.json index 3643bd823..990ad4add 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,14 +14,14 @@ ], "activationEvents": [ "*", - "onCommand:sap.loadYeomanUI" + "onCommand:sap.loadYeomanUI_projects" ], "main": "./dist/extension", "contributes": { "commands": [ { - "command": "sap.loadYeomanUI", - "title": "Yeoman User Interface" + "command": "sap.loadYeomanUI_projects", + "title": "Yeoman User Interface (projects)" } ] }, diff --git a/backend/src/extension.ts b/backend/src/extension.ts index 9e7c89b72..3b576ef4e 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -1,17 +1,19 @@ -import * as fs from 'fs'; +import * as fsextra from 'fs-extra'; +import * as _ from 'lodash'; import * as path from 'path'; import * as vscode from 'vscode'; import { YeomanUI } from "./yeomanui"; import {RpcExtension} from '@sap-devx/webview-rpc/out.ext/rpc-extension'; import { YouiLog } from "./youi-log"; import { OutputChannelLog } from './output-channel-log'; +import { GeneratorFilter, GeneratorType } from './filter'; + export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( - vscode.commands.registerCommand('sap.loadYeomanUI', () => { - YeomanUIPanel.createOrShow(context.extensionPath); - }) - ); + vscode.commands.registerCommand('sap.loadYeomanUI_projects', () => { + YeomanUIPanel.createOrShow(context.extensionPath, new GeneratorFilter(GeneratorType.project)); + })); if (vscode.window.registerWebviewPanelSerializer) { // Make sure we register a serializer in activation event @@ -33,11 +35,12 @@ export class YeomanUIPanel { */ public static readonly viewType = 'yeomanui'; public static currentPanel: YeomanUIPanel | undefined; + public static genFilter: GeneratorFilter; + + public static createOrShow(extensionPath: string, genFilter?: GeneratorFilter) { + YeomanUIPanel.genFilter = genFilter; - public static createOrShow(extensionPath: string) { - const column = vscode.window.activeTextEditor - ? vscode.window.activeTextEditor.viewColumn - : undefined; + const column = _.get(vscode.window, "activeTextEditor.viewColumn"); // If we already have a panel, show it. if (YeomanUIPanel.currentPanel) { @@ -55,7 +58,7 @@ export class YeomanUIPanel { enableScripts: true, // And restrict the webview to only loading content from our extension's `media` directory. - localResourceRoots: [vscode.Uri.file(path.join(extensionPath, 'dist', 'media'))] + localResourceRoots: [vscode.Uri.file(YeomanUIPanel.getMediaPath(extensionPath))] } ); @@ -73,13 +76,15 @@ export class YeomanUIPanel { private disposables: vscode.Disposable[] = []; private questionsResolutions: Map; - private constructor(panel: vscode.WebviewPanel, extensionPath: string) { + private constructor(panel: vscode.WebviewPanel, extensionPath: string, genFilter?: GeneratorFilter) { this.questionsResolutions = new Map(); this.panel = panel; this.extensionPath = extensionPath; this.rpc = new RpcExtension(this.panel.webview); const logger: YouiLog = new OutputChannelLog(); + this.yeomanui = new YeomanUI(this.rpc, logger); + this.yeomanui.setGenFilter(genFilter); // Set the webview's initial html content this._update(); @@ -131,14 +136,16 @@ export class YeomanUIPanel { } } + private static getMediaPath(extensionPath: string): string { + return path.join(extensionPath, 'dist', 'media'); + } + private _update() { // TODO: don't use sync - let indexHtml: string = fs.readFileSync(path.join(this.extensionPath, 'dist', 'media', 'index.html'), "utf8"); + let indexHtml: string = fsextra.readFileSync(path.join(YeomanUIPanel.getMediaPath(this.extensionPath), 'index.html'), "utf8"); if (indexHtml) { // Local path to main script run in the webview - const scriptPathOnDisk = vscode.Uri.file( - path.join(this.extensionPath, 'dist', 'media', path.sep) - ); + const scriptPathOnDisk = vscode.Uri.file(path.join(YeomanUIPanel.getMediaPath(this.extensionPath), path.sep)); const scriptUri = this.panel.webview.asWebviewUri(scriptPathOnDisk); // TODO: very fragile: assuming double quotes and src is first attribute diff --git a/backend/src/filter.ts b/backend/src/filter.ts index 721193ad6..e717736d8 100644 --- a/backend/src/filter.ts +++ b/backend/src/filter.ts @@ -4,6 +4,6 @@ export enum GeneratorType { } export class GeneratorFilter { - type?: GeneratorType; - category?: string[]; + constructor(public readonly type?: GeneratorType, + public readonly category: string[] = []) {} } diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index 28f60977c..f1d68bbd7 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -47,6 +47,7 @@ export class YeomanUI { private gen: Generator | undefined; private promptCount: number; private currentQuestions: Environment.Adapter.Questions; + private genFilter: GeneratorFilter; constructor(rpc: IRpc, logger: YouiLog) { this.rpc = rpc; @@ -63,19 +64,23 @@ export class YeomanUI { this.currentQuestions = {}; } - public async getGenerators(filter?: GeneratorFilter): Promise { + public setGenFilter(genFilter?: GeneratorFilter) { + this.genFilter = genFilter; + } + + public async getGenerators(): Promise { // optimization: looking up generators takes a long time, so if generators are already loaded don't bother // on the other hand, we never look for newly installed generators... const promise: Promise = new Promise(resolve => { const env: Environment.Options = Environment.createEnv(); - env.lookup(async () => this.onEnvLookup(env, resolve, filter)); + env.lookup(async () => this.onEnvLookup(env, resolve, this.genFilter)); }); return promise; } - public runGenerator(generatorName: string) { + public async runGenerator(generatorName: string) { // TODO: ensure generatorName is a valid dir name const destinationRoot: string = path.join(os.homedir(), "projects", generatorName); @@ -164,12 +169,12 @@ export class YeomanUI { } } - public async receiveIsWebviewReady(filter?: GeneratorFilter) { + public async receiveIsWebviewReady() { // TODO: loading generators takes a long time; consider prefetching list of generators if (this.rpc) { - const generators: IPrompt = await this.getGenerators(filter); + const generators: IPrompt = await this.getGenerators(); const response: any = await this.rpc.invoke("showPrompt", [generators.questions, generators.name]); - this.runGenerator(response.name); + await this.runGenerator(response.name); } } diff --git a/backend/src/youi-adapter.ts b/backend/src/youi-adapter.ts index 7d89711e0..1497f999d 100644 --- a/backend/src/youi-adapter.ts +++ b/backend/src/youi-adapter.ts @@ -1,6 +1,7 @@ import { Adapter } from "yeoman-environment"; import { YeomanUI } from "./yeomanui"; import { YouiLog } from "./youi-log"; +import * as _ from "lodash"; const chalk = require('chalk'); /** @@ -62,12 +63,12 @@ export class YouiAdapter implements Adapter { try { return cb(result as any); } catch (err) { - this.yeomanui.doGeneratorDone(false, (err.message ? err.message : 'Yeoman UI detected an error')); + this.yeomanui.doGeneratorDone(false, (_.get(err, "message", 'Yeoman UI detected an error'))); return; } - } else { - return result; - } + } + + return result; }).catch((reason) => { throw reason; }); diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index 49e073b72..f854b4b87 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -167,9 +167,9 @@ describe('yeomanui unit test', () => { fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); - const genFilter = new GeneratorFilter(); - genFilter.type = GeneratorType.project; - const result = await yeomanUi.getGenerators(genFilter); + const genFilter = new GeneratorFilter(GeneratorType.project); + yeomanUi.setGenFilter(genFilter); + const result = await yeomanUi.getGenerators(); expect(result.questions[0].choices).to.have.lengthOf(2); const test1Choice = result.questions[0].choices[0]; @@ -206,9 +206,9 @@ describe('yeomanui unit test', () => { fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); - const genFilter = new GeneratorFilter(); - genFilter.type = GeneratorType.module; - const result = await yeomanUi.getGenerators(genFilter); + const genFilter = new GeneratorFilter(GeneratorType.module); + yeomanUi.setGenFilter(genFilter); + const result = await yeomanUi.getGenerators(); expect(result.questions[0].choices).to.have.lengthOf(1); const test1Choice = result.questions[0].choices[0]; @@ -242,6 +242,7 @@ describe('yeomanui unit test', () => { fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); + yeomanUi.setGenFilter(); const result = await yeomanUi.getGenerators(); expect(result.questions[0].choices).to.have.lengthOf(5); diff --git a/generator-foodq/package.json b/generator-foodq/package.json index 4e494a973..e9986ed13 100644 --- a/generator-foodq/package.json +++ b/generator-foodq/package.json @@ -22,5 +22,8 @@ "yeoman-generator": "^1.1.1", "chalk": "^2.0.0", "inquirer": "^6.2.2" + }, + "generator-filter": { + "type": "project" } } From 2691f6ffc5536f0bc39e6a4df39420f883a0ea10 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Sun, 15 Dec 2019 14:11:49 +0200 Subject: [PATCH 09/19] add command to show all projects --- backend/.nycrc.json | 2 +- backend/package.json | 16 +++++++++------- backend/src/extension.ts | 14 ++++++++++---- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 44583638b..7f1a636f6 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -8,7 +8,7 @@ "report-dir": "./reports/coverage", "check-coverage": true, "branches": 11, - "lines": 30, + "lines": 29, "functions": 23, "statements": 30 } diff --git a/backend/package.json b/backend/package.json index 990ad4add..3c98d7b7b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,16 +14,18 @@ ], "activationEvents": [ "*", - "onCommand:sap.loadYeomanUI_projects" + "onCommand:sap.loadYeomanUI_projects", + "onCommand:sap.loadYeomanUI_all" ], "main": "./dist/extension", "contributes": { - "commands": [ - { - "command": "sap.loadYeomanUI_projects", - "title": "Yeoman User Interface (projects)" - } - ] + "commands": [{ + "command": "sap.loadYeomanUI_projects", + "title": "Yeoman User Interface (projects)" + }, { + "command": "sap.loadYeomanUI_all", + "title": "Yeoman User Interface" + }] }, "scripts": { "frontend": "npm run frontend:install && npm run frontend:build && npm run frontend:copy", diff --git a/backend/src/extension.ts b/backend/src/extension.ts index 3b576ef4e..4a82e8581 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -11,8 +11,13 @@ import { GeneratorFilter, GeneratorType } from './filter'; export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( - vscode.commands.registerCommand('sap.loadYeomanUI_projects', () => { - YeomanUIPanel.createOrShow(context.extensionPath, new GeneratorFilter(GeneratorType.project)); + vscode.commands.registerCommand('sap.loadYeomanUI_projects', () => { + YeomanUIPanel.createOrShow(context.extensionPath, new GeneratorFilter(GeneratorType.project)); + })); + + context.subscriptions.push( + vscode.commands.registerCommand('sap.loadYeomanUI_all', () => { + YeomanUIPanel.createOrShow(context.extensionPath); })); if (vscode.window.registerWebviewPanelSerializer) { @@ -44,6 +49,7 @@ export class YeomanUIPanel { // If we already have a panel, show it. if (YeomanUIPanel.currentPanel) { + YeomanUIPanel.currentPanel.yeomanui.setGenFilter(YeomanUIPanel.genFilter); YeomanUIPanel.currentPanel.panel.reveal(column); return; } @@ -76,7 +82,7 @@ export class YeomanUIPanel { private disposables: vscode.Disposable[] = []; private questionsResolutions: Map; - private constructor(panel: vscode.WebviewPanel, extensionPath: string, genFilter?: GeneratorFilter) { + private constructor(panel: vscode.WebviewPanel, extensionPath: string) { this.questionsResolutions = new Map(); this.panel = panel; this.extensionPath = extensionPath; @@ -84,7 +90,7 @@ export class YeomanUIPanel { const logger: YouiLog = new OutputChannelLog(); this.yeomanui = new YeomanUI(this.rpc, logger); - this.yeomanui.setGenFilter(genFilter); + this.yeomanui.setGenFilter(YeomanUIPanel.genFilter); // Set the webview's initial html content this._update(); From 05037442be72207e0292f1823c1fc8922c84f8cf Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Sun, 15 Dec 2019 14:30:46 +0200 Subject: [PATCH 10/19] expose command method --- backend/.nycrc.json | 2 +- backend/src/extension.ts | 17 +++++++++++++---- backend/src/filter.ts | 10 ++++++++-- backend/tests/yeomanui.spec.ts | 4 ++-- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 7f1a636f6..457f85077 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -9,6 +9,6 @@ "check-coverage": true, "branches": 11, "lines": 29, - "functions": 23, + "functions": 24, "statements": 30 } diff --git a/backend/src/extension.ts b/backend/src/extension.ts index 4a82e8581..687ac1b83 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -6,18 +6,20 @@ import { YeomanUI } from "./yeomanui"; import {RpcExtension} from '@sap-devx/webview-rpc/out.ext/rpc-extension'; import { YouiLog } from "./youi-log"; import { OutputChannelLog } from './output-channel-log'; -import { GeneratorFilter, GeneratorType } from './filter'; - +import { GeneratorFilter } from './filter'; +let thisContext: vscode.ExtensionContext; export function activate(context: vscode.ExtensionContext) { + thisContext = context; + context.subscriptions.push( vscode.commands.registerCommand('sap.loadYeomanUI_projects', () => { - YeomanUIPanel.createOrShow(context.extensionPath, new GeneratorFilter(GeneratorType.project)); + openYeomanUi({"type": "project"}); })); context.subscriptions.push( vscode.commands.registerCommand('sap.loadYeomanUI_all', () => { - YeomanUIPanel.createOrShow(context.extensionPath); + openYeomanUi(); })); if (vscode.window.registerWebviewPanelSerializer) { @@ -29,6 +31,13 @@ export function activate(context: vscode.ExtensionContext) { } }); } + + // expose method to all vsix extensions + return {"openYeomanUi": openYeomanUi}; +} + +export function openYeomanUi(genFilter?: any) { + YeomanUIPanel.createOrShow(thisContext.extensionPath, GeneratorFilter.create(genFilter)); } /** diff --git a/backend/src/filter.ts b/backend/src/filter.ts index e717736d8..60eb70c3b 100644 --- a/backend/src/filter.ts +++ b/backend/src/filter.ts @@ -1,9 +1,15 @@ +import * as _ from "lodash"; + export enum GeneratorType { project = "project", module = "module" } export class GeneratorFilter { - constructor(public readonly type?: GeneratorType, - public readonly category: string[] = []) {} + private constructor(public readonly type?: GeneratorType, + public readonly cetegories: string[] = []) {} + + public static create(filterObject: any) { + return new GeneratorFilter(_.get(filterObject, "type"), _.get(filterObject, "cetegories")); + } } diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index f854b4b87..d4d8cd8a7 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -167,7 +167,7 @@ describe('yeomanui unit test', () => { fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); - const genFilter = new GeneratorFilter(GeneratorType.project); + const genFilter = GeneratorFilter.create({type: GeneratorType.project}); yeomanUi.setGenFilter(genFilter); const result = await yeomanUi.getGenerators(); @@ -206,7 +206,7 @@ describe('yeomanui unit test', () => { fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); - const genFilter = new GeneratorFilter(GeneratorType.module); + const genFilter = GeneratorFilter.create({type: GeneratorType.module}); yeomanUi.setGenFilter(genFilter); const result = await yeomanUi.getGenerators(); From 54f172d7332e12f7e9f8f2c4230f7a7dcd788fda Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Sun, 15 Dec 2019 14:36:10 +0200 Subject: [PATCH 11/19] update logic --- backend/src/filter.ts | 2 +- backend/tests/yeomanui.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/filter.ts b/backend/src/filter.ts index 60eb70c3b..9882e7591 100644 --- a/backend/src/filter.ts +++ b/backend/src/filter.ts @@ -6,7 +6,7 @@ export enum GeneratorType { } export class GeneratorFilter { - private constructor(public readonly type?: GeneratorType, + public constructor(public readonly type?: GeneratorType, public readonly cetegories: string[] = []) {} public static create(filterObject: any) { diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index d4d8cd8a7..813556361 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -167,7 +167,7 @@ describe('yeomanui unit test', () => { fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); - const genFilter = GeneratorFilter.create({type: GeneratorType.project}); + const genFilter: GeneratorFilter = GeneratorFilter.create({type: GeneratorType.project}); yeomanUi.setGenFilter(genFilter); const result = await yeomanUi.getGenerators(); From b090543fb4bbd93efbf0e32f32221b9bed4b643f Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Sun, 15 Dec 2019 15:10:46 +0200 Subject: [PATCH 12/19] fix filter logic --- backend/.nycrc.json | 6 +++--- backend/src/filter.ts | 11 ++++++++--- backend/src/yeomanui.ts | 4 ++-- backend/tests/yeomanui.spec.ts | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 457f85077..7f2601aa9 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -7,8 +7,8 @@ "temp-dir": "./reports/.nyc_output", "report-dir": "./reports/coverage", "check-coverage": true, - "branches": 11, - "lines": 29, + "branches": 14, + "lines": 30, "functions": 24, - "statements": 30 + "statements": 31 } diff --git a/backend/src/filter.ts b/backend/src/filter.ts index 9882e7591..e3fe78325 100644 --- a/backend/src/filter.ts +++ b/backend/src/filter.ts @@ -6,10 +6,15 @@ export enum GeneratorType { } export class GeneratorFilter { - public constructor(public readonly type?: GeneratorType, - public readonly cetegories: string[] = []) {} + private constructor(public type?: GeneratorType, + public cetegories: string[] = []) {} public static create(filterObject: any) { - return new GeneratorFilter(_.get(filterObject, "type"), _.get(filterObject, "cetegories")); + const genType: GeneratorType = _.get(filterObject, "type"); + if (_.includes(_.values(GeneratorType), genType)) { + return new GeneratorFilter(genType); + } + + return new GeneratorFilter(); } } diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index f1d68bbd7..fdedb2142 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -226,8 +226,8 @@ export class YeomanUI { const filterType = _.get(filter, "type"); if (filterType) { - const genType: string = _.get(packageJson, ["generator-filter", "type"]); - if (filterType === genType) { + const genFilter: GeneratorFilter = GeneratorFilter.create(_.get(packageJson, ["generator-filter"])); + if (filterType === genFilter.type) { return this.createGeneratorChoice(genName, genPackagePath, packageJson); } } else { diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index 813556361..04002db20 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -1,3 +1,4 @@ +import * as mocha from "mocha"; import * as sinon from "sinon"; const datauri = require("datauri"); import * as fsextra from "fs-extra"; @@ -278,5 +279,22 @@ describe('yeomanui unit test', () => { expect(result.questions[0].choices).to.have.lengthOf(3); }); + + it("wrong generators filter type is provided", async () => { + envMock.expects("getGeneratorsMeta").returns({ + "test1:app": { + packagePath: "test1Path" + } + }); + envMock.expects("getGeneratorNames").returns(["test1"]); + + fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project123"}, "description": "test4Description"}`); + + yeomanUi.setGenFilter(GeneratorFilter.create({type: GeneratorType.project})); + const result = await yeomanUi.getGenerators(); + + // tslint:disable-next-line: no-unused-expression + expect(result.questions[0].choices).to.be.empty; + }); }); }); From bd5024e75c3e1149219db9897433a85ae666a78f Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Mon, 16 Dec 2019 07:36:36 +0200 Subject: [PATCH 13/19] expose command as API --- backend/.nycrc.json | 2 +- backend/package.json | 12 ++++++------ backend/src/extension.ts | 17 ++++------------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 7f2601aa9..7ec14c69e 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -8,7 +8,7 @@ "report-dir": "./reports/coverage", "check-coverage": true, "branches": 14, - "lines": 30, + "lines": 31, "functions": 24, "statements": 31 } diff --git a/backend/package.json b/backend/package.json index 3c98d7b7b..eb2941684 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,17 +14,17 @@ ], "activationEvents": [ "*", - "onCommand:sap.loadYeomanUI_projects", - "onCommand:sap.loadYeomanUI_all" + "onCommand:loadYeomanUI_projects", + "onCommand:loadYeomanUI" ], "main": "./dist/extension", "contributes": { "commands": [{ - "command": "sap.loadYeomanUI_projects", - "title": "Yeoman User Interface (projects)" + "command": "loadYeomanUI_projects", + "title": "Yeoman UI Project Generators" }, { - "command": "sap.loadYeomanUI_all", - "title": "Yeoman User Interface" + "command": "loadYeomanUI", + "title": "Yeoman UI Generators" }] }, "scripts": { diff --git a/backend/src/extension.ts b/backend/src/extension.ts index 687ac1b83..c5f9b9bdb 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -10,16 +10,14 @@ import { GeneratorFilter } from './filter'; let thisContext: vscode.ExtensionContext; export function activate(context: vscode.ExtensionContext) { - thisContext = context; - context.subscriptions.push( - vscode.commands.registerCommand('sap.loadYeomanUI_projects', () => { - openYeomanUi({"type": "project"}); + vscode.commands.registerCommand('loadYeomanUI', (genFilter?: GeneratorFilter) => { + YeomanUIPanel.createOrShow(context.extensionPath, GeneratorFilter.create(genFilter)); })); context.subscriptions.push( - vscode.commands.registerCommand('sap.loadYeomanUI_all', () => { - openYeomanUi(); + vscode.commands.registerCommand('loadYeomanUI_projects', () => { + vscode.commands.executeCommand("loadYeomanUI", GeneratorFilter.create({"type": "project"})); })); if (vscode.window.registerWebviewPanelSerializer) { @@ -31,13 +29,6 @@ export function activate(context: vscode.ExtensionContext) { } }); } - - // expose method to all vsix extensions - return {"openYeomanUi": openYeomanUi}; -} - -export function openYeomanUi(genFilter?: any) { - YeomanUIPanel.createOrShow(thisContext.extensionPath, GeneratorFilter.create(genFilter)); } /** From 55663bb2202a02d6ece94065cf5d44c15a1af9ec Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Mon, 16 Dec 2019 07:40:53 +0200 Subject: [PATCH 14/19] expose command as API --- backend/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/extension.ts b/backend/src/extension.ts index c5f9b9bdb..22f6f4dec 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -8,7 +8,7 @@ import { YouiLog } from "./youi-log"; import { OutputChannelLog } from './output-channel-log'; import { GeneratorFilter } from './filter'; -let thisContext: vscode.ExtensionContext; + export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand('loadYeomanUI', (genFilter?: GeneratorFilter) => { From 42648925330236a328ad2e6aad53b39e66048489 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Mon, 16 Dec 2019 08:18:17 +0200 Subject: [PATCH 15/19] add extension tests --- backend/.nycrc.json | 8 ++-- backend/src/extension.ts | 2 +- backend/tests/extension.spec.ts | 73 +++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 backend/tests/extension.spec.ts diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 7ec14c69e..2a5fb7d39 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -7,8 +7,8 @@ "temp-dir": "./reports/.nyc_output", "report-dir": "./reports/coverage", "check-coverage": true, - "branches": 14, - "lines": 31, - "functions": 24, - "statements": 31 + "branches": 15, + "lines": 38, + "functions": 28, + "statements": 38 } diff --git a/backend/src/extension.ts b/backend/src/extension.ts index 22f6f4dec..a5a118855 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -11,7 +11,7 @@ import { GeneratorFilter } from './filter'; export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( - vscode.commands.registerCommand('loadYeomanUI', (genFilter?: GeneratorFilter) => { + vscode.commands.registerCommand('loadYeomanUI', (genFilter?: any) => { YeomanUIPanel.createOrShow(context.extensionPath, GeneratorFilter.create(genFilter)); })); diff --git a/backend/tests/extension.spec.ts b/backend/tests/extension.spec.ts new file mode 100644 index 000000000..c928ec794 --- /dev/null +++ b/backend/tests/extension.spec.ts @@ -0,0 +1,73 @@ +import * as mocha from "mocha"; +import { expect } from "chai"; +import * as sinon from "sinon"; +import * as _ from "lodash"; +import { mockVscode } from "./mockUtil"; +import { GeneratorFilter } from "../src/filter"; + +const oRegisteredCommands = {}; +const testVscode = { + commands: { + registerCommand: (id: string, cmd: any) => { _.set(oRegisteredCommands, id, cmd); return Promise.resolve(oRegisteredCommands); }, + executeCommand: () => Promise.reject() + }, + window: {} +}; +mockVscode(testVscode, "src/extension.ts"); +import * as extension from "../src/extension"; + +describe('extension unit test', () => { + let sandbox: any; + let commandsMock: any; + let windowMock: any; + let yeomanUiPanelMock: any; + + before(() => { + sandbox = sinon.createSandbox(); + }); + + after(() => { + sandbox.restore(); + }); + + beforeEach(() => { + commandsMock = sandbox.mock(testVscode.commands); + windowMock = sandbox.mock(testVscode.window); + yeomanUiPanelMock = sandbox.mock(extension.YeomanUIPanel); + }); + + afterEach(() => { + commandsMock.verify(); + windowMock.verify(); + yeomanUiPanelMock.verify(); + }); + + describe('activate', () => { + let testContext: any; + beforeEach(() => { + testContext = { subscriptions: [], extensionPath: "testExtensionpath" }; + }); + + it("commands registration", () => { + extension.activate(testContext); + expect(_.size(_.keys(oRegisteredCommands))).to.be.equal(2); + expect(_.keys(oRegisteredCommands)[0]).to.be.equal("loadYeomanUI"); + expect(_.keys(oRegisteredCommands)[1]).to.be.equal("loadYeomanUI_projects"); + }); + + it("execution loadYeomanUI command", () => { + extension.activate(testContext); + const loadYeomanUICommand = _.get(oRegisteredCommands, "loadYeomanUI"); + yeomanUiPanelMock.expects("createOrShow").withExactArgs(testContext.extensionPath, GeneratorFilter.create({})); + loadYeomanUICommand(); + }); + + it("execution loadYeomanUI_projects command", () => { + extension.activate(testContext); + + const loadYeomanUIProjectsCommand = _.get(oRegisteredCommands, "loadYeomanUI_projects"); + commandsMock.expects("executeCommand").withExactArgs("loadYeomanUI", GeneratorFilter.create({"type": "project"})); + loadYeomanUIProjectsCommand(); + }); + }); +}); \ No newline at end of file From 4c7ceffbb370f94092785ff9845da575dd40af63 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Mon, 16 Dec 2019 13:18:40 +0200 Subject: [PATCH 16/19] add filter test --- backend/.nycrc.json | 8 ++++---- backend/src/filter.ts | 35 +++++++++++++++++++++++++-------- backend/tests/filter.spec.ts | 38 ++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 backend/tests/filter.spec.ts diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 2a5fb7d39..756c4ef1d 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -7,8 +7,8 @@ "temp-dir": "./reports/.nyc_output", "report-dir": "./reports/coverage", "check-coverage": true, - "branches": 15, - "lines": 38, - "functions": 28, - "statements": 38 + "branches": 19, + "lines": 40, + "functions": 30, + "statements": 40 } diff --git a/backend/src/filter.ts b/backend/src/filter.ts index e3fe78325..2345e27e6 100644 --- a/backend/src/filter.ts +++ b/backend/src/filter.ts @@ -5,16 +5,35 @@ export enum GeneratorType { module = "module" } +function getCategories(filterObject?: any): string[] { + const categories: string[] = _.get(filterObject, 'categories', []); + if (_.isArray(categories)) { + const strValues = _.filter(categories, category => { + return _.isString(category); + }); + if (_.isEmpty(_.difference(categories, strValues))) { + return categories; + } + } + + return []; +} + +function getType(filterObject?: any): GeneratorType { + const genType: GeneratorType = _.get(filterObject, "type"); + if (_.includes(_.values(GeneratorType), genType)) { + return GeneratorType[genType]; + } +} + export class GeneratorFilter { - private constructor(public type?: GeneratorType, - public cetegories: string[] = []) {} + constructor(public readonly type?: GeneratorType, + public readonly categories: string[] = []) {} - public static create(filterObject: any) { - const genType: GeneratorType = _.get(filterObject, "type"); - if (_.includes(_.values(GeneratorType), genType)) { - return new GeneratorFilter(genType); - } + public static create(filterObject?: any) { + const categories: string[] = getCategories(filterObject); + const type: GeneratorType = getType(filterObject); - return new GeneratorFilter(); + return new GeneratorFilter(type, categories); } } diff --git a/backend/tests/filter.spec.ts b/backend/tests/filter.spec.ts new file mode 100644 index 000000000..a2d9f6a6e --- /dev/null +++ b/backend/tests/filter.spec.ts @@ -0,0 +1,38 @@ +import * as mocha from "mocha"; +import { expect } from "chai"; + +import {GeneratorFilter, GeneratorType} from "../src/filter"; + +describe('filter unit test', () => { + it('categories property is not of array type', () => { + const genFilter: GeneratorFilter = GeneratorFilter.create({categories: {}}); + expect(genFilter.categories).to.be.deep.equal([]); + }); + + it('categories property array hold values other than strings', () => { + const genFilter: GeneratorFilter = GeneratorFilter.create({categories: ["test", true, {}]}); + expect(genFilter.categories).to.be.deep.equal([]); + }); + + it('type property is not equal to any declared type property', () => { + const testCategories: string[] = ["test1", "test2"]; + const genFilter: GeneratorFilter = GeneratorFilter.create({type: "test123", categories: testCategories}); + // tslint:disable-next-line: no-unused-expression + expect(genFilter.type).to.be.undefined; + expect(genFilter.categories).to.be.deep.equal(testCategories); + }); + + it('type property is project and category property has strings in array ', () => { + const testCategories: string[] = ["test1", "test2"]; + const genFilter: GeneratorFilter = GeneratorFilter.create({type: "project", categories: testCategories}); + expect(genFilter.type).to.be.equal(GeneratorType.project); + expect(genFilter.categories).to.be.deep.equal(testCategories); + }); + + it('type property is module and category property has strings in array ', () => { + const testCategories: string[] = ["test1", "test2"]; + const genFilter: GeneratorFilter = GeneratorFilter.create({type: "module", categories: testCategories}); + expect(genFilter.type).to.be.equal(GeneratorType.module); + expect(genFilter.categories).to.be.deep.equal(testCategories); + }); +}); \ No newline at end of file From 3ba00f678a89b1b3566274320cc098be23078f14 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Mon, 16 Dec 2019 14:05:10 +0200 Subject: [PATCH 17/19] add more tests --- backend/.nycrc.json | 6 ++--- backend/src/filter.ts | 13 +++++---- backend/src/yeomanui.ts | 17 ++++++------ backend/tests/filter.spec.ts | 2 +- backend/tests/yeomanui.spec.ts | 49 +++++++++++++++++++++++++++++++--- 5 files changed, 66 insertions(+), 21 deletions(-) diff --git a/backend/.nycrc.json b/backend/.nycrc.json index 756c4ef1d..d698f9e7a 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -7,8 +7,8 @@ "temp-dir": "./reports/.nyc_output", "report-dir": "./reports/coverage", "check-coverage": true, - "branches": 19, - "lines": 40, + "branches": 22, + "lines": 41, "functions": 30, - "statements": 40 + "statements": 41 } diff --git a/backend/src/filter.ts b/backend/src/filter.ts index 2345e27e6..749e59c10 100644 --- a/backend/src/filter.ts +++ b/backend/src/filter.ts @@ -2,7 +2,8 @@ import * as _ from "lodash"; export enum GeneratorType { project = "project", - module = "module" + module = "module", + all = "all" } function getCategories(filterObject?: any): string[] { @@ -20,15 +21,17 @@ function getCategories(filterObject?: any): string[] { } function getType(filterObject?: any): GeneratorType { - const genType: GeneratorType = _.get(filterObject, "type"); + const genType: GeneratorType = _.get(filterObject, "type", GeneratorType.all); if (_.includes(_.values(GeneratorType), genType)) { - return GeneratorType[genType]; + return genType; } + + return GeneratorType.all; } export class GeneratorFilter { - constructor(public readonly type?: GeneratorType, - public readonly categories: string[] = []) {} + constructor(public readonly type: GeneratorType, + public readonly categories: string[]) {} public static create(filterObject?: any) { const categories: string[] = getCategories(filterObject); diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index fdedb2142..74a5ce79e 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -64,7 +64,7 @@ export class YeomanUI { this.currentQuestions = {}; } - public setGenFilter(genFilter?: GeneratorFilter) { + public setGenFilter(genFilter: GeneratorFilter) { this.genFilter = genFilter; } @@ -221,18 +221,17 @@ export class YeomanUI { try { packageJson = await this.getGenPackageJson(genPackagePath); } catch (error) { - return; + return Promise.resolve(undefined); } - const filterType = _.get(filter, "type"); - if (filterType) { - const genFilter: GeneratorFilter = GeneratorFilter.create(_.get(packageJson, ["generator-filter"])); - if (filterType === genFilter.type) { + const genFilter: GeneratorFilter = GeneratorFilter.create(_.get(packageJson, ["generator-filter"])); + const typeEqual: boolean = (filter.type === GeneratorType.all || filter.type === genFilter.type); + const categoriesHasIntersection: boolean = (_.isEmpty(filter.categories) || !_.isEmpty(_.intersection(filter.categories, genFilter.categories))); + if (typeEqual && categoriesHasIntersection) { return this.createGeneratorChoice(genName, genPackagePath, packageJson); - } - } else { - return this.createGeneratorChoice(genName, genPackagePath, packageJson); } + + return Promise.resolve(undefined); } private async createGeneratorChoice(genName: string, genPackagePath: string, packageJson: any): Promise { diff --git a/backend/tests/filter.spec.ts b/backend/tests/filter.spec.ts index a2d9f6a6e..046b66c22 100644 --- a/backend/tests/filter.spec.ts +++ b/backend/tests/filter.spec.ts @@ -18,7 +18,7 @@ describe('filter unit test', () => { const testCategories: string[] = ["test1", "test2"]; const genFilter: GeneratorFilter = GeneratorFilter.create({type: "test123", categories: testCategories}); // tslint:disable-next-line: no-unused-expression - expect(genFilter.type).to.be.undefined; + expect(genFilter.type).to.be.equal(GeneratorType.all); expect(genFilter.categories).to.be.deep.equal(testCategories); }); diff --git a/backend/tests/yeomanui.spec.ts b/backend/tests/yeomanui.spec.ts index 04002db20..3ad7b2acb 100644 --- a/backend/tests/yeomanui.spec.ts +++ b/backend/tests/yeomanui.spec.ts @@ -233,20 +233,24 @@ describe('yeomanui unit test', () => { }, "test5:app": { packagePath: "test5Path" + }, + "test6:app": { + packagePath: "test6Path" } }); - envMock.expects("getGeneratorNames").returns(["test1", "test2", "test3", "test4", "test5"]); + envMock.expects("getGeneratorNames").returns(["test1", "test2", "test3", "test4", "test5", "test6"]); fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test1Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test2Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project_test"}}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test3Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "module"}}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project"}, "description": "test4Description"}`); fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test6Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "all"}}`); - yeomanUi.setGenFilter(); + yeomanUi.setGenFilter(GeneratorFilter.create()); const result = await yeomanUi.getGenerators(); - expect(result.questions[0].choices).to.have.lengthOf(5); + expect(result.questions[0].choices).to.have.lengthOf(6); }); it("get generators with accessible package.json", async () => { @@ -296,5 +300,44 @@ describe('yeomanui unit test', () => { // tslint:disable-next-line: no-unused-expression expect(result.questions[0].choices).to.be.empty; }); + + it("get generators with type project and categories cat1 and cat2", async () => { + envMock.expects("getGeneratorsMeta").returns({ + "test1:app": { + packagePath: "test1Path" + }, + "test2:app": { + packagePath: "test2Path" + }, + "test3:app": { + packagePath: "test3Path" + }, + "test4:app": { + packagePath: "test4Path" + }, + "test5:app": { + packagePath: "test5Path" + } + }); + envMock.expects("getGeneratorNames").returns(["test1", "test2", "test3", "test4", "test5"]); + + fsExtraMock.expects("readFile").withExactArgs(path.join("test1Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project", "categories": ["cat2"]}, "description": "test1Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test2Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project", "categories": ["cat2", "cat1"]}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test3Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "module"}}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test4Path", PACKAGE_JSON), UTF8).resolves(`{"generator-filter": {"type": "project", "categories": ["cat1"]}, "description": "test4Description"}`); + fsExtraMock.expects("readFile").withExactArgs(path.join("test5Path", PACKAGE_JSON), UTF8).resolves(`{"description": "test5Description"}`); + + const genFilter: GeneratorFilter = GeneratorFilter.create({type: GeneratorType.project, categories: ["cat1", "cat2"]}); + yeomanUi.setGenFilter(genFilter); + const result = await yeomanUi.getGenerators(); + + expect(result.questions[0].choices).to.have.lengthOf(3); + const test1Choice = result.questions[0].choices[0]; + const test2Choice = result.questions[0].choices[1]; + const test3Choice = result.questions[0].choices[2]; + expect(test1Choice.name).to.be.equal("test1"); + expect(test2Choice.name).to.be.equal("test2"); + expect(test3Choice.name).to.be.equal("test4"); + }); }); }); From ef493869e13e09d3011fdeff630d0ba11d4c9e4b Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Mon, 16 Dec 2019 14:11:32 +0200 Subject: [PATCH 18/19] small fix --- backend/src/yeomanui.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index 74a5ce79e..b40f74c6b 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -65,7 +65,7 @@ export class YeomanUI { } public setGenFilter(genFilter: GeneratorFilter) { - this.genFilter = genFilter; + this.genFilter = genFilter ? genFilter : GeneratorFilter.create(); } public async getGenerators(): Promise { From d6bc5d2804e56d3a60d86ca09e02c4fe3dfcbec1 Mon Sep 17 00:00:00 2001 From: Stanislav Lvovsky Date: Mon, 16 Dec 2019 14:33:41 +0200 Subject: [PATCH 19/19] update extension test --- backend/src/extension.ts | 6 +++--- backend/tests/extension.spec.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/extension.ts b/backend/src/extension.ts index a5a118855..81b741d46 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -11,13 +11,13 @@ import { GeneratorFilter } from './filter'; export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( - vscode.commands.registerCommand('loadYeomanUI', (genFilter?: any) => { - YeomanUIPanel.createOrShow(context.extensionPath, GeneratorFilter.create(genFilter)); + vscode.commands.registerCommand('loadYeomanUI', (filterObj?: any) => { + YeomanUIPanel.createOrShow(context.extensionPath, GeneratorFilter.create(filterObj)); })); context.subscriptions.push( vscode.commands.registerCommand('loadYeomanUI_projects', () => { - vscode.commands.executeCommand("loadYeomanUI", GeneratorFilter.create({"type": "project"})); + vscode.commands.executeCommand("loadYeomanUI", {"type": "project"}); })); if (vscode.window.registerWebviewPanelSerializer) { diff --git a/backend/tests/extension.spec.ts b/backend/tests/extension.spec.ts index c928ec794..2d90141c5 100644 --- a/backend/tests/extension.spec.ts +++ b/backend/tests/extension.spec.ts @@ -66,7 +66,7 @@ describe('extension unit test', () => { extension.activate(testContext); const loadYeomanUIProjectsCommand = _.get(oRegisteredCommands, "loadYeomanUI_projects"); - commandsMock.expects("executeCommand").withExactArgs("loadYeomanUI", GeneratorFilter.create({"type": "project"})); + commandsMock.expects("executeCommand").withExactArgs("loadYeomanUI", {"type": "project"}); loadYeomanUIProjectsCommand(); }); });