@bobfrankston/npmglobalize 1.0.138 → 1.0.140
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/git.js +13 -0
- package/lib/types.d.ts +2 -10
- package/lib/types.js +3 -11
- package/lib.js +71 -10
- package/package.json +3 -3
package/lib/git.js
CHANGED
|
@@ -673,6 +673,19 @@ export function pushWithProtection(cwd, verbose) {
|
|
|
673
673
|
console.log(colors.green(' ✓ Already up-to-date'));
|
|
674
674
|
return true;
|
|
675
675
|
}
|
|
676
|
+
// No upstream branch — auto-set and retry
|
|
677
|
+
if (combined.includes('no upstream branch') || combined.includes('has no upstream')) {
|
|
678
|
+
if (verbose)
|
|
679
|
+
console.log(colors.yellow(' No upstream branch — setting upstream...'));
|
|
680
|
+
const branchResult = runCommand('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, silent: true });
|
|
681
|
+
const branch = branchResult.output.trim() || 'master';
|
|
682
|
+
pushResult = runCommand('git', ['push', '--set-upstream', 'origin', branch], { cwd, silent: true });
|
|
683
|
+
if (pushResult.success) {
|
|
684
|
+
if (verbose)
|
|
685
|
+
console.log(colors.green(' ✓ Pushed to remote (set upstream)'));
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
676
689
|
// Transient network errors (HTTP 408, RPC failed, unexpected disconnect) — retry once
|
|
677
690
|
if (/rpc failed|curl \d+|unexpected disconnect|hung up unexpectedly/i.test(pushResult.stderr)) {
|
|
678
691
|
console.log(colors.yellow('Git push failed with transient error — retrying...'));
|
package/lib/types.d.ts
CHANGED
|
@@ -6,16 +6,8 @@ import { type SpawnSyncOptions, type SpawnSyncReturns } from 'child_process';
|
|
|
6
6
|
/** Wrapper for spawnSync that avoids DEP0190 (args + shell: true).
|
|
7
7
|
* When shell is true, joins cmd+args into a single command string. */
|
|
8
8
|
export declare function spawnSafe(cmd: string, args: string[], options?: SpawnSyncOptions): SpawnSyncReturns<string>;
|
|
9
|
-
/**
|
|
10
|
-
export declare const colors:
|
|
11
|
-
red: (text: string) => string;
|
|
12
|
-
yellow: (text: string) => string;
|
|
13
|
-
green: (text: string) => string;
|
|
14
|
-
italic: (text: string) => string;
|
|
15
|
-
blue: (text: string) => string;
|
|
16
|
-
cyan: (text: string) => string;
|
|
17
|
-
dim: (text: string) => string;
|
|
18
|
-
};
|
|
9
|
+
/** Semantic color functions — adapts to terminal light/dark theme */
|
|
10
|
+
export declare const colors: import("@bobfrankston/themecolors").SemanticColors;
|
|
19
11
|
/** Get npm command for current platform (npm.cmd on Windows, npm elsewhere) */
|
|
20
12
|
export declare function getNpmCommand(): string;
|
|
21
13
|
/** Options for the globalize operation */
|
package/lib/types.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Leaf module — no internal dependencies.
|
|
4
4
|
*/
|
|
5
5
|
import { spawnSync } from 'child_process';
|
|
6
|
-
import {
|
|
6
|
+
import { themeColors } from '@bobfrankston/themecolors';
|
|
7
7
|
import readline from 'readline';
|
|
8
8
|
/** Wrapper for spawnSync that avoids DEP0190 (args + shell: true).
|
|
9
9
|
* When shell is true, joins cmd+args into a single command string. */
|
|
@@ -16,16 +16,8 @@ export function spawnSafe(cmd, args, options = {}) {
|
|
|
16
16
|
}
|
|
17
17
|
return spawnSync(cmd, args, opts);
|
|
18
18
|
}
|
|
19
|
-
/**
|
|
20
|
-
export const colors =
|
|
21
|
-
red: (text) => styleText('red', text),
|
|
22
|
-
yellow: (text) => styleText('yellow', text),
|
|
23
|
-
green: (text) => styleText('green', text),
|
|
24
|
-
italic: (text) => styleText('italic', text),
|
|
25
|
-
blue: (text) => styleText('blue', text),
|
|
26
|
-
cyan: (text) => styleText('cyan', text),
|
|
27
|
-
dim: (text) => styleText('dim', text),
|
|
28
|
-
};
|
|
19
|
+
/** Semantic color functions — adapts to terminal light/dark theme */
|
|
20
|
+
export const colors = themeColors();
|
|
29
21
|
/** Get npm command for current platform (npm.cmd on Windows, npm elsewhere) */
|
|
30
22
|
export function getNpmCommand() {
|
|
31
23
|
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
package/lib.js
CHANGED
|
@@ -137,6 +137,10 @@ function getNpmCommand() {
|
|
|
137
137
|
return process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
138
138
|
}
|
|
139
139
|
const DEP_KEYS = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'];
|
|
140
|
+
/** Format current time as HH:MM:SS for progress timestamps */
|
|
141
|
+
function timestamp() {
|
|
142
|
+
return colors.dim(new Date().toLocaleTimeString('en-US', { hour12: false }));
|
|
143
|
+
}
|
|
140
144
|
/** Read and parse package.json from a directory */
|
|
141
145
|
export function readPackageJson(dir) {
|
|
142
146
|
const pkgPath = path.join(dir, 'package.json');
|
|
@@ -1003,7 +1007,7 @@ export function fixVersionTagMismatch(cwd, pkg, verbose = false) {
|
|
|
1003
1007
|
function waitForNpmVersion(pkgName, version, maxWaitMs = 90000) {
|
|
1004
1008
|
const interval = 3000;
|
|
1005
1009
|
const maxAttempts = Math.ceil(maxWaitMs / interval);
|
|
1006
|
-
process.stdout.write(
|
|
1010
|
+
process.stdout.write(`${timestamp()} Waiting for ${pkgName}@${version} on npm registry`);
|
|
1007
1011
|
for (let i = 0; i < maxAttempts; i++) {
|
|
1008
1012
|
const result = spawnSafe('npm', ['view', `${pkgName}@${version}`, 'version'], {
|
|
1009
1013
|
shell: process.platform === 'win32',
|
|
@@ -1647,6 +1651,20 @@ function pushWithProtection(cwd, verbose) {
|
|
|
1647
1651
|
console.log(colors.green(' ✓ Already up-to-date'));
|
|
1648
1652
|
return true;
|
|
1649
1653
|
}
|
|
1654
|
+
// No upstream branch — auto-set and retry
|
|
1655
|
+
if (combined.includes('no upstream branch') || combined.includes('has no upstream')) {
|
|
1656
|
+
if (verbose)
|
|
1657
|
+
console.log(colors.yellow(' No upstream branch — setting upstream...'));
|
|
1658
|
+
// Detect current branch name
|
|
1659
|
+
const branchResult = runCommand('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, silent: true });
|
|
1660
|
+
const branch = branchResult.output.trim() || 'master';
|
|
1661
|
+
pushResult = runCommand('git', ['push', '--set-upstream', 'origin', branch], { cwd, silent: true });
|
|
1662
|
+
if (pushResult.success) {
|
|
1663
|
+
if (verbose)
|
|
1664
|
+
console.log(colors.green(' ✓ Pushed to remote (set upstream)'));
|
|
1665
|
+
return true;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1650
1668
|
// Transient network errors (HTTP 408, RPC failed, unexpected disconnect) — retry once
|
|
1651
1669
|
if (/rpc failed|curl \d+|unexpected disconnect|hung up unexpectedly/i.test(pushResult.stderr)) {
|
|
1652
1670
|
console.log(colors.yellow('Git push failed with transient error — retrying...'));
|
|
@@ -2623,7 +2641,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2623
2641
|
const pkg = readPackageJson(cwd);
|
|
2624
2642
|
// Run build step if package.json has a build script (skip if CLI already built)
|
|
2625
2643
|
if (pkg.scripts?.build && !options._fromCli) {
|
|
2626
|
-
console.log(
|
|
2644
|
+
console.log(`${timestamp()} Running build...`);
|
|
2627
2645
|
if (!dryRun) {
|
|
2628
2646
|
const buildResult = runCommand('npm', ['run', 'build'], { cwd, silent: !verbose });
|
|
2629
2647
|
if (!buildResult.success) {
|
|
@@ -2634,7 +2652,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2634
2652
|
console.log(colors.yellow('Continuing with --force despite build failure...'));
|
|
2635
2653
|
}
|
|
2636
2654
|
else {
|
|
2637
|
-
console.log(colors.green('✓ Build succeeded'));
|
|
2655
|
+
console.log(`${timestamp()} ${colors.green('✓ Build succeeded')}`);
|
|
2638
2656
|
}
|
|
2639
2657
|
}
|
|
2640
2658
|
else {
|
|
@@ -3378,7 +3396,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3378
3396
|
// Git operations
|
|
3379
3397
|
if (currentGitStatus.hasUncommitted) {
|
|
3380
3398
|
const commitMsg = message || 'Pre-release commit';
|
|
3381
|
-
console.log(
|
|
3399
|
+
console.log(`${timestamp()} Committing changes: ${commitMsg}`);
|
|
3382
3400
|
if (!dryRun) {
|
|
3383
3401
|
// Remove 'nul' files that break git on Windows
|
|
3384
3402
|
const nulCount = removeNulFiles(cwd);
|
|
@@ -3476,7 +3494,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3476
3494
|
console.log(`Skipping version bump — ${pkg.version} already set locally.`);
|
|
3477
3495
|
}
|
|
3478
3496
|
else {
|
|
3479
|
-
console.log(
|
|
3497
|
+
console.log(`${timestamp()} Bumping version (${bump})...`);
|
|
3480
3498
|
}
|
|
3481
3499
|
if (!dryRun && !skipVersionBump) {
|
|
3482
3500
|
// Temporarily disable postversion hook to prevent double-publishing or push
|
|
@@ -3720,8 +3738,51 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3720
3738
|
else if (!skipVersionBump) {
|
|
3721
3739
|
console.log(` [dry-run] Would run: npm version ${bump}`);
|
|
3722
3740
|
}
|
|
3741
|
+
// Check for public package depending on private/unpublished scoped dependencies
|
|
3742
|
+
// Only scoped deps can be private — unscoped are always public on npm.
|
|
3743
|
+
// Use a single fast `npm view` per dep instead of the full checkNpmAccess.
|
|
3744
|
+
const publishAccess = effectiveNpmVisibility || currentAccess || (isScoped ? 'restricted' : 'public');
|
|
3745
|
+
if (publishAccess === 'public') {
|
|
3746
|
+
const scopedDeps = [];
|
|
3747
|
+
for (const depKey of ['dependencies', 'peerDependencies']) {
|
|
3748
|
+
const deps = pkg[depKey];
|
|
3749
|
+
if (!deps)
|
|
3750
|
+
continue;
|
|
3751
|
+
for (const depName of Object.keys(deps)) {
|
|
3752
|
+
if (depName.startsWith('@'))
|
|
3753
|
+
scopedDeps.push(depName);
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
if (scopedDeps.length > 0) {
|
|
3757
|
+
const privateDeps = [];
|
|
3758
|
+
for (const depName of scopedDeps) {
|
|
3759
|
+
const viewResult = spawnSafe('npm', ['view', depName, 'name'], {
|
|
3760
|
+
encoding: 'utf-8', stdio: 'pipe', shell: true
|
|
3761
|
+
});
|
|
3762
|
+
if (viewResult.status !== 0) {
|
|
3763
|
+
const stderr = viewResult.stderr || '';
|
|
3764
|
+
if (stderr.includes('404') || stderr.includes('not found')) {
|
|
3765
|
+
privateDeps.push(`${depName} (not on npm)`);
|
|
3766
|
+
}
|
|
3767
|
+
else {
|
|
3768
|
+
privateDeps.push(`${depName} (restricted)`);
|
|
3769
|
+
}
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
if (privateDeps.length > 0) {
|
|
3773
|
+
console.log('');
|
|
3774
|
+
console.error(colors.red('WARNING: Public package depends on PRIVATE/missing dependencies:'));
|
|
3775
|
+
for (const d of privateDeps) {
|
|
3776
|
+
console.error(colors.red(` ${d}`));
|
|
3777
|
+
}
|
|
3778
|
+
console.error(colors.yellow('Consumers will get E404 when installing this package.'));
|
|
3779
|
+
console.error(colors.yellow('Fix: publish those deps as public, or make this package private.'));
|
|
3780
|
+
console.log('');
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3723
3784
|
// Publish
|
|
3724
|
-
console.log(
|
|
3785
|
+
console.log(`${timestamp()} Publishing to npm...`);
|
|
3725
3786
|
if (!dryRun) {
|
|
3726
3787
|
// Check npm authentication right before publishing
|
|
3727
3788
|
const authStatus = checkNpmAuth();
|
|
@@ -3885,7 +3946,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3885
3946
|
// Determine what was published
|
|
3886
3947
|
const finalAccess = effectiveNpmVisibility || currentAccess || (isScoped ? 'restricted' : 'public');
|
|
3887
3948
|
const accessLabel = (finalAccess === 'restricted' || finalAccess === 'private') ? 'PRIVATE' : 'PUBLIC';
|
|
3888
|
-
console.log(colors.green(`✓ Published to npm as ${accessLabel}`));
|
|
3949
|
+
console.log(`${timestamp()} ${colors.green(`✓ Published to npm as ${accessLabel}`)}`);
|
|
3889
3950
|
}
|
|
3890
3951
|
else {
|
|
3891
3952
|
console.log(` [dry-run] Would run: npm publish ${quiet ? '--quiet' : ''}`);
|
|
@@ -3893,7 +3954,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3893
3954
|
// Push to git (with push-protection detection and auto-bypass)
|
|
3894
3955
|
if (currentGitStatus.hasRemote) {
|
|
3895
3956
|
if (verbose) {
|
|
3896
|
-
console.log(
|
|
3957
|
+
console.log(`${timestamp()} Pushing to git...`);
|
|
3897
3958
|
}
|
|
3898
3959
|
if (!dryRun) {
|
|
3899
3960
|
if (pushWithProtection(cwd, verbose)) {
|
|
@@ -3957,7 +4018,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3957
4018
|
}
|
|
3958
4019
|
}
|
|
3959
4020
|
else {
|
|
3960
|
-
console.log(
|
|
4021
|
+
console.log(`${timestamp()} Installing globally from registry: ${pkgName}@${pkgVersion}...`);
|
|
3961
4022
|
if (!dryRun) {
|
|
3962
4023
|
waitForNpmVersion(pkgName, pkgVersion);
|
|
3963
4024
|
const installResult = installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd);
|
|
@@ -4028,7 +4089,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4028
4089
|
else if (!files) {
|
|
4029
4090
|
console.log('Keeping npm versions (--nofiles mode).');
|
|
4030
4091
|
}
|
|
4031
|
-
console.log(
|
|
4092
|
+
console.log(`${timestamp()} Done!`);
|
|
4032
4093
|
// Run final audit report if not already run
|
|
4033
4094
|
const auditAlreadyRun = (fix || updateDeps) && (transformResult.transformed || alreadyTransformed || updateDeps);
|
|
4034
4095
|
if (!auditAlreadyRun && (fix || updateDeps || transformResult.transformed) && !dryRun) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/npmglobalize",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.140",
|
|
4
4
|
"description": "Transform file: dependencies to npm versions for publishing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@bobfrankston/freezepak": "^0.1.6",
|
|
35
35
|
"@bobfrankston/importgen": "^0.1.32",
|
|
36
|
-
"@bobfrankston/themecolors": "^0.1.
|
|
37
|
-
"@bobfrankston/userconfig": "^1.0.
|
|
36
|
+
"@bobfrankston/themecolors": "^0.1.4",
|
|
37
|
+
"@bobfrankston/userconfig": "^1.0.6",
|
|
38
38
|
"@npmcli/package-json": "^7.0.4",
|
|
39
39
|
"json5": "^2.2.3",
|
|
40
40
|
"libnpmversion": "^8.0.3",
|