public async getHelp()

in app/lib/tfcommand.ts [488:609]


	public async getHelp(cmd: command.TFXCommand): Promise<string> {
		const includeUndocumented = await this.commandArgs.includeUndocumented.val();

		this.commandArgs.output.setValue("help");
		let result = eol;
		let continuedHierarchy: command.CommandHierarchy = cmd.commandHierarchy;
		cmd.execPath.forEach(segment => {
			continuedHierarchy = continuedHierarchy[segment];
		});

		if (continuedHierarchy === null) {
			// Need help with a particular command
			let singleArgData = (argName: string, maxArgLen: number) => {
				// Lodash's kebab adds a dash between letters and numbers, so this is just a hack to avoid that.
				let argKebab = argName === "json5" ? "json5" : _.kebabCase(argName);
				const argObj = this.commandArgs[argName];
				const shorthandArg = argObj.aliases.filter(a => a.length === 2 && a.substr(0, 1) === "-")[0];
				if (shorthandArg) {
					argKebab = `${argKebab}, ${shorthandArg}`;
				}

				if (argObj.undocumented && !includeUndocumented) {
					return "";
				}

				return (
					"  --" +
					argKebab +
					"  " +
					repeatStr(" ", maxArgLen - argKebab.length) +
					gray(argObj.description || argObj.friendlyName + ".") +
					eol
				);
			};
			let commandName = cmd.execPath[cmd.execPath.length - 1];
			result +=
				cyan("Syntax: ") +
				eol +
				cyan("tfx ") +
				yellow(cmd.execPath.join(" ")) +
				green(" --arg1 arg1val1 arg1val2[...]") +
				gray(" --arg2 arg2val1 arg2val2[...]") +
				eol +
				eol;

			return loader
				.load(cmd.execPath, ["--service-url", "null"])
				.then(tfCommand => {
					result += cyan("Command: ") + commandName + eol;
					result += tfCommand.description + eol + eol;
					result += cyan("Arguments: ") + eol;

					let uniqueArgs = this.getHelpArgs();
					uniqueArgs = _.uniq(uniqueArgs);
					let maxArgLen = uniqueArgs.map(a => _.kebabCase(a)).reduce((a, b) => Math.max(a, b.length), 0);
					if (uniqueArgs.length === 0) {
						result += "[No arguments for this command]" + eol;
					}
					uniqueArgs.forEach(arg => {
						result += singleArgData(arg, maxArgLen);
					});

					if (this.serverCommand) {
						result += eol + cyan("Global server command arguments:") + eol;
						["authType", "username", "password", "token", "serviceUrl", "fiddler", "proxy"].forEach(arg => {
							result += singleArgData(arg, 11);
						});
					}

					result += eol + cyan("Global arguments:") + eol;
					["help", "save", "noColor", "noPrompt", "output", "json", "traceLevel", "debugLogStream"].forEach(arg => {
						result += singleArgData(arg, 9);
					});

					result +=
						eol +
						gray(
							"To see more commands, type " +
								resetColors("tfx " + cmd.execPath.slice(0, cmd.execPath.length - 1).join(" ") + " --help"),
						);
				})
				.then(() => {
					return result;
				});
		} else {
			// Need help with a suite of commands
			// There is a weird coloring bug when colors are nested, so we don't do that.
			result +=
				cyan("Available ") +
				"commands" +
				cyan(" and ") +
				yellow("command groups") +
				cyan(" in " + ["tfx"].concat(cmd.execPath).join(" / ") + ":") +
				eol;
			let commandDescriptionPromises: Promise<void>[] = [];
			Object.keys(continuedHierarchy).forEach(command => {
				if (command === "default") {
					return;
				}
				let pr = loader.load(cmd.execPath.concat([command]), ["--service-url", "null"]).then(tfCommand => {
					let coloredCommand = command;
					if (continuedHierarchy[command] !== null) {
						coloredCommand = yellow(command);
					}
					result += " - " + coloredCommand + gray(": " + tfCommand.description) + eol;
				});
				commandDescriptionPromises.push(pr);
			});
			return Promise.all(commandDescriptionPromises)
				.then(() => {
					result +=
						eol +
						eol +
						gray("For help with an individual command, type ") +
						resetColors("tfx " + cmd.execPath.join(" ") + " <command> --help") +
						eol;
				})
				.then(() => {
					return result;
				});
		}
	}