dprint 0.54.0 → 0.55.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/hashes.json +17 -0
- package/install_api.cjs +255 -27
- package/package.json +16 -12
package/hashes.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"win32-x64": "31f22db986f62258be1f42a9f3c3e334d9277f938e8948af1055f0308d7d6f41",
|
|
3
|
+
"win32-arm64": "f2ca5597b61fd91fccc0807014dbdbbb4913298d390c85746e4086b9e6573b20",
|
|
4
|
+
"darwin-x64": "f95a06d61508250fd1de20638143b3de13fadc313d45a2ce716925b1d1f96ed2",
|
|
5
|
+
"darwin-arm64": "67442fee500dbfc53d4e019ab18de929868e796ffe9c24df9c905001efe1d822",
|
|
6
|
+
"linux-x64-glibc": "8155ae8516e6dba1cb528efb9e636ab666b1dec7f67ba3548bed77634eeedbbc",
|
|
7
|
+
"linux-x64-musl": "eac4737c1a7b2cab9e600ff66b80aa657a8185a3dc5b6bc7b11d82c4268932a0",
|
|
8
|
+
"linux-arm64-glibc": "8f8edab6a515a05af423b324c4dd2b862ad81146f4e9c932190a6c07245d16ca",
|
|
9
|
+
"linux-arm64-musl": "655e4d16a6bdfb19249c1ae2442b1ff7f654c6711280220b0ec2b98e351e15e0",
|
|
10
|
+
"linux-riscv64-glibc": "45fcb3902b3cb0b49a64130f478c67d613350edaba17cd6afa47e51b6fa86ef4",
|
|
11
|
+
"linux-loong64-glibc": "84b7a8e0a666a8dc429a57a3716c50648c8c807495dec129619e959a91c9e10e",
|
|
12
|
+
"linux-loong64-musl": "12f2b2c44787174fee2c23a9f92970a40217e4d11f275349b67ad00814425c3f",
|
|
13
|
+
"linux-ppc64-glibc": "b56ad03b133c2a8859116fcaeba60363403d31bc3017dc2ec0b829a162f8a65b",
|
|
14
|
+
"linux-ppc64-musl": "f114533153aa3d4ff4c731d13cddd19f0ef5384305f17c0b560ff895206500b0",
|
|
15
|
+
"android-arm64": "6b43057475766b02af46c94a5a3279175a4f2927ace088dfdccc7d148073ccb5",
|
|
16
|
+
"android-x64": "7829ce89f50afb15e720e939aed58d3c8f2a0dbdb3c6e84054afda1bf0127280"
|
|
17
|
+
}
|
package/install_api.cjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
const path = require("path");
|
|
7
|
-
/** @type {
|
|
7
|
+
/** @type {boolean | undefined} */
|
|
8
8
|
let cachedIsMusl = undefined;
|
|
9
9
|
|
|
10
10
|
module.exports = {
|
|
@@ -21,11 +21,18 @@ module.exports = {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const target = getTarget();
|
|
24
|
-
const
|
|
25
|
-
const sourceExecutablePath = path.join(sourcePackagePath, dprintFileName);
|
|
24
|
+
const sourceExecutablePath = resolveSourceExecutablePath(target, dprintFileName);
|
|
26
25
|
|
|
27
|
-
if (
|
|
28
|
-
|
|
26
|
+
if (sourceExecutablePath == null) {
|
|
27
|
+
// the @dprint/<target> optional dependency isn't installed (for example
|
|
28
|
+
// the user ran `npm install --omit=optional`), so download the binary
|
|
29
|
+
// directly from the registry like esbuild does
|
|
30
|
+
downloadExecutable(target, dprintFileName, targetExecutablePath);
|
|
31
|
+
if (os.platform() !== "win32") {
|
|
32
|
+
// chmod +x
|
|
33
|
+
chmodX(targetExecutablePath);
|
|
34
|
+
}
|
|
35
|
+
return targetExecutablePath;
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
try {
|
|
@@ -59,6 +66,200 @@ module.exports = {
|
|
|
59
66
|
},
|
|
60
67
|
};
|
|
61
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Resolves the path to the executable provided by the @dprint/<target>
|
|
71
|
+
* optional dependency, or undefined when that package isn't installed.
|
|
72
|
+
* @param target {string}
|
|
73
|
+
* @param dprintFileName {string}
|
|
74
|
+
* @returns {string | undefined}
|
|
75
|
+
*/
|
|
76
|
+
function resolveSourceExecutablePath(target, dprintFileName) {
|
|
77
|
+
let sourcePackagePath;
|
|
78
|
+
try {
|
|
79
|
+
sourcePackagePath = path.dirname(require.resolve("@dprint/" + target + "/package.json"));
|
|
80
|
+
} catch {
|
|
81
|
+
// the optional dependency wasn't installed
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
const sourceExecutablePath = path.join(sourcePackagePath, dprintFileName);
|
|
85
|
+
return fs.existsSync(sourceExecutablePath) ? sourceExecutablePath : undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Downloads the binary tarball for the target from the registry and extracts
|
|
90
|
+
* the executable to the destination path.
|
|
91
|
+
* @param target {string}
|
|
92
|
+
* @param dprintFileName {string}
|
|
93
|
+
* @param destinationPath {string}
|
|
94
|
+
*/
|
|
95
|
+
function downloadExecutable(target, dprintFileName, destinationPath) {
|
|
96
|
+
const version = require("./package.json").version;
|
|
97
|
+
const registry = (process.env.npm_config_registry || "https://registry.npmjs.org")
|
|
98
|
+
.replace(/\/+$/, "");
|
|
99
|
+
// npm tarball urls drop the scope from the file name (e.g.
|
|
100
|
+
// https://registry.npmjs.org/@dprint/win32-x64/-/win32-x64-1.0.0.tgz)
|
|
101
|
+
const tarballUrl = registry + "/@dprint/" + target + "/-/" + target + "-" + version + ".tgz";
|
|
102
|
+
console.error("[dprint] Optional dependency @dprint/" + target + " was not installed. Downloading from " + tarballUrl);
|
|
103
|
+
const tarballBuffer = downloadBufferSync(tarballUrl);
|
|
104
|
+
// files inside an npm tarball live under the "package/" directory
|
|
105
|
+
const executableBuffer = extractFileFromTarGzip(tarballBuffer, "package/" + dprintFileName);
|
|
106
|
+
verifyExecutableHash(target, executableBuffer);
|
|
107
|
+
atomicWriteFile(destinationPath, executableBuffer);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Verifies the downloaded executable against the hash recorded at build time
|
|
112
|
+
* so that we only ever run the exact binary that was published.
|
|
113
|
+
* @param target {string}
|
|
114
|
+
* @param buffer {Buffer}
|
|
115
|
+
*/
|
|
116
|
+
function verifyExecutableHash(target, buffer) {
|
|
117
|
+
let hashes;
|
|
118
|
+
try {
|
|
119
|
+
hashes = require("./hashes.json");
|
|
120
|
+
} catch (err) {
|
|
121
|
+
throw new Error("Could not load hashes.json to verify the downloaded binary: " + (err && err.message || err));
|
|
122
|
+
}
|
|
123
|
+
const expected = hashes[target];
|
|
124
|
+
if (typeof expected !== "string") {
|
|
125
|
+
throw new Error("No known hash for @dprint/" + target + " to verify the download against.");
|
|
126
|
+
}
|
|
127
|
+
const actual = require("crypto").createHash("sha256").update(buffer).digest("hex");
|
|
128
|
+
if (actual !== expected) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
"Integrity check failed for the downloaded @dprint/" + target + " binary.\n"
|
|
131
|
+
+ " Expected sha256: " + expected + "\n"
|
|
132
|
+
+ " Actual sha256: " + actual,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Downloads a url to a buffer synchronously. Prefer curl since it transparently
|
|
139
|
+
* supports proxies (http_proxy/https_proxy/no_proxy and npm's proxy config),
|
|
140
|
+
* redirects and TLS, then fall back to node for environments without curl.
|
|
141
|
+
* @param url {string}
|
|
142
|
+
* @returns {Buffer}
|
|
143
|
+
*/
|
|
144
|
+
function downloadBufferSync(url) {
|
|
145
|
+
const fromCurl = downloadBufferWithCurl(url);
|
|
146
|
+
return fromCurl != null ? fromCurl : downloadBufferWithNode(url);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @param url {string}
|
|
151
|
+
* @returns {Buffer | undefined} undefined when curl isn't available
|
|
152
|
+
*/
|
|
153
|
+
function downloadBufferWithCurl(url) {
|
|
154
|
+
// -f: fail on http errors, -s: silent, -S: still show errors, -L: follow redirects
|
|
155
|
+
const args = ["-fsSL"];
|
|
156
|
+
const proxy = process.env.npm_config_https_proxy
|
|
157
|
+
|| process.env.npm_config_proxy
|
|
158
|
+
|| process.env.HTTPS_PROXY
|
|
159
|
+
|| process.env.https_proxy;
|
|
160
|
+
if (proxy) {
|
|
161
|
+
args.push("--proxy", proxy);
|
|
162
|
+
}
|
|
163
|
+
const noProxy = process.env.npm_config_noproxy || process.env.NO_PROXY || process.env.no_proxy;
|
|
164
|
+
if (noProxy) {
|
|
165
|
+
args.push("--noproxy", noProxy);
|
|
166
|
+
}
|
|
167
|
+
args.push("-o", "-", url);
|
|
168
|
+
try {
|
|
169
|
+
return require("child_process").execFileSync("curl", args, { maxBuffer: 512 * 1024 * 1024 });
|
|
170
|
+
} catch (err) {
|
|
171
|
+
if (err && err.code === "ENOENT") {
|
|
172
|
+
// curl isn't installed, fall back to node
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
throw err;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Node has no synchronous https client, so spawn a child node process that
|
|
181
|
+
* streams the response to stdout. Does not support proxies.
|
|
182
|
+
* @param url {string}
|
|
183
|
+
* @returns {Buffer}
|
|
184
|
+
*/
|
|
185
|
+
function downloadBufferWithNode(url) {
|
|
186
|
+
const script = "const https=require('https');"
|
|
187
|
+
+ "function f(u){https.get(u,r=>{"
|
|
188
|
+
+ "const s=r.statusCode;"
|
|
189
|
+
+ "if((s===301||s===302||s===303||s===307||s===308)&&r.headers.location){f(new URL(r.headers.location,u).toString());return;}"
|
|
190
|
+
+ "if(s!==200){console.error('[dprint] Unexpected status code '+s+' downloading '+u);process.exit(1);}"
|
|
191
|
+
+ "r.pipe(process.stdout);"
|
|
192
|
+
+ "}).on('error',e=>{console.error(String(e&&e.message||e));process.exit(1);});}"
|
|
193
|
+
+ "f(process.argv[1]);";
|
|
194
|
+
return require("child_process").execFileSync(
|
|
195
|
+
process.execPath,
|
|
196
|
+
["-e", script, url],
|
|
197
|
+
{ maxBuffer: 512 * 1024 * 1024 },
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Extracts a single file from a gzipped tarball buffer.
|
|
203
|
+
* @param buffer {Buffer}
|
|
204
|
+
* @param subpath {string}
|
|
205
|
+
* @returns {Buffer}
|
|
206
|
+
*/
|
|
207
|
+
function extractFileFromTarGzip(buffer, subpath) {
|
|
208
|
+
const zlib = require("zlib");
|
|
209
|
+
let tar;
|
|
210
|
+
try {
|
|
211
|
+
tar = zlib.gunzipSync(buffer);
|
|
212
|
+
} catch (err) {
|
|
213
|
+
throw new Error("Invalid gzip data in downloaded tarball: " + (err && err.message || err));
|
|
214
|
+
}
|
|
215
|
+
let offset = 0;
|
|
216
|
+
while (offset < tar.length) {
|
|
217
|
+
const name = readTarString(tar, offset, 100);
|
|
218
|
+
const size = parseInt(readTarString(tar, offset + 124, 12).trim(), 8);
|
|
219
|
+
offset += 512;
|
|
220
|
+
if (!isNaN(size)) {
|
|
221
|
+
if (name === subpath) {
|
|
222
|
+
return tar.subarray(offset, offset + size);
|
|
223
|
+
}
|
|
224
|
+
// entries are padded to 512 byte boundaries
|
|
225
|
+
offset += (size + 511) & ~511;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
throw new Error("Could not find " + JSON.stringify(subpath) + " in downloaded tarball");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @param buffer {Buffer}
|
|
233
|
+
* @param offset {number}
|
|
234
|
+
* @param length {number}
|
|
235
|
+
*/
|
|
236
|
+
function readTarString(buffer, offset, length) {
|
|
237
|
+
return buffer.toString("utf8", offset, offset + length).replace(/\0.*$/, "");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* @param destinationPath {string}
|
|
242
|
+
* @param buffer {Buffer}
|
|
243
|
+
*/
|
|
244
|
+
function atomicWriteFile(destinationPath, buffer) {
|
|
245
|
+
const crypto = require("crypto");
|
|
246
|
+
const rand = crypto.randomBytes(4).toString("hex");
|
|
247
|
+
const tempFilePath = destinationPath + "." + rand;
|
|
248
|
+
fs.writeFileSync(tempFilePath, buffer);
|
|
249
|
+
try {
|
|
250
|
+
fs.renameSync(tempFilePath, destinationPath);
|
|
251
|
+
} catch (err) {
|
|
252
|
+
// will maybe throw when another process had already done this
|
|
253
|
+
// so just ignore and delete the created temporary file
|
|
254
|
+
try {
|
|
255
|
+
fs.unlinkSync(tempFilePath);
|
|
256
|
+
} catch (_err2) {
|
|
257
|
+
// ignore
|
|
258
|
+
}
|
|
259
|
+
throw err;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
62
263
|
/** @filePath {string} */
|
|
63
264
|
function chmodX(filePath) {
|
|
64
265
|
const fd = fs.openSync(filePath, "r");
|
|
@@ -81,8 +282,8 @@ function getTarget() {
|
|
|
81
282
|
|
|
82
283
|
function getArch() {
|
|
83
284
|
const arch = os.arch();
|
|
84
|
-
if (arch !== "arm64" && arch !== "x64" && arch !== "riscv64" && arch !== "loong64") {
|
|
85
|
-
throw new Error("Unsupported architecture " + os.arch() + ". Only x64,
|
|
285
|
+
if (arch !== "arm64" && arch !== "x64" && arch !== "riscv64" && arch !== "loong64" && arch !== "ppc64") {
|
|
286
|
+
throw new Error("Unsupported architecture " + os.arch() + ". Only x64, arm64, riscv64, loong64 and ppc64 binaries are available.");
|
|
86
287
|
}
|
|
87
288
|
return arch;
|
|
88
289
|
}
|
|
@@ -91,8 +292,8 @@ function getLinuxFamily() {
|
|
|
91
292
|
return getIsMusl() ? "musl" : "glibc";
|
|
92
293
|
|
|
93
294
|
function getIsMusl() {
|
|
94
|
-
// code adapted from https://github.com/
|
|
95
|
-
//
|
|
295
|
+
// code adapted from https://github.com/napi-rs/package-template/blob/main/index.js
|
|
296
|
+
// which is in turn based on https://github.com/lovell/detect-libc (Apache 2.0 license)
|
|
96
297
|
if (cachedIsMusl == null) {
|
|
97
298
|
cachedIsMusl = innerGet();
|
|
98
299
|
}
|
|
@@ -103,7 +304,14 @@ function getLinuxFamily() {
|
|
|
103
304
|
if (os.platform() !== "linux") {
|
|
104
305
|
return false;
|
|
105
306
|
}
|
|
106
|
-
|
|
307
|
+
let musl = isMuslFromFilesystem();
|
|
308
|
+
if (musl == null) {
|
|
309
|
+
musl = isMuslFromReport();
|
|
310
|
+
}
|
|
311
|
+
if (musl == null) {
|
|
312
|
+
musl = isMuslFromChildProcess();
|
|
313
|
+
}
|
|
314
|
+
return musl;
|
|
107
315
|
} catch (err) {
|
|
108
316
|
// just in case
|
|
109
317
|
console.warn("Error checking if musl.", err);
|
|
@@ -111,32 +319,52 @@ function getLinuxFamily() {
|
|
|
111
319
|
}
|
|
112
320
|
}
|
|
113
321
|
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
return
|
|
322
|
+
function isMuslFromFilesystem() {
|
|
323
|
+
try {
|
|
324
|
+
return fs.readFileSync("/usr/bin/ldd", "utf-8").includes("musl");
|
|
325
|
+
} catch {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function isMuslFromReport() {
|
|
331
|
+
if (typeof process.report?.getReport !== "function") {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
// excludeNetwork avoids a slow reverse DNS lookup while generating the
|
|
335
|
+
// report, but it's a global flag so restore it once we're done
|
|
336
|
+
const originalExcludeNetwork = process.report.excludeNetwork;
|
|
337
|
+
let rawReport;
|
|
338
|
+
try {
|
|
339
|
+
process.report.excludeNetwork = true;
|
|
340
|
+
rawReport = process.report.getReport();
|
|
341
|
+
} finally {
|
|
342
|
+
process.report.excludeNetwork = originalExcludeNetwork;
|
|
117
343
|
}
|
|
118
|
-
const rawReport = process.report.getReport();
|
|
119
344
|
const report = typeof rawReport === "string" ? JSON.parse(rawReport) : rawReport;
|
|
120
|
-
if (!report
|
|
345
|
+
if (!report) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
if (report.header && report.header.glibcVersionRuntime) {
|
|
121
349
|
return false;
|
|
122
350
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const output = getCommandOutput();
|
|
128
|
-
const [_, ldd1] = output.split(/[\r\n]+/);
|
|
129
|
-
return ldd1 && ldd1.includes("musl");
|
|
351
|
+
if (Array.isArray(report.sharedObjects)) {
|
|
352
|
+
return report.sharedObjects.some(isFileMusl);
|
|
353
|
+
}
|
|
354
|
+
return false;
|
|
130
355
|
}
|
|
131
356
|
|
|
132
|
-
function
|
|
357
|
+
function isMuslFromChildProcess() {
|
|
133
358
|
try {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return "";
|
|
359
|
+
return require("child_process").execSync("ldd --version", { encoding: "utf8" }).includes("musl");
|
|
360
|
+
} catch {
|
|
361
|
+
return false;
|
|
138
362
|
}
|
|
139
363
|
}
|
|
364
|
+
|
|
365
|
+
function isFileMusl(f) {
|
|
366
|
+
return f.includes("libc.musl-") || f.includes("ld-musl-");
|
|
367
|
+
}
|
|
140
368
|
}
|
|
141
369
|
}
|
|
142
370
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dprint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.55.0",
|
|
4
4
|
"description": "Pluggable and configurable code formatting platform written in Rust.",
|
|
5
5
|
"bin": "bin.cjs",
|
|
6
6
|
"repository": {
|
|
@@ -22,16 +22,20 @@
|
|
|
22
22
|
"postinstall": "node ./install.cjs"
|
|
23
23
|
},
|
|
24
24
|
"optionalDependencies": {
|
|
25
|
-
"@dprint/win32-x64": "0.
|
|
26
|
-
"@dprint/win32-arm64": "0.
|
|
27
|
-
"@dprint/darwin-x64": "0.
|
|
28
|
-
"@dprint/darwin-arm64": "0.
|
|
29
|
-
"@dprint/linux-x64-glibc": "0.
|
|
30
|
-
"@dprint/linux-x64-musl": "0.
|
|
31
|
-
"@dprint/linux-arm64-glibc": "0.
|
|
32
|
-
"@dprint/linux-arm64-musl": "0.
|
|
33
|
-
"@dprint/linux-riscv64-glibc": "0.
|
|
34
|
-
"@dprint/linux-loong64-glibc": "0.
|
|
35
|
-
"@dprint/linux-loong64-musl": "0.
|
|
25
|
+
"@dprint/win32-x64": "0.55.0",
|
|
26
|
+
"@dprint/win32-arm64": "0.55.0",
|
|
27
|
+
"@dprint/darwin-x64": "0.55.0",
|
|
28
|
+
"@dprint/darwin-arm64": "0.55.0",
|
|
29
|
+
"@dprint/linux-x64-glibc": "0.55.0",
|
|
30
|
+
"@dprint/linux-x64-musl": "0.55.0",
|
|
31
|
+
"@dprint/linux-arm64-glibc": "0.55.0",
|
|
32
|
+
"@dprint/linux-arm64-musl": "0.55.0",
|
|
33
|
+
"@dprint/linux-riscv64-glibc": "0.55.0",
|
|
34
|
+
"@dprint/linux-loong64-glibc": "0.55.0",
|
|
35
|
+
"@dprint/linux-loong64-musl": "0.55.0",
|
|
36
|
+
"@dprint/linux-ppc64-glibc": "0.55.0",
|
|
37
|
+
"@dprint/linux-ppc64-musl": "0.55.0",
|
|
38
|
+
"@dprint/android-arm64": "0.55.0",
|
|
39
|
+
"@dprint/android-x64": "0.55.0"
|
|
36
40
|
}
|
|
37
41
|
}
|