UNPKG

@broadcom/jclcheck-for-zowe-cli

Version:

JCLCheck Plug-in for Zowe CLI

281 lines 12.4 kB
"use strict"; /** * 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