Hardhat provides a comprehensive set of utility functions for common development tasks including contract name parsing, coverage tracking for testing, and LSP (Language Server Protocol) helpers for IDE integration.
Functions for working with contract names and fully qualified names in Solidity projects.
/**
* Combines a source file name and contract name into a fully qualified name
* @param sourceName - The name or path of the source file (e.g., "contracts/MyToken.sol")
* @param contractName - The name of the contract declared in that source file
* @returns The fully qualified name in the form "sourceName:contractName"
*/
function getFullyQualifiedName(
sourceName: string,
contractName: string
): string;
/**
* Checks whether a given string is a fully qualified name
* @param name - The string to test
* @returns true if the string contains a colon, false otherwise
*/
function isFullyQualifiedName(name: string): boolean;
/**
* Parses a fully qualified name into its source and contract components
* @param fullyQualifiedName - The name in the form "sourceName:contractName"
* @returns An object with sourceName and contractName properties
* @throws HardhatError if the input does not contain a source segment
*/
function parseFullyQualifiedName(fullyQualifiedName: string): {
sourceName: string;
contractName: string;
};
/**
* Splits a string into optional source and contract name parts
* @param name - The string to split, which may be "contractName" or "source:contractName"
* @returns An object with sourceName (optional) and contractName
*/
function parseName(name: string): {
sourceName?: string;
contractName: string;
};Usage Examples:
import {
getFullyQualifiedName,
isFullyQualifiedName,
parseFullyQualifiedName,
parseName
} from "hardhat/utils/contract-names";
// Create fully qualified names
const fqn = getFullyQualifiedName("contracts/tokens/ERC20.sol", "MyToken");
// Result: "contracts/tokens/ERC20.sol:MyToken"
// Check if a name is fully qualified
if (isFullyQualifiedName("contracts/MyContract.sol:MyContract")) {
console.log("This is a fully qualified name");
}
// Parse fully qualified names
const { sourceName, contractName } = parseFullyQualifiedName(fqn);
console.log(`Source: ${sourceName}, Contract: ${contractName}`);
// Parse any name format (handles both simple and fully qualified names)
const simple = parseName("SimpleContract");
// { contractName: "SimpleContract" } (sourceName is undefined)
const qualified = parseName("contracts/Complex.sol:ComplexContract");
// { sourceName: "contracts/Complex.sol", contractName: "ComplexContract" }Functions for managing test coverage collection and reporting.
/**
* Marks the start of test coverage collection
* Called at the beginning of test runs to initialize coverage tracking
*/
function markTestRunStart(): void;
/**
* Marks the completion of test coverage collection
* Called after all tests complete to finalize coverage data
*/
function markTestRunDone(): void;
/**
* Marks the completion of a test worker for coverage
* Used in parallel test execution to track worker completion
*/
function markTestWorkerDone(): void;Usage Examples:
import {
markTestRunStart,
markTestRunDone,
markTestWorkerDone
} from "hardhat/internal/coverage";
// In test runner implementation
export async function runTests() {
// Start coverage collection
markTestRunStart();
try {
// Run all tests
await executeTestSuite();
} finally {
// Always mark coverage as done
markTestRunDone();
}
}
// In parallel test worker
export async function runWorkerTests() {
// ... run worker tests ...
markTestWorkerDone();
}Language Server Protocol helpers for IDE integration and development tools.
/**
* Factory function for reading source files with proper caching and error handling
* @returns Function that can read source file content
*/
function readSourceFileFactory(): (sourcePath: string) => Promise<string>;
/**
* Dependency resolver implementation for Solidity imports
*/
class ResolverImplementation implements Resolver {
constructor(options: ResolverOptions);
/** Resolve import path to absolute file path */
resolve(importPath: string, sourcePath: string): Promise<string>;
/** Check if a file exists */
exists(path: string): Promise<boolean>;
/** Read file content */
readFile(path: string): Promise<string>;
}
interface Resolver {
resolve(importPath: string, sourcePath: string): Promise<string>;
exists(path: string): Promise<boolean>;
readFile(path: string): Promise<string>;
}
interface ResolverOptions {
projectRoot: string;
nodeModulesPath?: string;
remappings?: string[];
}Utilities for formatting resolution and compilation errors with user-friendly messages.
/**
* Formats project root resolution errors with helpful context
* @param error - The original resolution error
* @returns Formatted error message with resolution suggestions
*/
function formatProjectRootResolutionError(error: Error): string;
/**
* Formats npm root resolution errors for dependency issues
* @param error - The original npm resolution error
* @returns Formatted error message with installation suggestions
*/
function formatNpmRootResolutionError(error: Error): string;
/**
* Formats import resolution errors for Solidity files
* @param error - The original import resolution error
* @param importPath - The import path that failed to resolve
* @returns Formatted error message with resolution suggestions
*/
function formatImportResolutionError(error: Error, importPath: string): string;Usage Examples:
import {
readSourceFileFactory,
ResolverImplementation,
formatImportResolutionError
} from "hardhat/internal/lsp-helpers";
// Create source file reader
const readSourceFile = readSourceFileFactory();
// Read a Solidity file
try {
const content = await readSourceFile("contracts/MyContract.sol");
console.log(`File content: ${content.substring(0, 100)}...`);
} catch (error) {
console.error(`Failed to read file: ${error.message}`);
}
// Create dependency resolver
const resolver = new ResolverImplementation({
projectRoot: "/path/to/project",
nodeModulesPath: "/path/to/node_modules",
remappings: ["@openzeppelin/=node_modules/@openzeppelin/"]
});
// Resolve an import
try {
const resolvedPath = await resolver.resolve(
"@openzeppelin/contracts/token/ERC20/ERC20.sol",
"contracts/MyToken.sol"
);
console.log(`Resolved to: ${resolvedPath}`);
} catch (error) {
const formattedError = formatImportResolutionError(
error,
"@openzeppelin/contracts/token/ERC20/ERC20.sol"
);
console.error(formattedError);
}Type definitions supporting utility functions and development tools.
/**
* Utility type for extracting parameters except the first
*/
type ParametersExceptFirst<T extends (...args: any[]) => any> =
T extends (first: any, ...rest: infer R) => any ? R : never;
/**
* Utility type for extracting parameters except the last
*/
type ParametersExceptLast<T extends (...args: any[]) => any> =
T extends (...args: [...infer R, any]) => any ? R : never;
/**
* Utility type for extracting parameters except first and last
*/
type ParametersExceptFirstAndLast<T extends (...args: any[]) => any> =
T extends (first: any, ...middle: infer M, last: any) => any ? M : never;
/**
* Utility type for extracting the last parameter
*/
type LastParameter<T extends (...args: any[]) => any> =
T extends (...args: [...any[], infer L]) => any ? L : never;
/**
* Utility type for extracting function parameters
*/
type Params<T extends (...args: any[]) => any> = Parameters<T>;
/**
* Utility type for extracting function return type
*/
type Return<T extends (...args: any[]) => any> = ReturnType<T>;