@nomicfoundation/hardhat-utils 3.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +5 -0
- package/dist/src/bigint.d.ts +32 -0
- package/dist/src/bigint.d.ts.map +1 -0
- package/dist/src/bigint.js +54 -0
- package/dist/src/bigint.js.map +1 -0
- package/dist/src/bytecode.d.ts +27 -0
- package/dist/src/bytecode.d.ts.map +1 -0
- package/dist/src/bytecode.js +60 -0
- package/dist/src/bytecode.js.map +1 -0
- package/dist/src/bytes.d.ts +34 -0
- package/dist/src/bytes.d.ts.map +1 -0
- package/dist/src/bytes.js +47 -0
- package/dist/src/bytes.js.map +1 -0
- package/dist/src/ci.d.ts +7 -0
- package/dist/src/ci.d.ts.map +1 -0
- package/dist/src/ci.js +18 -0
- package/dist/src/ci.js.map +1 -0
- package/dist/src/common-errors.d.ts +5 -0
- package/dist/src/common-errors.d.ts.map +1 -0
- package/dist/src/common-errors.js +7 -0
- package/dist/src/common-errors.js.map +1 -0
- package/dist/src/crypto.d.ts +25 -0
- package/dist/src/crypto.d.ts.map +1 -0
- package/dist/src/crypto.js +32 -0
- package/dist/src/crypto.js.map +1 -0
- package/dist/src/date.d.ts +21 -0
- package/dist/src/date.d.ts.map +1 -0
- package/dist/src/date.js +27 -0
- package/dist/src/date.js.map +1 -0
- package/dist/src/debug.d.ts +16 -0
- package/dist/src/debug.d.ts.map +1 -0
- package/dist/src/debug.js +28 -0
- package/dist/src/debug.js.map +1 -0
- package/dist/src/error.d.ts +80 -0
- package/dist/src/error.d.ts.map +1 -0
- package/dist/src/error.js +97 -0
- package/dist/src/error.js.map +1 -0
- package/dist/src/errors/bytecode.d.ts +18 -0
- package/dist/src/errors/bytecode.d.ts.map +1 -0
- package/dist/src/errors/bytecode.js +59 -0
- package/dist/src/errors/bytecode.js.map +1 -0
- package/dist/src/errors/fs.d.ts +25 -0
- package/dist/src/errors/fs.d.ts.map +1 -0
- package/dist/src/errors/fs.js +41 -0
- package/dist/src/errors/fs.js.map +1 -0
- package/dist/src/errors/package.d.ts +8 -0
- package/dist/src/errors/package.d.ts.map +1 -0
- package/dist/src/errors/package.js +12 -0
- package/dist/src/errors/package.js.map +1 -0
- package/dist/src/errors/request.d.ts +25 -0
- package/dist/src/errors/request.d.ts.map +1 -0
- package/dist/src/errors/request.js +64 -0
- package/dist/src/errors/request.js.map +1 -0
- package/dist/src/errors/subprocess.d.ts +8 -0
- package/dist/src/errors/subprocess.d.ts.map +1 -0
- package/dist/src/errors/subprocess.js +12 -0
- package/dist/src/errors/subprocess.js.map +1 -0
- package/dist/src/eth.d.ts +56 -0
- package/dist/src/eth.d.ts.map +1 -0
- package/dist/src/eth.js +78 -0
- package/dist/src/eth.js.map +1 -0
- package/dist/src/fs.d.ts +241 -0
- package/dist/src/fs.d.ts.map +1 -0
- package/dist/src/fs.js +581 -0
- package/dist/src/fs.js.map +1 -0
- package/dist/src/global-dir.d.ts +28 -0
- package/dist/src/global-dir.d.ts.map +1 -0
- package/dist/src/global-dir.js +42 -0
- package/dist/src/global-dir.js.map +1 -0
- package/dist/src/hex.d.ts +117 -0
- package/dist/src/hex.d.ts.map +1 -0
- package/dist/src/hex.js +187 -0
- package/dist/src/hex.js.map +1 -0
- package/dist/src/internal/bytecode.d.ts +45 -0
- package/dist/src/internal/bytecode.d.ts.map +1 -0
- package/dist/src/internal/bytecode.js +73 -0
- package/dist/src/internal/bytecode.js.map +1 -0
- package/dist/src/internal/eth.d.ts +21 -0
- package/dist/src/internal/eth.d.ts.map +1 -0
- package/dist/src/internal/eth.js +58 -0
- package/dist/src/internal/eth.js.map +1 -0
- package/dist/src/internal/global-dir.d.ts +4 -0
- package/dist/src/internal/global-dir.d.ts.map +1 -0
- package/dist/src/internal/global-dir.js +6 -0
- package/dist/src/internal/global-dir.js.map +1 -0
- package/dist/src/internal/hex.d.ts +2 -0
- package/dist/src/internal/hex.d.ts.map +1 -0
- package/dist/src/internal/hex.js +16 -0
- package/dist/src/internal/hex.js.map +1 -0
- package/dist/src/internal/lang.d.ts +2 -0
- package/dist/src/internal/lang.d.ts.map +1 -0
- package/dist/src/internal/lang.js +9 -0
- package/dist/src/internal/lang.js.map +1 -0
- package/dist/src/internal/package.d.ts +2 -0
- package/dist/src/internal/package.d.ts.map +1 -0
- package/dist/src/internal/package.js +15 -0
- package/dist/src/internal/package.js.map +1 -0
- package/dist/src/internal/request.d.ts +20 -0
- package/dist/src/internal/request.d.ts.map +1 -0
- package/dist/src/internal/request.js +101 -0
- package/dist/src/internal/request.js.map +1 -0
- package/dist/src/lang.d.ts +30 -0
- package/dist/src/lang.d.ts.map +1 -0
- package/dist/src/lang.js +41 -0
- package/dist/src/lang.js.map +1 -0
- package/dist/src/number.d.ts +23 -0
- package/dist/src/number.d.ts.map +1 -0
- package/dist/src/number.js +30 -0
- package/dist/src/number.js.map +1 -0
- package/dist/src/package.d.ts +75 -0
- package/dist/src/package.d.ts.map +1 -0
- package/dist/src/package.js +97 -0
- package/dist/src/package.js.map +1 -0
- package/dist/src/path.d.ts +26 -0
- package/dist/src/path.d.ts.map +1 -0
- package/dist/src/path.js +38 -0
- package/dist/src/path.js.map +1 -0
- package/dist/src/request.d.ts +118 -0
- package/dist/src/request.d.ts.map +1 -0
- package/dist/src/request.js +208 -0
- package/dist/src/request.js.map +1 -0
- package/dist/src/stream.d.ts +10 -0
- package/dist/src/stream.d.ts.map +1 -0
- package/dist/src/stream.js +16 -0
- package/dist/src/stream.js.map +1 -0
- package/dist/src/string.d.ts +45 -0
- package/dist/src/string.d.ts.map +1 -0
- package/dist/src/string.js +60 -0
- package/dist/src/string.js.map +1 -0
- package/dist/src/subprocess.d.ts +13 -0
- package/dist/src/subprocess.d.ts.map +1 -0
- package/dist/src/subprocess.js +33 -0
- package/dist/src/subprocess.js.map +1 -0
- package/dist/src/synchronization.d.ts +6 -0
- package/dist/src/synchronization.d.ts.map +1 -0
- package/dist/src/synchronization.js +107 -0
- package/dist/src/synchronization.js.map +1 -0
- package/package.json +90 -0
- package/src/bigint.ts +61 -0
- package/src/bytecode.ts +90 -0
- package/src/bytes.ts +51 -0
- package/src/ci.ts +19 -0
- package/src/common-errors.ts +7 -0
- package/src/crypto.ts +35 -0
- package/src/date.ts +28 -0
- package/src/debug.ts +38 -0
- package/src/error.ts +105 -0
- package/src/errors/bytecode.ts +75 -0
- package/src/errors/fs.ts +47 -0
- package/src/errors/package.ts +13 -0
- package/src/errors/request.ts +84 -0
- package/src/errors/subprocess.ts +17 -0
- package/src/eth.ts +91 -0
- package/src/fs.ts +678 -0
- package/src/global-dir.ts +51 -0
- package/src/hex.ts +232 -0
- package/src/internal/bytecode.ts +129 -0
- package/src/internal/eth.ts +71 -0
- package/src/internal/global-dir.ts +10 -0
- package/src/internal/hex.ts +21 -0
- package/src/internal/lang.ts +12 -0
- package/src/internal/package.ts +15 -0
- package/src/internal/request.ts +165 -0
- package/src/lang.ts +48 -0
- package/src/number.ts +38 -0
- package/src/package.ts +143 -0
- package/src/path.ts +45 -0
- package/src/request.ts +341 -0
- package/src/stream.ts +16 -0
- package/src/string.ts +69 -0
- package/src/subprocess.ts +46 -0
- package/src/synchronization.ts +126 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { DispatcherOptions, RequestOptions } from "../request.js";
|
|
2
|
+
import type EventEmitter from "node:events";
|
|
3
|
+
import type UndiciT from "undici";
|
|
4
|
+
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
import { mkdir } from "../fs.js";
|
|
8
|
+
import { isObject } from "../lang.js";
|
|
9
|
+
import {
|
|
10
|
+
ConnectionRefusedError,
|
|
11
|
+
DEFAULT_MAX_REDIRECTS,
|
|
12
|
+
DEFAULT_TIMEOUT_IN_MILLISECONDS,
|
|
13
|
+
DEFAULT_USER_AGENT,
|
|
14
|
+
getDispatcher,
|
|
15
|
+
RequestTimeoutError,
|
|
16
|
+
ResponseStatusCodeError,
|
|
17
|
+
} from "../request.js";
|
|
18
|
+
|
|
19
|
+
export async function generateTempFilePath(filePath: string): Promise<string> {
|
|
20
|
+
const { dir, ext, name } = path.parse(filePath);
|
|
21
|
+
|
|
22
|
+
await mkdir(dir);
|
|
23
|
+
|
|
24
|
+
return path.format({
|
|
25
|
+
dir,
|
|
26
|
+
ext,
|
|
27
|
+
name: `tmp-${name}`,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function getBaseRequestOptions(
|
|
32
|
+
requestUrl: string,
|
|
33
|
+
{ extraHeaders, abortSignal, queryParams }: RequestOptions = {},
|
|
34
|
+
dispatcherOrDispatcherOptions?: UndiciT.Dispatcher | DispatcherOptions,
|
|
35
|
+
): Promise<{
|
|
36
|
+
query?: Record<string, any> | undefined;
|
|
37
|
+
signal?: EventEmitter | AbortSignal | undefined;
|
|
38
|
+
dispatcher: UndiciT.Dispatcher;
|
|
39
|
+
headers: Record<string, string>;
|
|
40
|
+
throwOnError: true;
|
|
41
|
+
}> {
|
|
42
|
+
const { Dispatcher } = await import("undici");
|
|
43
|
+
const dispatcher =
|
|
44
|
+
dispatcherOrDispatcherOptions instanceof Dispatcher
|
|
45
|
+
? dispatcherOrDispatcherOptions
|
|
46
|
+
: await getDispatcher(requestUrl, dispatcherOrDispatcherOptions);
|
|
47
|
+
|
|
48
|
+
// We could use the global dispatcher if neither dispatcher nor dispatcherOptions were passed,
|
|
49
|
+
// but there's no way to configure it, so we don't do it.
|
|
50
|
+
// https://github.com/nodejs/undici/blob/961b76ad7cac17d23580d172702e11a080974f5d/lib/global.js#L9
|
|
51
|
+
return {
|
|
52
|
+
dispatcher,
|
|
53
|
+
headers: getHeaders(requestUrl, extraHeaders),
|
|
54
|
+
throwOnError: true,
|
|
55
|
+
...(abortSignal !== undefined ? { signal: abortSignal } : {}),
|
|
56
|
+
...(queryParams !== undefined ? { query: queryParams } : {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function getHeaders(
|
|
61
|
+
requestUrl: string,
|
|
62
|
+
extraHeaders: Record<string, string> = {},
|
|
63
|
+
): Record<string, string> {
|
|
64
|
+
const headers: Record<string, string> = {
|
|
65
|
+
...extraHeaders,
|
|
66
|
+
"User-Agent": extraHeaders["User-Agent"] ?? DEFAULT_USER_AGENT,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const authHeader = getAuthHeader(requestUrl);
|
|
70
|
+
if (authHeader !== undefined) {
|
|
71
|
+
headers.Authorization = authHeader;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return headers;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function getAuthHeader(requestUrl: string): string | undefined {
|
|
78
|
+
const parsedUrl = new URL(requestUrl);
|
|
79
|
+
if (parsedUrl.username === "") {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return `Basic ${Buffer.from(
|
|
84
|
+
`${parsedUrl.username}:${parsedUrl.password}`,
|
|
85
|
+
).toString("base64")}`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function getProxyDispatcher(
|
|
89
|
+
proxy: string,
|
|
90
|
+
options: Omit<UndiciT.ProxyAgent.Options, "uri">,
|
|
91
|
+
): Promise<UndiciT.ProxyAgent> {
|
|
92
|
+
const { ProxyAgent } = await import("undici");
|
|
93
|
+
|
|
94
|
+
return new ProxyAgent({
|
|
95
|
+
uri: proxy,
|
|
96
|
+
...options,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function getPoolDispatcher(
|
|
101
|
+
requestUrl: string,
|
|
102
|
+
options: UndiciT.Pool.Options,
|
|
103
|
+
): Promise<UndiciT.Pool> {
|
|
104
|
+
const { Pool } = await import("undici");
|
|
105
|
+
|
|
106
|
+
const parsedUrl = new URL(requestUrl);
|
|
107
|
+
return new Pool(parsedUrl.origin, options);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export async function getBasicDispatcher(
|
|
111
|
+
options: UndiciT.Agent.Options,
|
|
112
|
+
): Promise<UndiciT.Agent> {
|
|
113
|
+
const { Agent } = await import("undici");
|
|
114
|
+
|
|
115
|
+
return new Agent(options);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function getBaseDispatcherOptions(
|
|
119
|
+
timeout: number = DEFAULT_TIMEOUT_IN_MILLISECONDS,
|
|
120
|
+
isTestDispatcher: boolean = false,
|
|
121
|
+
): UndiciT.Client.Options {
|
|
122
|
+
// These have good defaults for production, but need to be tweaked to avoid hanging tests.
|
|
123
|
+
// https://github.com/nodejs/undici/blob/961b76ad7cac17d23580d172702e11a080974f5d/docs/docs/best-practices/writing-tests.md
|
|
124
|
+
const keepAliveTimeouts = isTestDispatcher
|
|
125
|
+
? { keepAliveTimeout: 10, keepAliveMaxTimeout: 10 }
|
|
126
|
+
: {};
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
headersTimeout: timeout,
|
|
130
|
+
bodyTimeout: timeout,
|
|
131
|
+
connectTimeout: timeout,
|
|
132
|
+
maxRedirections: DEFAULT_MAX_REDIRECTS,
|
|
133
|
+
...keepAliveTimeouts,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function sanitizeUrl(requestUrl: string): string {
|
|
138
|
+
const parsedUrl = new URL(requestUrl);
|
|
139
|
+
// Return only the origin to avoid leaking sensitive information
|
|
140
|
+
return parsedUrl.origin;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function handleError(e: Error, requestUrl: string): void {
|
|
144
|
+
let causeCode: unknown;
|
|
145
|
+
if (isObject(e.cause)) {
|
|
146
|
+
causeCode = e.cause.code;
|
|
147
|
+
}
|
|
148
|
+
const errorCode = "code" in e ? e.code : causeCode;
|
|
149
|
+
|
|
150
|
+
if (errorCode === "ECONNREFUSED") {
|
|
151
|
+
throw new ConnectionRefusedError(requestUrl, e);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (
|
|
155
|
+
errorCode === "UND_ERR_CONNECT_TIMEOUT" ||
|
|
156
|
+
errorCode === "UND_ERR_HEADERS_TIMEOUT" ||
|
|
157
|
+
errorCode === "UND_ERR_BODY_TIMEOUT"
|
|
158
|
+
) {
|
|
159
|
+
throw new RequestTimeoutError(requestUrl, e);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (errorCode === "UND_ERR_RESPONSE_STATUS_CODE") {
|
|
163
|
+
throw new ResponseStatusCodeError(requestUrl, e);
|
|
164
|
+
}
|
|
165
|
+
}
|
package/src/lang.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getDeepCloneFunction } from "./internal/lang.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a deep clone of the provided value.
|
|
5
|
+
*
|
|
6
|
+
* @param value The value to clone.
|
|
7
|
+
* @returns The deep clone of the provided value.
|
|
8
|
+
*/
|
|
9
|
+
export async function deepClone<T>(value: T): Promise<T> {
|
|
10
|
+
const _deepClone = await getDeepCloneFunction();
|
|
11
|
+
|
|
12
|
+
return _deepClone<T>(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if two values are deeply equal.
|
|
17
|
+
*
|
|
18
|
+
* @param x The first value to compare.
|
|
19
|
+
* @param y The second value to compare.
|
|
20
|
+
* @returns True if the values are deeply equal, false otherwise.
|
|
21
|
+
*/
|
|
22
|
+
export async function deepEqual<T>(x: T, y: T): Promise<boolean> {
|
|
23
|
+
const { deepEqual: _deepEqual } = await import("fast-equals");
|
|
24
|
+
|
|
25
|
+
return _deepEqual(x, y);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Checks if a value is an object. This function returns false for arrays.
|
|
30
|
+
*
|
|
31
|
+
* @param value The value to check.
|
|
32
|
+
* @returns True if the value is an object, false otherwise.
|
|
33
|
+
*/
|
|
34
|
+
export function isObject(
|
|
35
|
+
value: unknown,
|
|
36
|
+
): value is Record<string | symbol, unknown> {
|
|
37
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Pauses the execution for the specified number of seconds.
|
|
42
|
+
*
|
|
43
|
+
* @param seconds The number of seconds to pause the execution.
|
|
44
|
+
* @returns A promise that resolves after the specified number of seconds.
|
|
45
|
+
*/
|
|
46
|
+
export async function sleep(seconds: number): Promise<void> {
|
|
47
|
+
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
|
|
48
|
+
}
|
package/src/number.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bytesToHexString,
|
|
3
|
+
hexStringToBytes,
|
|
4
|
+
hexStringToBigInt,
|
|
5
|
+
numberToHexString,
|
|
6
|
+
hexStringToNumber,
|
|
7
|
+
} from "./hex.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Converts a Uint8Array to a bigint.
|
|
11
|
+
*
|
|
12
|
+
* @param bytes The Uint8Array to convert.
|
|
13
|
+
* @returns The converted bigint.
|
|
14
|
+
*/
|
|
15
|
+
export function bytesToBigInt(bytes: Uint8Array): bigint {
|
|
16
|
+
return hexStringToBigInt(bytesToHexString(bytes));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Converts a Uint8Array to a number.
|
|
21
|
+
*
|
|
22
|
+
* @param bytes The Uint8Array to convert.
|
|
23
|
+
* @returns The converted number.
|
|
24
|
+
*/
|
|
25
|
+
export function bytesToNumber(bytes: Uint8Array): number {
|
|
26
|
+
return hexStringToNumber(bytesToHexString(bytes));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Converts a non-negative safe integer or bigint to a Uint8Array.
|
|
31
|
+
*
|
|
32
|
+
* @param value The number or bigint to convert.
|
|
33
|
+
* @returns The converted Uint8Array.
|
|
34
|
+
* @throws InvalidParameterError If the input is not a safe integer or is negative.
|
|
35
|
+
*/
|
|
36
|
+
export function numberToBytes(value: number | bigint): Uint8Array {
|
|
37
|
+
return hexStringToBytes(numberToHexString(value));
|
|
38
|
+
}
|
package/src/package.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { ensureError } from "./error.js";
|
|
5
|
+
import {
|
|
6
|
+
PackageJsonNotFoundError,
|
|
7
|
+
PackageJsonReadError,
|
|
8
|
+
} from "./errors/package.js";
|
|
9
|
+
import { exists, findUp, getRealPath, readJsonFile } from "./fs.js";
|
|
10
|
+
import { getFilePath } from "./internal/package.js";
|
|
11
|
+
import { ensureTrailingSlash } from "./string.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The structure of a `package.json` file. This is a subset of the actual
|
|
15
|
+
* `package.json` file, if you need to access other fields you add them here.
|
|
16
|
+
*/
|
|
17
|
+
export interface PackageJson {
|
|
18
|
+
name: string;
|
|
19
|
+
version: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
type?: "commonjs" | "module";
|
|
22
|
+
engines?: {
|
|
23
|
+
node?: string;
|
|
24
|
+
};
|
|
25
|
+
dependencies?: Record<string, string>;
|
|
26
|
+
devDependencies?: Record<string, string>;
|
|
27
|
+
peerDependencies?: Record<string, string>;
|
|
28
|
+
optionalDependencies?: Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Searches for the nearest `package.json` file, starting from the directory of
|
|
33
|
+
* the provided file path or url string and moving up the directory tree.
|
|
34
|
+
*
|
|
35
|
+
* @param pathOrUrl A path or url string from which to start the search. The url
|
|
36
|
+
* must be a file url. This is useful when you want to find the nearest
|
|
37
|
+
* `package.json` file relative to the current module, as you can use
|
|
38
|
+
* `import.meta.url`.
|
|
39
|
+
* @returns The absolute path to the nearest `package.json` file.
|
|
40
|
+
* @throws PackageJsonNotFoundError If no `package.json` file is found.
|
|
41
|
+
*/
|
|
42
|
+
export async function findClosestPackageJson(
|
|
43
|
+
pathOrUrl: string,
|
|
44
|
+
): Promise<string> {
|
|
45
|
+
const filePath = getFilePath(pathOrUrl);
|
|
46
|
+
|
|
47
|
+
if (filePath === undefined) {
|
|
48
|
+
throw new PackageJsonNotFoundError(pathOrUrl);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const packageJsonPath = await findUp("package.json", filePath);
|
|
52
|
+
|
|
53
|
+
if (packageJsonPath === undefined) {
|
|
54
|
+
throw new PackageJsonNotFoundError(pathOrUrl);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return packageJsonPath;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Reads the nearest `package.json` file, starting from provided path or url
|
|
62
|
+
* string and moving up the directory tree.
|
|
63
|
+
*
|
|
64
|
+
* @param pathOrUrl A path or url string from which to start the search. The url
|
|
65
|
+
* must be a file url. This is useful when you want to find the nearest
|
|
66
|
+
* `package.json` file relative to the current module, as you can use
|
|
67
|
+
* `import.meta.url`.
|
|
68
|
+
* @returns The contents of the nearest `package.json` file, parsed as a
|
|
69
|
+
* {@link PackageJson} object.
|
|
70
|
+
* @throws PackageJsonNotFoundError If no `package.json` file is found.
|
|
71
|
+
* @throws PackageJsonReadError If the `package.json` file is found but cannot
|
|
72
|
+
* be read.
|
|
73
|
+
*/
|
|
74
|
+
export async function readClosestPackageJson(
|
|
75
|
+
pathOrUrl: string,
|
|
76
|
+
): Promise<PackageJson> {
|
|
77
|
+
const packageJsonPath = await findClosestPackageJson(pathOrUrl);
|
|
78
|
+
try {
|
|
79
|
+
return await readJsonFile<PackageJson>(packageJsonPath);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
ensureError(e);
|
|
82
|
+
throw new PackageJsonReadError(packageJsonPath, e);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Finds the root directory of the nearest package, starting from the provided
|
|
88
|
+
* path or url string and moving up the directory tree.
|
|
89
|
+
*
|
|
90
|
+
* This function uses `findClosestPackageJson` to find the nearest `package.json`
|
|
91
|
+
* file and then returns the directory that contains that file.
|
|
92
|
+
*
|
|
93
|
+
* @param pathOrUrl A path or url string from which to start the search. The url
|
|
94
|
+
* must be a file url. This is useful when you want to find the nearest
|
|
95
|
+
* `package.json` file relative to the current module, as you can use
|
|
96
|
+
* `import.meta.url`.
|
|
97
|
+
* @returns The absolute path of the root directory of the nearest package.
|
|
98
|
+
*/
|
|
99
|
+
export async function findClosestPackageRoot(
|
|
100
|
+
filePathOrUrl: string,
|
|
101
|
+
): Promise<string> {
|
|
102
|
+
const packageJsonPath = await findClosestPackageJson(filePathOrUrl);
|
|
103
|
+
|
|
104
|
+
return path.dirname(packageJsonPath);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Resolve a dependency starting by following the Node.js resolution algorithm
|
|
109
|
+
* starting from `from`, and returns the dependency's package.json file, or
|
|
110
|
+
* `undefined` if the dependency is not found.
|
|
111
|
+
*
|
|
112
|
+
* Note: This function uses Node.js's CommonJS resolution algorithm to find the
|
|
113
|
+
* package.json file, and works with packages using package#exports, even if
|
|
114
|
+
* they don't export the package.json file.
|
|
115
|
+
*
|
|
116
|
+
* @param from The absolute path from where to start the search (i.e. the file
|
|
117
|
+
* importing the dependency, or its package root).
|
|
118
|
+
* @param dependencyPackageName The name of the package to find.
|
|
119
|
+
* @returns The absolute real path (resolved symlinks) of the package.json.
|
|
120
|
+
*/
|
|
121
|
+
export async function findDependencyPackageJson(
|
|
122
|
+
from: string,
|
|
123
|
+
dependencyPackageName: string,
|
|
124
|
+
): Promise<string | undefined> {
|
|
125
|
+
const require = createRequire(ensureTrailingSlash(from));
|
|
126
|
+
|
|
127
|
+
const lookupPaths = require.resolve.paths(dependencyPackageName) ?? [];
|
|
128
|
+
|
|
129
|
+
const pathToTest = [...dependencyPackageName.split("/"), "package.json"];
|
|
130
|
+
|
|
131
|
+
for (const lookupPath of lookupPaths) {
|
|
132
|
+
const packageJsonPath = path.join(lookupPath, ...pathToTest);
|
|
133
|
+
|
|
134
|
+
if (await exists(packageJsonPath)) {
|
|
135
|
+
return getRealPath(packageJsonPath);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export {
|
|
141
|
+
PackageJsonNotFoundError,
|
|
142
|
+
PackageJsonReadError,
|
|
143
|
+
} from "./errors/package.js";
|
package/src/path.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves a user-provided path into an absolute path.
|
|
5
|
+
*
|
|
6
|
+
* If the path is already absolute, it is returned as is, otherwise it is
|
|
7
|
+
* resolved relative to the root.
|
|
8
|
+
*
|
|
9
|
+
* @param root A root path to resolve relative paths against.
|
|
10
|
+
* @param target The target path to resolve.
|
|
11
|
+
* @returns An absolute path.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveFromRoot(root: string, target: string): string {
|
|
14
|
+
if (path.isAbsolute(target)) {
|
|
15
|
+
return target;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return path.resolve(root, target);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Tries to return a shorter version of the path if its inside the given folder.
|
|
23
|
+
*
|
|
24
|
+
* This is useful for displaying paths in the terminal, as they can be shorter
|
|
25
|
+
* when they are insidde the current working directory. For example, if the
|
|
26
|
+
* current working directory is `/home/user/project`, and the path is
|
|
27
|
+
* `/home/user/project/contracts/File.sol`, the shorter path is
|
|
28
|
+
* `contracts/File.sol`.
|
|
29
|
+
*
|
|
30
|
+
* @param absolutePath The path to shorten.
|
|
31
|
+
* @param folder The absolute path to the folder.
|
|
32
|
+
* @returns The shorter path, if possible, or the original path.
|
|
33
|
+
*/
|
|
34
|
+
export function shortenPath(
|
|
35
|
+
absolutePath: string,
|
|
36
|
+
folder: string = process.cwd(),
|
|
37
|
+
): string {
|
|
38
|
+
const relativePath = path.relative(folder, absolutePath);
|
|
39
|
+
|
|
40
|
+
if (relativePath.length < absolutePath.length) {
|
|
41
|
+
return relativePath;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return absolutePath;
|
|
45
|
+
}
|