@broadcom/jclcheck-for-zowe-cli
Version:
JCLCheck Plug-in for Zowe CLI
281 lines • 12.4 kB
JavaScript
;
/**
* Copyright (c) 2023. Broadcom. All rights reserved.
*
* This software and all information contained therein is confidential and
* proprietary and shall not be duplicated, used, disclosed or disseminated
* in any way except as authorized by the applicable license agreement,
* without the express written permission of BROADCOM. All authorized reproductions
* must be marked with this language.
*
* EXCEPT AS SET FORTH IN THE APPLICABLE LICENSE AGREEMENT, TO THE EXTENT
* PERMITTED BY APPLICABLE LAW, BROADCOM PROVIDES THIS SOFTWARE WITHOUT
* WARRANTY OF ANY KIND, INCLUDING WITHOUT LIMITATION, ANY IMPLIED
* WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN
* NO EVENT WILL BROADCOM BE LIABLE TO THE END USER OR ANY THIRD PARTY FOR ANY
* LOSS OR DAMAGE, DIRECT OR INDIRECT, FROM THE USE OF THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, LOST PROFITS, BUSINESS INTERRUPTION,
* GOODWILL, OR LOST DATA, EVEN IF CA IS EXPRESSLY ADVISED OF SUCH LOSS OR
* DAMAGE.
*
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
*
**/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const readline = require("readline");
const path = require("path");
const fs = require("fs");
const Utils_1 = require("./Utils");
const stream_1 = require("stream");
const ConfigException_1 = require("./ConfigException");
const yaml = require('js-yaml');
class ConfigYaml {
/**
* Load the configuration file and optionally the user configuration file.
* The result is a complete IConfig object available.
* @param configPath The yaml file path.
* @param userConfigPath The user config yaml file path.
*/
static load(options) {
return __awaiter(this, void 0, void 0, function* () {
// Validate and ensure the options are correct/defaulted
let opts = options;
if (opts == null) {
opts = {};
}
// Create an instance
const newConfig = new ConfigYaml(opts);
// Load the configuration yaml file
const config = newConfig.loadYaml(newConfig.configPath);
if (config.global == null) {
config.global = {};
}
// The default always task precedence
if (fs.existsSync(ConfigYaml.DefaultUserConfigFile) &&
newConfig.userConfigPaths.indexOf(ConfigYaml.DefaultUserConfigFile) < 0) {
newConfig.userConfigPaths.unshift(ConfigYaml.DefaultUserConfigFile);
}
// console.log(newConfig.userConfigPaths);
// Load the user configuration files and the precedence is the order
// that they appear in the array (i.e. index 0 has the highest).
let userConfig = {};
for (const ucp of newConfig.userConfigPaths) {
if (fs.existsSync(ucp)) {
userConfig = Object.assign(Object.assign({}, newConfig.loadYaml(ucp)), userConfig);
}
}
newConfig.userConfig = userConfig;
// Traverse over the inputs section with the user input to allow
// customization of the user inputs from user config.
if (config.input != null) {
Utils_1.Utils.traverse(config.input, newConfig.userConfig);
}
// If specified, gather input from various sources
if (config.input != null) {
newConfig.loadedInputs = yield newConfig.gatherInput(config.input);
}
else {
newConfig.loadedInputs = {};
}
// Fill in the rest of the configuration variables from various sources
Utils_1.Utils.traverse(config, newConfig.userConfig);
Utils_1.Utils.traverse(config, newConfig.loadedInputs);
Utils_1.Utils.traverse(config, config.global);
// Merge the user config with the loaded inputs
newConfig.userConfig = Object.assign(Object.assign({}, newConfig.userConfig), newConfig.loadedInputs);
config.user = newConfig.userConfig;
// Set the loaded config for next access
newConfig.loadedConfig = config;
return newConfig;
});
}
constructor(options) {
this.configPath = options.configPath || path.join(process.cwd(), ConfigYaml.DefaultConfigFile);
this.userConfigPaths = options.userConfigPaths || [];
}
/**
* Returns the loaded config
*/
get config() {
return this.loadedConfig;
}
/**
* Builds the full set of tasks in the loaded config file.
*/
/**
* Get the file path of the configuration file used
*/
get path() {
return this.configPath;
}
/**
* Gather user input from various sources (prompt, env, or user config file)
* @param inputs The various inputs and their sources
* @param userConfig The use configuration to check if values are specified.
*/
gatherInput(inputs) {
return __awaiter(this, void 0, void 0, function* () {
const loadedInputs = {};
// Create a mutable stdout
const mutableStdout = new stream_1.Writable({
write(chunk, encoding, callback) {
if (!this.muted) {
process.stdout.write(chunk, encoding);
}
callback();
}
});
mutableStdout.muted = false;
// Create an rl for prompting
const rl = readline.createInterface({
input: process.stdin,
output: mutableStdout,
terminal: true
});
// Iterate over the input keys and gather from various sources
for (const input of Object.keys(inputs)) {
const userIn = inputs[input];
let supplied = false;
for (const source of userIn.sources) {
if (typeof source !== "string") {
throw new ConfigException_1.ConfigException(`Input "${input}" source must be "prompt, env, or user".`);
}
let value;
switch (source) {
// If user was specified, check if the user config has the
// value specified and if so, break the loop. The value
// is filled in later during config loading.
case "user": {
if (this.userConfig != null) {
const uc = this.userConfig[input];
if (uc != null) {
if (typeof uc === "string") {
if ((uc.trim() !== "") || (uc.trim() === "" && userIn.allowBlank)) {
supplied = true;
}
}
else {
supplied = true;
}
}
}
break;
}
// Prompt the user for the value
case "prompt": {
const desc = `${(userIn.desc != null) ? `${userIn.desc}` : "Specify value for"}`;
const question = `${desc} "${input}"${(userIn.mask) ? " (masked)" : ""}: `;
const answer = yield this.ask(rl, question, mutableStdout, userIn.mask || false);
value = this.processInputValue(answer, userIn);
if (value != null) {
loadedInputs[input] = value;
supplied = true;
}
// Add a blank line to keep correct spacing
if (userIn.mask) {
process.stdout.write("\n");
}
break;
}
// Check the ENV var "ZOWE_TASKS_VAR_<varname>"
case "env": {
value = this.processInputValue(process.env[`${ConfigYaml.EnvPrefix}_${input.toUpperCase()}`], userIn);
if (value != null) {
loadedInputs[input] = value;
supplied = true;
}
break;
}
}
// If the value was found, break from the loop
if (supplied) {
break;
}
}
// If it was not supplied by this time, throw an error.
if (!supplied) {
rl.close();
const srcStrs = [];
userIn.sources.forEach((src) => {
srcStrs.push(src);
});
throw new ConfigException_1.ConfigException(`No value supplied for "${input}" from "${srcStrs.toString()}".`);
}
}
// Close the rl
rl.close();
return loadedInputs;
});
}
/**
* Process the input value and return either a string, number, or boolean
* value.
* @param value The value that was inputted as a string.
* @param input The input parameters.
*/
processInputValue(value, input) {
let processedValue;
if (value != null) {
if (value.trim() === "" && input.allowBlank) {
processedValue = "";
}
else {
if (value[0] === "\"" && value[value.length - 1] === "\"") {
processedValue = value.substr(1, value.length - 2);
}
else if (!isNaN(parseInt(value, 10))) {
processedValue = parseInt(value, 10);
}
else if (value === "true" || value === "false") {
processedValue = (value == "true");
}
else {
processedValue = value;
}
}
}
return processedValue;
}
/**
* Ask the user a question and obtain a response.
* @param rl The readline interface object that was previously created.
* @param question The question to ask.
*/
ask(rl, question, mutableStdout, mute = false) {
return new Promise((answered) => {
mutableStdout.muted = false;
rl.question(question, (answer) => {
answered((answer == null || answer.trim() === "") ? "" : answer);
});
mutableStdout.muted = mute;
});
}
/**
* Load a yaml file into an object.
* @param filePath The full path to the yaml file.
*/
loadYaml(filePath) {
let config;
try {
config = yaml.load(fs.readFileSync(filePath, "utf8"));
}
catch (e) {
throw new ConfigException_1.ConfigException(`Unable to load Yaml config file "${filePath}":\n${e.message}`);
}
return config;
}
}
exports.default = ConfigYaml;
ConfigYaml.DefaultConfigFile = "../../zowe-tasks.yml";
ConfigYaml.DefaultUserConfigFile = "../../zowe-tasks-user.yml";
ConfigYaml.EnvPrefix = "ZOWE_TASKS";
//# sourceMappingURL=ConfigYaml.js.map