@bobfrankston/npmglobalize 1.0.151 → 1.0.152

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/cli.js CHANGED
@@ -75,6 +75,10 @@ Other Options:
75
75
  (noEmit projects: removes TS ignores from .npmignore)
76
76
  -asis Skip ignore file checks (or set "asis": true in .globalize.json5)
77
77
  -rebase Automatically rebase if local is behind remote
78
+ -clean-nested-modules, -clean-nested
79
+ Before npm pack, wipe node_modules/ in each file: dep target.
80
+ Fixes arborist "Cannot read properties of null" crashes when
81
+ sibling file: deps have their own nested node_modules.
78
82
  -show Show package.json dependency changes
79
83
  -package, -pkg Update package.json scripts to use npmglobalize
80
84
  -h, -help Show this help
@@ -318,6 +322,11 @@ function parseArgs(args) {
318
322
  options.importgen = false;
319
323
  options.explicitKeys.add('importgen');
320
324
  break;
325
+ case '-clean-nested':
326
+ case '-clean-nested-modules':
327
+ options.cleanNestedModules = true;
328
+ options.explicitKeys.add('cleanNestedModules');
329
+ break;
321
330
  default:
322
331
  if (arg.startsWith('-')) {
323
332
  unrecognized.push(arg);
package/lib/config.js CHANGED
@@ -64,7 +64,7 @@ export function writeConfig(dir, config, explicitKeys) {
64
64
  const existing = readConfig(dir);
65
65
  // Filter out temporary flags and default values (unless explicitly set)
66
66
  const filtered = {};
67
- const omitKeys = new Set(['cleanup', 'init', 'dryRun', 'message', 'conform', 'asis', 'help', 'error', 'updateDeps', 'updateMajor', 'publishDeps', 'forcePublish', 'once']);
67
+ const omitKeys = new Set(['cleanup', 'init', 'dryRun', 'message', 'conform', 'asis', 'help', 'error', 'updateDeps', 'updateMajor', 'publishDeps', 'forcePublish', 'once', 'cleanNestedModules']);
68
68
  for (const [key, value] of Object.entries(config)) {
69
69
  if (omitKeys.has(key))
70
70
  continue;
package/lib/types.d.ts CHANGED
@@ -82,6 +82,9 @@ export interface GlobalizeOptions {
82
82
  local?: boolean;
83
83
  /** Freeze node_modules: replace symlinks/junctions with real copies for network share use */
84
84
  freeze?: boolean;
85
+ /** Before `npm pack`, delete `node_modules/` inside each `file:` dep target.
86
+ * Works around arborist crashes when siblings have nested node_modules. */
87
+ cleanNestedModules?: boolean;
85
88
  /** Internal: signals this call is from workspace orchestrator */
86
89
  _fromWorkspace?: boolean;
87
90
  /** Internal: signals this call is from CLI (version already printed) */
package/lib.d.ts CHANGED
@@ -95,6 +95,9 @@ export interface GlobalizeOptions {
95
95
  local?: boolean;
96
96
  /** Freeze node_modules: replace symlinks/junctions with real copies for network share use */
97
97
  freeze?: boolean;
98
+ /** Before `npm pack`, delete `node_modules/` inside each `file:` dep target.
99
+ * Works around arborist crashes when siblings have nested node_modules. */
100
+ cleanNestedModules?: boolean;
98
101
  /** Internal: auto-initialize git repos without prompting (user chose "all") */
99
102
  autoInit?: boolean;
100
103
  /** Internal: signals this call is from workspace orchestrator */
package/lib.js CHANGED
@@ -236,7 +236,7 @@ export function writeConfig(dir, config, explicitKeys) {
236
236
  const existing = readConfig(dir);
237
237
  // Filter out temporary flags and default values (unless explicitly set)
238
238
  const filtered = {};
239
- const omitKeys = new Set(['cleanup', 'init', 'dryRun', 'message', 'conform', 'asis', 'help', 'error', 'updateDeps', 'updateMajor', 'publishDeps', 'forcePublish', 'once']);
239
+ const omitKeys = new Set(['cleanup', 'init', 'dryRun', 'message', 'conform', 'asis', 'help', 'error', 'updateDeps', 'updateMajor', 'publishDeps', 'forcePublish', 'once', 'cleanNestedModules']);
240
240
  for (const [key, value] of Object.entries(config)) {
241
241
  if (omitKeys.has(key))
242
242
  continue;
@@ -1262,6 +1262,39 @@ 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
+ function cleanNestedDepModules(pkg, cwd, verbose) {
1269
+ const cleaned = [];
1270
+ const seen = new Set();
1271
+ for (const key of ['.dependencies', '.devDependencies', 'dependencies', 'devDependencies']) {
1272
+ const deps = pkg?.[key];
1273
+ if (!deps || typeof deps !== 'object')
1274
+ continue;
1275
+ for (const [name, spec] of Object.entries(deps)) {
1276
+ if (seen.has(name))
1277
+ continue;
1278
+ if (typeof spec !== 'string' || !spec.startsWith('file:'))
1279
+ continue;
1280
+ const target = path.resolve(cwd, spec.slice('file:'.length));
1281
+ const nm = path.join(target, 'node_modules');
1282
+ if (!fs.existsSync(nm))
1283
+ continue;
1284
+ seen.add(name);
1285
+ try {
1286
+ fs.rmSync(nm, { recursive: true, force: true });
1287
+ cleaned.push(name);
1288
+ if (verbose)
1289
+ console.log(colors.dim(` cleaned ${nm}`));
1290
+ }
1291
+ catch (e) {
1292
+ console.error(colors.yellow(` warning: could not clean ${nm}: ${e.message}`));
1293
+ }
1294
+ }
1295
+ }
1296
+ return cleaned;
1297
+ }
1265
1298
  /** Run npm install -g with retries for registry propagation delay */
1266
1299
  function installGlobalWithRetry(pkgSpec, cwd, maxRetries = 3) {
1267
1300
  let result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
@@ -4237,6 +4270,16 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
4237
4270
  if (verbose) {
4238
4271
  console.log(colors.green(`✓ Authenticated as ${authStatus.username}`));
4239
4272
  }
4273
+ // Optionally clean nested node_modules in file: dep targets before pack
4274
+ 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(', ')}`));
4278
+ }
4279
+ else if (verbose) {
4280
+ console.log(colors.dim(' --clean-nested-modules: nothing to clean'));
4281
+ }
4282
+ }
4240
4283
  // Create tarball first
4241
4284
  const packResult = runCommand('npm', ['pack'], { cwd, silent: true });
4242
4285
  if (!packResult.success) {
@@ -4248,6 +4291,9 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
4248
4291
  console.error(colors.yellow(` Caused by referenced module: ${d.referencedModule}`));
4249
4292
  if (d.hint)
4250
4293
  console.error(colors.yellow(` Hint: ${d.hint}`));
4294
+ if (d.summary.includes('arborist') && !options.cleanNestedModules) {
4295
+ console.error(colors.yellow(` Retry with --clean-nested-modules to wipe node_modules/ inside each file: dep target`));
4296
+ }
4251
4297
  recordBuildIssue(pkg.name || path.basename(cwd), 'error', d.referencedModule ? `${d.summary} (via ${d.referencedModule})` : d.summary);
4252
4298
  return false;
4253
4299
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/npmglobalize",
3
- "version": "1.0.151",
3
+ "version": "1.0.152",
4
4
  "description": "Transform file: dependencies to npm versions for publishing",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@bobfrankston/freezepak": "^0.1.7",
35
- "@bobfrankston/importgen": "^0.1.33",
35
+ "@bobfrankston/importgen": "^0.1.34",
36
36
  "@bobfrankston/themecolors": "^0.1.5",
37
37
  "@bobfrankston/userconfig": "^1.0.7",
38
38
  "@npmcli/package-json": "^7.0.4",
@@ -60,7 +60,7 @@
60
60
  ".transformedSnapshot": {
61
61
  "dependencies": {
62
62
  "@bobfrankston/freezepak": "^0.1.7",
63
- "@bobfrankston/importgen": "^0.1.33",
63
+ "@bobfrankston/importgen": "^0.1.34",
64
64
  "@bobfrankston/themecolors": "^0.1.5",
65
65
  "@bobfrankston/userconfig": "^1.0.7",
66
66
  "@npmcli/package-json": "^7.0.4",