@bobfrankston/npmglobalize 1.0.123 → 1.0.125
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/lib.d.ts +2 -0
- package/lib.js +78 -21
- package/package.json +1 -1
package/lib.d.ts
CHANGED
|
@@ -78,6 +78,8 @@ export interface GlobalizeOptions {
|
|
|
78
78
|
local?: boolean;
|
|
79
79
|
/** Freeze node_modules: replace symlinks/junctions with real copies for network share use */
|
|
80
80
|
freeze?: boolean;
|
|
81
|
+
/** Internal: auto-initialize git repos without prompting (user chose "all") */
|
|
82
|
+
autoInit?: boolean;
|
|
81
83
|
/** Internal: signals this call is from workspace orchestrator */
|
|
82
84
|
_fromWorkspace?: boolean;
|
|
83
85
|
/** Internal: signals this call is from CLI (version already printed) */
|
package/lib.js
CHANGED
|
@@ -681,6 +681,55 @@ function hasUnpublishedTransitiveDeps(packageName, pkg, baseDir, verbose) {
|
|
|
681
681
|
}
|
|
682
682
|
return false;
|
|
683
683
|
}
|
|
684
|
+
/** Check if local package directory has changes newer than the npm-published version.
|
|
685
|
+
* Detects uncommitted changes or commits made after the version was published. */
|
|
686
|
+
function hasLocalChanges(packageName, version, targetPath, verbose) {
|
|
687
|
+
try {
|
|
688
|
+
// Check 1: Uncommitted changes in the package directory
|
|
689
|
+
const statusResult = spawnSafe('git', ['-C', targetPath, 'status', '--porcelain', '.'], {
|
|
690
|
+
encoding: 'utf-8',
|
|
691
|
+
stdio: 'pipe',
|
|
692
|
+
shell: true
|
|
693
|
+
});
|
|
694
|
+
if (statusResult.status === 0 && statusResult.stdout.trim()) {
|
|
695
|
+
if (verbose) {
|
|
696
|
+
console.log(colors.yellow(` ${packageName} has uncommitted changes`));
|
|
697
|
+
}
|
|
698
|
+
return true;
|
|
699
|
+
}
|
|
700
|
+
// Check 2: Compare latest commit time in directory vs npm publish time
|
|
701
|
+
const timeResult = spawnSafe('npm', ['view', packageName, 'time', '--json'], {
|
|
702
|
+
encoding: 'utf-8',
|
|
703
|
+
stdio: 'pipe',
|
|
704
|
+
shell: true
|
|
705
|
+
});
|
|
706
|
+
if (timeResult.status !== 0 || !timeResult.stdout.trim())
|
|
707
|
+
return false;
|
|
708
|
+
const times = JSON.parse(timeResult.stdout.trim());
|
|
709
|
+
const publishTime = times[version];
|
|
710
|
+
if (!publishTime)
|
|
711
|
+
return false;
|
|
712
|
+
const publishDate = new Date(publishTime);
|
|
713
|
+
const logResult = spawnSafe('git', ['-C', targetPath, 'log', '-1', '--format=%aI', '--', '.'], {
|
|
714
|
+
encoding: 'utf-8',
|
|
715
|
+
stdio: 'pipe',
|
|
716
|
+
shell: true
|
|
717
|
+
});
|
|
718
|
+
if (logResult.status !== 0 || !logResult.stdout.trim())
|
|
719
|
+
return false;
|
|
720
|
+
const latestCommitDate = new Date(logResult.stdout.trim());
|
|
721
|
+
if (latestCommitDate > publishDate) {
|
|
722
|
+
if (verbose) {
|
|
723
|
+
console.log(colors.yellow(` ${packageName} has commits newer than npm publish`));
|
|
724
|
+
}
|
|
725
|
+
return true;
|
|
726
|
+
}
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
catch {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
684
733
|
/** Transform file: dependencies to npm versions */
|
|
685
734
|
export function transformDeps(pkg, baseDir, verbose = false, forcePublish = false) {
|
|
686
735
|
let transformed = false;
|
|
@@ -744,6 +793,10 @@ export function transformDeps(pkg, baseDir, verbose = false, forcePublish = fals
|
|
|
744
793
|
unpublished.push({ name, version: targetVersion, path: targetPath });
|
|
745
794
|
console.log(colors.yellow(` ⟳ ${name}@${targetVersion} has unpublished transitive deps — will republish`));
|
|
746
795
|
}
|
|
796
|
+
else if (hasLocalChanges(name, targetVersion, targetPath, verbose)) {
|
|
797
|
+
unpublished.push({ name, version: targetVersion, path: targetPath });
|
|
798
|
+
console.log(colors.yellow(` ⟳ ${name}@${targetVersion} has local changes not on npm — will republish`));
|
|
799
|
+
}
|
|
747
800
|
}
|
|
748
801
|
pkg[key][name] = npmVersion;
|
|
749
802
|
if (verbose) {
|
|
@@ -2379,8 +2432,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2379
2432
|
if (dryRun) {
|
|
2380
2433
|
console.log(' [dry-run] Would initialize git repository');
|
|
2381
2434
|
}
|
|
2382
|
-
else if (!init) {
|
|
2383
|
-
const choice = await promptChoice('No git repository found. What would you like to do?\n 1) Initialize git repository (default)\n 2) Use local install only (skip git/publish)\n 3) Abort\nChoice:', ['1', '2', '3', '']);
|
|
2435
|
+
else if (!init && !options.autoInit) {
|
|
2436
|
+
const choice = await promptChoice('No git repository found. What would you like to do?\n 1) Initialize git repository (default)\n a) Initialize ALL (don\'t ask again for remaining deps)\n 2) Use local install only (skip git/publish)\n 3) Abort\nChoice:', ['1', 'a', '2', '3', '']);
|
|
2384
2437
|
if (choice === '2') {
|
|
2385
2438
|
console.log(colors.dim('Switching to local-only mode...'));
|
|
2386
2439
|
writeConfig(cwd, { ...configOptions, local: true }, new Set(['local']));
|
|
@@ -2390,7 +2443,10 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2390
2443
|
console.log('Aborted. Run with --init to initialize.');
|
|
2391
2444
|
return false;
|
|
2392
2445
|
}
|
|
2393
|
-
|
|
2446
|
+
if (choice === 'a') {
|
|
2447
|
+
options.autoInit = true;
|
|
2448
|
+
}
|
|
2449
|
+
// choice is '1', 'a', or '' (default)
|
|
2394
2450
|
const success = await initGit(cwd, gitVisibility, dryRun);
|
|
2395
2451
|
if (!success)
|
|
2396
2452
|
return false;
|
|
@@ -2405,8 +2461,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2405
2461
|
}
|
|
2406
2462
|
else if (!gitStatus.hasRemote) {
|
|
2407
2463
|
// Git repo exists but no remote - need to create GitHub repo
|
|
2408
|
-
if (!init) {
|
|
2409
|
-
const choice = await promptChoice('No git remote configured. What would you like to do?\n 1) Create GitHub repository (default)\n 2) Use local install only (skip git/publish)\n 3) Abort\nChoice:', ['1', '2', '3', '']);
|
|
2464
|
+
if (!init && !options.autoInit) {
|
|
2465
|
+
const choice = await promptChoice('No git remote configured. What would you like to do?\n 1) Create GitHub repository (default)\n a) Initialize ALL (don\'t ask again for remaining deps)\n 2) Use local install only (skip git/publish)\n 3) Abort\nChoice:', ['1', 'a', '2', '3', '']);
|
|
2410
2466
|
if (choice === '2') {
|
|
2411
2467
|
console.log(colors.dim('Switching to local-only mode...'));
|
|
2412
2468
|
writeConfig(cwd, { ...configOptions, local: true }, new Set(['local']));
|
|
@@ -2416,6 +2472,9 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2416
2472
|
console.log('Aborted. Run with --init to set up GitHub repository.');
|
|
2417
2473
|
return false;
|
|
2418
2474
|
}
|
|
2475
|
+
if (choice === 'a') {
|
|
2476
|
+
options.autoInit = true;
|
|
2477
|
+
}
|
|
2419
2478
|
}
|
|
2420
2479
|
const success = await initGit(cwd, gitVisibility, dryRun);
|
|
2421
2480
|
if (!success)
|
|
@@ -2959,7 +3018,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2959
3018
|
conform, // Propagate conform to dependencies
|
|
2960
3019
|
publishDeps, // Propagate so transitive deps also get published
|
|
2961
3020
|
forcePublish, // Propagate so transitive deps get force-published too
|
|
2962
|
-
rebase // Propagate so behind-remote deps get rebased automatically
|
|
3021
|
+
rebase, // Propagate so behind-remote deps get rebased automatically
|
|
3022
|
+
autoInit: options.autoInit // Propagate "init all" choice
|
|
2963
3023
|
});
|
|
2964
3024
|
if (!depSuccess) {
|
|
2965
3025
|
console.error(colors.red(`Failed to publish ${name}`));
|
|
@@ -2997,13 +3057,12 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2997
3057
|
else if (!alreadyTransformed && verbose) {
|
|
2998
3058
|
console.log(' No file: dependencies found.');
|
|
2999
3059
|
}
|
|
3000
|
-
// Hoist workspace sub-package deps into root for
|
|
3001
|
-
// npm install -g
|
|
3002
|
-
//
|
|
3003
|
-
//
|
|
3004
|
-
//
|
|
3005
|
-
//
|
|
3006
|
-
// All changes are temporary — restoreDeps removes them via .dependencies backup.
|
|
3060
|
+
// Hoist workspace sub-package third-party deps into root for global install.
|
|
3061
|
+
// npm install -g from local handles workspace linking, but third-party deps
|
|
3062
|
+
// (express, ws, etc.) in sub-packages must also be in root dependencies
|
|
3063
|
+
// so they get installed. Workspace sibling refs are skipped — npm install -g .
|
|
3064
|
+
// handles those via workspace linking.
|
|
3065
|
+
// Changes are temporary — restoreDeps removes them via .dependencies backup.
|
|
3007
3066
|
if (pkg.workspaces) {
|
|
3008
3067
|
const wsPatterns = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages || [];
|
|
3009
3068
|
// Collect all workspace sub-package dirs
|
|
@@ -3024,8 +3083,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3024
3083
|
wsDirs.push(dir);
|
|
3025
3084
|
}
|
|
3026
3085
|
}
|
|
3027
|
-
// Collect workspace package names
|
|
3028
|
-
const
|
|
3086
|
+
// Collect workspace package names (to skip as siblings)
|
|
3087
|
+
const wsNames = new Set();
|
|
3029
3088
|
for (const dir of wsDirs) {
|
|
3030
3089
|
const pkgJsonPath = path.join(dir, 'package.json');
|
|
3031
3090
|
if (!fs.existsSync(pkgJsonPath))
|
|
@@ -3033,7 +3092,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3033
3092
|
try {
|
|
3034
3093
|
const subPkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
|
|
3035
3094
|
if (subPkg.name)
|
|
3036
|
-
|
|
3095
|
+
wsNames.add(subPkg.name);
|
|
3037
3096
|
}
|
|
3038
3097
|
catch { /* skip */ }
|
|
3039
3098
|
}
|
|
@@ -3053,8 +3112,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3053
3112
|
}
|
|
3054
3113
|
const deps = subPkg.dependencies || {};
|
|
3055
3114
|
for (const [dep, ver] of Object.entries(deps)) {
|
|
3056
|
-
if (
|
|
3057
|
-
continue; // sibling workspace — handled
|
|
3115
|
+
if (wsNames.has(dep))
|
|
3116
|
+
continue; // sibling workspace — handled by npm install -g .
|
|
3058
3117
|
if (dep in rootDeps)
|
|
3059
3118
|
continue; // already in root
|
|
3060
3119
|
if (hoisted.some(m => m.dep === dep))
|
|
@@ -3062,8 +3121,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3062
3121
|
hoisted.push({ dep, version: ver, from: subPkg.name || path.basename(dir) });
|
|
3063
3122
|
}
|
|
3064
3123
|
}
|
|
3065
|
-
|
|
3066
|
-
if (needsUpdate) {
|
|
3124
|
+
if (hoisted.length > 0) {
|
|
3067
3125
|
// Ensure .dependencies backup exists so restoreDeps will remove hoisted deps
|
|
3068
3126
|
if (!pkg['.dependencies']) {
|
|
3069
3127
|
pkg['.dependencies'] = { ...(pkg.dependencies || {}) };
|
|
@@ -3071,7 +3129,6 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3071
3129
|
}
|
|
3072
3130
|
if (!pkg.dependencies)
|
|
3073
3131
|
pkg.dependencies = {};
|
|
3074
|
-
// Hoist third-party deps
|
|
3075
3132
|
for (const m of hoisted) {
|
|
3076
3133
|
let version = m.version;
|
|
3077
3134
|
if (typeof version === 'string' && version.startsWith('file:')) {
|