@bobfrankston/npmglobalize 1.0.151 → 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.
- package/README.md +5 -0
- package/cli.js +9 -0
- package/lib/config.js +1 -1
- package/lib/types.d.ts +3 -0
- package/lib.d.ts +3 -0
- package/lib.js +74 -1
- package/package.json +3 -3
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/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,59 @@ function waitForNpmVersion(pkgName, version, maxWaitMs = 90000) {
|
|
|
1262
1262
|
process.stdout.write(' timed out\n');
|
|
1263
1263
|
return false;
|
|
1264
1264
|
}
|
|
1265
|
+
function cleanNestedDepModules(pkg, cwd, verbose) {
|
|
1266
|
+
const stashed = [];
|
|
1267
|
+
const seen = new Set();
|
|
1268
|
+
const suffix = `.npmglobalize-stash-${process.pid}`;
|
|
1269
|
+
for (const key of ['.dependencies', '.devDependencies', 'dependencies', 'devDependencies']) {
|
|
1270
|
+
const deps = pkg?.[key];
|
|
1271
|
+
if (!deps || typeof deps !== 'object')
|
|
1272
|
+
continue;
|
|
1273
|
+
for (const [name, spec] of Object.entries(deps)) {
|
|
1274
|
+
if (seen.has(name))
|
|
1275
|
+
continue;
|
|
1276
|
+
if (typeof spec !== 'string' || !spec.startsWith('file:'))
|
|
1277
|
+
continue;
|
|
1278
|
+
const target = path.resolve(cwd, spec.slice('file:'.length));
|
|
1279
|
+
const nm = path.join(target, 'node_modules');
|
|
1280
|
+
if (!fs.existsSync(nm))
|
|
1281
|
+
continue;
|
|
1282
|
+
seen.add(name);
|
|
1283
|
+
const backup = nm + suffix;
|
|
1284
|
+
try {
|
|
1285
|
+
if (fs.existsSync(backup))
|
|
1286
|
+
fs.rmSync(backup, { recursive: true, force: true });
|
|
1287
|
+
fs.renameSync(nm, backup);
|
|
1288
|
+
stashed.push({ name, nm, backup });
|
|
1289
|
+
if (verbose)
|
|
1290
|
+
console.log(colors.dim(` stashed ${nm} -> ${path.basename(backup)}`));
|
|
1291
|
+
}
|
|
1292
|
+
catch (e) {
|
|
1293
|
+
console.error(colors.yellow(` warning: could not stash ${nm}: ${e.message}`));
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
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
|
+
}
|
|
1317
|
+
}
|
|
1265
1318
|
/** Run npm install -g with retries for registry propagation delay */
|
|
1266
1319
|
function installGlobalWithRetry(pkgSpec, cwd, maxRetries = 3) {
|
|
1267
1320
|
let result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
|
|
@@ -4237,8 +4290,25 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4237
4290
|
if (verbose) {
|
|
4238
4291
|
console.log(colors.green(`✓ Authenticated as ${authStatus.username}`));
|
|
4239
4292
|
}
|
|
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 = [];
|
|
4297
|
+
if (options.cleanNestedModules) {
|
|
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(', ')}`));
|
|
4301
|
+
}
|
|
4302
|
+
else if (verbose) {
|
|
4303
|
+
console.log(colors.dim(' --clean-nested-modules: nothing to clean'));
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4240
4306
|
// Create tarball first
|
|
4241
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);
|
|
4242
4312
|
if (!packResult.success) {
|
|
4243
4313
|
const d = diagnoseNpmPackFailure(cwd, packResult.output, packResult.stderr, pkg);
|
|
4244
4314
|
console.error(colors.red(`ERROR: ${d.summary}`));
|
|
@@ -4248,6 +4318,9 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4248
4318
|
console.error(colors.yellow(` Caused by referenced module: ${d.referencedModule}`));
|
|
4249
4319
|
if (d.hint)
|
|
4250
4320
|
console.error(colors.yellow(` Hint: ${d.hint}`));
|
|
4321
|
+
if (d.summary.includes('arborist') && !options.cleanNestedModules) {
|
|
4322
|
+
console.error(colors.yellow(` Retry with --clean-nested-modules to wipe node_modules/ inside each file: dep target`));
|
|
4323
|
+
}
|
|
4251
4324
|
recordBuildIssue(pkg.name || path.basename(cwd), 'error', d.referencedModule ? `${d.summary} (via ${d.referencedModule})` : d.summary);
|
|
4252
4325
|
return false;
|
|
4253
4326
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/npmglobalize",
|
|
3
|
-
"version": "1.0.
|
|
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",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@bobfrankston/freezepak": "^0.1.7",
|
|
35
|
-
"@bobfrankston/importgen": "^0.1.
|
|
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.
|
|
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",
|