@bobfrankston/npmglobalize 1.0.139 → 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/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
- /** Color/style helpers using Node.js styleText (Node 24+) */
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 { styleText } from 'util';
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
- /** Color/style helpers using Node.js styleText (Node 24+) */
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(`Waiting for ${pkgName}@${version} on npm registry`);
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',
@@ -2637,7 +2641,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2637
2641
  const pkg = readPackageJson(cwd);
2638
2642
  // Run build step if package.json has a build script (skip if CLI already built)
2639
2643
  if (pkg.scripts?.build && !options._fromCli) {
2640
- console.log('Running build...');
2644
+ console.log(`${timestamp()} Running build...`);
2641
2645
  if (!dryRun) {
2642
2646
  const buildResult = runCommand('npm', ['run', 'build'], { cwd, silent: !verbose });
2643
2647
  if (!buildResult.success) {
@@ -2648,7 +2652,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2648
2652
  console.log(colors.yellow('Continuing with --force despite build failure...'));
2649
2653
  }
2650
2654
  else {
2651
- console.log(colors.green('✓ Build succeeded'));
2655
+ console.log(`${timestamp()} ${colors.green('✓ Build succeeded')}`);
2652
2656
  }
2653
2657
  }
2654
2658
  else {
@@ -3392,7 +3396,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3392
3396
  // Git operations
3393
3397
  if (currentGitStatus.hasUncommitted) {
3394
3398
  const commitMsg = message || 'Pre-release commit';
3395
- console.log(`Committing changes: ${commitMsg}`);
3399
+ console.log(`${timestamp()} Committing changes: ${commitMsg}`);
3396
3400
  if (!dryRun) {
3397
3401
  // Remove 'nul' files that break git on Windows
3398
3402
  const nulCount = removeNulFiles(cwd);
@@ -3490,7 +3494,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3490
3494
  console.log(`Skipping version bump — ${pkg.version} already set locally.`);
3491
3495
  }
3492
3496
  else {
3493
- console.log(`Bumping version (${bump})...`);
3497
+ console.log(`${timestamp()} Bumping version (${bump})...`);
3494
3498
  }
3495
3499
  if (!dryRun && !skipVersionBump) {
3496
3500
  // Temporarily disable postversion hook to prevent double-publishing or push
@@ -3734,38 +3738,51 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3734
3738
  else if (!skipVersionBump) {
3735
3739
  console.log(` [dry-run] Would run: npm version ${bump}`);
3736
3740
  }
3737
- // Check for public package depending on private dependencies
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.
3738
3744
  const publishAccess = effectiveNpmVisibility || currentAccess || (isScoped ? 'restricted' : 'public');
3739
3745
  if (publishAccess === 'public') {
3740
- const privateDeps = [];
3746
+ const scopedDeps = [];
3741
3747
  for (const depKey of ['dependencies', 'peerDependencies']) {
3742
3748
  const deps = pkg[depKey];
3743
3749
  if (!deps)
3744
3750
  continue;
3745
3751
  for (const depName of Object.keys(deps)) {
3746
- const depAccess = checkNpmAccess(depName);
3747
- if (depAccess === 'restricted') {
3748
- privateDeps.push(depName);
3749
- }
3750
- else if (depAccess === null && depName.startsWith('@')) {
3751
- // Scoped package not on npm — will be private by default
3752
- privateDeps.push(`${depName} (not yet published)`);
3753
- }
3752
+ if (depName.startsWith('@'))
3753
+ scopedDeps.push(depName);
3754
3754
  }
3755
3755
  }
3756
- if (privateDeps.length > 0) {
3757
- console.log('');
3758
- console.error(colors.red('WARNING: Public package depends on PRIVATE dependencies:'));
3759
- for (const d of privateDeps) {
3760
- console.error(colors.red(` ${d}`));
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('');
3761
3781
  }
3762
- console.error(colors.yellow('Consumers will get E404 when installing this package.'));
3763
- console.error(colors.yellow('Fix: publish those deps as public, or make this package private.'));
3764
- console.log('');
3765
3782
  }
3766
3783
  }
3767
3784
  // Publish
3768
- console.log('Publishing to npm...');
3785
+ console.log(`${timestamp()} Publishing to npm...`);
3769
3786
  if (!dryRun) {
3770
3787
  // Check npm authentication right before publishing
3771
3788
  const authStatus = checkNpmAuth();
@@ -3929,7 +3946,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3929
3946
  // Determine what was published
3930
3947
  const finalAccess = effectiveNpmVisibility || currentAccess || (isScoped ? 'restricted' : 'public');
3931
3948
  const accessLabel = (finalAccess === 'restricted' || finalAccess === 'private') ? 'PRIVATE' : 'PUBLIC';
3932
- console.log(colors.green(`✓ Published to npm as ${accessLabel}`));
3949
+ console.log(`${timestamp()} ${colors.green(`✓ Published to npm as ${accessLabel}`)}`);
3933
3950
  }
3934
3951
  else {
3935
3952
  console.log(` [dry-run] Would run: npm publish ${quiet ? '--quiet' : ''}`);
@@ -3937,7 +3954,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3937
3954
  // Push to git (with push-protection detection and auto-bypass)
3938
3955
  if (currentGitStatus.hasRemote) {
3939
3956
  if (verbose) {
3940
- console.log('Pushing to git...');
3957
+ console.log(`${timestamp()} Pushing to git...`);
3941
3958
  }
3942
3959
  if (!dryRun) {
3943
3960
  if (pushWithProtection(cwd, verbose)) {
@@ -4001,7 +4018,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
4001
4018
  }
4002
4019
  }
4003
4020
  else {
4004
- console.log(`Installing globally from registry: ${pkgName}@${pkgVersion}...`);
4021
+ console.log(`${timestamp()} Installing globally from registry: ${pkgName}@${pkgVersion}...`);
4005
4022
  if (!dryRun) {
4006
4023
  waitForNpmVersion(pkgName, pkgVersion);
4007
4024
  const installResult = installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd);
@@ -4072,7 +4089,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
4072
4089
  else if (!files) {
4073
4090
  console.log('Keeping npm versions (--nofiles mode).');
4074
4091
  }
4075
- console.log('Done!');
4092
+ console.log(`${timestamp()} Done!`);
4076
4093
  // Run final audit report if not already run
4077
4094
  const auditAlreadyRun = (fix || updateDeps) && (transformResult.transformed || alreadyTransformed || updateDeps);
4078
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.139",
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,7 +33,7 @@
33
33
  "dependencies": {
34
34
  "@bobfrankston/freezepak": "^0.1.6",
35
35
  "@bobfrankston/importgen": "^0.1.32",
36
- "@bobfrankston/themecolors": "^0.1.2",
36
+ "@bobfrankston/themecolors": "^0.1.4",
37
37
  "@bobfrankston/userconfig": "^1.0.6",
38
38
  "@npmcli/package-json": "^7.0.4",
39
39
  "json5": "^2.2.3",