@sap/generator-base-mta-module
Version:
Generator for collecting user inputs on multitarget application module
351 lines • 14.2 kB
JavaScript
"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