fulmine.js 5.19.9 → 5.20.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/src/verify.js CHANGED
@@ -29,6 +29,7 @@ limitations under the License.
29
29
 
30
30
  const fs = require("fs");
31
31
  const path = require("path");
32
+ const { detectManager, UWS_SPEC, UWS_OVERRIDE } = require("./adopt.js");
32
33
 
33
34
  // The oldest glibc the pinned uWS binaries are built against. A runtime older than this loads the
34
35
  // file and then fails on a symbol, which is a worse error than not finding it at all.
@@ -251,6 +252,20 @@ function checkDockerfiles(dir) {
251
252
  return results;
252
253
  }
253
254
 
255
+ /**
256
+ * The project's package.json, or nothing where there is none to read.
257
+ *
258
+ * @param {string} dir
259
+ * @returns {any}
260
+ */
261
+ function readPackage(dir) {
262
+ try {
263
+ return JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf8"));
264
+ } catch {
265
+ return undefined;
266
+ }
267
+ }
268
+
254
269
  /**
255
270
  * The dependencies that need a different API here. Read from package.json rather than from
256
271
  * node_modules, so a project is answered before it installs anything.
@@ -261,12 +276,8 @@ function checkDockerfiles(dir) {
261
276
  function checkDependencies(dir) {
262
277
  /** @type {ReturnType<typeof result>[]} */
263
278
  const results = [];
264
- let pkg;
265
- try {
266
- pkg = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf8"));
267
- } catch {
268
- return results;
269
- }
279
+ const pkg = readPackage(dir);
280
+ if (!pkg) return results;
270
281
  const installed = { ...pkg.dependencies, ...pkg.devDependencies };
271
282
  for (const name of Object.keys(NEEDS_A_LOOK)) {
272
283
  if (installed[name]) {
@@ -276,6 +287,83 @@ function checkDependencies(dir) {
276
287
  return results;
277
288
  }
278
289
 
290
+ // pnpm refuses a git dependency of a dependency since this version, and µWebSockets.js is one
291
+ const PNPM_BLOCKS_GIT_SUBDEPS = [10, 26];
292
+
293
+ /**
294
+ * Whether the package manager will install this at all. pnpm 10.26 and later refuse a dependency
295
+ * of a dependency that comes from git, which µWebSockets.js does, so `pnpm add fulmine.js` fails
296
+ * before anything runs. What lets it through is readable from the project: the two lines
297
+ * `npx fulmine.js pnpm` writes, the setting turned off, or an override taking µWebSockets.js from
298
+ * a registry. pnpm 11 reads its settings from pnpm-workspace.yaml only, so that is what is read.
299
+ *
300
+ * @param {string} dir
301
+ * @param {any} pkg the parsed package.json
302
+ * @returns {ReturnType<typeof result>|undefined} nothing to say for npm and yarn
303
+ */
304
+ function checkPackageManager(dir, pkg) {
305
+ const { manager, why } = detectManager(dir, pkg);
306
+ if (manager !== "pnpm") return undefined;
307
+
308
+ const declared = /^pnpm@(\d+)\.(\d+)/.exec(pkg.packageManager ?? "");
309
+ if (declared) {
310
+ const [major, minor] = [Number(declared[1]), Number(declared[2])];
311
+ const [blockMajor, blockMinor] = PNPM_BLOCKS_GIT_SUBDEPS;
312
+ if (major < blockMajor || (major === blockMajor && minor < blockMinor)) {
313
+ return result("ok", `pnpm ${declared[1]}.${declared[2]} installs a git dependency of a dependency`);
314
+ }
315
+ }
316
+
317
+ let workspace = "";
318
+ try {
319
+ workspace = fs.readFileSync(path.join(dir, "pnpm-workspace.yaml"), "utf8");
320
+ } catch {
321
+ // no workspace file, so every setting is at its default
322
+ }
323
+
324
+ // the recipe: the project owns the git dependency, and the copy this package asks for is dropped
325
+ const dropped = new RegExp(`^\\s*["']?${UWS_OVERRIDE.replace(/\./g, "\\.")}["']?:\\s*["']?-["']?\\s*$`, "m").test(
326
+ workspace
327
+ );
328
+ const own = pkg.dependencies?.["uWebSockets.js"];
329
+ if (dropped && typeof own === "string") {
330
+ if (own === UWS_SPEC) {
331
+ return result(
332
+ "ok",
333
+ "pnpm, with µWebSockets.js as the project's own dependency at the pin this package uses"
334
+ );
335
+ }
336
+ return result(
337
+ "note",
338
+ `pnpm, with µWebSockets.js as the project's own dependency at ${own}`,
339
+ `this package pins ${UWS_SPEC} and was tested against it. \`npx fulmine.js pnpm\` writes the pin.`
340
+ );
341
+ }
342
+ if (dropped) {
343
+ return result(
344
+ "no",
345
+ "pnpm-workspace.yaml drops µWebSockets.js from this package, and the project does not declare it",
346
+ `nothing would install it. \`npx fulmine.js pnpm\` adds "uWebSockets.js": "${UWS_SPEC}" to dependencies.`
347
+ );
348
+ }
349
+
350
+ if (/^\s*blockExoticSubdeps:\s*false\s*$/m.test(workspace)) {
351
+ return result("ok", "pnpm, with blockExoticSubdeps off in pnpm-workspace.yaml");
352
+ }
353
+ const registry = /^\s*["']?uWebSockets\.js["']?:\s*["']?([~^]?\d[^"'\s]*)/m.exec(workspace);
354
+ if (registry) {
355
+ return result("ok", `pnpm, with µWebSockets.js overridden to ${registry[1]} from a registry`);
356
+ }
357
+
358
+ return result(
359
+ "no",
360
+ `pnpm (${why}) will refuse to install this`,
361
+ "pnpm 10.26 and later block a git dependency of a dependency, and µWebSockets.js is one:\n" +
362
+ " pnpm add fulmine.js fails with ERR_PNPM_EXOTIC_SUBDEP. `npx fulmine.js pnpm` writes the two\n" +
363
+ " lines that let it through, see docs/deployment.md."
364
+ );
365
+ }
366
+
279
367
  /**
280
368
  * Runs every check and prints the report. Anything that would stop the application from starting
281
369
  * is a failure and the command exits non-zero, so it can be a step in a pipeline.
@@ -292,6 +380,10 @@ function verify(argv) {
292
380
  results.push(libc);
293
381
  }
294
382
  results.push(checkBinary(), ...checkDockerfiles(dir), ...checkDependencies(dir));
383
+ const manager = checkPackageManager(dir, readPackage(dir) ?? {});
384
+ if (manager) {
385
+ results.push(manager);
386
+ }
295
387
 
296
388
  console.log(`\nWhether this machine and this project can run fulmine.js\n`);
297
389
  const label = { ok: "ok ", note: "note", no: "NO " };
@@ -312,4 +404,13 @@ function verify(argv) {
312
404
  return blocking === 0 ? 0 : 1;
313
405
  }
314
406
 
315
- module.exports = { verify, checkNode, checkLibc, currentGlibc, checkBinary, checkDockerfiles, checkDependencies };
407
+ module.exports = {
408
+ verify,
409
+ checkNode,
410
+ checkLibc,
411
+ currentGlibc,
412
+ checkBinary,
413
+ checkDockerfiles,
414
+ checkDependencies,
415
+ checkPackageManager
416
+ };