From 4524c087c0024cf6327b7475d07de4a94df03324 Mon Sep 17 00:00:00 2001 From: Armando Andini Date: Wed, 16 Apr 2025 14:26:26 -0300 Subject: [PATCH 1/5] Add readSourceFile hook --- .../builtin-plugins/flatten/task-action.ts | 3 +- .../solidity/build-system/build-system.ts | 1 + .../build-system/dependency-graph-building.ts | 3 ++ .../resolver/dependency-resolver.ts | 54 +++++++++++-------- .../solidity/type-extensions.ts | 6 +++ .../build-system/dependency-graph-building.ts | 11 +++- .../resolver/dependency-resolver.ts | 18 ++++++- 7 files changed, 71 insertions(+), 25 deletions(-) diff --git a/v-next/hardhat/src/internal/builtin-plugins/flatten/task-action.ts b/v-next/hardhat/src/internal/builtin-plugins/flatten/task-action.ts index 2a590a39b0a..eaeb71e9867 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/flatten/task-action.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/flatten/task-action.ts @@ -37,7 +37,7 @@ export interface FlattenMetadata { const flattenAction: NewTaskActionFunction = async ( { files, logFunction, warnFunction }, - { solidity, config }, + { solidity, config, hooks }, ): Promise => { const log = logFunction ?? console.log; const warn = warnFunction ?? console.warn; @@ -59,6 +59,7 @@ const flattenAction: NewTaskActionFunction = async ( rootPaths.toSorted(), // We sort them to have a deterministic order config.paths.root, config.solidity.remappings, + hooks, ); let flattened = ""; diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts index 83041517c7e..9183d8ec5b2 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts @@ -303,6 +303,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { rootFilePaths.toSorted(), // We sort them to have a deterministic order this.#options.projectRoot, this.#options.solidityConfig.remappings, + this.#hooks, ); const buildProfileName = options?.buildProfile ?? DEFAULT_BUILD_PROFILE; diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts index e456ff7abbe..19c3d3b22b7 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts @@ -4,11 +4,13 @@ import type { ResolvedFile } from "../../../../types/solidity/resolved-file.js"; import { DependencyGraphImplementation } from "./dependency-graph.js"; import { ResolverImplementation } from "./resolver/dependency-resolver.js"; import { isNpmParsedRootPath, parseRootPath } from "./root-paths-utils.js"; +import { HookManager } from "../../../../types/hooks.js"; export async function buildDependencyGraph( rootFiles: string[], projectRoot: string, userRemappings: string[], + hooks: HookManager, ): Promise<{ dependencyGraph: DependencyGraphImplementation; resolver: Resolver; @@ -16,6 +18,7 @@ export async function buildDependencyGraph( const resolver = await ResolverImplementation.create( projectRoot, userRemappings, + hooks, ); const dependencyGraph = new DependencyGraphImplementation(); diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts index 68bcff644a0..8a516d79bc5 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts @@ -41,6 +41,7 @@ import { parseRemappingString, selectBestRemapping, } from "./remappings.js"; +import { HookManager } from "../../../../../types/hooks.js"; // Things to note: // - This resolver assumes that the root of the project is the folder with the @@ -92,6 +93,7 @@ const PROJECT_ROOT_SENTINEL: unique symbol = Symbol(); export class ResolverImplementation implements Resolver { readonly #projectRoot: string; readonly #userRemappings: ResolvedUserRemapping[]; + readonly #hooks: HookManager; /** * IMPORTANT: This mutex must be acquired before writing to any of the mutable @@ -148,6 +150,7 @@ export class ResolverImplementation implements Resolver { public static async create( projectRoot: string, userRemappingStrings: string[], + hooks: HookManager, ): Promise { const userRemappings = await Promise.all( userRemappingStrings.map((remappingString) => @@ -155,16 +158,18 @@ export class ResolverImplementation implements Resolver { ), ); - return new ResolverImplementation(projectRoot, userRemappings); + return new ResolverImplementation(projectRoot, userRemappings, hooks); } private constructor( projectRoot: string, userRemappings: ResolvedUserRemapping[], + hooks: HookManager, ) { this.#projectRoot = projectRoot; this.#userRemappings = userRemappings; this.#dependencyMaps.set(PROJECT_ROOT_SENTINEL, new Map()); + this.#hooks = hooks; } public async resolveProjectFile( @@ -243,7 +248,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); @@ -337,7 +342,7 @@ export class ResolverImplementation implements Resolver { new NpmPackageResolvedFileImplementation({ sourceName, fsPath, - content: await readFileContent(fsPath), + content: await this.#readFileContent(fsPath), package: npmPackage, }); @@ -820,7 +825,7 @@ export class ResolverImplementation implements Resolver { new ProjectResolvedFileImplementation({ sourceName, fsPath, - content: await readFileContent(fsPath), + content: await this.#readFileContent(fsPath), }); this.#resolvedFileBySourceName.set(sourceName, resolvedFile); @@ -885,7 +890,7 @@ export class ResolverImplementation implements Resolver { new NpmPackageResolvedFileImplementation({ sourceName, fsPath, - content: await readFileContent(fsPath), + content: await this.#readFileContent(fsPath), package: remapping.targetNpmPackage, }); @@ -938,7 +943,7 @@ export class ResolverImplementation implements Resolver { new NpmPackageResolvedFileImplementation({ sourceName, fsPath: filePath, - content: await readFileContent(filePath), + content: await this.#readFileContent(filePath), package: from.package, }); @@ -993,7 +998,7 @@ export class ResolverImplementation implements Resolver { new NpmPackageResolvedFileImplementation({ sourceName, fsPath, - content: await readFileContent(fsPath), + content: await this.#readFileContent(fsPath), package: from.package, }); @@ -1053,7 +1058,7 @@ export class ResolverImplementation implements Resolver { new NpmPackageResolvedFileImplementation({ sourceName, fsPath, - content: await readFileContent(fsPath), + content: await this.#readFileContent(fsPath), package: importedPackage, }); @@ -1343,6 +1348,25 @@ 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 { + const text = await this.#hooks.runHandlerChain( + "solidity", + "readSourceFile", + [absolutePath], + async (_context, absPath) => await readUtf8File(absPath), + ); + const { imports, versionPragmas } = analyze(text); + + return { + text, + importPaths: imports, + versionPragmas, + }; + } } async function validateAndResolveUserRemapping( @@ -1542,20 +1566,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 { - 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 diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/type-extensions.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/type-extensions.ts index 69c3e5a1da0..56eafb027a4 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/type-extensions.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/type-extensions.ts @@ -114,5 +114,11 @@ declare module "../../../types/hooks.js" { artifactPaths: string[], ) => Promise, ) => Promise; + + readSourceFile: ( + context: HookContext, + absPath: string, + next: (nextContext: HookContext, absPath: string) => Promise, + ) => Promise; } } diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts index e6c35da99e8..21e0e3dbf77 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts @@ -1,19 +1,27 @@ import assert from "node:assert/strict"; import path from "node:path"; -import { describe, it } from "node:test"; +import { before, describe, it } from "node:test"; import { useFixtureProject } from "@nomicfoundation/hardhat-test-utils"; import { buildDependencyGraph } from "../../../../../src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.js"; +import { HardhatRuntimeEnvironment } from "../../../../../src/types/hre.js"; +import { createHardhatRuntimeEnvironment } from "../../../../../src/internal/hre-intialization.js"; describe("buildDependencyGraph", () => { useFixtureProject("solidity/example-project"); + let hre: HardhatRuntimeEnvironment; + + before(async () => { + hre = await createHardhatRuntimeEnvironment({}); + }); it("should return an empty graph if no files are provided", async () => { const { dependencyGraph, resolver } = await buildDependencyGraph( [], process.cwd(), [], + hre.hooks, ); assert.equal(dependencyGraph.getRoots().size, 0); @@ -39,6 +47,7 @@ describe("buildDependencyGraph", () => { rootSourceNames.map((sourceName) => path.join(process.cwd(), sourceName)), process.cwd(), ["remapped/=npm/@openzeppelin/contracts@5.1.0/access/"], + hre.hooks, ); const roots = dependencyGraph.getRoots(); diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts index c52117a5893..c944013e5b1 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts @@ -20,6 +20,8 @@ import { ResolverImplementation, } from "../../../../../../src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.js"; import { ResolvedFileType } from "../../../../../../src/types/solidity/resolved-file.js"; +import { createHardhatRuntimeEnvironment } from "../../../../../../src/internal/hre-intialization.js"; +import { HardhatRuntimeEnvironment } from "../../../../../../src/types/hre.js"; const TEST_FIXTURES_ROOT = path.resolve(import.meta.dirname, "test-fixtures"); @@ -106,10 +108,12 @@ describe("Resolver", () => { // Some of the error messages in the resolver use a file path based on the // CWD, so we set it for these tests let originalCwd: string; + let hre: HardhatRuntimeEnvironment; - before(() => { + before(async () => { originalCwd = process.cwd(); process.chdir(FIXTURE_HARDHAT_PROJECT_ROOT); + hre = await createHardhatRuntimeEnvironment({}); }); after(() => { @@ -121,6 +125,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); let file = "foo.sol"; @@ -144,6 +149,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); assertResolvedProjectFile( @@ -172,6 +178,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); await assertRejectsWithHardhatError( @@ -195,6 +202,7 @@ describe("Resolver", () => { resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); contractsFileSol = await resolver.resolveProjectFile( @@ -930,6 +938,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); const file = await resolver.resolveNpmDependencyFileAsRoot( "exports/Exported.sol", @@ -954,6 +963,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); await assertRejectsWithHardhatError( @@ -971,6 +981,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); await assertRejectsWithHardhatError( @@ -988,6 +999,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); await assertRejectsWithHardhatError( @@ -1008,6 +1020,7 @@ describe("Resolver", () => { resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], + hre.hooks, ); file = await resolver.resolveProjectFile( path.resolve(FIXTURE_HARDHAT_PROJECT_ROOT, "contracts/File.sol"), @@ -1163,6 +1176,7 @@ describe("Resolver", () => { resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, ["remapped_pkg/=npm/exports@3.0.0/"], + hre.hooks, ); const resolvedFile = await resolver.resolveImport( @@ -1192,6 +1206,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, ["remapped_file=npm/exports@3.0.0/SingleExport.sol"], + hre.hooks, ); const resolvedFile = await resolver.resolveImport( @@ -1221,6 +1236,7 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, ["remapped_pkg/=npm/exports@3.0.0/"], + hre.hooks, ); await assertRejectsWithHardhatError( From aca67252c85608d808a0883416d1e88c1104ea99 Mon Sep 17 00:00:00 2001 From: Armando Andini Date: Thu, 24 Apr 2025 11:21:55 -0300 Subject: [PATCH 2/5] Export dependency resolver --- v-next/hardhat/package.json | 1 + v-next/hardhat/src/dependency-resolver.ts | 1 + v-next/hardhat/src/types/solidity/build-system.ts | 2 ++ 3 files changed, 4 insertions(+) create mode 100644 v-next/hardhat/src/dependency-resolver.ts diff --git a/v-next/hardhat/package.json b/v-next/hardhat/package.json index feceee5996e..0e3021a713e 100644 --- a/v-next/hardhat/package.json +++ b/v-next/hardhat/package.json @@ -20,6 +20,7 @@ "./config": "./dist/src/config.js", "./hre": "./dist/src/hre.js", "./plugins": "./dist/src/plugins.js", + "./dependency-resolver": "./dist/src/dependency-resolver.js", "./types/arguments": "./dist/src/types/arguments.js", "./types/artifacts": "./dist/src/types/artifacts.js", "./types/config": "./dist/src/types/config.js", diff --git a/v-next/hardhat/src/dependency-resolver.ts b/v-next/hardhat/src/dependency-resolver.ts new file mode 100644 index 00000000000..831834f9576 --- /dev/null +++ b/v-next/hardhat/src/dependency-resolver.ts @@ -0,0 +1 @@ +export { ResolverImplementation } from "./internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.js"; diff --git a/v-next/hardhat/src/types/solidity/build-system.ts b/v-next/hardhat/src/types/solidity/build-system.ts index d89cdf1679a..5ad3093617d 100644 --- a/v-next/hardhat/src/types/solidity/build-system.ts +++ b/v-next/hardhat/src/types/solidity/build-system.ts @@ -2,6 +2,8 @@ import type { CompilationJob } from "./compilation-job.js"; import type { CompilerOutput, CompilerOutputError } from "./compiler-io.js"; import type { SolidityBuildInfo } from "./solidity-artifacts.js"; +export type { Resolver } from "../../internal/builtin-plugins/solidity/build-system/resolver/types.js"; + /** * The options of the `build` method. */ From 52f0617383cd9d21e87eed123b3823500e2668b9 Mon Sep 17 00:00:00 2001 From: Armando Andini Date: Thu, 24 Apr 2025 12:37:14 -0300 Subject: [PATCH 3/5] Inject readfile function instead of hooks --- v-next/hardhat/package.json | 2 +- v-next/hardhat/src/dependency-resolver.ts | 1 - .../builtin-plugins/flatten/task-action.ts | 3 ++- .../solidity/build-system/build-system.ts | 3 ++- .../build-system/dependency-graph-building.ts | 5 ++--- .../solidity/build-system/read-source-file.ts | 16 ++++++++++++++++ .../resolver/dependency-resolver.ts | 18 ++++++------------ v-next/hardhat/src/lsp-helpers.ts | 3 +++ .../build-system/dependency-graph-building.ts | 14 ++++---------- .../resolver/dependency-resolver.ts | 18 +----------------- 10 files changed, 37 insertions(+), 46 deletions(-) delete mode 100644 v-next/hardhat/src/dependency-resolver.ts create mode 100644 v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/read-source-file.ts create mode 100644 v-next/hardhat/src/lsp-helpers.ts diff --git a/v-next/hardhat/package.json b/v-next/hardhat/package.json index 0e3021a713e..c993a5016f5 100644 --- a/v-next/hardhat/package.json +++ b/v-next/hardhat/package.json @@ -20,7 +20,7 @@ "./config": "./dist/src/config.js", "./hre": "./dist/src/hre.js", "./plugins": "./dist/src/plugins.js", - "./dependency-resolver": "./dist/src/dependency-resolver.js", + "./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", diff --git a/v-next/hardhat/src/dependency-resolver.ts b/v-next/hardhat/src/dependency-resolver.ts deleted file mode 100644 index 831834f9576..00000000000 --- a/v-next/hardhat/src/dependency-resolver.ts +++ /dev/null @@ -1 +0,0 @@ -export { ResolverImplementation } from "./internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.js"; diff --git a/v-next/hardhat/src/internal/builtin-plugins/flatten/task-action.ts b/v-next/hardhat/src/internal/builtin-plugins/flatten/task-action.ts index eaeb71e9867..91d4e2e3fd4 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/flatten/task-action.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/flatten/task-action.ts @@ -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. @@ -59,7 +60,7 @@ const flattenAction: NewTaskActionFunction = async ( rootPaths.toSorted(), // We sort them to have a deterministic order config.paths.root, config.solidity.remappings, - hooks, + readSourceFileFactory(hooks), ); let flattened = ""; diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts index 9183d8ec5b2..369967d2ad2 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/build-system.ts @@ -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, @@ -303,7 +304,7 @@ export class SolidityBuildSystemImplementation implements SolidityBuildSystem { rootFilePaths.toSorted(), // We sort them to have a deterministic order this.#options.projectRoot, this.#options.solidityConfig.remappings, - this.#hooks, + readSourceFileFactory(this.#hooks), ); const buildProfileName = options?.buildProfile ?? DEFAULT_BUILD_PROFILE; diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts index 19c3d3b22b7..a3cf79debdf 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts @@ -4,13 +4,12 @@ import type { ResolvedFile } from "../../../../types/solidity/resolved-file.js"; import { DependencyGraphImplementation } from "./dependency-graph.js"; import { ResolverImplementation } from "./resolver/dependency-resolver.js"; import { isNpmParsedRootPath, parseRootPath } from "./root-paths-utils.js"; -import { HookManager } from "../../../../types/hooks.js"; export async function buildDependencyGraph( rootFiles: string[], projectRoot: string, userRemappings: string[], - hooks: HookManager, + readFile: (absPath: string) => Promise, ): Promise<{ dependencyGraph: DependencyGraphImplementation; resolver: Resolver; @@ -18,7 +17,7 @@ export async function buildDependencyGraph( const resolver = await ResolverImplementation.create( projectRoot, userRemappings, - hooks, + readFile, ); const dependencyGraph = new DependencyGraphImplementation(); diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/read-source-file.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/read-source-file.ts new file mode 100644 index 00000000000..2a9d0d9a95b --- /dev/null +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/read-source-file.ts @@ -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 { + return async (factoryAbsPath: string) => { + return hooks.runHandlerChain( + "solidity", + "readSourceFile", + [factoryAbsPath], + async (_context, absPath) => readUtf8File(absPath), + ); + }; +} diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts index 8a516d79bc5..7bef32cfe0c 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts @@ -41,7 +41,6 @@ import { parseRemappingString, selectBestRemapping, } from "./remappings.js"; -import { HookManager } from "../../../../../types/hooks.js"; // Things to note: // - This resolver assumes that the root of the project is the folder with the @@ -93,7 +92,7 @@ const PROJECT_ROOT_SENTINEL: unique symbol = Symbol(); export class ResolverImplementation implements Resolver { readonly #projectRoot: string; readonly #userRemappings: ResolvedUserRemapping[]; - readonly #hooks: HookManager; + readonly #readFile: (absPath: string) => Promise; /** * IMPORTANT: This mutex must be acquired before writing to any of the mutable @@ -150,7 +149,7 @@ export class ResolverImplementation implements Resolver { public static async create( projectRoot: string, userRemappingStrings: string[], - hooks: HookManager, + readFile: (absPath: string) => Promise = readUtf8File, ): Promise { const userRemappings = await Promise.all( userRemappingStrings.map((remappingString) => @@ -158,18 +157,18 @@ export class ResolverImplementation implements Resolver { ), ); - return new ResolverImplementation(projectRoot, userRemappings, hooks); + return new ResolverImplementation(projectRoot, userRemappings, readFile); } private constructor( projectRoot: string, userRemappings: ResolvedUserRemapping[], - hooks: HookManager, + readFile: (absPath: string) => Promise, ) { this.#projectRoot = projectRoot; this.#userRemappings = userRemappings; this.#dependencyMaps.set(PROJECT_ROOT_SENTINEL, new Map()); - this.#hooks = hooks; + this.#readFile = readFile; } public async resolveProjectFile( @@ -1353,12 +1352,7 @@ export class ResolverImplementation implements Resolver { * Reads and analyzes the file at the given absolute path. */ async #readFileContent(absolutePath: string): Promise { - const text = await this.#hooks.runHandlerChain( - "solidity", - "readSourceFile", - [absolutePath], - async (_context, absPath) => await readUtf8File(absPath), - ); + const text = await this.#readFile(absolutePath); const { imports, versionPragmas } = analyze(text); return { diff --git a/v-next/hardhat/src/lsp-helpers.ts b/v-next/hardhat/src/lsp-helpers.ts new file mode 100644 index 00000000000..fc6ad238c8e --- /dev/null +++ b/v-next/hardhat/src/lsp-helpers.ts @@ -0,0 +1,3 @@ +export { importUserConfig } from "./internal/config-loading.js"; +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"; diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts index 21e0e3dbf77..d7e4c40c223 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/dependency-graph-building.ts @@ -1,27 +1,21 @@ import assert from "node:assert/strict"; import path from "node:path"; -import { before, describe, it } from "node:test"; +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"; -import { HardhatRuntimeEnvironment } from "../../../../../src/types/hre.js"; -import { createHardhatRuntimeEnvironment } from "../../../../../src/internal/hre-intialization.js"; describe("buildDependencyGraph", () => { useFixtureProject("solidity/example-project"); - let hre: HardhatRuntimeEnvironment; - - before(async () => { - hre = await createHardhatRuntimeEnvironment({}); - }); it("should return an empty graph if no files are provided", async () => { const { dependencyGraph, resolver } = await buildDependencyGraph( [], process.cwd(), [], - hre.hooks, + readUtf8File, ); assert.equal(dependencyGraph.getRoots().size, 0); @@ -47,7 +41,7 @@ describe("buildDependencyGraph", () => { rootSourceNames.map((sourceName) => path.join(process.cwd(), sourceName)), process.cwd(), ["remapped/=npm/@openzeppelin/contracts@5.1.0/access/"], - hre.hooks, + readUtf8File, ); const roots = dependencyGraph.getRoots(); diff --git a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts index c944013e5b1..c52117a5893 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts @@ -20,8 +20,6 @@ import { ResolverImplementation, } from "../../../../../../src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.js"; import { ResolvedFileType } from "../../../../../../src/types/solidity/resolved-file.js"; -import { createHardhatRuntimeEnvironment } from "../../../../../../src/internal/hre-intialization.js"; -import { HardhatRuntimeEnvironment } from "../../../../../../src/types/hre.js"; const TEST_FIXTURES_ROOT = path.resolve(import.meta.dirname, "test-fixtures"); @@ -108,12 +106,10 @@ describe("Resolver", () => { // Some of the error messages in the resolver use a file path based on the // CWD, so we set it for these tests let originalCwd: string; - let hre: HardhatRuntimeEnvironment; - before(async () => { + before(() => { originalCwd = process.cwd(); process.chdir(FIXTURE_HARDHAT_PROJECT_ROOT); - hre = await createHardhatRuntimeEnvironment({}); }); after(() => { @@ -125,7 +121,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); let file = "foo.sol"; @@ -149,7 +144,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); assertResolvedProjectFile( @@ -178,7 +172,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); await assertRejectsWithHardhatError( @@ -202,7 +195,6 @@ describe("Resolver", () => { resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); contractsFileSol = await resolver.resolveProjectFile( @@ -938,7 +930,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); const file = await resolver.resolveNpmDependencyFileAsRoot( "exports/Exported.sol", @@ -963,7 +954,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); await assertRejectsWithHardhatError( @@ -981,7 +971,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); await assertRejectsWithHardhatError( @@ -999,7 +988,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); await assertRejectsWithHardhatError( @@ -1020,7 +1008,6 @@ describe("Resolver", () => { resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, [], - hre.hooks, ); file = await resolver.resolveProjectFile( path.resolve(FIXTURE_HARDHAT_PROJECT_ROOT, "contracts/File.sol"), @@ -1176,7 +1163,6 @@ describe("Resolver", () => { resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, ["remapped_pkg/=npm/exports@3.0.0/"], - hre.hooks, ); const resolvedFile = await resolver.resolveImport( @@ -1206,7 +1192,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, ["remapped_file=npm/exports@3.0.0/SingleExport.sol"], - hre.hooks, ); const resolvedFile = await resolver.resolveImport( @@ -1236,7 +1221,6 @@ describe("Resolver", () => { const resolver = await ResolverImplementation.create( FIXTURE_HARDHAT_PROJECT_ROOT, ["remapped_pkg/=npm/exports@3.0.0/"], - hre.hooks, ); await assertRejectsWithHardhatError( From b7807947e4124b3957a0eab73f4780f81288a2e9 Mon Sep 17 00:00:00 2001 From: Armando Andini Date: Mon, 5 May 2025 14:18:39 +0100 Subject: [PATCH 4/5] Add changeset --- .changeset/dull-queens-dress.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/dull-queens-dress.md diff --git a/.changeset/dull-queens-dress.md b/.changeset/dull-queens-dress.md new file mode 100644 index 00000000000..3da20301bef --- /dev/null +++ b/.changeset/dull-queens-dress.md @@ -0,0 +1,5 @@ +--- +"hardhat": patch +--- + +Export DependencyResolver, importUserConfig, and add a hook for reading solidity files From 5539400c1b1e915b135446a5fb019772731d8b20 Mon Sep 17 00:00:00 2001 From: Armando Andini Date: Mon, 5 May 2025 16:47:08 +0100 Subject: [PATCH 5/5] Address feedback --- v-next/hardhat/package.json | 2 +- v-next/hardhat/src/hre.ts | 1 + .../internal/builtin-plugins/solidity/type-extensions.ts | 7 +++++-- v-next/hardhat/src/lsp-helpers.ts | 3 ++- v-next/hardhat/src/types/solidity/build-system.ts | 2 -- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/v-next/hardhat/package.json b/v-next/hardhat/package.json index c993a5016f5..93ac152d8eb 100644 --- a/v-next/hardhat/package.json +++ b/v-next/hardhat/package.json @@ -20,7 +20,7 @@ "./config": "./dist/src/config.js", "./hre": "./dist/src/hre.js", "./plugins": "./dist/src/plugins.js", - "./lsp-helpers": "./dist/src/lsp-helpers.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", diff --git a/v-next/hardhat/src/hre.ts b/v-next/hardhat/src/hre.ts index cf7084ecd20..10c17c7624f 100644 --- a/v-next/hardhat/src/hre.ts +++ b/v-next/hardhat/src/hre.ts @@ -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"; diff --git a/v-next/hardhat/src/internal/builtin-plugins/solidity/type-extensions.ts b/v-next/hardhat/src/internal/builtin-plugins/solidity/type-extensions.ts index 56eafb027a4..33c70497707 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/solidity/type-extensions.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/solidity/type-extensions.ts @@ -117,8 +117,11 @@ declare module "../../../types/hooks.js" { readSourceFile: ( context: HookContext, - absPath: string, - next: (nextContext: HookContext, absPath: string) => Promise, + absolutePath: string, + next: ( + nextContext: HookContext, + nextAbsolutePath: string, + ) => Promise, ) => Promise; } } diff --git a/v-next/hardhat/src/lsp-helpers.ts b/v-next/hardhat/src/lsp-helpers.ts index fc6ad238c8e..01772df9839 100644 --- a/v-next/hardhat/src/lsp-helpers.ts +++ b/v-next/hardhat/src/lsp-helpers.ts @@ -1,3 +1,4 @@ -export { importUserConfig } from "./internal/config-loading.js"; 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"; diff --git a/v-next/hardhat/src/types/solidity/build-system.ts b/v-next/hardhat/src/types/solidity/build-system.ts index 5ad3093617d..d89cdf1679a 100644 --- a/v-next/hardhat/src/types/solidity/build-system.ts +++ b/v-next/hardhat/src/types/solidity/build-system.ts @@ -2,8 +2,6 @@ import type { CompilationJob } from "./compilation-job.js"; import type { CompilerOutput, CompilerOutputError } from "./compiler-io.js"; import type { SolidityBuildInfo } from "./solidity-artifacts.js"; -export type { Resolver } from "../../internal/builtin-plugins/solidity/build-system/resolver/types.js"; - /** * The options of the `build` method. */