-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Hardhat 2 plugins deprecation message on load #7991
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
f33c123
Add UsingHardhat2PluginError error and a module to thow it
alcuadrado 4e3bc1e
Throw UsingHardhat2PluginError in every removed `hardhat/config` fun…
alcuadrado 092484a
Don't report UsingHardhat2PluginError to Sentry
alcuadrado 842433e
Add a special case in `main`'s error handling
alcuadrado 99aa28a
Also trap in `hardhat/plugins`'s functions
alcuadrado 4b96b17
Export 'hardhat/types' as a barrel file.
alcuadrado 0b7fe31
Export common HH2 subpaths as an empty module.
alcuadrado 2c2e1f5
Create healthy-ears-knock.md
alcuadrado efc983b
Fix tests on windows
alcuadrado c85f051
Update v-next/hardhat/src/internal/using-hardhat2-plugin-errors.ts
alcuadrado 664645e
Update v-next/hardhat/src/internal/using-hardhat2-plugin-errors.ts
alcuadrado 2754dd3
Update v-next/hardhat/src/internal/using-hardhat2-plugin-errors.ts
alcuadrado bf27001
Remove duplicated comment
alcuadrado 654127f
Add more docs
alcuadrado 314a2e0
Simplify how the regex is shown
alcuadrado File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "hardhat": patch | ||
| --- | ||
|
|
||
| Throw better error messages when trying to use a Hardhat 2 plugin with Hardhat 3 [#7991](https://github.com/NomicFoundation/hardhat/pull/7991). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
v-next/hardhat/src/internal/deprecated-module-imported-from-hardhat2-plugin.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| // This is an empty module that is used to exported it with a subpath that's | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤯 this is very smart! |
||
| // commonly used by Hardhat 2 plugins. This is to avoid the plugins breaking | ||
| // when the `require` it, so that they have an opportunity to run a function | ||
| // that throws a better error message. | ||
|
|
||
| // The reason this module can be empty is that Hardhat 2 plugins are CJS modules | ||
| // so they can destructure the require and get `undefined` values, instead of | ||
| // a load-time error. | ||
|
|
||
| // We could also throw from this file, but if it gets imported by an ESM module | ||
| // you don't get an import-stack-trace, so you loose the possibility of figuring | ||
| // out which plugin is triggering the error. | ||
108 changes: 108 additions & 0 deletions
108
v-next/hardhat/src/internal/using-hardhat2-plugin-errors.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| import { fileURLToPath } from "node:url"; | ||
|
|
||
| import { CustomError } from "@nomicfoundation/hardhat-utils/error"; | ||
| import { shortenPath } from "@nomicfoundation/hardhat-utils/path"; | ||
| import chalk from "chalk"; | ||
|
|
||
| export class UsingHardhat2PluginError extends CustomError { | ||
| public readonly callerRelativePath: string | undefined; | ||
| constructor() { | ||
| const callerPath = getCallerRelativePath(); | ||
|
|
||
| let message: string; | ||
| if (callerPath !== undefined) { | ||
| message = `You are trying to use a Hardhat 2 plugin in a Hardhat 3 project. | ||
|
|
||
| This file is part of a Hardhat 2 plugin calling an API that was removed in Hardhat 3: ${chalk.bold(callerPath)} | ||
|
|
||
| Please read https://hardhat.org/migrate-from-hardhat2 to learn how to migrate your project to Hardhat 3. | ||
| `; | ||
| } else { | ||
| message = `You are trying to use a Hardhat 2 plugin in a Hardhat 3 project. | ||
|
|
||
| Check the stack trace below to identify which plugin is causing this. | ||
|
|
||
| Please read https://hardhat.org/migrate-from-hardhat2 to learn how to migrate your project to Hardhat 3. | ||
| `; | ||
| } | ||
|
|
||
| super(message); | ||
| this.callerRelativePath = callerPath; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns the relative path of the file that called a deprecated Hardhat | ||
| * plugin API, based on the stack trace. This helps identify which plugin | ||
| * file is triggering usage of Hardhat 2 APIs in a Hardhat 3 project. | ||
| * | ||
| * @param {number} [depth=5] The stack trace depth to locate the caller's | ||
| * source file. By default, depth 5 is used because: | ||
| * 0 = message | ||
| * 1 = getCallerRelativePath | ||
| * 2 = UsingHardhat2PluginError constructor | ||
| * 3 = throwUsingHardhat2PluginError | ||
| * 4 = deprecated function | ||
| * 5 = actual caller (the plugin file) | ||
| * | ||
| * @returns {string|undefined} The shortened relative path of the caller file, | ||
| * or undefined if not found. | ||
| * | ||
| * @example | ||
| * If the stack trace is: | ||
| * // Error | ||
| * // at getCallerRelativePath (src/internal/using-hardhat2-plugin-errors.ts:34:15) | ||
| * // at UsingHardhat2PluginError.constructor (src/internal/using-hardhat2-plugin-errors.ts:7:3) | ||
| * // at throwUsingHardhat2PluginError (src/internal/using-hardhat2-plugin-errors.ts:90:3) | ||
| * // at deprecatedFunction (plugins/example-plugin/deprecated.js:50:10) | ||
| * // at main (plugins/example-plugin/index.js:100:5) | ||
| * Calling getCallerRelativePath() returns 'plugins/example-plugin/index.js' | ||
| */ | ||
| export function getCallerRelativePath(depth: number = 5): string | undefined { | ||
|
alcuadrado marked this conversation as resolved.
|
||
| try { | ||
| const stack = new Error().stack; | ||
| if (stack === undefined) { | ||
| return undefined; | ||
| } | ||
|
|
||
| const lines = stack.split("\n"); | ||
| const callerLine = lines[depth]; | ||
| if (callerLine === undefined) { | ||
| return undefined; | ||
| } | ||
|
|
||
| /** | ||
| * Matches a single stack trace line: | ||
| * | ||
| * at FunctionName (path/to/file.ts:10:5) | ||
| * at path/to/file.ts:10:5 | ||
| * | ||
| * Captures: | ||
| * - group 1: file location (without line/column) | ||
| */ | ||
| const STACK_TRACE_LINE_REGEX = | ||
| /^at (?:.+? \()?([^\(].*?)(?::\d+)?(?::\d+)?\)?$/; | ||
|
|
||
| const match = callerLine.trim().match(STACK_TRACE_LINE_REGEX); | ||
| if (match === null || match[1] === undefined) { | ||
| return undefined; | ||
| } | ||
|
|
||
| let filePath = match[1]; | ||
|
|
||
| // Handle file:// URLs from ESM stack traces | ||
| if (filePath.startsWith("file://")) { | ||
| filePath = fileURLToPath(filePath); | ||
| } | ||
|
|
||
| return shortenPath(filePath); | ||
| } catch { | ||
| return undefined; | ||
| } | ||
| } | ||
|
|
||
| export function throwUsingHardhat2PluginError(): never { | ||
| /* eslint-disable-next-line no-restricted-syntax -- Intentionally throwing a | ||
| custom error here so that we always print the stack trace */ | ||
| throw new UsingHardhat2PluginError(); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,17 @@ | ||
| export { HardhatPluginError } from "@nomicfoundation/hardhat-errors"; | ||
|
|
||
| import { throwUsingHardhat2PluginError } from "./internal/using-hardhat2-plugin-errors.js"; | ||
|
|
||
| /** | ||
| * @deprecated This function is part of the Hardhat 2 plugin API. | ||
| */ | ||
| export function lazyFunction(..._args: any): any { | ||
| throwUsingHardhat2PluginError(); | ||
| } | ||
|
|
||
| /** | ||
| * @deprecated This function is part of the Hardhat 2 plugin API. | ||
| */ | ||
| export function lazyObject(..._args: any): any { | ||
| throwUsingHardhat2PluginError(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| export * from "./arguments.js"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whoops, did we forget to add this file earlier? |
||
| export * from "./artifacts.js"; | ||
| export * from "./config.js"; | ||
| export * from "./global-options.js"; | ||
| export * from "./hooks.js"; | ||
| export * from "./hre.js"; | ||
| export * from "./network.js"; | ||
| export * from "./plugins.js"; | ||
| export * from "./providers.js"; | ||
| export * from "./solidity.js"; | ||
| export * from "./tasks.js"; | ||
| export * from "./test.js"; | ||
| export * from "./user-interruptions.js"; | ||
| export * from "./utils.js"; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| import assert from "node:assert/strict"; | ||
| import path from "node:path"; | ||
| import { describe, it } from "node:test"; | ||
|
|
||
| import { assertThrows } from "@nomicfoundation/hardhat-test-utils"; | ||
|
|
||
| import { | ||
| extendConfig, | ||
| extendEnvironment, | ||
| extendProvider, | ||
| scope, | ||
| subtask, | ||
| } from "../src/config.js"; | ||
| import { UsingHardhat2PluginError } from "../src/internal/using-hardhat2-plugin-errors.js"; | ||
|
|
||
| describe("Hardhat 2 plugin compatibility", () => { | ||
| it("should throw when calling extendConfig", () => { | ||
| assertThrows( | ||
| () => extendConfig(), | ||
| (error) => { | ||
| assert.ok( | ||
| error instanceof UsingHardhat2PluginError, | ||
| "Should be a UsingHardhat2PluginError", | ||
| ); | ||
| assert.ok( | ||
| error.callerRelativePath?.includes(path.join("test", "config.ts")) === | ||
| true, | ||
| "Should have the caller path", | ||
| ); | ||
| return true; | ||
| }, | ||
| ); | ||
| }); | ||
|
|
||
| it("should throw when calling extendEnvironment", () => { | ||
| assertThrows( | ||
| () => extendEnvironment(), | ||
| (error) => { | ||
| assert.ok( | ||
| error instanceof UsingHardhat2PluginError, | ||
| "Should be a UsingHardhat2PluginError", | ||
| ); | ||
| assert.ok( | ||
| error.callerRelativePath?.includes(path.join("test", "config.ts")) === | ||
| true, | ||
| "Should have the caller path", | ||
| ); | ||
| return true; | ||
| }, | ||
| ); | ||
| }); | ||
|
|
||
| it("should throw when calling extendProvider", () => { | ||
| assertThrows( | ||
| () => extendProvider(), | ||
| (error) => { | ||
| assert.ok( | ||
| error instanceof UsingHardhat2PluginError, | ||
| "Should be a UsingHardhat2PluginError", | ||
| ); | ||
| assert.ok( | ||
| error.callerRelativePath?.includes(path.join("test", "config.ts")) === | ||
| true, | ||
| "Should have the caller path", | ||
| ); | ||
| return true; | ||
| }, | ||
| ); | ||
| }); | ||
|
|
||
| it("should throw when calling scope", () => { | ||
| assertThrows( | ||
| () => scope(), | ||
| (error) => { | ||
| assert.ok( | ||
| error instanceof UsingHardhat2PluginError, | ||
| "Should be a UsingHardhat2PluginError", | ||
| ); | ||
| assert.ok( | ||
| error.callerRelativePath?.includes(path.join("test", "config.ts")) === | ||
| true, | ||
| "Should have the caller path", | ||
| ); | ||
| return true; | ||
| }, | ||
| ); | ||
| }); | ||
|
|
||
| it("should throw when calling subtask", () => { | ||
| assertThrows( | ||
| () => subtask(), | ||
| (error) => { | ||
| assert.ok( | ||
| error instanceof UsingHardhat2PluginError, | ||
| "Should be a UsingHardhat2PluginError", | ||
| ); | ||
| assert.ok( | ||
| error.callerRelativePath?.includes(path.join("test", "config.ts")) === | ||
| true, | ||
| "Should have the caller path", | ||
| ); | ||
| return true; | ||
| }, | ||
| ); | ||
| }); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.