@bobfrankston/npmglobalize 1.0.184 → 1.0.186
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 +1 -0
- package/lib.js +60 -0
- package/package.json +1 -1
package/lib.d.ts
CHANGED
|
@@ -296,6 +296,7 @@ export declare function parseVersionTag(tag: string): number[] | null;
|
|
|
296
296
|
export declare function compareVersions(a: number[], b: number[]): number;
|
|
297
297
|
/** Fix version/tag mismatches */
|
|
298
298
|
export declare function fixVersionTagMismatch(cwd: string, pkg: any, verbose?: boolean): boolean;
|
|
299
|
+
export declare function printPnpmSuggestionSummary(): void;
|
|
299
300
|
/** Return declared deps (dependencies + devDependencies) that don't resolve from
|
|
300
301
|
* `pkgDir`. Skips `workspace:`/`link:` specs (handled by workspace tooling /
|
|
301
302
|
* rarely used). `file:` deps are checked: npm installs them as junctions
|
package/lib.js
CHANGED
|
@@ -29,6 +29,7 @@ function spawnSafe(cmd, args, options = {}) {
|
|
|
29
29
|
return spawnSync(cmd, args, opts);
|
|
30
30
|
}
|
|
31
31
|
import readline from 'readline';
|
|
32
|
+
import { styleText } from 'util';
|
|
32
33
|
import libversion from 'libnpmversion';
|
|
33
34
|
import JSON5 from 'json5';
|
|
34
35
|
import { fileURLToPath } from 'url';
|
|
@@ -1666,6 +1667,59 @@ export function fixVersionTagMismatch(cwd, pkg, verbose = false) {
|
|
|
1666
1667
|
function sleepSync(ms) {
|
|
1667
1668
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
1668
1669
|
}
|
|
1670
|
+
/** User-requested pnpm-eval hook (2026-05-14). The first local `npm install`
|
|
1671
|
+
* failure in a process prints a yellow-on-red banner and pauses 60s so the
|
|
1672
|
+
* user can read it. Every failure (first and subsequent) is captured in
|
|
1673
|
+
* `_pnpmFailureContexts` so `printPnpmSuggestionSummary()` can re-emit the
|
|
1674
|
+
* banner — listing all failure sites — at end-of-run, in case the live
|
|
1675
|
+
* banner scrolled past. Remove once pnpm-vs-npm decision is made. */
|
|
1676
|
+
let _pnpmSuggestionShown = false;
|
|
1677
|
+
const _pnpmFailureContexts = [];
|
|
1678
|
+
function _pnpmBanner(contexts) {
|
|
1679
|
+
const width = 76;
|
|
1680
|
+
const wrap = (s) => styleText(['yellow', 'bgRed', 'bold'], ' ' + s.padEnd(width - 2) + ' ');
|
|
1681
|
+
const body = [
|
|
1682
|
+
'',
|
|
1683
|
+
contexts.length > 1
|
|
1684
|
+
? `npm install FAILED -- ${contexts.length} sites -- consider trying pnpm`
|
|
1685
|
+
: 'npm install FAILED -- consider trying pnpm',
|
|
1686
|
+
'',
|
|
1687
|
+
];
|
|
1688
|
+
for (const c of contexts) {
|
|
1689
|
+
const label = ` - ${c}`;
|
|
1690
|
+
body.push(label.length > width - 2 ? label.slice(0, width - 5) + '...' : label);
|
|
1691
|
+
}
|
|
1692
|
+
body.push('', 'pnpm uses a content-addressed store with strict node_modules and', 'much faster installs. Commands mirror npm; great workspace support.', '', 'Try: npm i -g pnpm && pnpm import && pnpm install', '');
|
|
1693
|
+
return body.map(wrap);
|
|
1694
|
+
}
|
|
1695
|
+
async function suggestPnpmOnInstallFailure(context) {
|
|
1696
|
+
_pnpmFailureContexts.push(context);
|
|
1697
|
+
if (_pnpmSuggestionShown)
|
|
1698
|
+
return;
|
|
1699
|
+
_pnpmSuggestionShown = true;
|
|
1700
|
+
const lines = _pnpmBanner([context]);
|
|
1701
|
+
console.error('');
|
|
1702
|
+
for (const l of lines)
|
|
1703
|
+
console.error(l);
|
|
1704
|
+
console.error(styleText(['yellow', 'bgRed', 'bold'], ' ' + 'Pausing 60s so you can read this. Ctrl+C to abort.'.padEnd(74) + ' '));
|
|
1705
|
+
console.error('');
|
|
1706
|
+
await new Promise(resolve => setTimeout(resolve, 60_000));
|
|
1707
|
+
}
|
|
1708
|
+
/** Re-emit the pnpm banner at end-of-run if any `npm install` failed.
|
|
1709
|
+
* No-op when nothing failed. Safe to call from multiple summary paths —
|
|
1710
|
+
* guarded so the summary banner prints at most once per process. */
|
|
1711
|
+
let _pnpmSummaryPrinted = false;
|
|
1712
|
+
export function printPnpmSuggestionSummary() {
|
|
1713
|
+
if (_pnpmSummaryPrinted)
|
|
1714
|
+
return;
|
|
1715
|
+
if (_pnpmFailureContexts.length === 0)
|
|
1716
|
+
return;
|
|
1717
|
+
_pnpmSummaryPrinted = true;
|
|
1718
|
+
console.error('');
|
|
1719
|
+
for (const l of _pnpmBanner(_pnpmFailureContexts))
|
|
1720
|
+
console.error(l);
|
|
1721
|
+
console.error('');
|
|
1722
|
+
}
|
|
1669
1723
|
/** Wait for a package version to appear on the npm registry.
|
|
1670
1724
|
* First-time publishes (brand-new package name) take much longer to
|
|
1671
1725
|
* propagate than version bumps — npm has no cached metadata to update,
|
|
@@ -1828,6 +1882,7 @@ export async function ensureFileDepModules(cwd, verbose = false, visited = new S
|
|
|
1828
1882
|
console.error(colors.red(` ✗ npm install failed in ${abs}`));
|
|
1829
1883
|
if (r.stderr)
|
|
1830
1884
|
console.error(colors.dim(r.stderr.split('\n').slice(0, 5).join('\n')));
|
|
1885
|
+
await suggestPnpmOnInstallFailure(`ensureFileDepModules (cwd): ${abs}`);
|
|
1831
1886
|
}
|
|
1832
1887
|
}
|
|
1833
1888
|
for (const key of ['dependencies', 'devDependencies']) {
|
|
@@ -1865,6 +1920,7 @@ export async function ensureFileDepModules(cwd, verbose = false, visited = new S
|
|
|
1865
1920
|
console.error(colors.red(` ✗ npm install failed in ${target}`));
|
|
1866
1921
|
if (r.stderr)
|
|
1867
1922
|
console.error(colors.dim(r.stderr.split('\n').slice(0, 5).join('\n')));
|
|
1923
|
+
await suggestPnpmOnInstallFailure(`ensureFileDepModules (file: dep ${name}): ${target}`);
|
|
1868
1924
|
}
|
|
1869
1925
|
}
|
|
1870
1926
|
await ensureFileDepModules(target, verbose, visited);
|
|
@@ -1993,6 +2049,7 @@ export async function ensureWorkspaceDepModules(rootDir, members, verbose = fals
|
|
|
1993
2049
|
console.error(colors.red(` ✗ npm install failed in ${root}`));
|
|
1994
2050
|
if (r.stderr)
|
|
1995
2051
|
console.error(colors.dim(r.stderr.split('\n').slice(0, 5).join('\n')));
|
|
2052
|
+
await suggestPnpmOnInstallFailure(`ensureWorkspaceDepModules: ${root}`);
|
|
1996
2053
|
}
|
|
1997
2054
|
}
|
|
1998
2055
|
/** Run npm install -g with retries for registry propagation delay.
|
|
@@ -4788,6 +4845,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4788
4845
|
console.log(` ${colors.yellow('!')} ${s}`);
|
|
4789
4846
|
console.log(colors.yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
4790
4847
|
console.log('');
|
|
4848
|
+
printPnpmSuggestionSummary();
|
|
4791
4849
|
return true;
|
|
4792
4850
|
}
|
|
4793
4851
|
// Skip if private
|
|
@@ -5901,6 +5959,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5901
5959
|
}
|
|
5902
5960
|
console.log(colors.green('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
5903
5961
|
console.log('');
|
|
5962
|
+
printPnpmSuggestionSummary();
|
|
5904
5963
|
// Only show "To use run" message if package provides commands (has bin field)
|
|
5905
5964
|
if (finalPkg.bin) {
|
|
5906
5965
|
const commandName = finalPkg.name.includes('/') ? finalPkg.name.split('/')[1] : finalPkg.name;
|
|
@@ -6254,6 +6313,7 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
6254
6313
|
}
|
|
6255
6314
|
console.log(colors.green('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
6256
6315
|
console.log('');
|
|
6316
|
+
printPnpmSuggestionSummary();
|
|
6257
6317
|
// Global install of the workspace root (monorepo CLI)
|
|
6258
6318
|
const { install = false, link = false, wsl = false, dryRun = false, verbose = false } = options;
|
|
6259
6319
|
const rootPkgFinal = readPackageJson(rootDir);
|