@zowe/imperative
Version:
framework for building configurable CLIs
228 lines • 10.2 kB
JavaScript
"use strict";
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractHelpGenerator = void 0;
const utilities_1 = require("../../../../utilities");
const util_1 = require("util");
const ImperativeError_1 = require("../../../../error/src/ImperativeError");
const Logger_1 = require("../../../../logger/src/Logger");
const constants_1 = require("../../../../constants");
class AbstractHelpGenerator {
/**
* Get a heading for the CLI / help
* @param {string} header - The text you want to display in the header
* @param indent - prefix the the heading and dashes with this string (defaults to one space)
* @param color - the color to highlight the header in
* @returns {string} the formatted/colored header
*/
static formatHelpHeader(header, indent = " ", color) {
if (header == null || header.trim().length === 0) {
throw new ImperativeError_1.ImperativeError({
msg: "Null or empty header provided; could not be formatted."
});
}
const numDashes = header.length + 1;
const headerText = utilities_1.TextUtils.formatMessage("{{indent}}{{headerText}}\n{{indent}}{{dashes}}", { headerText: header.toUpperCase(), dashes: Array(numDashes).join("-"), indent });
return utilities_1.TextUtils.chalk[color](headerText);
}
/**
* Get log instance
*/
get log() {
return this.mLog;
}
// TODO - rework these parameter (and possible the help generator scheme)
constructor(defaultParms, commandParms) {
/**
* Produce markdown - not help text.
*/
this.mProduceMarkdown = false;
/**
* The configured experimental command description.
* Has a default, generic description which can be overridden through parameters
* to the constructor
* @type {string}
*/
this.mExperimentalCommandDescription = constants_1.Constants.DEFAULT_EXPERIMENTAL_COMMAND_EXPLANATION;
/**
* A map of group names to option names and aliases - useful in help text/doc generation
* e.g. this.grouptoOption["job options"] -> [ "--async | -a ", "--activate | -A"]
*/
this.groupToOption = {};
/**
* A map of option names and aliases to their descriptions - useful in help text/doc generation
* e.g. this.optionToDescription["--async | a"] -> "Don't wait for this job to complete before returning"
*/
this.optionToDescription = {};
if (commandParms.commandDefinition == null || commandParms.fullCommandTree == null) {
throw new ImperativeError_1.ImperativeError({
msg: "Error initializing help generator. The command definition or command definition tree was null or undefined.",
additionalDetails: JSON.stringify(commandParms.commandDefinition) + "\n\n" + JSON.stringify(commandParms.fullCommandTree)
});
}
this.mCommandDefinition = commandParms.commandDefinition;
this.mDefinitionTree = commandParms.fullCommandTree;
this.mProduceMarkdown = defaultParms.produceMarkdown;
this.mRootCommandName = defaultParms.rootCommandName;
this.mPrimaryHighlightColor = defaultParms.primaryHighlightColor;
this.mLog = Logger_1.Logger.getImperativeLogger();
if (commandParms.experimentalCommandsDescription != null) {
// use the configured experimental command description, if any
this.mExperimentalCommandDescription = commandParms.experimentalCommandsDescription;
}
}
getOptionAndAliasesString(option, caseSensitive) {
var _a;
let aliasString = "";
if (!(option.aliases == null) && option.aliases.length > 0 &&
option.aliases.join("").trim().length !== 0) {
const formattedOptAliases = [];
aliasString += " | ";
for (const alias of option.aliases) {
if (!(alias == null) && alias.length > 0) {
formattedOptAliases.push("{{codeBegin}}" +
(alias.length === 1 ? "-" : "--") + alias + "{{codeEnd}}");
}
else {
this.log.warn("The aliases for option " + option.name + " contained a null or empty alias. " +
"This has been ignored; please take corrective action in your option definition.");
}
}
aliasString += formattedOptAliases.join(" | ");
}
const explainedType = this.explainType(option.type);
aliasString += " {{italic}}" + this.dimGrey("(" + explainedType + ")") + "{{italic}}";
// if (!option.required) {
// aliasString += " {{italic}}" + this.dimGrey("(optional)") + "{{italic}}";
// }
if (caseSensitive) {
aliasString += " {{italic}}" + this.dimGrey("(case sensitive)") + "{{italic}}";
}
return this.renderHelp((0, util_1.format)("{{codeBegin}}%s{{codeEnd}}%s", (((_a = option.name) === null || _a === void 0 ? void 0 : _a.length) === 1 ? "-" : "--") + option.name, aliasString));
}
buildOptionMaps() {
this.groupToOption = {};
this.optionToDescription = {};
if (this.mCommandDefinition.options == null) {
return;
}
for (const option of this.mCommandDefinition.options.filter(opt => !opt.hidden)) {
const group = option.group;
if (!this.groupToOption[group]) {
this.groupToOption[group] = [];
}
const caseSensitive = this.getCaseSensitiveFlagByOptionName(option.name);
const optionAndAliases = this.getOptionAndAliasesString(option, caseSensitive);
this.groupToOption[group].push(optionAndAliases);
// build the option help text
let optionText = option.description;
const defaultValueText = [undefined, null].includes(option.defaultValue) ? "" : this.grey("\nDefault value: " + option.defaultValue);
const allowableValuesText = option.allowableValues ? this.grey("\nAllowed values: " + option.allowableValues.values.join(", ")) : "";
if (defaultValueText.length > 0 || allowableValuesText.length > 0) {
optionText += "\n";
optionText += defaultValueText + allowableValuesText;
}
// Place the help text in the map
this.optionToDescription[optionAndAliases] = optionText;
}
}
getCaseSensitiveFlagByOptionName(optionName) {
if (!(this.mCommandDefinition.customize == null) &&
!(this.mCommandDefinition.customize.commandStatement == null) &&
!(this.mCommandDefinition.customize.commandStatement.children == null)) {
for (const child of this.mCommandDefinition.customize.commandStatement.children) {
if (child.name.toUpperCase() === optionName.toUpperCase()) {
return child.caseSensitive;
}
}
}
return undefined;
}
renderHelp(help) {
if (help == null) {
throw new ImperativeError_1.ImperativeError({
msg: "Help unable to be rendered - the supplied help text was null or undefined."
});
}
// avoid replacing any literal {{strings like this}} in the help
const validTags = ["indent", "space", "italic", "header", "bullet", "codeBegin", "codeEnd"];
const mustachePattern = /\{\{([a-z0-9-]*?)\}\}/ig;
help = help.replace(mustachePattern, (fullMatch, variableName) => {
if (validTags.indexOf(variableName) >= 0) {
return fullMatch;
}
else {
// temporarily change the mustache delimiter to avoid
// replacing literal curly braces in the help
return "{{=<% %>=}}" + fullMatch + "<%={{ }}=%>";
}
});
if (this.mProduceMarkdown) {
return utilities_1.TextUtils.renderWithMustache(help, {
indent: "\t",
space: " ",
italic: "*",
header: "#",
bullet: "*",
codeBegin: "`",
codeEnd: "`"
});
}
else {
return utilities_1.TextUtils.renderWithMustache(help, {
indent: "",
space: "",
header: "",
italic: "",
bullet: "",
codeBegin: "",
codeEnd: ""
});
}
}
explainType(type) {
let explainedType = type;
if (explainedType === "existingLocalFile") {
explainedType = "local file path";
}
else if (explainedType === "stringOrEmpty") {
explainedType = "string";
}
return explainedType;
}
/**
* Highlight text in dim grey (disabled if producing markdown)
* @param {string} text - the text you would like to highlight
* @returns {string} the highlighted text
*/
dimGrey(text) {
if (this.mProduceMarkdown) {
return text;
}
return utilities_1.TextUtils.chalk.grey.dim(text);
}
/**
* Highlight text in grey (disabled if producing markdown)
* @param {string} text - the text you would like to highlight
* @returns {string} the highlighted text
*/
grey(text) {
if (this.mProduceMarkdown) {
return text;
}
return utilities_1.TextUtils.chalk.grey(text);
}
}
exports.AbstractHelpGenerator = AbstractHelpGenerator;
AbstractHelpGenerator.SHORT_DASH = "-";
AbstractHelpGenerator.LONG_DASH = "--";
//# sourceMappingURL=AbstractHelpGenerator.js.map