inup 1.6.6 → 1.6.8
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/README.md +25 -2
- package/dist/{interactive-ui.js → app/interactive-ui.js} +34 -21
- package/dist/{core → app}/upgrade-runner.js +18 -22
- package/dist/cli.js +19 -18
- package/dist/{services → features/audit}/background-audit.js +2 -2
- package/dist/features/{headless/vulnerability-audit.js → audit/headless-audit.js} +8 -11
- package/dist/features/audit/index.js +36 -0
- package/dist/{ui/presenters/vulnerability.js → features/audit/presenter.js} +1 -3
- package/dist/{ui/controllers → features/audit}/vulnerability-audit-controller.js +14 -8
- package/dist/{services → features/audit}/vulnerability-checker.js +9 -10
- package/dist/features/changelog/clients/github-client.js +41 -21
- package/dist/features/changelog/clients/npm-registry-client.js +16 -2
- package/dist/features/changelog/index.js +1 -1
- package/dist/features/changelog/services/package-metadata-service.js +6 -2
- package/dist/features/changelog/services/release-notes-service.js +9 -12
- package/dist/features/changelog/types.js +3 -0
- package/dist/features/debug/index.js +3 -4
- package/dist/features/debug/{services/perf-logger.js → perf-logger.js} +15 -15
- package/dist/features/debug/types.js +3 -0
- package/dist/features/headless/headless-runner.js +32 -19
- package/dist/features/headless/index.js +2 -5
- package/dist/features/headless/report.js +2 -0
- package/dist/features/interactive/controllers/index.js +6 -0
- package/dist/{ui → features/interactive}/controllers/package-info-modal-controller.js +3 -3
- package/dist/features/interactive/index.js +21 -0
- package/dist/{ui → features/interactive}/input-handler.js +6 -6
- package/dist/{ui → features/interactive}/modal/index.js +1 -1
- package/dist/{ui → features/interactive}/modal/layout.js +5 -5
- package/dist/{ui/renderer/package-list.js → features/interactive/modal/package-info-sections/index.js} +3 -3
- package/dist/{ui → features/interactive}/modal/package-info-sections/release-notes.js +1 -1
- package/dist/{ui → features/interactive}/modal/package-info-sections/sections.js +55 -24
- package/dist/{ui → features/interactive}/modal/package-info-sections/text.js +6 -6
- package/dist/{ui → features/interactive}/modal/package-info.js +33 -18
- package/dist/features/interactive/modal/types.js +3 -0
- package/dist/{ui → features/interactive}/presenters/health.js +2 -2
- package/dist/{ui → features/interactive}/renderer/confirmation.js +6 -3
- package/dist/{ui → features/interactive}/renderer/help-modal.js +3 -3
- package/dist/{ui → features/interactive}/renderer/index.js +3 -4
- package/dist/{types.js → features/interactive/renderer/package-list/index.js} +3 -4
- package/dist/{ui → features/interactive}/renderer/package-list/interface.js +15 -16
- package/dist/{ui → features/interactive}/renderer/package-list/rows.js +31 -25
- package/dist/features/{debug → interactive}/renderer/performance-modal.js +3 -3
- package/dist/{ui/utils/version.js → features/interactive/renderer/version-format.js} +9 -13
- package/dist/{ui → features/interactive}/session/action-dispatcher.js +2 -2
- package/dist/{ui → features/interactive}/session/index.js +5 -4
- package/dist/{ui → features/interactive}/session/interactive-session.js +44 -23
- package/dist/{ui → features/interactive}/session/selection-state-builder.js +25 -9
- package/dist/{ui → features/interactive}/state/filter-manager.js +3 -3
- package/dist/{ui → features/interactive}/state/index.js +7 -7
- package/dist/{ui → features/interactive}/state/state-manager.js +10 -8
- package/dist/{ui → features/interactive}/state/theme-manager.js +7 -5
- package/dist/{ui → features/interactive}/themes-colors.js +3 -1
- package/dist/features/upgrade/index.js +8 -0
- package/dist/{core → features/upgrade}/package-detector.js +96 -37
- package/dist/{core → features/upgrade}/upgrader.js +84 -35
- package/dist/index.js +2 -2
- package/dist/{config → shared/config}/package-meta.js +1 -1
- package/dist/{config → shared/config}/project-config.js +10 -8
- package/dist/{utils/config.js → shared/config/user-config.js} +11 -11
- package/dist/{utils → shared}/debug-logger.js +9 -9
- package/dist/{utils → shared}/exec.js +4 -4
- package/dist/{ui/modal/package-info-sections.js → shared/fs/index.js} +4 -3
- package/dist/{utils/filesystem → shared/fs}/io.js +3 -4
- package/dist/shared/fs/paths.js +19 -0
- package/dist/{utils/filesystem → shared/fs}/scan.js +23 -20
- package/dist/{utils → shared}/git.js +3 -3
- package/dist/{services → shared}/http/etag-store.js +56 -4
- package/dist/{services → shared}/http/resizable-semaphore.js +3 -1
- package/dist/{utils → shared}/local-env.js +8 -8
- package/dist/{services/package-manager-detector.js → shared/package-manager.js} +26 -25
- package/dist/shared/pnpm-catalogs.js +138 -0
- package/dist/{services → shared/registry}/npm-registry.js +54 -33
- package/dist/shared/registry/registry-config.js +76 -0
- package/dist/{services → shared/registry}/version-checker.js +25 -26
- package/dist/{ui/utils → shared/terminal}/cursor.js +1 -1
- package/dist/{ui/utils → shared/terminal}/index.js +5 -7
- package/dist/{ui/utils → shared/terminal}/terminal-input.js +5 -0
- package/dist/shared/terminal/text.js +48 -0
- package/dist/shared/types/index.js +20 -0
- package/dist/{utils/version.js → shared/versions.js} +45 -30
- package/package.json +21 -8
- package/dist/core/index.js +0 -23
- package/dist/features/changelog/types/changelog.types.js +0 -3
- package/dist/features/debug/types/debug.types.js +0 -3
- package/dist/services/index.js +0 -25
- package/dist/ui/controllers/index.js +0 -8
- package/dist/ui/index.js +0 -27
- package/dist/ui/presenters/index.js +0 -11
- package/dist/ui/utils/text.js +0 -76
- package/dist/utils/filesystem/paths.js +0 -19
- package/dist/utils/filesystem.js +0 -20
- package/dist/utils/index.js +0 -34
- /package/dist/{ui/modal → features/audit}/types.js +0 -0
- /package/dist/features/debug/{services/performance-tracker.js → performance-tracker.js} +0 -0
- /package/dist/{ui → features/interactive}/keymap.js +0 -0
- /package/dist/{ui → features/interactive}/modal/theme-selector.js +0 -0
- /package/dist/{ui → features/interactive}/state/modal-manager.js +0 -0
- /package/dist/{ui → features/interactive}/state/navigation-manager.js +0 -0
- /package/dist/{ui → features/interactive}/themes.js +0 -0
- /package/dist/{config → shared/config}/constants.js +0 -0
- /package/dist/{config → shared/config}/index.js +0 -0
- /package/dist/{utils → shared}/engines.js +0 -0
- /package/dist/{services → shared}/http/adaptive-controller.js +0 -0
- /package/dist/{services → shared}/http/inflight.js +0 -0
- /package/dist/{services → shared}/http/retry.js +0 -0
- /package/dist/{utils → shared}/manifest.js +0 -0
- /package/dist/{utils → shared/terminal}/color.js +0 -0
- /package/dist/{types → shared/types}/domain.js +0 -0
- /package/dist/{types → shared/types}/streaming.js +0 -0
- /package/dist/{types → shared/types}/ui.js +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StateManager = void 0;
|
|
4
|
-
const navigation_manager_1 = require("./navigation-manager");
|
|
5
|
-
const modal_manager_1 = require("./modal-manager");
|
|
6
4
|
const filter_manager_1 = require("./filter-manager");
|
|
5
|
+
const modal_manager_1 = require("./modal-manager");
|
|
6
|
+
const navigation_manager_1 = require("./navigation-manager");
|
|
7
7
|
const theme_manager_1 = require("./theme-manager");
|
|
8
8
|
class StateManager {
|
|
9
9
|
navigationManager;
|
|
@@ -99,7 +99,7 @@ class StateManager {
|
|
|
99
99
|
return;
|
|
100
100
|
const currentRow = this.navigationManager.getCurrentRow();
|
|
101
101
|
const currentState = states[currentRow];
|
|
102
|
-
if (
|
|
102
|
+
if (currentState?.loadState !== 'ready')
|
|
103
103
|
return;
|
|
104
104
|
if (direction === 'left') {
|
|
105
105
|
// Move selection left with wraparound: latest -> range -> none -> latest
|
|
@@ -114,8 +114,9 @@ class StateManager {
|
|
|
114
114
|
else if (currentState.selectedOption === 'range') {
|
|
115
115
|
currentState.selectedOption = 'none';
|
|
116
116
|
}
|
|
117
|
-
else
|
|
118
|
-
//
|
|
117
|
+
else {
|
|
118
|
+
// selectedOption === 'none' (the union has exactly three members):
|
|
119
|
+
// wrap around to the last available option.
|
|
119
120
|
if (currentState.hasMajorUpdate) {
|
|
120
121
|
currentState.selectedOption = 'latest';
|
|
121
122
|
}
|
|
@@ -143,8 +144,9 @@ class StateManager {
|
|
|
143
144
|
currentState.selectedOption = 'none';
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
|
-
else
|
|
147
|
-
//
|
|
147
|
+
else {
|
|
148
|
+
// selectedOption === 'latest' (the union has exactly three members):
|
|
149
|
+
// wrap around to none.
|
|
148
150
|
currentState.selectedOption = 'none';
|
|
149
151
|
}
|
|
150
152
|
}
|
|
@@ -185,7 +187,7 @@ class StateManager {
|
|
|
185
187
|
if (states.length === 0)
|
|
186
188
|
return;
|
|
187
189
|
const currentState = states[this.navigationManager.getCurrentRow()];
|
|
188
|
-
if (
|
|
190
|
+
if (currentState?.loadState !== 'ready')
|
|
189
191
|
return;
|
|
190
192
|
if (currentState.selectedOption !== 'none') {
|
|
191
193
|
currentState.selectedOption = 'none';
|
|
@@ -3,15 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ThemeManager = void 0;
|
|
4
4
|
exports.getThemeColors = getThemeColors;
|
|
5
5
|
exports.getCurrentThemeName = getCurrentThemeName;
|
|
6
|
+
const user_config_1 = require("../../../shared/config/user-config");
|
|
6
7
|
const themes_1 = require("../themes");
|
|
7
|
-
const config_1 = require("../../utils/config");
|
|
8
8
|
// Global theme state for renderers to access
|
|
9
9
|
let globalCurrentTheme = themes_1.defaultTheme;
|
|
10
10
|
class ThemeManager {
|
|
11
11
|
state;
|
|
12
12
|
constructor() {
|
|
13
13
|
// Load saved theme from config, fallback to default
|
|
14
|
-
const savedTheme =
|
|
14
|
+
const savedTheme = user_config_1.configManager.getTheme();
|
|
15
15
|
const initialTheme = savedTheme && themes_1.themeNames.includes(savedTheme) ? savedTheme : themes_1.defaultTheme;
|
|
16
16
|
this.state = {
|
|
17
17
|
showThemeModal: false,
|
|
@@ -55,7 +55,7 @@ class ThemeManager {
|
|
|
55
55
|
this.state.currentTheme = this.state.previewTheme;
|
|
56
56
|
globalCurrentTheme = this.state.currentTheme;
|
|
57
57
|
// Save theme to config
|
|
58
|
-
|
|
58
|
+
user_config_1.configManager.setTheme(this.state.currentTheme);
|
|
59
59
|
this.closeThemeModal();
|
|
60
60
|
}
|
|
61
61
|
setTheme(themeName) {
|
|
@@ -64,7 +64,7 @@ class ThemeManager {
|
|
|
64
64
|
this.state.previewTheme = themeName;
|
|
65
65
|
globalCurrentTheme = themeName;
|
|
66
66
|
// Save theme to config
|
|
67
|
-
|
|
67
|
+
user_config_1.configManager.setTheme(themeName);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
toggleThemeModal() {
|
|
@@ -79,7 +79,9 @@ class ThemeManager {
|
|
|
79
79
|
exports.ThemeManager = ThemeManager;
|
|
80
80
|
// Helper function for renderers to get current theme colors
|
|
81
81
|
function getThemeColors() {
|
|
82
|
-
|
|
82
|
+
// globalCurrentTheme is only ever assigned a name validated against
|
|
83
|
+
// themeNames, so the lookup always resolves.
|
|
84
|
+
return themes_1.themes[globalCurrentTheme].colors;
|
|
83
85
|
}
|
|
84
86
|
// Helper function to get current theme name
|
|
85
87
|
function getCurrentThemeName() {
|
|
@@ -6,12 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.themeColors = void 0;
|
|
7
7
|
exports.getThemeColor = getThemeColor;
|
|
8
8
|
exports.getThemeBgColor = getThemeBgColor;
|
|
9
|
+
exports.hexToRgb = hexToRgb;
|
|
9
10
|
exports.getTerminalBgColorCode = getTerminalBgColorCode;
|
|
10
11
|
exports.getTerminalResetCode = getTerminalResetCode;
|
|
11
12
|
exports.coloredInupLogo = coloredInupLogo;
|
|
12
13
|
const chalk_1 = __importDefault(require("chalk"));
|
|
14
|
+
const config_1 = require("../../shared/config");
|
|
13
15
|
const theme_manager_1 = require("./state/theme-manager");
|
|
14
|
-
const config_1 = require("../config");
|
|
15
16
|
// Centralized theme color definitions - single source of truth
|
|
16
17
|
const themeColorDefinitions = {
|
|
17
18
|
default: {
|
|
@@ -173,6 +174,7 @@ function getThemeBgColor() {
|
|
|
173
174
|
*/
|
|
174
175
|
function hexToRgb(hex) {
|
|
175
176
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
177
|
+
// Malformed input falls back to black — a safe default for a color parser.
|
|
176
178
|
return result
|
|
177
179
|
? {
|
|
178
180
|
r: parseInt(result[1], 16),
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PackageUpgrader = exports.PackageDetector = void 0;
|
|
4
|
+
var package_detector_1 = require("./package-detector");
|
|
5
|
+
Object.defineProperty(exports, "PackageDetector", { enumerable: true, get: function () { return package_detector_1.PackageDetector; } });
|
|
6
|
+
var upgrader_1 = require("./upgrader");
|
|
7
|
+
Object.defineProperty(exports, "PackageUpgrader", { enumerable: true, get: function () { return upgrader_1.PackageUpgrader; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -39,12 +39,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.PackageDetector = void 0;
|
|
40
40
|
const chalk_1 = __importDefault(require("chalk"));
|
|
41
41
|
const semver = __importStar(require("semver"));
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
42
|
+
const config_1 = require("../../shared/config");
|
|
43
|
+
const debug_logger_1 = require("../../shared/debug-logger");
|
|
44
|
+
const fs_1 = require("../../shared/fs");
|
|
45
|
+
const pnpm_catalogs_1 = require("../../shared/pnpm-catalogs");
|
|
46
|
+
const npm_registry_1 = require("../../shared/registry/npm-registry");
|
|
47
|
+
const terminal_1 = require("../../shared/terminal");
|
|
48
|
+
const versions_1 = require("../../shared/versions");
|
|
49
|
+
const debug_1 = require("../debug");
|
|
48
50
|
class PackageDetector {
|
|
49
51
|
packageJsonPath = null;
|
|
50
52
|
packageJson = null;
|
|
@@ -63,9 +65,9 @@ class PackageDetector {
|
|
|
63
65
|
this.ignorePackages = options?.ignorePackages || [];
|
|
64
66
|
this.maxDepth = options?.maxDepth ?? 10;
|
|
65
67
|
this.adaptive = options?.adaptive ?? true;
|
|
66
|
-
this.packageJsonPath = (0,
|
|
68
|
+
this.packageJsonPath = (0, fs_1.findPackageJson)(this.cwd);
|
|
67
69
|
if (this.packageJsonPath) {
|
|
68
|
-
this.packageJson = (0,
|
|
70
|
+
this.packageJson = (0, fs_1.readPackageJson)(this.packageJsonPath);
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
hasPackageJson() {
|
|
@@ -103,7 +105,7 @@ class PackageDetector {
|
|
|
103
105
|
throw new Error('No package.json found in current directory');
|
|
104
106
|
}
|
|
105
107
|
const t0 = Date.now();
|
|
106
|
-
|
|
108
|
+
debug_logger_1.debugLog.info('PackageDetector', `Starting scan in ${this.cwd}`);
|
|
107
109
|
const prepared = await this.prepareDependencies();
|
|
108
110
|
const initialPayload = {
|
|
109
111
|
allDependencies: prepared.allDependencies,
|
|
@@ -119,8 +121,8 @@ class PackageDetector {
|
|
|
119
121
|
let batchIndex = 0;
|
|
120
122
|
let lastBatchEndAt = Date.now();
|
|
121
123
|
const tFetch = Date.now();
|
|
122
|
-
|
|
123
|
-
await (0,
|
|
124
|
+
debug_logger_1.debugLog.info('PackageDetector', 'fetching version data via npm registry in batches');
|
|
125
|
+
await (0, npm_registry_1.fetchPackageVersions)(prepared.uniquePackages, {
|
|
124
126
|
currentVersions: prepared.currentVersions,
|
|
125
127
|
batchSize: this.batchSize,
|
|
126
128
|
maxConcurrency: this.maxConcurrency,
|
|
@@ -167,11 +169,11 @@ class PackageDetector {
|
|
|
167
169
|
});
|
|
168
170
|
},
|
|
169
171
|
});
|
|
170
|
-
|
|
172
|
+
debug_logger_1.debugLog.perf('PackageDetector', `registry fetch (${resolved}/${prepared.uniquePackages.length} resolved)`, tFetch);
|
|
171
173
|
performanceTracker.recordPhaseDuration('registryFetch', Date.now() - tFetch);
|
|
172
174
|
const finalPackages = prepared.uniquePackages.flatMap((packageName) => packageLookup.get(packageName) ?? []);
|
|
173
175
|
const progress = this.createProgressSnapshot(prepared.uniquePackages.length, resolved, failed, false);
|
|
174
|
-
|
|
176
|
+
debug_logger_1.debugLog.perf('PackageDetector', `total scan complete (${finalPackages.filter((p) => p.isOutdated).length} outdated of ${finalPackages.length} deps)`, t0);
|
|
175
177
|
onEvent({
|
|
176
178
|
type: 'complete',
|
|
177
179
|
payload: {
|
|
@@ -179,7 +181,7 @@ class PackageDetector {
|
|
|
179
181
|
progress,
|
|
180
182
|
},
|
|
181
183
|
});
|
|
182
|
-
|
|
184
|
+
terminal_1.ConsoleUtils.clearProgress();
|
|
183
185
|
return finalPackages;
|
|
184
186
|
}
|
|
185
187
|
async prepareDependencies() {
|
|
@@ -187,7 +189,7 @@ class PackageDetector {
|
|
|
187
189
|
this.showProgress('🔍 Scanning repository for package.json files...');
|
|
188
190
|
const tScan = Date.now();
|
|
189
191
|
const allPackageJsonFiles = await this.findPackageJsonFilesWithTimeout(30000);
|
|
190
|
-
|
|
192
|
+
debug_logger_1.debugLog.perf('PackageDetector', `file scan (${allPackageJsonFiles.length} files)`, tScan, {
|
|
191
193
|
files: allPackageJsonFiles,
|
|
192
194
|
});
|
|
193
195
|
performanceTracker.recordPhaseDuration('discovery', Date.now() - tScan);
|
|
@@ -195,11 +197,11 @@ class PackageDetector {
|
|
|
195
197
|
this.showProgress(`🔍 Found ${allPackageJsonFiles.length} package.json file${allPackageJsonFiles.length === 1 ? '' : 's'}`);
|
|
196
198
|
this.showProgress('🔍 Reading dependencies from package.json files...');
|
|
197
199
|
const tDeps = Date.now();
|
|
198
|
-
const allDepsRaw = await (0,
|
|
200
|
+
const allDepsRaw = await (0, fs_1.collectAllDependenciesAsync)(allPackageJsonFiles, {
|
|
199
201
|
includePeerDeps: true,
|
|
200
202
|
includeOptionalDeps: true,
|
|
201
203
|
});
|
|
202
|
-
|
|
204
|
+
debug_logger_1.debugLog.perf('PackageDetector', `dependency collection (${allDepsRaw.length} raw deps)`, tDeps);
|
|
203
205
|
performanceTracker.recordPhaseDuration('depCollection', Date.now() - tDeps);
|
|
204
206
|
performanceTracker.recordCounts({ rawDependencies: allDepsRaw.length });
|
|
205
207
|
this.showProgress('🔍 Identifying unique packages...');
|
|
@@ -209,12 +211,57 @@ class PackageDetector {
|
|
|
209
211
|
let ignoredCount = 0;
|
|
210
212
|
const seenWorkspaceRefs = new Set();
|
|
211
213
|
const seenIgnored = new Set();
|
|
212
|
-
|
|
213
|
-
|
|
214
|
+
// pnpm catalogs: `"react": "catalog:"` gets its real range from
|
|
215
|
+
// pnpm-workspace.yaml. Each catalog entry becomes ONE upgradable dependency
|
|
216
|
+
// sourced from that file, no matter how many workspace packages reference it.
|
|
217
|
+
const catalogs = pnpm_catalogs_1.PnpmCatalogs.load(this.cwd);
|
|
218
|
+
// Entries here always carry catalogReferencedBy (set on first-seen below),
|
|
219
|
+
// so require it in the value type — that lets re-references push onto the
|
|
220
|
+
// array without an optional-fallback branch.
|
|
221
|
+
const seenCatalogEntries = new Map();
|
|
222
|
+
for (const rawDep of allDepsRaw) {
|
|
223
|
+
let dep = {
|
|
224
|
+
name: rawDep.name,
|
|
225
|
+
version: rawDep.version,
|
|
226
|
+
type: rawDep.type,
|
|
227
|
+
packageJsonPath: rawDep.packageJsonPath,
|
|
228
|
+
};
|
|
229
|
+
if ((0, pnpm_catalogs_1.isCatalogReference)(rawDep.version)) {
|
|
230
|
+
// A catalog ref resolves its range from pnpm-workspace.yaml. If that
|
|
231
|
+
// file was absent (catalogs === null) or the entry is missing, we can't
|
|
232
|
+
// resolve a range — warn and skip.
|
|
233
|
+
const resolution = catalogs?.resolve(rawDep.name, rawDep.version);
|
|
234
|
+
if (!catalogs || !resolution) {
|
|
235
|
+
debug_logger_1.debugLog.warn('PackageDetector', `skipping unresolvable catalog ref: ${rawDep.name}@${rawDep.version}`);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const catalogKey = `${resolution.catalog}:${rawDep.name}`;
|
|
239
|
+
const existing = seenCatalogEntries.get(catalogKey);
|
|
240
|
+
if (existing) {
|
|
241
|
+
// Same catalog entry, another referencing package: remember who uses
|
|
242
|
+
// it (for the info modal's Used-by tab) but keep the single entry.
|
|
243
|
+
if (!existing.catalogReferencedBy.includes(rawDep.packageJsonPath)) {
|
|
244
|
+
existing.catalogReferencedBy.push(rawDep.packageJsonPath);
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const catalogEntry = {
|
|
249
|
+
name: rawDep.name,
|
|
250
|
+
version: resolution.range,
|
|
251
|
+
type: rawDep.type,
|
|
252
|
+
packageJsonPath: catalogs.path,
|
|
253
|
+
catalog: resolution.catalog,
|
|
254
|
+
catalogEntries: catalogs.entriesOf(resolution.catalog),
|
|
255
|
+
catalogReferencedBy: [rawDep.packageJsonPath],
|
|
256
|
+
};
|
|
257
|
+
seenCatalogEntries.set(catalogKey, catalogEntry);
|
|
258
|
+
dep = catalogEntry;
|
|
259
|
+
}
|
|
260
|
+
if (this.isNonRegistrySpecifier(dep.version)) {
|
|
214
261
|
const key = `${dep.name}@${dep.version}`;
|
|
215
262
|
if (!seenWorkspaceRefs.has(key)) {
|
|
216
263
|
seenWorkspaceRefs.add(key);
|
|
217
|
-
|
|
264
|
+
debug_logger_1.debugLog.info('PackageDetector', `skipping non-registry specifier: ${key}`);
|
|
218
265
|
}
|
|
219
266
|
continue;
|
|
220
267
|
}
|
|
@@ -222,16 +269,11 @@ class PackageDetector {
|
|
|
222
269
|
ignoredCount++;
|
|
223
270
|
if (!seenIgnored.has(dep.name)) {
|
|
224
271
|
seenIgnored.add(dep.name);
|
|
225
|
-
|
|
272
|
+
debug_logger_1.debugLog.info('PackageDetector', `ignoring package: ${dep.name}`);
|
|
226
273
|
}
|
|
227
274
|
continue;
|
|
228
275
|
}
|
|
229
|
-
allDependencies.push(
|
|
230
|
-
name: dep.name,
|
|
231
|
-
version: dep.version,
|
|
232
|
-
type: dep.type,
|
|
233
|
-
packageJsonPath: dep.packageJsonPath,
|
|
234
|
-
});
|
|
276
|
+
allDependencies.push(dep);
|
|
235
277
|
uniquePackageNames.add(dep.name);
|
|
236
278
|
}
|
|
237
279
|
if (ignoredCount > 0) {
|
|
@@ -246,7 +288,7 @@ class PackageDetector {
|
|
|
246
288
|
return 1;
|
|
247
289
|
return a.localeCompare(b);
|
|
248
290
|
});
|
|
249
|
-
|
|
291
|
+
debug_logger_1.debugLog.info('PackageDetector', `${uniquePackages.length} unique packages to check, ${ignoredCount} ignored`);
|
|
250
292
|
performanceTracker.recordPhaseDuration('filter', Date.now() - tFilter);
|
|
251
293
|
performanceTracker.recordCounts({
|
|
252
294
|
uniquePackages: uniquePackages.length,
|
|
@@ -274,12 +316,12 @@ class PackageDetector {
|
|
|
274
316
|
if (!packageData || packageData.latestVersion === 'unknown') {
|
|
275
317
|
if (!loggedNoData.has(dep.name)) {
|
|
276
318
|
loggedNoData.add(dep.name);
|
|
277
|
-
|
|
319
|
+
debug_logger_1.debugLog.warn('PackageDetector', `no data returned for ${dep.name} — marking unavailable`);
|
|
278
320
|
}
|
|
279
321
|
return this.createFailedPackageInfo(dep);
|
|
280
322
|
}
|
|
281
323
|
const { latestVersion, allVersions } = packageData;
|
|
282
|
-
const closestMinorVersion = (0,
|
|
324
|
+
const closestMinorVersion = (0, versions_1.findClosestMinorVersion)(dep.version, allVersions);
|
|
283
325
|
const installedClean = semver.coerce(dep.version)?.version || dep.version;
|
|
284
326
|
const minorClean = closestMinorVersion
|
|
285
327
|
? semver.coerce(closestMinorVersion)?.version || closestMinorVersion
|
|
@@ -294,7 +336,7 @@ class PackageDetector {
|
|
|
294
336
|
const outdatedKey = `${dep.name}@${dep.version}`;
|
|
295
337
|
if (!loggedOutdated.has(outdatedKey)) {
|
|
296
338
|
loggedOutdated.add(outdatedKey);
|
|
297
|
-
|
|
339
|
+
debug_logger_1.debugLog.info('PackageDetector', `outdated: ${dep.name} ${dep.version} → range:${closestMinorVersion ?? '-'} latest:${latestVersion}`);
|
|
298
340
|
}
|
|
299
341
|
}
|
|
300
342
|
return {
|
|
@@ -304,6 +346,9 @@ class PackageDetector {
|
|
|
304
346
|
latestVersion,
|
|
305
347
|
type: dep.type,
|
|
306
348
|
packageJsonPath: dep.packageJsonPath,
|
|
349
|
+
catalog: dep.catalog,
|
|
350
|
+
catalogEntries: dep.catalogEntries,
|
|
351
|
+
catalogReferencedBy: dep.catalogReferencedBy,
|
|
307
352
|
isOutdated,
|
|
308
353
|
hasRangeUpdate,
|
|
309
354
|
hasMajorUpdate,
|
|
@@ -313,7 +358,7 @@ class PackageDetector {
|
|
|
313
358
|
};
|
|
314
359
|
}
|
|
315
360
|
catch (error) {
|
|
316
|
-
|
|
361
|
+
debug_logger_1.debugLog.error('PackageDetector', `error processing ${dep.name}`, error);
|
|
317
362
|
return this.createFailedPackageInfo(dep);
|
|
318
363
|
}
|
|
319
364
|
});
|
|
@@ -326,6 +371,9 @@ class PackageDetector {
|
|
|
326
371
|
latestVersion: 'unknown',
|
|
327
372
|
type: dep.type,
|
|
328
373
|
packageJsonPath: dep.packageJsonPath,
|
|
374
|
+
catalog: dep.catalog,
|
|
375
|
+
catalogEntries: dep.catalogEntries,
|
|
376
|
+
catalogReferencedBy: dep.catalogReferencedBy,
|
|
329
377
|
isOutdated: false,
|
|
330
378
|
hasRangeUpdate: false,
|
|
331
379
|
hasMajorUpdate: false,
|
|
@@ -346,8 +394,8 @@ class PackageDetector {
|
|
|
346
394
|
let timeoutId;
|
|
347
395
|
try {
|
|
348
396
|
const files = await Promise.race([
|
|
349
|
-
(0,
|
|
350
|
-
const truncatedDir = currentDir.length > 50 ?
|
|
397
|
+
(0, fs_1.findAllPackageJsonFilesAsync)(this.cwd, this.excludePatterns, this.maxDepth, (currentDir, foundCount) => {
|
|
398
|
+
const truncatedDir = currentDir.length > 50 ? `...${currentDir.slice(-47)}` : currentDir;
|
|
351
399
|
this.showProgress(`🔍 Scanning ${truncatedDir} (found ${foundCount})`);
|
|
352
400
|
}, {
|
|
353
401
|
scanDirs: this.scanDirs,
|
|
@@ -387,17 +435,28 @@ class PackageDetector {
|
|
|
387
435
|
list.map((dir) => ` - ${dir}`).join('\n') +
|
|
388
436
|
`\n Add the directory name(s) to "scanDirs" in .inuprc to include them.`));
|
|
389
437
|
}
|
|
390
|
-
|
|
438
|
+
/**
|
|
439
|
+
* Specifiers that don't point at a plain registry range, so there is nothing to resolve or
|
|
440
|
+
* upgrade: workspace/file/link refs, git hosts and URLs, tarball URLs, and `npm:` aliases.
|
|
441
|
+
* An `npm:` alias in particular must never be looked up under its alias name — the packument
|
|
442
|
+
* for that name is a different (or nonexistent) package.
|
|
443
|
+
*/
|
|
444
|
+
isNonRegistrySpecifier(version) {
|
|
391
445
|
return (version.includes('workspace:') ||
|
|
392
446
|
version === '*' ||
|
|
393
447
|
version.startsWith('file:') ||
|
|
394
448
|
version.startsWith('link:') ||
|
|
395
449
|
version.startsWith('github:') ||
|
|
396
450
|
version.startsWith('gitlab:') ||
|
|
397
|
-
version.startsWith('bitbucket:')
|
|
451
|
+
version.startsWith('bitbucket:') ||
|
|
452
|
+
version.startsWith('npm:') ||
|
|
453
|
+
version.startsWith('git:') ||
|
|
454
|
+
version.startsWith('git+') ||
|
|
455
|
+
version.startsWith('http:') ||
|
|
456
|
+
version.startsWith('https:'));
|
|
398
457
|
}
|
|
399
458
|
showProgress(message) {
|
|
400
|
-
|
|
459
|
+
terminal_1.ConsoleUtils.showProgress(message);
|
|
401
460
|
}
|
|
402
461
|
getOutdatedPackagesOnly(packages) {
|
|
403
462
|
return packages.filter((pkg) => pkg.isOutdated);
|
|
@@ -4,12 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.PackageUpgrader = void 0;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
7
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
11
|
const nanospinner_1 = require("nanospinner");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const utils_1 = require("../utils");
|
|
12
|
+
const exec_1 = require("../../shared/exec");
|
|
13
|
+
const fs_1 = require("../../shared/fs");
|
|
14
|
+
const pnpm_catalogs_1 = require("../../shared/pnpm-catalogs");
|
|
13
15
|
class PackageUpgrader {
|
|
14
16
|
packageManager;
|
|
15
17
|
quiet;
|
|
@@ -25,15 +27,23 @@ class PackageUpgrader {
|
|
|
25
27
|
this.log(chalk_1.default.yellow('No packages to upgrade.'));
|
|
26
28
|
return;
|
|
27
29
|
}
|
|
30
|
+
// Catalog entries live in pnpm-workspace.yaml, not a package.json — they
|
|
31
|
+
// take the YAML write path below. The type predicate narrows the catalog
|
|
32
|
+
// group so downstream code sees `catalog` as a required string.
|
|
33
|
+
const catalogChoices = choices.filter((choice) => choice.catalog !== undefined);
|
|
34
|
+
const fileChoices = choices.filter((choice) => choice.catalog === undefined);
|
|
28
35
|
// Group choices by package.json path and dependency type
|
|
29
|
-
const choicesByFileAndType = this.groupChoicesByFileAndType(
|
|
36
|
+
const choicesByFileAndType = this.groupChoicesByFileAndType(fileChoices);
|
|
30
37
|
for (const [fileAndType, choiceList] of Object.entries(choicesByFileAndType)) {
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
// groupChoicesByFileAndType only creates a group once it has a member,
|
|
39
|
+
// so choiceList is always non-empty here.
|
|
33
40
|
const [packageJsonPath, type] = fileAndType.split('|');
|
|
34
41
|
this.log(`Processing ${type} in ${packageJsonPath}`);
|
|
35
42
|
await this.upgradeChoiceGroup(choiceList, packageJsonPath, type);
|
|
36
43
|
}
|
|
44
|
+
if (catalogChoices.length > 0) {
|
|
45
|
+
await this.upgradeCatalogChoices(catalogChoices);
|
|
46
|
+
}
|
|
37
47
|
// Count unique packages upgraded
|
|
38
48
|
const uniquePackages = new Set(choices.map((c) => c.name));
|
|
39
49
|
this.log(chalk_1.default.green(`\n✅ Successfully upgraded ${uniquePackages.size} package(s)!`));
|
|
@@ -41,20 +51,19 @@ class PackageUpgrader {
|
|
|
41
51
|
await this.runInstall(choices);
|
|
42
52
|
}
|
|
43
53
|
async runInstall(choices) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
54
|
+
// The sole caller (upgradePackages) returns early on an empty selection,
|
|
55
|
+
// so choices is always non-empty here.
|
|
47
56
|
// Determine the directory to run install in
|
|
48
57
|
// Use workspace root if it exists, otherwise use the directory of the first package.json
|
|
49
58
|
const firstPackageJsonPath = choices[0].packageJsonPath;
|
|
50
|
-
const firstPackageDir = (0,
|
|
51
|
-
const workspaceRoot = (0,
|
|
59
|
+
const firstPackageDir = (0, node_path_1.dirname)(firstPackageJsonPath);
|
|
60
|
+
const workspaceRoot = (0, fs_1.findWorkspaceRoot)(firstPackageDir, this.packageManager.name);
|
|
52
61
|
const installDir = workspaceRoot || firstPackageDir;
|
|
53
62
|
// Check if package manager is installed
|
|
54
63
|
try {
|
|
55
|
-
(0,
|
|
64
|
+
(0, exec_1.executeCommand)(`${this.packageManager.name} --version`, installDir);
|
|
56
65
|
}
|
|
57
|
-
catch
|
|
66
|
+
catch {
|
|
58
67
|
this.log(chalk_1.default.yellow(`\n⚠️ ${this.packageManager.displayName} is detected but not installed on your system.\n` +
|
|
59
68
|
`Please run the install command manually:\n` +
|
|
60
69
|
` cd ${installDir}\n` +
|
|
@@ -69,7 +78,7 @@ class PackageUpgrader {
|
|
|
69
78
|
// inherited fds, so its progress output bypasses any JS shim — redirecting at spawn time is
|
|
70
79
|
// the only reliable way to keep stdout reserved for the --json document. stderr stays inherited.
|
|
71
80
|
const stdio = this.quiet ? ['inherit', 2, 'inherit'] : 'inherit';
|
|
72
|
-
const result = (0,
|
|
81
|
+
const result = (0, node_child_process_1.spawnSync)(installCommand, {
|
|
73
82
|
cwd: installDir,
|
|
74
83
|
stdio,
|
|
75
84
|
shell: true,
|
|
@@ -84,6 +93,53 @@ class PackageUpgrader {
|
|
|
84
93
|
throw new Error(`${installCommand} exited with code ${result.status}`);
|
|
85
94
|
}
|
|
86
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Apply catalog upgrades by rewriting the referenced ranges inside
|
|
98
|
+
* pnpm-workspace.yaml (comment- and format-preserving). One write per file.
|
|
99
|
+
*/
|
|
100
|
+
async upgradeCatalogChoices(choices) {
|
|
101
|
+
const choicesByFile = new Map();
|
|
102
|
+
choices.forEach((choice) => {
|
|
103
|
+
const group = choicesByFile.get(choice.packageJsonPath) ?? [];
|
|
104
|
+
group.push(choice);
|
|
105
|
+
choicesByFile.set(choice.packageJsonPath, group);
|
|
106
|
+
});
|
|
107
|
+
for (const [workspaceFilePath, fileChoices] of choicesByFile) {
|
|
108
|
+
if (!(0, node_fs_1.existsSync)(workspaceFilePath)) {
|
|
109
|
+
this.log(chalk_1.default.yellow(`⚠️ Skipping catalog entries in ${workspaceFilePath} - file not found`));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
this.log(`Processing catalog entries in ${workspaceFilePath}`);
|
|
113
|
+
const spinner = this.quiet
|
|
114
|
+
? null
|
|
115
|
+
: (0, nanospinner_1.createSpinner)(`Upgrading catalog entries in ${workspaceFilePath}...`).start();
|
|
116
|
+
try {
|
|
117
|
+
(0, pnpm_catalogs_1.writeCatalogUpdates)(workspaceFilePath, fileChoices.map((choice) => ({
|
|
118
|
+
catalog: choice.catalog,
|
|
119
|
+
name: choice.name,
|
|
120
|
+
range: choice.targetVersion,
|
|
121
|
+
})));
|
|
122
|
+
const message = `Upgraded ${fileChoices.length} catalog entr${fileChoices.length === 1 ? 'y' : 'ies'} in ${workspaceFilePath}`;
|
|
123
|
+
if (spinner)
|
|
124
|
+
spinner.success({ text: message });
|
|
125
|
+
else
|
|
126
|
+
this.log(chalk_1.default.green(`✔ ${message}`));
|
|
127
|
+
fileChoices.forEach((choice) => {
|
|
128
|
+
const upgradeTypeColor = choice.upgradeType === 'range' ? chalk_1.default.yellow : chalk_1.default.red;
|
|
129
|
+
const catalogLabel = choice.catalog === 'default' ? 'catalog' : `catalog:${choice.catalog}`;
|
|
130
|
+
this.log(` ${chalk_1.default.green('✓')} ${chalk_1.default.cyan(choice.name)} (${catalogLabel}) → ${upgradeTypeColor(choice.targetVersion)}`);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (spinner)
|
|
135
|
+
spinner.error({ text: `Failed to upgrade catalog entries in ${workspaceFilePath}` });
|
|
136
|
+
else
|
|
137
|
+
this.log(chalk_1.default.red(`✖ Failed to upgrade catalog entries in ${workspaceFilePath}`));
|
|
138
|
+
console.error(chalk_1.default.red(`Error: ${error}`));
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
87
143
|
groupChoicesByFileAndType(choices) {
|
|
88
144
|
const groups = {};
|
|
89
145
|
choices.forEach((choice) => {
|
|
@@ -97,7 +153,7 @@ class PackageUpgrader {
|
|
|
97
153
|
}
|
|
98
154
|
async upgradeChoiceGroup(choices, packageJsonPath, type) {
|
|
99
155
|
// Validate that package.json exists
|
|
100
|
-
if (!(0,
|
|
156
|
+
if (!(0, node_fs_1.existsSync)(packageJsonPath)) {
|
|
101
157
|
this.log(chalk_1.default.yellow(`⚠️ Skipping ${type} in ${packageJsonPath} - package.json file not found`));
|
|
102
158
|
return;
|
|
103
159
|
}
|
|
@@ -108,40 +164,33 @@ class PackageUpgrader {
|
|
|
108
164
|
: (0, nanospinner_1.createSpinner)(`Upgrading ${type} in ${packageDir}...`).start();
|
|
109
165
|
try {
|
|
110
166
|
// Read the current package.json — keep the raw text so we can round-trip its formatting
|
|
111
|
-
const rawContent = (0,
|
|
112
|
-
const packageJson = (0,
|
|
167
|
+
const rawContent = (0, node_fs_1.readFileSync)(packageJsonPath, 'utf-8');
|
|
168
|
+
const packageJson = (0, fs_1.readPackageJson)(packageJsonPath);
|
|
113
169
|
// Group by upgrade type (range vs latest)
|
|
114
170
|
const rangeChoices = choices.filter((c) => c.upgradeType === 'range');
|
|
115
171
|
const latestChoices = choices.filter((c) => c.upgradeType === 'latest');
|
|
116
|
-
let modified = false;
|
|
117
172
|
// Upgrade range versions by directly modifying package.json
|
|
118
173
|
if (rangeChoices.length > 0) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
174
|
+
const section = packageJson[type] ?? {};
|
|
175
|
+
packageJson[type] = section;
|
|
122
176
|
rangeChoices.forEach((choice) => {
|
|
123
|
-
|
|
124
|
-
modified = true;
|
|
177
|
+
section[choice.name] = choice.targetVersion;
|
|
125
178
|
});
|
|
126
179
|
}
|
|
127
180
|
// Upgrade to latest versions by directly modifying package.json
|
|
128
181
|
if (latestChoices.length > 0) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
182
|
+
const section = packageJson[type] ?? {};
|
|
183
|
+
packageJson[type] = section;
|
|
132
184
|
latestChoices.forEach((choice) => {
|
|
133
|
-
|
|
134
|
-
modified = true;
|
|
185
|
+
section[choice.name] = choice.targetVersion;
|
|
135
186
|
});
|
|
136
187
|
}
|
|
137
188
|
// Write back the modified package.json, preserving the original indentation and
|
|
138
189
|
// trailing-newline style. Skip the write entirely when nothing actually changed.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
(0, fs_1.writeFileSync)(packageJsonPath, nextContent);
|
|
144
|
-
}
|
|
190
|
+
const format = (0, fs_1.detectJsonFormat)(rawContent);
|
|
191
|
+
const nextContent = JSON.stringify(packageJson, null, format.indent) + (format.trailingNewline ? '\n' : '');
|
|
192
|
+
if (nextContent !== rawContent) {
|
|
193
|
+
(0, node_fs_1.writeFileSync)(packageJsonPath, nextContent);
|
|
145
194
|
}
|
|
146
195
|
if (spinner)
|
|
147
196
|
spinner.success({ text: `Upgraded ${choices.length} ${type} in ${packageDir}` });
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.UpgradeRunner = void 0;
|
|
7
|
-
var
|
|
8
|
-
Object.defineProperty(exports, "UpgradeRunner", { enumerable: true, get: function () { return
|
|
7
|
+
var upgrade_runner_1 = require("./app/upgrade-runner");
|
|
8
|
+
Object.defineProperty(exports, "UpgradeRunner", { enumerable: true, get: function () { return upgrade_runner_1.UpgradeRunner; } });
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.PACKAGE_VERSION = exports.PACKAGE_NAME = void 0;
|
|
7
|
-
const package_json_1 = __importDefault(require("
|
|
7
|
+
const package_json_1 = __importDefault(require("../../../package.json"));
|
|
8
8
|
exports.PACKAGE_NAME = package_json_1.default.name;
|
|
9
9
|
exports.PACKAGE_VERSION = package_json_1.default.version;
|
|
10
10
|
//# sourceMappingURL=package-meta.js.map
|