Skip to content

Commit 67c897c

Browse files
authored
Merge pull request #5341 from NomicFoundation/tasks-def
Improve task types & validation
2 parents c9df7e6 + 516fd25 commit 67c897c

File tree

4 files changed

+67
-42
lines changed

4 files changed

+67
-42
lines changed

v-next/core/src/internal/tasks/builders.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,7 @@ export class NewTaskDefinitionBuilderImplementation
223223
}
224224

225225
if (defaultValue !== undefined) {
226-
let isValid = true;
227-
228-
if (Array.isArray(defaultValue)) {
229-
isValid =
230-
isVariadic &&
231-
defaultValue.every((v) => isParameterValueValid(parameterType, v));
232-
} else {
233-
isValid = isParameterValueValid(parameterType, defaultValue);
234-
}
235-
236-
if (!isValid) {
226+
if (!isParameterValueValid(parameterType, defaultValue, isVariadic)) {
237227
throw new HardhatError(
238228
HardhatError.ERRORS.ARGUMENTS.INVALID_VALUE_FOR_TYPE,
239229
{

v-next/core/src/types/common.ts

+14
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ export interface ParameterToValueTypeMap {
2222
[ParameterType.FILE]: string;
2323
}
2424

25+
/**
26+
* All the possible values for a parameter.
27+
*/
28+
export type ParameterValue =
29+
ParameterToValueTypeMap[keyof ParameterToValueTypeMap];
30+
2531
/**
2632
* Maps a `ParameterType` to its corresponding value type.
2733
*
@@ -57,11 +63,19 @@ const parameterTypeValidators: Record<
5763
*
5864
* This function uses a map of validators, where each validator is a function
5965
* that checks if a value is valid for a specific parameter type.
66+
* If the parameter type is variadic, the value is considered valid if it is an
67+
* array and all its elements are valid for the parameter type.
6068
*/
6169
export function isParameterValueValid(
6270
type: ParameterType,
6371
value: unknown,
72+
isVariadic: boolean = false,
6473
): boolean {
6574
const validator = parameterTypeValidators[type];
75+
76+
if (isVariadic) {
77+
return Array.isArray(value) && value.every(validator);
78+
}
79+
6680
return validator(value);
6781
}

v-next/core/src/types/tasks.ts

+21-12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import type { ParameterType, ParameterTypeToValueType } from "./common.js";
1+
import type {
2+
ParameterType,
3+
ParameterTypeToValueType,
4+
ParameterValue,
5+
} from "./common.js";
26
import type { HardhatRuntimeEnvironment } from "./hre.js";
37

48
// We add the TaskManager to the HRE with a module augmentation to avoid
@@ -23,6 +27,15 @@ declare module "./config.js" {
2327
}
2428
}
2529

30+
export interface TaskParameter<T extends ParameterType = ParameterType> {
31+
name: string;
32+
description: string;
33+
parameterType: T;
34+
defaultValue?:
35+
| ParameterTypeToValueType<T>
36+
| Array<ParameterTypeToValueType<T>>;
37+
}
38+
2639
/**
2740
* A named task parameter is one that is used as `--<name> value` in the CLI.
2841
*
@@ -32,11 +45,9 @@ declare module "./config.js" {
3245
* parameter is considered a flag, and can be used as `--<name>` to set it to
3346
* `true`.
3447
*/
35-
export interface NamedTaskParameter {
36-
name: string;
37-
description: string;
38-
parameterType: ParameterType;
39-
defaultValue?: any;
48+
export interface NamedTaskParameter<T extends ParameterType = ParameterType>
49+
extends TaskParameter<T> {
50+
defaultValue?: ParameterTypeToValueType<T>;
4051
}
4152

4253
/**
@@ -46,19 +57,17 @@ export interface NamedTaskParameter {
4657
* If the parameter is variadic, it can have multiple values. A variadic parameter
4758
* can only be the last positional parameter, and it consumes all the remaining values.
4859
*/
49-
export interface PositionalTaskParameter {
50-
name: string;
51-
description: string;
52-
parameterType: ParameterType;
53-
defaultValue?: any;
60+
export interface PositionalTaskParameter<
61+
T extends ParameterType = ParameterType,
62+
> extends TaskParameter<T> {
5463
isVariadic: boolean;
5564
}
5665

5766
/**
5867
* A type representing the arguments or concrete parameters of a task. That is,
5968
* the actual values passed to it.
6069
*/
61-
export type TaskArguments = Record<string, any>;
70+
export type TaskArguments = Record<string, ParameterValue | ParameterValue[]>;
6271

6372
/**
6473
* The type of a new task's action function.

v-next/hardhat/src/internal/cli/main.ts

+31-19
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
1-
import {
2-
buildGlobalParameterMap,
3-
resolvePluginList,
4-
} from "@nomicfoundation/hardhat-core";
5-
import { ParameterType } from "@nomicfoundation/hardhat-core/types/common";
6-
import {
1+
import type { ParameterValue } from "@nomicfoundation/hardhat-core/types/common";
2+
import type {
73
GlobalArguments,
84
GlobalParameter,
95
GlobalParameterMap,
106
} from "@nomicfoundation/hardhat-core/types/global-parameters";
11-
import { HardhatRuntimeEnvironment } from "@nomicfoundation/hardhat-core/types/hre";
12-
import {
7+
import type { HardhatRuntimeEnvironment } from "@nomicfoundation/hardhat-core/types/hre";
8+
import type {
139
NamedTaskParameter,
14-
PositionalTaskParameter,
1510
Task,
11+
TaskArguments,
12+
TaskParameter,
1613
} from "@nomicfoundation/hardhat-core/types/tasks";
14+
1715
import "tsx"; // NOTE: This is important, it allows us to load .ts files form the CLI
18-
import { HardhatError } from "@nomicfoundation/hardhat-errors";
16+
17+
import {
18+
buildGlobalParameterMap,
19+
resolvePluginList,
20+
} from "@nomicfoundation/hardhat-core";
21+
import { ParameterType } from "@nomicfoundation/hardhat-core/types/common";
22+
import {
23+
HardhatError,
24+
assertHardhatInvariant,
25+
} from "@nomicfoundation/hardhat-errors";
1926
import { isCi } from "@nomicfoundation/hardhat-utils/ci";
2027

2128
import { builtinPlugins } from "../builtin-plugins/index.js";
@@ -231,7 +238,7 @@ export function parseTaskAndArguments(
231238
):
232239
| {
233240
task: Task;
234-
taskArguments: Record<string, any>;
241+
taskArguments: TaskArguments;
235242
}
236243
| string[] {
237244
const taskOrId = getTaskFromCliArguments(cliArguments, usedCliArguments, hre);
@@ -312,8 +319,8 @@ function parseTaskArguments(
312319
cliArguments: string[],
313320
usedCliArguments: boolean[],
314321
task: Task,
315-
): Record<string, any> {
316-
const taskArguments: Record<string, unknown> = {};
322+
): TaskArguments {
323+
const taskArguments: TaskArguments = {};
317324

318325
// Parse named parameters
319326
parseDoubleDashArgs(
@@ -345,7 +352,7 @@ function parseDoubleDashArgs(
345352
cliArguments: string[],
346353
usedCliArguments: boolean[],
347354
parametersMap: Map<string, NamedTaskParameter | GlobalParameter>,
348-
argumentsMap: Record<string, any>,
355+
argumentsMap: TaskArguments,
349356
) {
350357
for (let i = 0; i < cliArguments.length; i++) {
351358
if (usedCliArguments[i]) {
@@ -433,7 +440,7 @@ function parsePositionalAndVariadicParameters(
433440
cliArguments: string[],
434441
usedCliArguments: boolean[],
435442
task: Task,
436-
taskArguments: Record<string, any>,
443+
taskArguments: TaskArguments,
437444
) {
438445
let paramI = 0;
439446

@@ -472,16 +479,21 @@ function parsePositionalAndVariadicParameters(
472479
// Handle variadic parameters. No longer increment "paramI" becuase there can only be one variadic parameter and it
473480
// will consume all remaining arguments.
474481
taskArguments[paramInfo.name] = taskArguments[paramInfo.name] ?? [];
475-
taskArguments[paramInfo.name].push(formattedValue);
482+
const variadicTaskArg = taskArguments[paramInfo.name];
483+
assertHardhatInvariant(
484+
Array.isArray(variadicTaskArg),
485+
"Variadic parameter values should be an array",
486+
);
487+
variadicTaskArg.push(formattedValue);
476488
}
477489

478490
// Check if all the required parameters have been used
479491
validateRequiredParameters(task.positionalParameters, taskArguments);
480492
}
481493

482494
function validateRequiredParameters(
483-
parameters: PositionalTaskParameter[] | NamedTaskParameter[],
484-
taskArguments: Record<string, any>,
495+
parameters: TaskParameter[],
496+
taskArguments: TaskArguments,
485497
) {
486498
const missingRequiredParam = parameters.find(
487499
(param) =>
@@ -507,7 +519,7 @@ function parseParameterValue(
507519
strValue: string,
508520
type: ParameterType,
509521
argName: string,
510-
): any {
522+
): ParameterValue {
511523
switch (type) {
512524
case ParameterType.STRING:
513525
return validateAndParseString(argName, strValue);

0 commit comments

Comments
 (0)