UNPKG

@sap/generator-base-mta-module

Version:

Generator for collecting user inputs on multitarget application module

351 lines 14.2 kB
"use strict"; const Generator = require("yeoman-generator"); const fs = require("fs"); const path = require("path"); const promptValidator_1 = require("./promptValidator"); const mta_lib_1 = require("@sap/mta-lib"); const messages_1 = require("./messages"); const CONFIG_FILE_OPT = "configPath"; const DEFAULT_MODULE_NAME_OPT = "defaultName"; const MTA_YAML_FILE_PATH_OPT = "mtaFilePath"; const MTA_FILES_LIST_OPT = "mtaFilesPathsList"; const MODULE_TARGET_FOLDER_OPT = "targetFolderPath"; const ADD_MTA_ID_OPT = "addMtaId"; const NO_FOLDER_MODULE_OPT = "noTargetFolder"; const MODULE_REL_TARGET_FOLDER_OPT = "relativeTargetFolderPath"; const REGISTER_SET_OPTION = "registerSetOption"; class MtaModuleGenerator extends Generator { constructor(args, options) { super(args, options); this.defModuleNameObj = { moduleName: undefined, folderName: undefined }; this.moduleData = {}; this.isWhenCalled = false; this.option(CONFIG_FILE_OPT, { type: String, hide: true, default: "", description: "configuration file path" }); this.option(DEFAULT_MODULE_NAME_OPT, { type: String, default: "", description: "default module name based on module type" }); this.option(MTA_YAML_FILE_PATH_OPT, { type: String, default: "", description: "path to mta.yaml" }); this.option(MODULE_TARGET_FOLDER_OPT, { type: String, default: "", description: "path at which the module folder is generated" }); this.option(ADD_MTA_ID_OPT, { type: Boolean, default: false, description: "add the MTA ID to the module name" }); this.option(MTA_FILES_LIST_OPT, { type: String, hide: true, default: "", description: "List of possible paths to the mta.yaml file, separated by a comma" }); this.option(NO_FOLDER_MODULE_OPT, { type: Boolean, default: false, description: "don't create a folder for the module" }); this.option(MODULE_REL_TARGET_FOLDER_OPT, { type: String, default: "", description: "path relative to mta.yaml location at which the module folder is generated" }); // handle ui prompts if (options.prompts) { promptValidator_1.setupPromptsSteps(options.prompts, options.prompts.size()); } if (options[REGISTER_SET_OPTION]) { this.options[REGISTER_SET_OPTION]((name, value) => { this.options[name] = value; }); } } async prompting() { const aPrompts = await this._constructStepPrompts(); // execute prompts const promptAnswers = await this.prompt(aPrompts); // handle back functionality limitations: // "when" functions for each step are not guaranteed to be called when pressing the back button so we // have to call them explicitly for their logic to run. if (!this.isWhenCalled) { await this._whenTargetFolderPrompt(promptAnswers); this._whenModuleNamePrompt(promptAnswers); } // we have to keep state of defModuleNameObj in back flow, // we keep it in answers, based on fact that this.prompt returns reference to answers if (!promptAnswers.defModuleNameObj) { promptAnswers.defModuleNameObj = this.defModuleNameObj; } // -----after prompts--------------------------- this.moduleData.moduleName = promptAnswers.moduleName; const moduleFolderName = this._getModuleFolderName(this.moduleData.moduleName, promptAnswers); // the module folder path relative to folder with mta.yaml file this.moduleData.modulePath = this._getRelativeFolderPath(moduleFolderName, this.targetFolderPath); // write mta info to shared configuration file if (this.options[CONFIG_FILE_OPT]) { const oModuleConfig = { "generator-base-module": this.moduleData }; this.fs.extendJSON(this.options[CONFIG_FILE_OPT], oModuleConfig); } } async _constructStepPrompts() { const aPrompts = []; // check if mta.yaml file has been passed via options and if this file really mta.yaml const isValidPath = await this._isValidMtaFilePath(this.options[MTA_YAML_FILE_PATH_OPT]); if (isValidPath) { this.mtaFilePath = this.options[MTA_YAML_FILE_PATH_OPT]; } else { const mtaFilePrompt = await this._getMtaFilePrompt(this.options[MTA_FILES_LIST_OPT]); aPrompts.push(mtaFilePrompt); } // display prompt regarding folder to generate module in const targetFolderPrompt = this._getTargetFolderPrompt(this.options[MODULE_REL_TARGET_FOLDER_OPT]); aPrompts.push(targetFolderPrompt); // display prompt regarding module name (module name should be unique) const moduleNamePrompt = this._getModuleNamePrompt(this.options[ADD_MTA_ID_OPT]); aPrompts.push(moduleNamePrompt); return aPrompts; } async _getMtaFilePrompt(sMtaFileList) { let mtaFilePrompt; const msg = messages_1.messages.MTA_PATH_PROMPT_MSG; if (sMtaFileList) { const mtaFileChoices = sMtaFileList.trim().split(","); mtaFilePrompt = { type: "list", guiOptions: { hint: messages_1.messages.MTA_PATH_PROMPT_HINT }, name: "filePath", message: msg, default: mtaFileChoices[0], choices: mtaFileChoices }; } else { // get mta.yaml from current working dir const defMtaFilePath = await this._getMtaFilePath(process.cwd()); // display prompt regarding mta.yaml file location mtaFilePrompt = { type: "input", guiType: "file-browser", name: "filePath", message: msg, default: defMtaFilePath, validate: promptValidator_1.validateMtaPath }; } return mtaFilePrompt; } _getTargetFolderPrompt(relativeFolderPath) { return { type: "input", guiType: "folder-browser", guiOptions: { applyDefaultWhenDirty: true }, name: "folderPath", message: messages_1.messages.TARGET_FOLDER_PROMPT_MSG, default: () => { return this._defaultTargetFolderPrompt(relativeFolderPath, this.mtaProjectPath); }, validate: promptValidator_1.validateTargetFolderPath, when: async (answers) => { this.isWhenCalled = true; return await this._whenTargetFolderPrompt(answers); } }; } _getModuleNamePrompt(mtaIDOption) { let defModuleName; return { type: "input", guiOptions: { applyDefaultWhenDirty: true }, name: "moduleName", message: messages_1.messages.MODULE_NAME_PROMPT_MSG, default: async (answers) => { defModuleName = await this._defaultModuleNamePrompt(answers, mtaIDOption); return defModuleName; }, validate: // istanbul ignore next async (value) => { return await promptValidator_1.validateModuleName(value, this.mtaProjectPath, this.targetFolderPath, defModuleName); }, when: (answers) => { return this._whenModuleNamePrompt(answers); } }; } // if module with name exists in mta.yaml, add index to module name // add mta id prefix, if required async _getUniqueModuleName(name, mtaID) { if (!name) { return undefined; } let sModuleName = name; if (mtaID) { // add mta_id to module name sModuleName = mtaID + "_" + sModuleName; } const startModuleName = sModuleName; for (let i = 1; await this.mta.doesNameExist(sModuleName); i++) { sModuleName = startModuleName + "_" + i; } return sModuleName; } // get module folder path relative to mta.yaml _getRelativeFolderPath(name, destinationFolderPath) { const mtaProjectPath = path.dirname(this.moduleData.mtaFilePath); if (!destinationFolderPath) { return undefined; } this.log(`The "${this.moduleData.moduleName}" module will be generated in the "${name}" folder located at ${destinationFolderPath}.`); // target folder is the same as folder with mta.yaml mentioned by user if (destinationFolderPath === mtaProjectPath) { return name; } else { return path.join(path.relative(mtaProjectPath, destinationFolderPath), name); } } // checks if mta.yaml file exists async _isValidMtaFilePath(mtaFilePath) { if (!mtaFilePath) { return false; } const sDirPath = path.dirname(mtaFilePath); const filePath = await this._getMtaFilePath(sDirPath); return filePath === mtaFilePath; } // gets mta.yaml file from folder async _getMtaFilePath(sDirPath) { const mtaInst = new mta_lib_1.default(sDirPath); try { return await mtaInst.getMtaFilePath(false); } catch (error) { return undefined; } } // checks if target folder exists _isValidTargetFolderPath(sTargetFolderPath) { if (!sTargetFolderPath) { return false; } return fs.existsSync(sTargetFolderPath); } async _getDefaultModuleName(name, destinationFolderPath, mtaID) { const moduleName = await this._getUniqueModuleName(name, mtaID); // module name not passed if (!moduleName) { return { moduleName: undefined, folderName: undefined }; } if (destinationFolderPath) { const folderName = this._getFolderNameWithoutMtaId(moduleName, mtaID); if (!fs.existsSync(path.join(destinationFolderPath, folderName))) { return { moduleName, folderName }; } } else { return { moduleName, folderName: undefined }; } // module folder name not unique return { moduleName: undefined, folderName: undefined }; } _getFolderNameWithoutMtaId(name, mtaID) { let sFolderName = name; if (mtaID) { // remove mta_id from folder name const prefix = mtaID + "_"; if (sFolderName.startsWith(prefix)) { sFolderName = sFolderName.substring(prefix.length); } } return sFolderName; } _defaultTargetFolderPrompt(relativeFolderPath, mtaProjectPath) { if (!relativeFolderPath) { return mtaProjectPath; } const absolutePath = path.join(mtaProjectPath, relativeFolderPath); if (this._isValidTargetFolderPath(absolutePath)) { return absolutePath; } else { return mtaProjectPath; } } // prepare all required data before target folder prompt, evaluate if prompt should be displayed async _whenTargetFolderPrompt(answers) { const mtaFilePath = answers.filePath ? answers.filePath : this.mtaFilePath; // dont show prompt if answer to mtaFile prompt is invalid, (in yeoman-ui all prompts are displayed even if there was an invalid answer) const isMTAFilePathAnswerValid = await promptValidator_1.validateMtaPath(mtaFilePath); if (isMTAFilePathAnswerValid !== true) { return false; } // get absolute path of the "mta.yaml" file this.moduleData.mtaFilePath = path.resolve(mtaFilePath); this.mtaProjectPath = path.dirname(this.moduleData.mtaFilePath); this.mta = new mta_lib_1.default(this.mtaProjectPath); // clean removes the temp file that may been left in the system from previous run on the same project path await this.mta.clean(); // handle destination folder path only if NO_FOLDER_MODULE option is not provided (false) if (this.options[NO_FOLDER_MODULE_OPT]) { this.targetFolderPath = undefined; return false; } // check if target folder path is provided, and exists const isValidFolderPath = this._isValidTargetFolderPath(this.options[MODULE_TARGET_FOLDER_OPT]); if (isValidFolderPath) { this.targetFolderPath = this.options[MODULE_TARGET_FOLDER_OPT]; return false; } return true; } async _defaultModuleNamePrompt(answers, mtaIDOption) { let mtaID; if (mtaIDOption) { mtaID = await this.mta.getMtaID(); } this.defModuleNameObj = await this._getDefaultModuleName(this.options[DEFAULT_MODULE_NAME_OPT], this.targetFolderPath, mtaID); return this.defModuleNameObj.moduleName; } _whenModuleNamePrompt(answers) { // dont show prompt if mta file path is undefined if (!this.mta) { return false; } this.targetFolderPath = answers.folderPath ? answers.folderPath : this.targetFolderPath; return true; } _getModuleFolderName(userModuleName, answers) { let moduleFolderName; if (userModuleName === answers.defModuleNameObj.moduleName) { // user accepted default, module folder name should be as calculated before moduleFolderName = answers.defModuleNameObj.folderName; } else { moduleFolderName = userModuleName; } return moduleFolderName; } } module.exports = MtaModuleGenerator; //# sourceMappingURL=index_unbundled.js.map