Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/dull-queens-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"hardhat": patch
---

Export DependencyResolver, importUserConfig, and add a hook for reading solidity files
1 change: 1 addition & 0 deletions v-next/hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"./config": "./dist/src/config.js",
"./hre": "./dist/src/hre.js",
"./plugins": "./dist/src/plugins.js",
"./internal/lsp-helpers": "./dist/src/lsp-helpers.js",
"./types/arguments": "./dist/src/types/arguments.js",
"./types/artifacts": "./dist/src/types/artifacts.js",
"./types/config": "./dist/src/types/config.js",
Expand Down
1 change: 1 addition & 0 deletions v-next/hardhat/src/hre.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
// type-extensions are loaded when the user imports `hardhat/hre`.
import "./internal/builtin-plugins/index.js";

export { importUserConfig } from "./internal/config-loading.js";
export { resolveHardhatConfigPath } from "./internal/config-loading.js";
export { createHardhatRuntimeEnvironment } from "./internal/hre-initialization.js";
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import chalk from "chalk";

import { getHardhatVersion } from "../../utils/package.js";
import { buildDependencyGraph } from "../solidity/build-system/dependency-graph-building.js";
import { readSourceFileFactory } from "../solidity/build-system/read-source-file.js";
import { isNpmRootPath } from "../solidity/build-system/root-paths-utils.js";

