hardhat
Version:
Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
279 lines (205 loc) • 7.13 kB
text/typescript
import {
HardhatParamDefinitions,
ParamDefinition,
ParamDefinitionsMap,
ScopeDefinition,
ScopesMap,
TaskDefinition,
TasksMap,
} from "../../types";
import { HardhatError } from "../core/errors";
import { ERRORS } from "../core/errors-list";
import { ArgumentsParser } from "./ArgumentsParser";
export class HelpPrinter {
constructor(
private readonly _programName: string,
private readonly _executableName: string,
private readonly _version: string,
private readonly _hardhatParamDefinitions: HardhatParamDefinitions,
private readonly _tasks: TasksMap,
private readonly _scopes: ScopesMap
) {}
public printGlobalHelp(includeSubtasks = false) {
console.log(`${this._programName} version ${this._version}\n`);
console.log(
`Usage: ${this._executableName} [GLOBAL OPTIONS] [SCOPE] <TASK> [TASK OPTIONS]\n`
);
console.log("GLOBAL OPTIONS:\n");
let length = this._printParamDetails(this._hardhatParamDefinitions);
console.log("\n\nAVAILABLE TASKS:\n");
length = this._printTasks(this._tasks, includeSubtasks, length);
if (Object.keys(this._scopes).length > 0) {
console.log("\n\nAVAILABLE TASK SCOPES:\n");
this._printScopes(this._scopes, length);
}
console.log("");
console.log(
`To get help for a specific task run: npx ${this._executableName} help [SCOPE] <TASK>\n`
);
}
public printScopeHelp(
scopeDefinition: ScopeDefinition,
includeSubtasks = false
) {
const name = scopeDefinition.name;
const description = scopeDefinition.description ?? "";
console.log(`${this._programName} version ${this._version}`);
console.log(
`\nUsage: hardhat [GLOBAL OPTIONS] ${name} <TASK> [TASK OPTIONS]`
);
console.log(`\nAVAILABLE TASKS:\n`);
if (this._scopes[name] === undefined) {
throw new HardhatError(ERRORS.ARGUMENTS.UNRECOGNIZED_SCOPE, {
scope: name,
});
}
this._printTasks(this._scopes[name].tasks, includeSubtasks);
console.log(`\n${name}: ${description}`);
console.log(
`\nFor global options help run: ${this._executableName} help\n`
);
}
public printTaskHelp(taskDefinition: TaskDefinition) {
const {
description = "",
name,
paramDefinitions,
positionalParamDefinitions,
} = taskDefinition;
console.log(`${this._programName} version ${this._version}\n`);
const paramsList = this._getParamsList(paramDefinitions);
const positionalParamsList = this._getPositionalParamsList(
positionalParamDefinitions
);
const scope =
taskDefinition.scope !== undefined ? `${taskDefinition.scope} ` : "";
console.log(
`Usage: ${this._executableName} [GLOBAL OPTIONS] ${scope}${name}${paramsList}${positionalParamsList}\n`
);
if (Object.keys(paramDefinitions).length > 0) {
console.log("OPTIONS:\n");
this._printParamDetails(paramDefinitions);
console.log("");
}
if (positionalParamDefinitions.length > 0) {
console.log("POSITIONAL ARGUMENTS:\n");
this._printPositionalParamDetails(positionalParamDefinitions);
console.log("");
}
console.log(`${name}: ${description}\n`);
console.log(`For global options help run: ${this._executableName} help\n`);
}
private _printTasks(
tasksMap: TasksMap,
includeSubtasks: boolean,
length: number = 0
) {
const taskNameList = Object.entries(tasksMap)
.filter(
([, taskDefinition]) => includeSubtasks || !taskDefinition.isSubtask
)
.map(([taskName]) => taskName)
.sort();
const nameLength = taskNameList
.map((n) => n.length)
.reduce((a, b) => Math.max(a, b), length);
for (const name of taskNameList) {
const { description = "" } = tasksMap[name];
console.log(` ${name.padEnd(nameLength)}\t${description}`);
}
return nameLength;
}
private _printScopes(scopesMap: ScopesMap, length: number) {
const scopeNamesList = Object.entries(scopesMap)
.map(([scopeName]) => scopeName)
.sort();
const nameLength = scopeNamesList
.map((n) => n.length)
.reduce((a, b) => Math.max(a, b), length);
for (const name of scopeNamesList) {
const { description = "" } = scopesMap[name];
console.log(` ${name.padEnd(nameLength)}\t${description}`);
}
return nameLength;
}
private _getParamValueDescription<T>(paramDefinition: ParamDefinition<T>) {
return `<${paramDefinition.type.name.toUpperCase()}>`;
}
private _getParamsList(paramDefinitions: ParamDefinitionsMap) {
let paramsList = "";
for (const name of Object.keys(paramDefinitions).sort()) {
const definition = paramDefinitions[name];
const { isFlag, isOptional } = definition;
paramsList += " ";
if (isOptional) {
paramsList += "[";
}
paramsList += `${ArgumentsParser.paramNameToCLA(name)}`;
if (!isFlag) {
paramsList += ` ${this._getParamValueDescription(definition)}`;
}
if (isOptional) {
paramsList += "]";
}
}
return paramsList;
}
private _getPositionalParamsList(
positionalParamDefinitions: Array<ParamDefinition<any>>
) {
let paramsList = "";
for (const definition of positionalParamDefinitions) {
const { isOptional, isVariadic, name } = definition;
paramsList += " ";
if (isOptional) {
paramsList += "[";
}
if (isVariadic) {
paramsList += "...";
}
paramsList += name;
if (isOptional) {
paramsList += "]";
}
}
return paramsList;
}
private _printParamDetails(paramDefinitions: ParamDefinitionsMap): number {
const paramsNameLength = Object.keys(paramDefinitions)
.map((n) => ArgumentsParser.paramNameToCLA(n).length)
.reduce((a, b) => Math.max(a, b), 0);
for (const name of Object.keys(paramDefinitions).sort()) {
const { description, defaultValue, isOptional, isFlag } =
paramDefinitions[name];
let msg = ` ${ArgumentsParser.paramNameToCLA(name).padEnd(
paramsNameLength
)}\t`;
if (description !== undefined) {
msg += `${description} `;
}
if (isOptional && defaultValue !== undefined && !isFlag) {
msg += `(default: ${JSON.stringify(defaultValue)})`;
}
console.log(msg);
}
return paramsNameLength;
}
private _printPositionalParamDetails(
positionalParamDefinitions: Array<ParamDefinition<any>>
) {
const paramsNameLength = positionalParamDefinitions
.map((d) => d.name.length)
.reduce((a, b) => Math.max(a, b), 0);
for (const definition of positionalParamDefinitions) {
const { name, description, isOptional, defaultValue } = definition;
let msg = ` ${name.padEnd(paramsNameLength)}\t`;
if (description !== undefined) {
msg += `${description} `;
}
if (isOptional && defaultValue !== undefined) {
msg += `(default: ${JSON.stringify(defaultValue)})`;
}
console.log(msg);
}
}
}