@bobfrankston/npmglobalize 1.0.152 → 1.0.153

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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/lib.js +40 -13
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -350,6 +350,11 @@ Workspace mode is auto-detected when run from a root with `"private": true` and
350
350
  -asis Skip ignore file checks (or set "asis": true in .globalize.json5)
351
351
  -fix-tags Automatically fix version/tag mismatches
352
352
  -rebase Automatically rebase if local is behind remote
353
+ -clean-nested-modules, -clean-nested
354
+ Before npm pack, wipe node_modules/ inside each file: dep
355
+ target. Fixes arborist "Cannot read properties of null"
356
+ crashes caused by sibling file: deps with nested
357
+ node_modules. Suggested automatically when the error hits.
353
358
  -show Show package.json dependency changes
354
359
  -package, -pkg Update package.json scripts to use npmglobalize (see below)
355
360
  -h, -help Show help
package/lib.js CHANGED
@@ -1262,12 +1262,10 @@ function waitForNpmVersion(pkgName, version, maxWaitMs = 90000) {
1262
1262
  process.stdout.write(' timed out\n');
1263
1263
  return false;
1264
1264
  }
1265
- /** Delete `node_modules/` inside each `file:` dep target.
1266
- * Works around arborist crashes during `npm pack` when sibling `file:` deps
1267
- * have their own populated `node_modules/`. Returns the names of cleaned deps. */
1268
1265
  function cleanNestedDepModules(pkg, cwd, verbose) {
1269
- const cleaned = [];
1266
+ const stashed = [];
1270
1267
  const seen = new Set();
1268
+ const suffix = `.npmglobalize-stash-${process.pid}`;
1271
1269
  for (const key of ['.dependencies', '.devDependencies', 'dependencies', 'devDependencies']) {
1272
1270
  const deps = pkg?.[key];
1273
1271
  if (!deps || typeof deps !== 'object')
@@ -1282,18 +1280,40 @@ function cleanNestedDepModules(pkg, cwd, verbose) {
1282
1280
  if (!fs.existsSync(nm))
1283
1281
  continue;
1284
1282
  seen.add(name);
1283
+ const backup = nm + suffix;
1285
1284
  try {
1286
- fs.rmSync(nm, { recursive: true, force: true });
1287
- cleaned.push(name);
1285
+ if (fs.existsSync(backup))
1286
+ fs.rmSync(backup, { recursive: true, force: true });
1287
+ fs.renameSync(nm, backup);
1288
+ stashed.push({ name, nm, backup });
1288
1289
  if (verbose)
1289
- console.log(colors.dim(` cleaned ${nm}`));
1290
+ console.log(colors.dim(` stashed ${nm} -> ${path.basename(backup)}`));
1290
1291
  }
1291
1292
  catch (e) {
1292
- console.error(colors.yellow(` warning: could not clean ${nm}: ${e.message}`));
1293
+ console.error(colors.yellow(` warning: could not stash ${nm}: ${e.message}`));
1293
1294
  }
1294
1295
  }
1295
1296
  }
1296
- return cleaned;
1297
+ return stashed;
1298
+ }
1299
+ /** Restore `node_modules/` previously moved aside by `cleanNestedDepModules`.
1300
+ * Safe to call multiple times; missing backups are skipped. */
1301
+ function restoreNestedDepModules(stashed, verbose) {
1302
+ for (const s of stashed) {
1303
+ try {
1304
+ if (!fs.existsSync(s.backup))
1305
+ continue;
1306
+ if (fs.existsSync(s.nm))
1307
+ fs.rmSync(s.nm, { recursive: true, force: true });
1308
+ fs.renameSync(s.backup, s.nm);
1309
+ if (verbose)
1310
+ console.log(colors.dim(` restored ${s.nm}`));
1311
+ }
1312
+ catch (e) {
1313
+ console.error(colors.yellow(` warning: could not restore ${s.nm}: ${e.message}`));
1314
+ console.error(colors.yellow(` backup remains at ${s.backup} — restore manually`));
1315
+ }
1316
+ }
1297
1317
  }
1298
1318
  /** Run npm install -g with retries for registry propagation delay */
1299
1319
  function installGlobalWithRetry(pkgSpec, cwd, maxRetries = 3) {
@@ -4270,11 +4290,14 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
4270
4290
  if (verbose) {
4271
4291
  console.log(colors.green(`✓ Authenticated as ${authStatus.username}`));
4272
4292
  }
4273
- // Optionally clean nested node_modules in file: dep targets before pack
4293
+ // Optionally stash nested node_modules in file: dep targets before pack
4294
+ // (arborist crashes when sibling file: deps have populated node_modules).
4295
+ // Restored immediately after pack so symlinked file: deps stay runnable.
4296
+ let stashedDepModules = [];
4274
4297
  if (options.cleanNestedModules) {
4275
- const cleaned = cleanNestedDepModules(pkg, cwd, verbose);
4276
- if (cleaned.length > 0) {
4277
- console.log(colors.yellow(` Cleaned node_modules in ${cleaned.length} file: dep target(s): ${cleaned.join(', ')}`));
4298
+ stashedDepModules = cleanNestedDepModules(pkg, cwd, verbose);
4299
+ if (stashedDepModules.length > 0) {
4300
+ console.log(colors.yellow(` Cleaned node_modules in ${stashedDepModules.length} file: dep target(s): ${stashedDepModules.map(s => s.name).join(', ')}`));
4278
4301
  }
4279
4302
  else if (verbose) {
4280
4303
  console.log(colors.dim(' --clean-nested-modules: nothing to clean'));
@@ -4282,6 +4305,10 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
4282
4305
  }
4283
4306
  // Create tarball first
4284
4307
  const packResult = runCommand('npm', ['pack'], { cwd, silent: true });
4308
+ // Restore stashed node_modules now that pack is done — must happen
4309
+ // before any subsequent install -g symlinks to these dep targets.
4310
+ if (stashedDepModules.length > 0)
4311
+ restoreNestedDepModules(stashedDepModules, verbose);
4285
4312
  if (!packResult.success) {
4286
4313
  const d = diagnoseNpmPackFailure(cwd, packResult.output, packResult.stderr, pkg);
4287
4314
  console.error(colors.red(`ERROR: ${d.summary}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/npmglobalize",
3
- "version": "1.0.152",
3
+ "version": "1.0.153",
4
4
  "description": "Transform file: dependencies to npm versions for publishing",
5
5
  "main": "index.js",
6
6
  "type": "module",