hardhat
Version:
Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
163 lines • 5.29 kB
JavaScript
export var FrameOrigin;
(function (FrameOrigin) {
FrameOrigin["FIRST_PARTY"] = "FIRST_PARTY";
FrameOrigin["THIRD_PARTY"] = "THIRD_PARTY";
FrameOrigin["USER_PROJECT"] = "USER_PROJECT";
FrameOrigin["NODE_INTERNAL"] = "NODE_INTERNAL";
FrameOrigin["OTHER"] = "OTHER";
})(FrameOrigin || (FrameOrigin = {}));
/**
* Builds the shared derived data used by classification and filtering.
*
* This keeps stack parsing and cause-chain traversal consistent across
* matchers, and avoids recomputing them for every category heuristic.
*/
export function createErrorContext(error) {
const errorChain = getErrorChain(error);
const stackFramesByError = new Map(errorChain.map((candidate) => [candidate, parseStackFrames(candidate)]));
return {
error,
errorChain,
lowercaseMessageByError: new Map(errorChain.map((candidate) => [
candidate,
candidate.message.toLowerCase(),
])),
stackFramesByError,
allStackFrames: errorChain.flatMap((candidate) => stackFramesByError.get(candidate) ?? []),
};
}
/**
* This function should be used instead of instanceof because it is robust
* under the presence of multiple installations of the same package (e.g.
* multiple hardhat-utils versions).
*
* @param error The error
* @param errorClass The error class
* @returns true if the error has the same name as the error class
*/
export function hasErrorClassName(error, errorClass) {
return error.name === errorClass.name;
}
/**
* Returns true when `value` contains any of the supplied substrings.
*/
export function includesAny(value, ...substrings) {
return (value !== undefined &&
substrings.some((substring) => value.includes(substring)));
}
/**
* Returns a Node-style `code` string from an error or any Error cause.
*
* Traversal stops when a cause is not an Error, a cycle is detected, or
* `maxCauseDepth` is reached.
*/
export function getNodeErrorCode(error, maxCauseDepth = 10) {
const seen = new Set();
let current = error;
let depth = 0;
while (current !== undefined && depth < maxCauseDepth && !seen.has(current)) {
if ("code" in current && typeof current.code === "string") {
return current.code;
}
seen.add(current);
current = getCause(current);
depth++;
}
}
/**
* Returns the error and its nested causes in outer-to-inner order.
*
* Traversal stops when a cause is not an Error, a cycle is detected, or
* `maxCauseDepth` is reached.
*/
function getErrorChain(error, maxCauseDepth = 10) {
const errors = [];
const seen = new Set();
let current = error;
while (current !== undefined &&
errors.length < maxCauseDepth &&
seen.has(current) === false) {
errors.push(current);
seen.add(current);
if (current.cause !== undefined && !(current.cause instanceof Error)) {
break;
}
current = getCause(current);
}
return errors;
}
/**
* Parses V8-style stack lines into normalized stack frames.
*
* Unrecognized lines are ignored, and path separators are normalized to `/`
* before the frame origin is inferred.
*/
function parseStackFrames(error) {
if (error.stack === undefined) {
return [];
}
return error.stack
.split("\n")
.slice(1)
.map((line) => line.trim())
.map(parseStackFrameLine)
.filter((frame) => frame !== undefined);
}
/**
* Parses a single V8 stack frame line.
*/
function parseStackFrameLine(line) {
const match = line.match(/^at (?:(.+?) \()?(.+?):\d+:\d+\)?$/) ??
line.match(/^at (?:(.+?) \()?(.+?)\)?$/);
if (match === null || match[2] === undefined) {
return;
}
const functionName = match[1] === undefined ? undefined : match[1].trim();
const location = normalizeLocation(match[2]);
return {
functionName,
location,
origin: getFrameOrigin(location),
};
}
/**
* Returns the Error-valued cause of an error, ignoring non-Error causes.
*/
function getCause(error) {
if ("cause" in error && error.cause instanceof Error) {
return error.cause;
}
}
/**
* Normalizes Windows paths and file URLs enough for substring-based matchers.
*/
function normalizeLocation(location) {
return location.replaceAll("\\", "/");
}
/**
* Infers who owns a stack frame from its normalized location.
*/
function getFrameOrigin(location) {
if (startsWithAny(location, "node:", "internal/") ||
includesAny(location, "node:internal/")) {
return FrameOrigin.NODE_INTERNAL;
}
if (location.includes("/node_modules/")) {
if (includesAny(location, "/node_modules/hardhat/", "/node_modules/@nomicfoundation/")) {
return FrameOrigin.FIRST_PARTY;
}
return FrameOrigin.THIRD_PARTY;
}
if (startsWithAny(location, "/", "file://", "[eval]") ||
/^[A-Za-z]:\//.test(location)) {
return FrameOrigin.USER_PROJECT;
}
return FrameOrigin.OTHER;
}
/**
* Returns true when `value` starts with any of the supplied prefixes.
*/
function startsWithAny(value, ...prefixes) {
return prefixes.some((prefix) => value.startsWith(prefix));
}
//# sourceMappingURL=helpers.js.map