@bobfrankston/npmglobalize 1.0.142 → 1.0.143
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/cli.js +14 -6
- package/lib.d.ts +3 -0
- package/lib.js +51 -14
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* npmglobalize CLI - Transform file: dependencies to npm versions for publishing
|
|
4
4
|
*/
|
|
5
|
-
import { globalize, globalizeWorkspace, readConfig, readPackageJson, readUserNpmConfig, writeConfig, writePackageJson, confirm, getBuildIssues, clearBuildIssues } from './lib.js';
|
|
5
|
+
import { globalize, globalizeWorkspace, readConfig, readPackageJson, readUserNpmConfig, writeConfig, writePackageJson, confirm, getBuildIssues, clearBuildIssues, recordBuildIssue, extractFirstTscError } from './lib.js';
|
|
6
6
|
import fs from 'fs';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import { styleText } from 'util';
|
|
@@ -402,15 +402,23 @@ export async function main() {
|
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
404
|
if (pkg.scripts?.build) {
|
|
405
|
-
const {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
405
|
+
const { spawnSync } = await import('child_process');
|
|
406
|
+
console.log(`Building ${cwd}...`);
|
|
407
|
+
const buildResult = spawnSync('npm', ['run', 'build'], {
|
|
408
|
+
cwd, encoding: 'utf-8', stdio: 'pipe', shell: true
|
|
409
|
+
});
|
|
410
|
+
if (buildResult.status === 0) {
|
|
409
411
|
console.log(styleText('green', '✓ Build succeeded'));
|
|
410
412
|
}
|
|
411
|
-
|
|
413
|
+
else {
|
|
414
|
+
const buildOutput = (buildResult.stderr || '') + (buildResult.stdout || '');
|
|
415
|
+
if (buildOutput)
|
|
416
|
+
console.error(buildOutput);
|
|
412
417
|
console.error(styleText('red', `Build failed in ${cwd}`));
|
|
418
|
+
const firstErr = extractFirstTscError(buildOutput);
|
|
419
|
+
recordBuildIssue(pkg.name || path.basename(cwd), 'error', firstErr || 'Build failed');
|
|
413
420
|
if (!cliOptions.force) {
|
|
421
|
+
printBuildSummary();
|
|
414
422
|
process.exit(1);
|
|
415
423
|
}
|
|
416
424
|
console.log(styleText('yellow', 'Continuing with --force...'));
|
package/lib.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ export declare function recordBuildIssue(module: string, severity: 'error' | 'wa
|
|
|
22
22
|
export declare function getBuildIssues(): readonly BuildIssue[];
|
|
23
23
|
/** Clear accumulated issues (call at start of run) */
|
|
24
24
|
export declare function clearBuildIssues(): void;
|
|
25
|
+
/** Extract the first TypeScript error line from build output for the summary.
|
|
26
|
+
* Returns a short string like "file.ts(42,5): error TS2339: Property 'foo' ..." */
|
|
27
|
+
export declare function extractFirstTscError(output: string): string | null;
|
|
25
28
|
/** Options for the globalize operation */
|
|
26
29
|
export interface GlobalizeOptions {
|
|
27
30
|
/** Bump type: patch (default), minor, major */
|
package/lib.js
CHANGED
|
@@ -46,6 +46,25 @@ export function getBuildIssues() {
|
|
|
46
46
|
export function clearBuildIssues() {
|
|
47
47
|
_buildIssues.length = 0;
|
|
48
48
|
}
|
|
49
|
+
/** Extract the first TypeScript error line from build output for the summary.
|
|
50
|
+
* Returns a short string like "file.ts(42,5): error TS2339: Property 'foo' ..." */
|
|
51
|
+
export function extractFirstTscError(output) {
|
|
52
|
+
if (!output)
|
|
53
|
+
return null;
|
|
54
|
+
// tsc errors: src/file.ts(line,col): error TS1234: message
|
|
55
|
+
const tscMatch = output.match(/^(.+?\(\d+,\d+\): error TS\d+: .+)$/m);
|
|
56
|
+
if (tscMatch) {
|
|
57
|
+
const line = tscMatch[1];
|
|
58
|
+
return line.length > 120 ? line.slice(0, 117) + '...' : line;
|
|
59
|
+
}
|
|
60
|
+
// Generic "error" line
|
|
61
|
+
const errMatch = output.match(/^(error .+)$/m);
|
|
62
|
+
if (errMatch) {
|
|
63
|
+
const line = errMatch[1];
|
|
64
|
+
return line.length > 120 ? line.slice(0, 117) + '...' : line;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
49
68
|
/**
|
|
50
69
|
* Remove 'nul' files from a directory tree (Windows reserved name issue).
|
|
51
70
|
* These files break git and npm on Windows. Uses \\?\ prefix to bypass name validation.
|
|
@@ -2746,17 +2765,24 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2746
2765
|
if (pkg.scripts?.build && !options._fromCli) {
|
|
2747
2766
|
console.log(`${timestamp()} Running build...`);
|
|
2748
2767
|
if (!dryRun) {
|
|
2749
|
-
|
|
2768
|
+
// Always capture output so we can extract tsc errors for the summary
|
|
2769
|
+
const buildResult = runCommand('npm', ['run', 'build'], { cwd, silent: true });
|
|
2750
2770
|
if (!buildResult.success) {
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2771
|
+
const buildOutput = buildResult.stderr || buildResult.output;
|
|
2772
|
+
if (buildOutput)
|
|
2773
|
+
console.error(buildOutput);
|
|
2774
|
+
console.error(colors.red('ERROR: Build failed'));
|
|
2775
|
+
diagnoseBuildFailure(buildOutput || '', cwd);
|
|
2776
|
+
const firstErr = extractFirstTscError(buildOutput || '');
|
|
2777
|
+
recordBuildIssue(pkg.name || path.basename(cwd), 'error', firstErr || 'Build failed');
|
|
2754
2778
|
if (!force) {
|
|
2755
2779
|
return false;
|
|
2756
2780
|
}
|
|
2757
2781
|
console.log(colors.yellow('Continuing with --force despite build failure...'));
|
|
2758
2782
|
}
|
|
2759
2783
|
else {
|
|
2784
|
+
if (verbose && buildResult.output)
|
|
2785
|
+
process.stdout.write(buildResult.output);
|
|
2760
2786
|
console.log(`${timestamp()} ${colors.green('✓ Build succeeded')}`);
|
|
2761
2787
|
}
|
|
2762
2788
|
}
|
|
@@ -4003,22 +4029,17 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4003
4029
|
// Ignore cleanup errors
|
|
4004
4030
|
}
|
|
4005
4031
|
if (!publishResult.success) {
|
|
4006
|
-
|
|
4007
|
-
recordBuildIssue(pkg.name || path.basename(cwd), 'error', 'npm publish failed');
|
|
4008
|
-
// Check for specific error types
|
|
4032
|
+
// Check for specific error types before recording
|
|
4009
4033
|
const output = (publishResult.output + '\n' + publishResult.stderr).toLowerCase();
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
}
|
|
4013
|
-
else if (output.includes('e409') || output.includes('409 conflict')) {
|
|
4014
|
-
console.error(colors.yellow('npm still processing previous version — wait and retry'));
|
|
4015
|
-
}
|
|
4016
|
-
else if (output.includes('cannot publish over') || output.includes('previously published')) {
|
|
4034
|
+
// "Already published" is benign — don't record as error
|
|
4035
|
+
if (output.includes('cannot publish over') || output.includes('previously published')) {
|
|
4017
4036
|
const currentPkgVersion = readPackageJson(cwd).version;
|
|
4018
4037
|
if (output.includes(currentPkgVersion)) {
|
|
4019
4038
|
console.log(colors.green('✓ Already published — continuing'));
|
|
4020
4039
|
}
|
|
4021
4040
|
else {
|
|
4041
|
+
console.error(colors.red('\nERROR: npm publish failed\n'));
|
|
4042
|
+
recordBuildIssue(pkg.name || path.basename(cwd), 'error', 'npm publish failed');
|
|
4022
4043
|
console.error(colors.yellow('Version conflict — run npmglobalize again'));
|
|
4023
4044
|
if (transformResult.transformed) {
|
|
4024
4045
|
const failPkg = readPackageJson(cwd);
|
|
@@ -4030,7 +4051,19 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4030
4051
|
return false;
|
|
4031
4052
|
}
|
|
4032
4053
|
}
|
|
4054
|
+
else if (output.includes('err_string_too_long') || output.includes('string longer than')) {
|
|
4055
|
+
console.error(colors.red('\nERROR: npm publish failed\n'));
|
|
4056
|
+
recordBuildIssue(pkg.name || path.basename(cwd), 'error', 'npm publish failed');
|
|
4057
|
+
console.error(colors.red('Tarball too large — check .npmignore. Run: npm pack --dry-run'));
|
|
4058
|
+
}
|
|
4059
|
+
else if (output.includes('e409') || output.includes('409 conflict')) {
|
|
4060
|
+
console.error(colors.red('\nERROR: npm publish failed\n'));
|
|
4061
|
+
recordBuildIssue(pkg.name || path.basename(cwd), 'error', 'npm publish failed');
|
|
4062
|
+
console.error(colors.yellow('npm still processing previous version — wait and retry'));
|
|
4063
|
+
}
|
|
4033
4064
|
else if (output.includes('403') || output.includes('forbidden')) {
|
|
4065
|
+
console.error(colors.red('\nERROR: npm publish failed\n'));
|
|
4066
|
+
recordBuildIssue(pkg.name || path.basename(cwd), 'error', 'npm publish failed');
|
|
4034
4067
|
console.error(colors.yellow('Publish forbidden — check npm login and package access'));
|
|
4035
4068
|
if (transformResult.transformed) {
|
|
4036
4069
|
const failPkg = readPackageJson(cwd);
|
|
@@ -4042,9 +4075,13 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4042
4075
|
return false;
|
|
4043
4076
|
}
|
|
4044
4077
|
else if (output.includes('402') || output.includes('payment required')) {
|
|
4078
|
+
console.error(colors.red('\nERROR: npm publish failed\n'));
|
|
4079
|
+
recordBuildIssue(pkg.name || path.basename(cwd), 'error', 'npm publish failed');
|
|
4045
4080
|
console.error(colors.yellow('Private packages need paid npm account — use --npm public'));
|
|
4046
4081
|
}
|
|
4047
4082
|
else {
|
|
4083
|
+
console.error(colors.red('\nERROR: npm publish failed\n'));
|
|
4084
|
+
recordBuildIssue(pkg.name || path.basename(cwd), 'error', 'npm publish failed');
|
|
4048
4085
|
console.error(colors.yellow('Publish failed — run npm login or check npm whoami'));
|
|
4049
4086
|
}
|
|
4050
4087
|
if (transformResult.transformed) {
|