UNPKG

hardhat

Version:

Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

391 lines (338 loc) 9.72 kB
import type { ArgumentTypeToValueType, OptionDefinition, PositionalArgumentDefinition, } from "../../../types/arguments.js"; import type { NewTaskActionFunction, NewTaskDefinitionBuilder, NewTaskDefinition, TaskOverrideActionFunction, TaskOverrideDefinitionBuilder, TaskOverrideDefinition, EmptyTaskDefinitionBuilder, EmptyTaskDefinition, ExtendTaskArguments, TaskArguments, LazyActionObject, } from "../../../types/tasks.js"; import { HardhatError } from "@nomicfoundation/hardhat-errors"; import { ArgumentType } from "../../../types/arguments.js"; import { TaskDefinitionType } from "../../../types/tasks.js"; import { formatTaskId } from "./utils.js"; import { validateId, validateOption, validatePositionalArgument, } from "./validations.js"; export class EmptyTaskDefinitionBuilderImplementation implements EmptyTaskDefinitionBuilder { readonly #id: string[]; readonly #description: string; constructor(id: string | string[], description: string = "") { validateId(id); this.#id = Array.isArray(id) ? id : [id]; this.#description = description; } public build(): EmptyTaskDefinition { return { type: TaskDefinitionType.EMPTY_TASK, id: this.#id, description: this.#description, }; } } export class NewTaskDefinitionBuilderImplementation< TaskArgumentsT extends TaskArguments = TaskArguments, > implements NewTaskDefinitionBuilder<TaskArgumentsT> { readonly #id: string[]; readonly #usedNames: Set<string> = new Set(); readonly #options: Record<string, OptionDefinition> = {}; readonly #positionalArgs: PositionalArgumentDefinition[] = []; #description: string; #action?: LazyActionObject<NewTaskActionFunction<TaskArgumentsT>>; constructor(id: string | string[], description: string = "") { validateId(id); this.#id = Array.isArray(id) ? id : [id]; this.#description = description; } public setDescription(description: string): this { this.#description = description; return this; } public setAction( action: LazyActionObject<NewTaskActionFunction<TaskArgumentsT>>, ): this { this.#action = action; return this; } public addOption< NameT extends string, TypeT extends ArgumentType = ArgumentType.STRING, >({ name, shortName, description = "", type, defaultValue, hidden, }: { name: NameT; shortName?: string; description?: string; type?: TypeT; defaultValue: ArgumentTypeToValueType<TypeT>; hidden?: boolean; }): NewTaskDefinitionBuilder< ExtendTaskArguments<NameT, TypeT, TaskArgumentsT> > { const argumentType = type ?? ArgumentType.STRING; const optionDefinition = { name, shortName, description, type: argumentType, defaultValue, hidden, }; validateOption(optionDefinition, this.#usedNames, this.#id); this.#options[name] = optionDefinition; return this; } public addFlag<NameT extends string>(flagConfig: { name: NameT; shortName?: string; description?: string; hidden?: boolean; }): NewTaskDefinitionBuilder< ExtendTaskArguments<NameT, ArgumentType.FLAG, TaskArgumentsT> > { return this.addOption({ ...flagConfig, type: ArgumentType.FLAG, defaultValue: false, hidden: flagConfig.hidden, }); } public addLevel<NameT extends string>(levelConfig: { name: NameT; shortName?: string; description?: string; defaultValue?: number; }): NewTaskDefinitionBuilder< ExtendTaskArguments<NameT, ArgumentType.LEVEL, TaskArgumentsT> > { return this.addOption({ ...levelConfig, type: ArgumentType.LEVEL, defaultValue: levelConfig.defaultValue ?? 0, }); } public addPositionalArgument< NameT extends string, TypeT extends ArgumentType = ArgumentType.STRING, >(argConfig: { name: NameT; description?: string; type?: TypeT; defaultValue?: ArgumentTypeToValueType<TypeT>; }): NewTaskDefinitionBuilder< ExtendTaskArguments<NameT, TypeT, TaskArgumentsT> > { return this.#addPositionalArgument({ ...argConfig, isVariadic: false, }); } public addVariadicArgument< NameT extends string, TypeT extends ArgumentType = ArgumentType.STRING, >(argConfig: { name: NameT; description?: string; type?: TypeT; defaultValue?: Array<ArgumentTypeToValueType<TypeT>>; }): NewTaskDefinitionBuilder< ExtendTaskArguments<NameT, TypeT, TaskArgumentsT> > { return this.#addPositionalArgument({ ...argConfig, isVariadic: true, }); } public build(): NewTaskDefinition { if (this.#action === undefined) { throw new HardhatError( HardhatError.ERRORS.CORE.TASK_DEFINITIONS.NO_ACTION, { task: formatTaskId(this.#id), }, ); } return { type: TaskDefinitionType.NEW_TASK, id: this.#id, description: this.#description, /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- The type of the action is narrowed in the setAction function to improve the argument types. Once the task is built, we use the more general type to avoid having to parameterize the NewTaskDefinition */ action: this.#action as LazyActionObject<NewTaskActionFunction>, options: this.#options, positionalArguments: this.#positionalArgs, }; } #addPositionalArgument< NameT extends string, TypeT extends ArgumentType = ArgumentType.STRING, >({ name, description = "", type, defaultValue, isVariadic, }: { name: NameT; description?: string; type?: TypeT; defaultValue?: | ArgumentTypeToValueType<TypeT> | Array<ArgumentTypeToValueType<TypeT>>; isVariadic: boolean; }): NewTaskDefinitionBuilder< ExtendTaskArguments<NameT, TypeT, TaskArgumentsT> > { const argumentType = type ?? ArgumentType.STRING; const positionalArgDef = { name, description, type: argumentType, defaultValue, isVariadic, }; const lastArg = this.#positionalArgs.at(-1); validatePositionalArgument( positionalArgDef, this.#usedNames, this.#id, lastArg, ); this.#positionalArgs.push(positionalArgDef); return this; } } export class TaskOverrideDefinitionBuilderImplementation< TaskArgumentsT extends TaskArguments = TaskArguments, > implements TaskOverrideDefinitionBuilder<TaskArgumentsT> { readonly #id: string[]; readonly #options: Record<string, OptionDefinition> = {}; #description?: string; #action?: LazyActionObject<TaskOverrideActionFunction<TaskArgumentsT>>; constructor(id: string | string[]) { validateId(id); this.#id = Array.isArray(id) ? id : [id]; } public setDescription(description: string): this { this.#description = description; return this; } public setAction( action: LazyActionObject<TaskOverrideActionFunction<TaskArgumentsT>>, ): this { this.#action = action; return this; } public addOption< NameT extends string, TypeT extends ArgumentType = ArgumentType.STRING, >({ name, shortName, description = "", type, defaultValue, hidden, }: { name: NameT; shortName?: string; description?: string; type?: TypeT; defaultValue: ArgumentTypeToValueType<TypeT>; hidden?: boolean; }): TaskOverrideDefinitionBuilder< ExtendTaskArguments<NameT, TypeT, TaskArgumentsT> > { const argumentType = type ?? ArgumentType.STRING; const optionDefinition = { name, shortName, description, type: argumentType, defaultValue, hidden, }; const usedNames = new Set<string>(); for (const option of Object.values(this.#options)) { usedNames.add(option.name); if (option.shortName !== undefined) { usedNames.add(option.shortName); } } validateOption(optionDefinition, usedNames, this.#id); this.#options[name] = optionDefinition; return this; } public addFlag<NameT extends string>(flagConfig: { name: string; shortName?: string; description?: string; hidden?: boolean; }): TaskOverrideDefinitionBuilder< ExtendTaskArguments<NameT, ArgumentType.FLAG, TaskArgumentsT> > { return this.addOption({ ...flagConfig, type: ArgumentType.FLAG, defaultValue: false, hidden: flagConfig.hidden, }); } public addLevel<NameT extends string>(levelConfig: { name: string; shortName?: string; description?: string; defaultValue?: number; }): TaskOverrideDefinitionBuilder< ExtendTaskArguments<NameT, ArgumentType.LEVEL, TaskArgumentsT> > { return this.addOption({ ...levelConfig, type: ArgumentType.LEVEL, defaultValue: levelConfig.defaultValue ?? 0, }); } public build(): TaskOverrideDefinition { if (this.#action === undefined) { throw new HardhatError( HardhatError.ERRORS.CORE.TASK_DEFINITIONS.NO_ACTION, { task: formatTaskId(this.#id), }, ); } return { type: TaskDefinitionType.TASK_OVERRIDE, id: this.#id, description: this.#description, /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- The type of the action is narrowed in the setAction function to improve the argument types. Once the task is built, we use the more general type to avoid having to parameterize the TaskOverrideDefinition */ action: this.#action as LazyActionObject<TaskOverrideActionFunction>, options: this.#options, }; } }