// Match every group where a SPDX license is defined. The first captured group is the license.
Expand Down Expand Up @@ -37,7 +38,7 @@ export interface FlattenMetadata {

const flattenAction: NewTaskActionFunction<FlattenActionArguments> = async (
{ files, logFunction, warnFunction },
{ solidity, config },
{ solidity, config, hooks },
): Promise<FlattenActionResult> => {
const log = logFunction ?? console.log;
const warn = warnFunction ?? console.warn;
Expand All @@ -59,6 +60,7 @@ const flattenAction: NewTaskActionFunction<FlattenActionArguments> = async (
rootPaths.toSorted(), // We sort them to have a deterministic order
config.paths.root,
config.solidity.remappings,
readSourceFileFactory(hooks),
);

let flattened = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { ObjectCache } from "./cache.js";
import { CompilationJobImplementation } from "./compilation-job.js";
import { downloadConfiguredCompilers, getCompiler } from "./compiler/index.js";
import { buildDependencyGraph } from "./dependency-graph-building.js";
import { readSourceFileFactory } from "./read-source-file.js";
import {
formatRootPath,
isNpmParsedRootPath,
Expand Down Expand Up @@ -303,6 +304,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem {
rootFilePaths.toSorted(), // We sort them to have a deterministic order
this.#options.projectRoot,
this.#options.solidityConfig.remappings,
readSourceFileFactory(this.#hooks),
);

const buildProfileName = options?.buildProfile ?? DEFAULT_BUILD_PROFILE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ export async function buildDependencyGraph(
rootFiles: string[],
projectRoot: string,
userRemappings: string[],
readFile: (absPath: string) => Promise<string>,
): Promise<{
dependencyGraph: DependencyGraphImplementation;
resolver: Resolver;
}> {
const resolver = await ResolverImplementation.create(
projectRoot,
userRemappings,
readFile,
);

const dependencyGraph = new DependencyGraphImplementation();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { HookManager } from "../../../../types/hooks.js";

import { readUtf8File } from "@nomicfoundation/hardhat-utils/fs";

export function readSourceFileFactory(
hooks: HookManager,
): (absPath: string) => Promise<string> {
return async (factoryAbsPath: string) => {
return hooks.runHandlerChain(
"solidity",
"readSourceFile",
[factoryAbsPath],
async (_context, absPath) => readUtf8File(absPath),
);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const PROJECT_ROOT_SENTINEL: unique symbol = Symbol();
export class ResolverImplementation implements Resolver {
readonly #projectRoot: string;
readonly #userRemappings: ResolvedUserRemapping[];
readonly #readFile: (absPath: string) => Promise<string>;

/**
* IMPORTANT: This mutex must be acquired before writing to any of the mutable
Expand Down Expand Up @@ -148,23 +149,26 @@ export class ResolverImplementation implements Resolver {
public static async create(
projectRoot: string,
userRemappingStrings: string[],
readFile: (absPath: string) => Promise<string> = readUtf8File,
): Promise<Resolver> {
const userRemappings = await Promise.all(
userRemappingStrings.map((remappingString) =>
validateAndResolveUserRemapping(projectRoot, remappingString),
),
);

return new ResolverImplementation(projectRoot, userRemappings);
return new ResolverImplementation(projectRoot, userRemappings, readFile);
}

private constructor(
projectRoot: string,
userRemappings: ResolvedUserRemapping[],
readFile: (absPath: string) => Promise<string>,
) {
this.#projectRoot = projectRoot;
this.#userRemappings = userRemappings;
this.#dependencyMaps.set(PROJECT_ROOT_SENTINEL, new Map());
this.#readFile = readFile;
}

public async resolveProjectFile(
Expand Down Expand Up @@ -243,7 +247,7 @@ export class ResolverImplementation implements Resolver {
new ProjectResolvedFileImplementation({
sourceName,
fsPath: fsPathWithTheRightCasing,
content: await readFileContent(fsPathWithTheRightCasing),
content: await this.#readFileContent(fsPathWithTheRightCasing),
});

this.#resolvedFileBySourceName.set(sourceName, resolvedFile);
Expand Down Expand Up @@ -337,7 +341,7 @@ export class ResolverImplementation implements Resolver {
new NpmPackageResolvedFileImplementation({
sourceName,
fsPath,
content: await readFileContent(fsPath),
content: await this.#readFileContent(fsPath),
package: npmPackage,
});

Expand Down Expand Up @@ -820,7 +824,7 @@ export class ResolverImplementation implements Resolver {
new ProjectResolvedFileImplementation({
sourceName,
fsPath,
content: await readFileContent(fsPath),
content: await this.#readFileContent(fsPath),
});

this.#resolvedFileBySourceName.set(sourceName, resolvedFile);
Expand Down Expand Up @@ -885,7 +889,7 @@ export class ResolverImplementation implements Resolver {
new NpmPackageResolvedFileImplementation({
sourceName,
fsPath,
content: await readFileContent(fsPath),
content: await this.#readFileContent(fsPath),
package: remapping.targetNpmPackage,
});

Expand Down Expand Up @@ -938,7 +942,7 @@ export class ResolverImplementation implements Resolver {
new NpmPackageResolvedFileImplementation({
sourceName,
fsPath: filePath,
content: await readFileContent(filePath),
content: await this.#readFileContent(filePath),
package: from.package,
});

Expand Down Expand Up @@ -993,7 +997,7 @@ export class ResolverImplementation implements Resolver {
new NpmPackageResolvedFileImplementation({
sourceName,
fsPath,
content: await readFileContent(fsPath),
content: await this.#readFileContent(fsPath),
package: from.package,
});

Expand Down Expand Up @@ -1053,7 +1057,7 @@ export class ResolverImplementation implements Resolver {
new NpmPackageResolvedFileImplementation({
sourceName,
fsPath,
content: await readFileContent(fsPath),
content: await this.#readFileContent(fsPath),
package: importedPackage,
});

Expand Down Expand Up @@ -1343,6 +1347,20 @@ export class ResolverImplementation implements Resolver {

return { package: match.groups.package, subpath: match.groups.path };
}

/**
* Reads and analyzes the file at the given absolute path.
*/
async #readFileContent(absolutePath: string): Promise<FileContent> {
const text = await this.#readFile(absolutePath);
const { imports, versionPragmas } = analyze(text);

return {
text,
importPaths: imports,
versionPragmas,
};
}
}

async function validateAndResolveUserRemapping(
Expand Down Expand Up @@ -1542,20 +1560,6 @@ function sourceNamePathJoin(...parts: string[]): string {
return fsPathToSourceNamePath(path.join(...parts));
}

/**
* Reads and analyzes the file at the given absolute path.
*/
async function readFileContent(absolutePath: string): Promise<FileContent> {
const text = await readUtf8File(absolutePath);
const { imports, versionPragmas } = analyze(text);

return {
text,
importPaths: imports,
versionPragmas,
};
}

/**
* Resolves a subpath for a given package, when it uses package#exports
* @param npmPackage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,14 @@ declare module "../../../types/hooks.js" {
artifactPaths: string[],
) => Promise<void>,
) => Promise<void>;

readSourceFile: (
context: HookContext,
absolutePath: string,
next: (
nextContext: HookContext,
nextAbsolutePath: string,
) => Promise<string>,
) => Promise<string>;
}
}
4 changes: 4 additions & 0 deletions v-next/hardhat/src/lsp-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { readSourceFileFactory } from "./internal/builtin-plugins/solidity/build-system/read-source-file.js";
export { ResolverImplementation } from "./internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.js";

export type { Resolver } from "./internal/builtin-plugins/solidity/build-system/resolver/types.js";
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from "node:path";
import { describe, it } from "node:test";

import { useFixtureProject } from "@nomicfoundation/hardhat-test-utils";
import { readUtf8File } from "@nomicfoundation/hardhat-utils/fs";

import { buildDependencyGraph } from "../../../../../src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.js";

Expand All @@ -14,6 +15,7 @@ describe("buildDependencyGraph", () => {
[],
process.cwd(),
[],
readUtf8File,
);

assert.equal(dependencyGraph.getRoots().size, 0);
Expand All @@ -39,6 +41,7 @@ describe("buildDependencyGraph", () => {
rootSourceNames.map((sourceName) => path.join(process.cwd(), sourceName)),
process.cwd(),
["remapped/=npm/@openzeppelin/contracts@5.1.0/access/"],
readUtf8File,
);

const roots = dependencyGraph.getRoots();
Expand Down
Loading