diff --git a/.circleci/config.yml b/.circleci/config.yml index 7800b110..ad4c4b2f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -88,3 +88,4 @@ workflows: only: /^v.*/ branches: ignore: /.*/ + \ No newline at end of file diff --git a/backend/.nycrc.json b/backend/.nycrc.json index b07d1625..f7d5f6aa 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -8,8 +8,8 @@ "temp-dir": "./reports/.nyc_output", "report-dir": "./reports/coverage", "check-coverage": true, - "branches": 42.9, - "lines": 52.8, - "functions": 39.9, - "statements": 52.7 + "branches": 51.5, + "lines": 56.2, + "functions": 43.3, + "statements": 56.1 } diff --git a/backend/package.json b/backend/package.json index 2f7f2347..09043d2e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -5,7 +5,7 @@ "license": "Apache 2.0", "description": "Provide rich user experience for Yeoman generators using VSCode extension or the browser", "repository": "https://github.com/SAP/yeoman-ui", - "version": "0.0.51", + "version": "0.0.53", "engines": { "vscode": "^1.39.2" }, @@ -76,7 +76,8 @@ } }, "scripts": { - "backend": "npm install && npm run compile", + "backend": "npm i && npm run compile", + "types": "cd ../types && npm i && npm run compile", "frontend": "npm run frontend:install && npm run frontend:build && npm run frontend:copy", "frontend:install": "cd ../frontend && npm i", "frontend:build": "cd ../frontend && npm run build", @@ -94,24 +95,25 @@ }, "dependencies": { "@sap-devx/webview-rpc": "^0.2.0", + "@vscode-logging/logger": "^0.1.2", + "chalk": "^3.0.0", "datauri": "^2.0.0", + "fs-extra": "^8.1.0", + "humanize-string": "^1.0.2", "lodash": "^4.17.15", "strip-ansi": "^6.0.0", - "ws": "^7.2.0", - "yeoman-environment": "^2.7.0", "titleize": "^1.0.1", - "humanize-string": "^1.0.2", - "fs-extra": "^8.1.0", - "chalk": "^3.0.0", - "@vscode-logging/logger": "^0.1.2" + "ws": "^7.2.0", + "yeoman-environment": "^2.8.0", + "@sap-devx/yeoman-ui-types": "0.0.1" }, "devDependencies": { - "@types/chai": "^4.2.5", - "@types/fs-extra": "^8.0.1", + "@types/chai": "^4.2.9", + "@types/fs-extra": "^8.1.0", "@types/inquirer": "^6.5.0", "@types/lodash": "^4.14.145", "@types/mocha": "^5.2.7", - "@types/node": "^10.12.21", + "@types/node": "^10.17.16", "@types/sinon": "^7.5.0", "@types/strip-ansi": "^5.2.1", "@types/ws": "^6.0.3", @@ -123,15 +125,15 @@ "nyc": "^14.1.1", "sinon": "^7.5.0", "ts-loader": "^6.2.1", - "ts-node": "^8.5.4", + "ts-node": "^8.6.2", "tslint": "^5.20.1", "tslint-config-prettier": "^1.18.0", "tslint-no-unused-expression-chai": "^0.1.4", "typescript": "^3.8.2", "utf-8-validate": "^5.0.2", - "vsce": "^1.68.0", + "vsce": "^1.73.0", "vscode": "^1.1.28", - "webpack": "^4.41.2", - "webpack-cli": "^3.3.10" + "webpack": "^4.41.6", + "webpack-cli": "^3.3.11" } } diff --git a/backend/src/extension.ts b/backend/src/extension.ts index 438a9a84..614ff7cb 100644 --- a/backend/src/extension.ts +++ b/backend/src/extension.ts @@ -192,9 +192,9 @@ export class YeomanUIPanel { } const uiMessages = _.assign({}, backendMessages, _.get(YeomanUIPanel, "messages", {})); this.panel.title = _.get(uiMessages, "panel_title"); - + this.setMessages(uiMessages); - + this.panel.webview.html = indexHtml; } } diff --git a/backend/src/yeomanui.ts b/backend/src/yeomanui.ts index 99a1e425..f7f69a81 100644 --- a/backend/src/yeomanui.ts +++ b/backend/src/yeomanui.ts @@ -4,9 +4,9 @@ import * as fsextra from "fs-extra"; import * as _ from "lodash"; import * as Environment from "yeoman-environment"; import * as inquirer from "inquirer"; +const datauri = require("datauri"); const titleize = require('titleize'); const humanizeString = require('humanize-string'); -const datauri = require("datauri"); import * as defaultImage from "./defaultImage"; import { YouiAdapter } from "./youi-adapter"; import { YouiLog } from "./youi-log"; @@ -15,6 +15,7 @@ import { IRpc } from "@sap-devx/webview-rpc/out.ext/rpc-common"; import Generator = require("yeoman-generator"); import { GeneratorType, GeneratorFilter } from "./filter"; import { IChildLogger } from "@vscode-logging/logger"; +import {IPrompt} from "@sap-devx/yeoman-ui-types"; export interface IGeneratorChoice { name: string; @@ -31,9 +32,7 @@ export interface IGeneratorQuestion { choices: IGeneratorChoice[]; } -export interface IPrompt { - name: string; - description: string; +export interface IQuestionsPrompt extends IPrompt{ questions: any[]; } @@ -42,7 +41,7 @@ export class YeomanUI { "Some quick example text of the generator description. This is a long text so that the example will look good."; private static YEOMAN_PNG = "yeoman.png"; private static isWin32 = (process.platform === 'win32'); - private static CWD = path.join(os.homedir(), 'projects'); + private static CWD: string = path.join(os.homedir(), 'projects'); private static NODE_MODULES = 'node_modules'; private static funcReplacer(key: any, value: any) { @@ -115,11 +114,11 @@ export class YeomanUI { return errorMessage; } - public async getGenerators(): Promise { + 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 promise: Promise = new Promise(resolve => { const env: Environment.Options = this.getEnv(); env.lookup(async () => this.onEnvLookup(env, resolve, this.genFilter)); }); @@ -137,27 +136,13 @@ export class YeomanUI { const meta: Environment.GeneratorMeta = this.getGenMetadata(generatorName); // TODO: support sub-generators env.register(meta.resolved); - const gen: any = env.create(meta.namespace, {}); - // check if generator defined a helper function called getPrompts() - const genGetPrompts = _.get(gen, "getPrompts"); - if (genGetPrompts) { - const promptNames: any[] = genGetPrompts(); - const prompts: IPrompt[] = promptNames.map(value => { - return _.assign({ questions: [], name: "", description: "" }, value); - }); - this.setPrompts(prompts); - } - const genGetImage = _.get(gen, "getImage"); - if (genGetImage) { - const image: any = genGetImage(); - if (image.then) { - image.then((contents: string) => { - this.logger.debug(`image contents: ${contents}`); - }); - } else if (image !== undefined) { - this.logger.debug(`image contents: ${image}`); - } + const genNamespace = this.getGenNamespace(generatorName); + const gen: any = env.create(genNamespace, {}); + // check if generator defined a helper function called setPromptsCallback() + const setPromptsCallback = _.get(gen, "setPromptsCallback"); + if (setPromptsCallback) { + setPromptsCallback(this.setPromptList.bind(this)); } this.setGenInstall(gen); @@ -216,7 +201,7 @@ export class YeomanUI { public async receiveIsWebviewReady() { try { // TODO: loading generators takes a long time; consider prefetching list of generators - const generators: IPrompt = await this.getGenerators(); + const generators: IQuestionsPrompt = await this.getGenerators(); const response: any = await this.rpc.invoke("showPrompt", [generators.questions, "select_generator"]); await this.runGenerator(response.name); } catch (error) { @@ -235,18 +220,20 @@ export class YeomanUI { public async showPrompt(questions: Environment.Adapter.Questions): Promise { this.currentQuestions = questions; - this.promptCount++; - const firstQuestionName = _.get(questions, "[0].name"); - let promptName: string = `Step ${this.promptCount}`; - if (firstQuestionName) { - promptName = _.startCase(firstQuestionName); - } - const mappedQuestions: Environment.Adapter.Questions = this.normalizeFunctions(questions); - if (_.isEmpty(mappedQuestions)) { - return {}; - } - - return this.rpc.invoke("showPrompt", [mappedQuestions, promptName]); + this.promptCount++; + + const promptName: string = this.getPromptName(questions); + const mappedQuestions: Environment.Adapter.Questions = this.normalizeFunctions(questions); + if (_.isEmpty(mappedQuestions)) { + return {}; + } + + return this.rpc.invoke("showPrompt", [mappedQuestions, promptName]); + } + + private getPromptName(questions: Environment.Adapter.Questions): string { + const firstQuestionName = _.get(questions, "[0].name"); + return (firstQuestionName ? _.startCase(firstQuestionName) : `Step ${this.promptCount}`); } private onGeneratorSuccess(generatorName: string, destinationRoot: string) { @@ -337,12 +324,12 @@ export class YeomanUI { this.logError(error); return Promise.resolve(undefined); } - + 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); + return this.createGeneratorChoice(genName, genPackagePath, packageJson); } return Promise.resolve(undefined); @@ -382,10 +369,10 @@ export class YeomanUI { } private getGenMetadata(genName: string): Environment.GeneratorMeta { - const namespace = this.getGenNamespace(genName); - const genMetadata = _.get(this, ["genMeta", namespace]); + const genNamespace = this.getGenNamespace(genName); + const genMetadata = _.get(this, ["genMeta", genNamespace]); if (_.isNil(genMetadata)) { - const debugMessage = `${namespace} generator metadata was not found.`; + const debugMessage = `${genNamespace} generator metadata was not found.`; this.logger.debug(debugMessage); } return genMetadata; @@ -408,10 +395,18 @@ export class YeomanUI { return JSON.parse(JSON.stringify(questions, YeomanUI.funcReplacer)); } + private setPromptList(prompts: IPrompt[]): Promise { + const promptsToDisplay: IPrompt[] = prompts.map((prompt: IPrompt) => { + return _.assign({ questions: [], name: "", description: ""}, prompt); + }); + + return this.rpc.invoke("setPromptList", [promptsToDisplay]); + } + private addCustomQuestionEventHandlers(questions: Environment.Adapter.Questions): void { - for (const index in questions) { + for (let index in questions) { const question = (questions as any[])[Number.parseInt(index)]; - const questionHandlers = this.customQuestionEventHandlers.get((question as any)["guiType"]); + const questionHandlers = this.customQuestionEventHandlers.get(question.guiType); if (questionHandlers) { questionHandlers.forEach((handler, methodName) => { (question as any)[methodName] = handler; @@ -419,8 +414,4 @@ export class YeomanUI { } } } - - private setPrompts(prompts: IPrompt[]): Promise { - return this.rpc.invoke("setPrompts", [prompts]); - } } diff --git a/frontend/jest.config.js b/frontend/jest.config.js index 1d4af42b..c2a53fe9 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -36,10 +36,10 @@ module.exports = { ], coverageThreshold: { "global": { - "branches": 94.2, + "branches": 95.8, "functions": 100, - "lines": 96.9, - "statements": 96.9 + "lines": 98.1, + "statements": 98.1 } } } diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 8efea644..916a2313 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -81,7 +81,6 @@ -