@bobfrankston/npmglobalize 1.0.143 → 1.0.144
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 +2 -1
- package/ignorepatterns.json5 +2 -1
- package/lib.d.ts +5 -1
- package/lib.js +126 -39
- package/package.json +15 -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, recordBuildIssue, extractFirstTscError } from './lib.js';
|
|
5
|
+
import { globalize, globalizeWorkspace, installCleanupHandlers, 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';
|
|
@@ -343,6 +343,7 @@ function printBuildSummary() {
|
|
|
343
343
|
console.log('');
|
|
344
344
|
}
|
|
345
345
|
export async function main() {
|
|
346
|
+
installCleanupHandlers();
|
|
346
347
|
// Show version at the very start
|
|
347
348
|
const ownPkgPath = path.join(__dirname, 'package.json');
|
|
348
349
|
const ownPkg = JSON.parse(fs.readFileSync(ownPkgPath, 'utf-8'));
|
package/ignorepatterns.json5
CHANGED
package/lib.d.ts
CHANGED
|
@@ -132,6 +132,8 @@ export declare function readConfig(dir: string): Partial<GlobalizeOptions>;
|
|
|
132
132
|
export declare function writeConfig(dir: string, config: Partial<GlobalizeOptions>, explicitKeys?: Set<string>): void;
|
|
133
133
|
/** Write package.json to a directory */
|
|
134
134
|
export declare function writePackageJson(dir: string, pkg: any): void;
|
|
135
|
+
/** Install signal/exit handlers that restore `.dependencies` backups on abnormal exit. */
|
|
136
|
+
export declare function installCleanupHandlers(): void;
|
|
135
137
|
/** Resolve a file: path to absolute path */
|
|
136
138
|
export declare function resolveFilePath(fileRef: string, baseDir: string): string;
|
|
137
139
|
/** Check if a dependency value is a file: reference */
|
|
@@ -188,7 +190,8 @@ export declare function transformDeps(pkg: any, baseDir: string, verbose?: boole
|
|
|
188
190
|
path: string;
|
|
189
191
|
}>;
|
|
190
192
|
};
|
|
191
|
-
/** Restore file: dependencies from .dependencies
|
|
193
|
+
/** Restore file: dependencies from .dependencies using a three-way merge that
|
|
194
|
+
* preserves any external modifications made since the last transform. */
|
|
192
195
|
export declare function restoreDeps(pkg: any, verbose?: boolean): boolean;
|
|
193
196
|
/** Check if .dependencies exist (already transformed) */
|
|
194
197
|
export declare function hasBackup(pkg: any): boolean;
|
|
@@ -268,6 +271,7 @@ declare const _default: {
|
|
|
268
271
|
validatePackageJson: typeof validatePackageJson;
|
|
269
272
|
confirm: typeof confirm;
|
|
270
273
|
initGit: typeof initGit;
|
|
274
|
+
installCleanupHandlers: typeof installCleanupHandlers;
|
|
271
275
|
};
|
|
272
276
|
export default _default;
|
|
273
277
|
//# sourceMappingURL=lib.d.ts.map
|
package/lib.js
CHANGED
|
@@ -313,10 +313,111 @@ export function writeConfig(dir, config, explicitKeys) {
|
|
|
313
313
|
lines.push('}');
|
|
314
314
|
fs.writeFileSync(configPath, lines.join('\n') + '\n');
|
|
315
315
|
}
|
|
316
|
+
/** Package.json paths with a live `.dependencies` backup on disk.
|
|
317
|
+
* Tracked so the exit handler can restore them if the process dies mid-run. */
|
|
318
|
+
const dirtyPackageJsons = new Set();
|
|
316
319
|
/** Write package.json to a directory */
|
|
317
320
|
export function writePackageJson(dir, pkg) {
|
|
318
321
|
const pkgPath = path.join(dir, 'package.json');
|
|
319
322
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
323
|
+
if (hasBackup(pkg)) {
|
|
324
|
+
dirtyPackageJsons.add(pkgPath);
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
dirtyPackageJsons.delete(pkgPath);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/** Three-way merge that restores `.dependencies` backup into `dependencies` while
|
|
331
|
+
* preserving external modifications made since the last transform.
|
|
332
|
+
*
|
|
333
|
+
* Uses `.transformedSnapshot` (written by transformDeps) to distinguish
|
|
334
|
+
* "untouched transform output" from "externally modified":
|
|
335
|
+
* - current[name] === snapshot[name] → untouched, restore to backup value
|
|
336
|
+
* - current[name] !== snapshot[name] → modified externally, keep current
|
|
337
|
+
* - name in backup but missing from current → removed externally, leave removed
|
|
338
|
+
* - name in current but not in backup → added externally, keep
|
|
339
|
+
*
|
|
340
|
+
* If no snapshot exists (legacy backup from before this mechanism), falls back to
|
|
341
|
+
* blind restore plus new-dep merge, matching the old behavior. */
|
|
342
|
+
function mergeRestore(pkg, verbose = false) {
|
|
343
|
+
const snapshot = pkg['.transformedSnapshot'];
|
|
344
|
+
let restored = false;
|
|
345
|
+
for (const key of DEP_KEYS) {
|
|
346
|
+
const dotKey = '.' + key;
|
|
347
|
+
if (!pkg[dotKey])
|
|
348
|
+
continue;
|
|
349
|
+
const backup = pkg[dotKey];
|
|
350
|
+
const current = pkg[key] || {};
|
|
351
|
+
const snap = snapshot?.[key];
|
|
352
|
+
const merged = { ...current };
|
|
353
|
+
for (const [name, backupValue] of Object.entries(backup)) {
|
|
354
|
+
if (!(name in current))
|
|
355
|
+
continue; // removed externally — leave removed
|
|
356
|
+
if (snap && name in snap) {
|
|
357
|
+
if (current[name] === snap[name]) {
|
|
358
|
+
merged[name] = backupValue; // untouched — restore
|
|
359
|
+
}
|
|
360
|
+
else if (verbose) {
|
|
361
|
+
console.log(colors.yellow(` Preserving externally-modified ${key}.${name}: ${current[name]} (transform wrote ${snap[name]})`));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
merged[name] = backupValue; // legacy: no snapshot, blind restore
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
pkg[key] = merged;
|
|
369
|
+
delete pkg[dotKey];
|
|
370
|
+
restored = true;
|
|
371
|
+
}
|
|
372
|
+
if (restored && snapshot) {
|
|
373
|
+
delete pkg['.transformedSnapshot'];
|
|
374
|
+
}
|
|
375
|
+
return restored;
|
|
376
|
+
}
|
|
377
|
+
/** Synchronous emergency restore — called from signal/exit handlers.
|
|
378
|
+
* Reads each tracked package.json, runs the three-way merge, writes it back. */
|
|
379
|
+
function emergencyRestoreDeps() {
|
|
380
|
+
if (dirtyPackageJsons.size === 0)
|
|
381
|
+
return;
|
|
382
|
+
console.error(colors.yellow(`\nRestoring file: dependencies in ${dirtyPackageJsons.size} package.json file(s)...`));
|
|
383
|
+
for (const pkgPath of dirtyPackageJsons) {
|
|
384
|
+
try {
|
|
385
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
386
|
+
if (mergeRestore(pkg)) {
|
|
387
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
388
|
+
console.error(colors.green(` ✓ ${pkgPath}`));
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
catch (err) {
|
|
392
|
+
console.error(colors.red(` ✗ ${pkgPath}: ${err.message}`));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
dirtyPackageJsons.clear();
|
|
396
|
+
}
|
|
397
|
+
let cleanupHandlersInstalled = false;
|
|
398
|
+
/** Install signal/exit handlers that restore `.dependencies` backups on abnormal exit. */
|
|
399
|
+
export function installCleanupHandlers() {
|
|
400
|
+
if (cleanupHandlersInstalled)
|
|
401
|
+
return;
|
|
402
|
+
cleanupHandlersInstalled = true;
|
|
403
|
+
process.on('exit', emergencyRestoreDeps);
|
|
404
|
+
const signalHandler = (signal) => {
|
|
405
|
+
emergencyRestoreDeps();
|
|
406
|
+
process.exit(128 + (signal === 'SIGINT' ? 2 : signal === 'SIGTERM' ? 15 : 1));
|
|
407
|
+
};
|
|
408
|
+
process.on('SIGINT', signalHandler);
|
|
409
|
+
process.on('SIGTERM', signalHandler);
|
|
410
|
+
process.on('SIGHUP', signalHandler);
|
|
411
|
+
process.on('uncaughtException', (err) => {
|
|
412
|
+
console.error(colors.red('\nUncaught exception:'), err);
|
|
413
|
+
emergencyRestoreDeps();
|
|
414
|
+
process.exit(1);
|
|
415
|
+
});
|
|
416
|
+
process.on('unhandledRejection', (reason) => {
|
|
417
|
+
console.error(colors.red('\nUnhandled rejection:'), reason);
|
|
418
|
+
emergencyRestoreDeps();
|
|
419
|
+
process.exit(1);
|
|
420
|
+
});
|
|
320
421
|
}
|
|
321
422
|
/** Resolve a file: path to absolute path */
|
|
322
423
|
export function resolveFilePath(fileRef, baseDir) {
|
|
@@ -766,36 +867,21 @@ function hasLocalChanges(packageName, version, targetPath, verbose) {
|
|
|
766
867
|
export function transformDeps(pkg, baseDir, verbose = false, forcePublish = false) {
|
|
767
868
|
let transformed = false;
|
|
768
869
|
const unpublished = [];
|
|
870
|
+
// If re-running on a previously-transformed pkg, merge-restore first.
|
|
871
|
+
// This preserves any external modifications (AI tools, npm install, manual edits)
|
|
872
|
+
// made since the last transform, then proceeds to re-transform from a clean slate.
|
|
873
|
+
if (hasBackup(pkg)) {
|
|
874
|
+
mergeRestore(pkg, verbose);
|
|
875
|
+
}
|
|
769
876
|
for (const key of DEP_KEYS) {
|
|
770
877
|
if (!pkg[key])
|
|
771
878
|
continue;
|
|
772
879
|
const dotKey = '.' + key;
|
|
773
|
-
// If .dependencies already exists, restore it and merge any new dependencies
|
|
774
|
-
if (pkg[dotKey]) {
|
|
775
|
-
// Save any new dependencies that aren't in .dependencies
|
|
776
|
-
const currentDeps = { ...pkg[key] };
|
|
777
|
-
// Restore .dependencies back to dependencies
|
|
778
|
-
pkg[key] = { ...pkg[dotKey] };
|
|
779
|
-
// Merge in any NEW dependencies that were added since transformation
|
|
780
|
-
for (const [name, value] of Object.entries(currentDeps)) {
|
|
781
|
-
if (!(name in pkg[dotKey])) {
|
|
782
|
-
// This is a new dependency, add it
|
|
783
|
-
pkg[key][name] = value;
|
|
784
|
-
// Also add to .dependencies backup
|
|
785
|
-
pkg[dotKey][name] = value;
|
|
786
|
-
if (verbose) {
|
|
787
|
-
console.log(` Merged new dependency: ${name}`);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
880
|
const hasFileRefs = Object.values(pkg[key]).some(v => isFileRef(v));
|
|
793
881
|
if (!hasFileRefs)
|
|
794
882
|
continue;
|
|
795
|
-
// Backup original
|
|
796
|
-
|
|
797
|
-
pkg[dotKey] = { ...pkg[key] };
|
|
798
|
-
}
|
|
883
|
+
// Backup original
|
|
884
|
+
pkg[dotKey] = { ...pkg[key] };
|
|
799
885
|
// Transform file: refs to npm versions
|
|
800
886
|
for (const [name, value] of Object.entries(pkg[key])) {
|
|
801
887
|
if (isFileRef(value)) {
|
|
@@ -846,6 +932,17 @@ export function transformDeps(pkg, baseDir, verbose = false, forcePublish = fals
|
|
|
846
932
|
}
|
|
847
933
|
}
|
|
848
934
|
}
|
|
935
|
+
// Record snapshot of transform output so restore can distinguish untouched
|
|
936
|
+
// entries from those modified externally since the transform ran.
|
|
937
|
+
if (transformed) {
|
|
938
|
+
const snapshot = {};
|
|
939
|
+
for (const key of DEP_KEYS) {
|
|
940
|
+
if (pkg['.' + key]) {
|
|
941
|
+
snapshot[key] = { ...pkg[key] };
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
pkg['.transformedSnapshot'] = snapshot;
|
|
945
|
+
}
|
|
849
946
|
return { transformed, unpublished };
|
|
850
947
|
}
|
|
851
948
|
/** Build and print a dependency tree of file: references.
|
|
@@ -889,21 +986,10 @@ function printDepTree(baseDir, indent = 0, visited = new Set()) {
|
|
|
889
986
|
}
|
|
890
987
|
}
|
|
891
988
|
}
|
|
892
|
-
/** Restore file: dependencies from .dependencies
|
|
989
|
+
/** Restore file: dependencies from .dependencies using a three-way merge that
|
|
990
|
+
* preserves any external modifications made since the last transform. */
|
|
893
991
|
export function restoreDeps(pkg, verbose = false) {
|
|
894
|
-
|
|
895
|
-
for (const key of DEP_KEYS) {
|
|
896
|
-
const dotKey = '.' + key;
|
|
897
|
-
if (pkg[dotKey]) {
|
|
898
|
-
pkg[key] = pkg[dotKey];
|
|
899
|
-
delete pkg[dotKey];
|
|
900
|
-
restored = true;
|
|
901
|
-
if (verbose) {
|
|
902
|
-
console.log(` Restored ${key} from ${dotKey}`);
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
return restored;
|
|
992
|
+
return mergeRestore(pkg, verbose);
|
|
907
993
|
}
|
|
908
994
|
/** Check if .dependencies exist (already transformed) */
|
|
909
995
|
export function hasBackup(pkg) {
|
|
@@ -4026,7 +4112,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4026
4112
|
}
|
|
4027
4113
|
}
|
|
4028
4114
|
catch (e) {
|
|
4029
|
-
|
|
4115
|
+
console.error(colors.yellow(` Warning: could not delete tarball ${tarballName} — remove manually`));
|
|
4030
4116
|
}
|
|
4031
4117
|
if (!publishResult.success) {
|
|
4032
4118
|
// Check for specific error types before recording
|
|
@@ -4563,6 +4649,7 @@ export default {
|
|
|
4563
4649
|
getGitStatus,
|
|
4564
4650
|
validatePackageJson,
|
|
4565
4651
|
confirm,
|
|
4566
|
-
initGit
|
|
4652
|
+
initGit,
|
|
4653
|
+
installCleanupHandlers
|
|
4567
4654
|
};
|
|
4568
4655
|
//# sourceMappingURL=lib.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/npmglobalize",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.144",
|
|
4
4
|
"description": "Transform file: dependencies to npm versions for publishing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -56,5 +56,19 @@
|
|
|
56
56
|
"npm-registry-fetch": "^19.1.1",
|
|
57
57
|
"pacote": "^21.0.4",
|
|
58
58
|
"simple-git": "^3.30.0"
|
|
59
|
+
},
|
|
60
|
+
".transformedSnapshot": {
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@bobfrankston/freezepak": "^0.1.6",
|
|
63
|
+
"@bobfrankston/importgen": "^0.1.32",
|
|
64
|
+
"@bobfrankston/themecolors": "^0.1.4",
|
|
65
|
+
"@bobfrankston/userconfig": "^1.0.6",
|
|
66
|
+
"@npmcli/package-json": "^7.0.4",
|
|
67
|
+
"json5": "^2.2.3",
|
|
68
|
+
"libnpmversion": "^8.0.3",
|
|
69
|
+
"npm-registry-fetch": "^19.1.1",
|
|
70
|
+
"pacote": "^21.0.4",
|
|
71
|
+
"simple-git": "^3.30.0"
|
|
72
|
+
}
|
|
59
73
|
}
|
|
60
74
|
}
|