inup 1.4.0 → 1.4.2
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 +31 -106
- package/dist/cli.js +0 -0
- package/dist/{constants.js → config/constants.js} +8 -3
- package/dist/config/index.js +18 -0
- package/dist/core/package-detector.js +17 -6
- package/dist/interactive-ui.js +104 -30
- package/dist/services/jsdelivr-registry.js +24 -44
- package/dist/services/npm-registry.js +45 -57
- package/dist/services/version-checker.js +2 -2
- package/dist/ui/index.js +18 -10
- package/dist/ui/input-handler.js +97 -3
- package/dist/ui/renderer/index.js +7 -2
- package/dist/ui/renderer/package-list.js +164 -80
- package/dist/ui/renderer/theme-selector.js +83 -0
- package/dist/ui/state/filter-manager.js +48 -0
- package/dist/ui/state/index.js +12 -0
- package/dist/ui/state/modal-manager.js +45 -0
- package/dist/ui/state/navigation-manager.js +154 -0
- package/dist/ui/state/state-manager.js +240 -0
- package/dist/ui/state/theme-manager.js +85 -0
- package/dist/ui/themes-colors.js +168 -0
- package/dist/ui/themes.js +27 -0
- package/dist/ui/utils/cursor.js +33 -0
- package/dist/ui/utils/index.js +8 -0
- package/dist/ui/{utils.js → utils/version.js} +24 -1
- package/dist/utils/config.js +57 -0
- package/dist/utils/version.js +11 -6
- package/package.json +16 -17
- package/dist/ui/state.js +0 -250
package/README.md
CHANGED
|
@@ -4,46 +4,17 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/inup)
|
|
5
5
|
[](https://www.npmjs.com/package/inup)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Interactive upgrade for your dependencies. Works with npm, yarn, pnpm, and bun.
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
Ever found yourself staring at a wall of outdated packages, wondering which ones to upgrade? This tool helps you:
|
|
14
|
-
|
|
15
|
-
- **Scans your entire project** - finds all package.json files in your workspace
|
|
16
|
-
- **Auto-detects your package manager** - works seamlessly with npm, yarn, pnpm, or bun
|
|
17
|
-
- **Checks for updates** - compares your current versions against the latest available
|
|
18
|
-
- **Lets you pick what to upgrade** - interactive interface to select exactly what you want
|
|
19
|
-
- **Does the heavy lifting** - updates your package.json files and runs the appropriate install command
|
|
20
|
-
|
|
21
|
-
## Why choose inup?
|
|
22
|
-
|
|
23
|
-
If you miss the convenience of `yarn upgrade-interactive` but want it to work with **any package manager**, this tool is perfect for you!
|
|
24
|
-
|
|
25
|
-
- **🚀 Fast & Efficient** - Batch upgrade multiple packages at once
|
|
26
|
-
- **🔒 Safe Updates** - Choose between minor updates or major version jumps
|
|
27
|
-
- **🏢 Monorepo Friendly** - Works seamlessly with workspaces
|
|
28
|
-
- **📦 Registry Aware** - Checks npm registry for latest versions
|
|
29
|
-
- **🎯 Selective Upgrades** - Pick exactly which packages to upgrade
|
|
30
|
-
- **⚡ Zero Config** - Works out of the box with sensible defaults
|
|
31
|
-
|
|
32
|
-
## Installation
|
|
33
|
-
|
|
34
|
-
### With npx (no installation needed)
|
|
11
|
+
## Install
|
|
35
12
|
|
|
36
13
|
```bash
|
|
37
14
|
npx inup
|
|
38
15
|
```
|
|
39
16
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
pnpm add -g inup
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Alternative: npm
|
|
17
|
+
Or install globally:
|
|
47
18
|
|
|
48
19
|
```bash
|
|
49
20
|
npm install -g inup
|
|
@@ -51,92 +22,46 @@ npm install -g inup
|
|
|
51
22
|
|
|
52
23
|
## Usage
|
|
53
24
|
|
|
54
|
-
Just run it in your project directory:
|
|
55
|
-
|
|
56
25
|
```bash
|
|
57
|
-
inup
|
|
26
|
+
npx inup
|
|
58
27
|
```
|
|
59
28
|
|
|
60
|
-
The tool
|
|
61
|
-
|
|
62
|
-
### Command line options
|
|
63
|
-
|
|
64
|
-
- `-d, --dir <directory>`: Run in a specific directory (default: current directory)
|
|
65
|
-
- `-e, --exclude <patterns>`: Skip directories matching these regex patterns (comma-separated)
|
|
66
|
-
- `-p, --peer`: Include peer dependencies in upgrade process (default: false)
|
|
67
|
-
- `-o, --optional`: Include optional dependencies in upgrade process (default: false)
|
|
68
|
-
- `--package-manager <name>`: Manually specify package manager (npm, yarn, pnpm, bun) - overrides auto-detection
|
|
69
|
-
|
|
70
|
-
**Note:** By default, the tool only processes `dependencies` and `devDependencies`. Both `peerDependencies` and `optionalDependencies` are excluded by default and must be explicitly included with their respective flags.
|
|
29
|
+
That's it. The tool scans your project, finds outdated packages, and lets you pick what to upgrade.
|
|
71
30
|
|
|
72
|
-
|
|
31
|
+
## Features
|
|
73
32
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
# Include optional dependencies
|
|
82
|
-
inup --optional
|
|
83
|
-
|
|
84
|
-
# Include both peer and optional dependencies
|
|
85
|
-
inup --peer --optional
|
|
33
|
+
- Auto-detects package manager (npm, yarn, pnpm, bun)
|
|
34
|
+
- Works with monorepos and workspaces
|
|
35
|
+
- Batch upgrades with keyboard shortcuts
|
|
36
|
+
- Search packages with `/`
|
|
37
|
+
- Multiple themes (press `t`)
|
|
38
|
+
- Package info modal (press `i`)
|
|
86
39
|
|
|
87
|
-
|
|
88
|
-
inup --exclude "example,test"
|
|
40
|
+
## Keyboard Shortcuts
|
|
89
41
|
|
|
90
|
-
|
|
91
|
-
|
|
42
|
+
- `↑/↓` - Navigate packages
|
|
43
|
+
- `←/→` - Select version (current, patch, minor, major)
|
|
44
|
+
- `Space` - Toggle selection
|
|
45
|
+
- `m` - Select all minor updates
|
|
46
|
+
- `l` - Select all latest updates
|
|
47
|
+
- `u` - Unselect all
|
|
48
|
+
- `/` - Search packages
|
|
49
|
+
- `t` - Change theme
|
|
50
|
+
- `i` - View package info
|
|
51
|
+
- `Enter` - Confirm and upgrade
|
|
92
52
|
|
|
93
|
-
|
|
94
|
-
inup --dir ../my-other-project
|
|
53
|
+
## Options
|
|
95
54
|
|
|
96
|
-
|
|
97
|
-
inup
|
|
55
|
+
```bash
|
|
56
|
+
inup [options]
|
|
98
57
|
|
|
99
|
-
|
|
100
|
-
|
|
58
|
+
-d, --dir <path> Run in specific directory
|
|
59
|
+
-e, --exclude <patterns> Skip directories (comma-separated regex)
|
|
60
|
+
-p, --peer Include peer dependencies
|
|
61
|
+
-o, --optional Include optional dependencies
|
|
62
|
+
--package-manager <name> Force package manager (npm, yarn, pnpm, bun)
|
|
101
63
|
```
|
|
102
64
|
|
|
103
|
-
### How it works
|
|
104
|
-
|
|
105
|
-
1. **Detects your package manager** - Auto-detects from lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb) or package.json
|
|
106
|
-
2. **Scans your project** - Finds all package.json files recursively (respects exclude patterns)
|
|
107
|
-
3. **Collects dependencies** - Gathers dependencies based on your options (dependencies, devDependencies, and optionally peerDependencies/optionalDependencies)
|
|
108
|
-
4. **Checks for updates** - Queries npm registry for latest versions
|
|
109
|
-
5. **Shows you options** - Interactive UI lets you pick what to upgrade (minor updates or latest versions)
|
|
110
|
-
6. **Updates safely** - Modifies package.json files and runs the appropriate install command (`npm install`, `yarn install`, `pnpm install`, or `bun install`)
|
|
111
|
-
|
|
112
|
-
### Package Manager Detection
|
|
113
|
-
|
|
114
|
-
inup automatically detects which package manager you're using by:
|
|
115
|
-
|
|
116
|
-
1. **Checking package.json** - Looks for the `packageManager` field
|
|
117
|
-
2. **Checking lock files** - Scans for:
|
|
118
|
-
- `pnpm-lock.yaml` → pnpm
|
|
119
|
-
- `bun.lockb` → bun
|
|
120
|
-
- `yarn.lock` → yarn
|
|
121
|
-
- `package-lock.json` → npm
|
|
122
|
-
3. **Fallback to npm** - If nothing is detected, defaults to npm with a warning
|
|
123
|
-
|
|
124
|
-
You can override auto-detection using the `--package-manager` flag.
|
|
125
|
-
|
|
126
|
-
### FAQ
|
|
127
|
-
|
|
128
|
-
**Q: How does inup detect my package manager?**
|
|
129
|
-
A: It checks your `package.json` `packageManager` field first, then looks for lock files. You can manually override with `--package-manager`.
|
|
130
|
-
|
|
131
|
-
**Q: What if I have multiple lock files?**
|
|
132
|
-
A: inup will use the most recently modified lock file and show a warning. Consider cleaning up unused lock files.
|
|
133
|
-
|
|
134
|
-
**Q: Can I force a specific package manager?**
|
|
135
|
-
A: Yes! Use `--package-manager npm` (or yarn, pnpm, bun) to override auto-detection.
|
|
136
|
-
|
|
137
|
-
**Q: What if the detected package manager isn't installed?**
|
|
138
|
-
A: inup will still update your package.json files but skip the install step. It will show you the manual install command to run.
|
|
139
|
-
|
|
140
65
|
## License
|
|
141
66
|
|
|
142
67
|
MIT
|
package/dist/cli.js
CHANGED
|
File without changes
|
|
@@ -3,12 +3,17 @@
|
|
|
3
3
|
* Constants for npm registry queries and configuration
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.WORKSPACE_FILES = exports.LOCK_FILES = exports.REQUEST_TIMEOUT = exports.CACHE_TTL = exports.MAX_CONCURRENT_REQUESTS = exports.JSDELIVR_CDN_URL = exports.NPM_REGISTRY_URL = void 0;
|
|
6
|
+
exports.WORKSPACE_FILES = exports.LOCK_FILES = exports.DEFAULT_REGISTRY = exports.REQUEST_TIMEOUT = exports.CACHE_TTL = exports.MAX_CONCURRENT_REQUESTS = exports.JSDELIVR_CDN_URL = exports.NPM_REGISTRY_URL = void 0;
|
|
7
7
|
exports.NPM_REGISTRY_URL = 'https://registry.npmjs.org';
|
|
8
8
|
exports.JSDELIVR_CDN_URL = 'https://cdn.jsdelivr.net/npm';
|
|
9
|
-
exports.MAX_CONCURRENT_REQUESTS =
|
|
9
|
+
exports.MAX_CONCURRENT_REQUESTS = 150;
|
|
10
10
|
exports.CACHE_TTL = 5 * 60 * 1000; // 5 minutes in milliseconds
|
|
11
|
-
exports.REQUEST_TIMEOUT =
|
|
11
|
+
exports.REQUEST_TIMEOUT = 60000; // 60 seconds in milliseconds
|
|
12
|
+
/**
|
|
13
|
+
* Registry selection: 'jsdelivr' for fast CDN lookups, 'npm' for direct npm registry
|
|
14
|
+
* Set to 'npm' to use npm registry by default instead of jsdelivr
|
|
15
|
+
*/
|
|
16
|
+
exports.DEFAULT_REGISTRY = 'jsdelivr';
|
|
12
17
|
/**
|
|
13
18
|
* Package manager lock files
|
|
14
19
|
*/
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./constants"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -37,6 +37,7 @@ exports.PackageDetector = void 0;
|
|
|
37
37
|
const semver = __importStar(require("semver"));
|
|
38
38
|
const utils_1 = require("../utils");
|
|
39
39
|
const services_1 = require("../services");
|
|
40
|
+
const config_1 = require("../config");
|
|
40
41
|
class PackageDetector {
|
|
41
42
|
constructor(options) {
|
|
42
43
|
this.packageJsonPath = null;
|
|
@@ -80,7 +81,7 @@ class PackageDetector {
|
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
const packageNames = Array.from(uniquePackageNames);
|
|
83
|
-
// Step 4: Fetch all package data in one call per package
|
|
84
|
+
// Step 4: Fetch all package data in one call per package
|
|
84
85
|
// Create a map of package names to their current versions for major version optimization
|
|
85
86
|
const currentVersions = new Map();
|
|
86
87
|
for (const dep of allDeps) {
|
|
@@ -89,11 +90,21 @@ class PackageDetector {
|
|
|
89
90
|
currentVersions.set(dep.name, dep.version);
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
|
-
const allPackageData =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
const allPackageData = config_1.DEFAULT_REGISTRY === 'jsdelivr'
|
|
94
|
+
? await (0, services_1.getAllPackageDataFromJsdelivr)(packageNames, currentVersions, (currentPackage, completed, total) => {
|
|
95
|
+
const percentage = Math.round((completed / total) * 100);
|
|
96
|
+
const truncatedPackage = currentPackage.length > 40
|
|
97
|
+
? currentPackage.substring(0, 37) + '...'
|
|
98
|
+
: currentPackage;
|
|
99
|
+
this.showProgress(`🌐 Fetching ${percentage}% (${truncatedPackage})`);
|
|
100
|
+
})
|
|
101
|
+
: await (0, services_1.getAllPackageData)(packageNames, (currentPackage, completed, total) => {
|
|
102
|
+
const percentage = Math.round((completed / total) * 100);
|
|
103
|
+
const truncatedPackage = currentPackage.length > 40
|
|
104
|
+
? currentPackage.substring(0, 37) + '...'
|
|
105
|
+
: currentPackage;
|
|
106
|
+
this.showProgress(`🌐 Fetching ${percentage}% (${truncatedPackage})`);
|
|
107
|
+
});
|
|
97
108
|
try {
|
|
98
109
|
for (const dep of allDeps) {
|
|
99
110
|
try {
|
package/dist/interactive-ui.js
CHANGED
|
@@ -43,6 +43,8 @@ const semver = __importStar(require("semver"));
|
|
|
43
43
|
const keypress = require('keypress');
|
|
44
44
|
const ui_1 = require("./ui");
|
|
45
45
|
const services_1 = require("./services");
|
|
46
|
+
const themes_1 = require("./ui/themes");
|
|
47
|
+
const themes_colors_1 = require("./ui/themes-colors");
|
|
46
48
|
class InteractiveUI {
|
|
47
49
|
constructor(packageManager) {
|
|
48
50
|
this.renderer = new ui_1.UIRenderer();
|
|
@@ -80,15 +82,15 @@ class InteractiveUI {
|
|
|
80
82
|
// Build label describing which types are shown
|
|
81
83
|
const types = [];
|
|
82
84
|
if (options.includePeerDeps)
|
|
83
|
-
types.push('Peer
|
|
85
|
+
types.push('Peer Deps');
|
|
84
86
|
if (options.includeOptionalDeps)
|
|
85
|
-
types.push('Optional
|
|
87
|
+
types.push('Optional Deps');
|
|
86
88
|
dependencyTypeLabel = types.join(' & ');
|
|
87
89
|
}
|
|
88
90
|
else {
|
|
89
91
|
// Default: show only regular dependencies and devDependencies
|
|
90
92
|
filteredPackages = outdatedPackages.filter((pkg) => pkg.type === 'dependencies' || pkg.type === 'devDependencies');
|
|
91
|
-
dependencyTypeLabel = '
|
|
93
|
+
dependencyTypeLabel = 'Deps & Dev Deps';
|
|
92
94
|
}
|
|
93
95
|
if (filteredPackages.length === 0) {
|
|
94
96
|
return [];
|
|
@@ -186,47 +188,48 @@ class InteractiveUI {
|
|
|
186
188
|
stateManager.setRenderableItems([]);
|
|
187
189
|
const handleAction = (action) => {
|
|
188
190
|
const uiState = stateManager.getUIState();
|
|
191
|
+
const filteredStates = stateManager.getFilteredStates(states);
|
|
189
192
|
switch (action.type) {
|
|
190
193
|
case 'navigate_up':
|
|
191
|
-
if (!uiState.showInfoModal) {
|
|
192
|
-
stateManager.navigateUp(
|
|
194
|
+
if (!uiState.showInfoModal && !uiState.showThemeModal) {
|
|
195
|
+
stateManager.navigateUp(filteredStates.length);
|
|
193
196
|
}
|
|
194
197
|
break;
|
|
195
198
|
case 'navigate_down':
|
|
196
|
-
if (!uiState.showInfoModal) {
|
|
197
|
-
stateManager.navigateDown(
|
|
199
|
+
if (!uiState.showInfoModal && !uiState.showThemeModal) {
|
|
200
|
+
stateManager.navigateDown(filteredStates.length);
|
|
198
201
|
}
|
|
199
202
|
break;
|
|
200
203
|
case 'select_left':
|
|
201
|
-
if (!uiState.showInfoModal) {
|
|
202
|
-
stateManager.updateSelection(
|
|
204
|
+
if (!uiState.showInfoModal && !uiState.showThemeModal) {
|
|
205
|
+
stateManager.updateSelection(filteredStates, 'left');
|
|
203
206
|
}
|
|
204
207
|
break;
|
|
205
208
|
case 'select_right':
|
|
206
|
-
if (!uiState.showInfoModal) {
|
|
207
|
-
stateManager.updateSelection(
|
|
209
|
+
if (!uiState.showInfoModal && !uiState.showThemeModal) {
|
|
210
|
+
stateManager.updateSelection(filteredStates, 'right');
|
|
208
211
|
}
|
|
209
212
|
break;
|
|
210
213
|
case 'bulk_select_minor':
|
|
211
|
-
if (!uiState.showInfoModal) {
|
|
212
|
-
stateManager.bulkSelectMinor(
|
|
214
|
+
if (!uiState.showInfoModal && !uiState.showThemeModal) {
|
|
215
|
+
stateManager.bulkSelectMinor(filteredStates);
|
|
213
216
|
}
|
|
214
217
|
break;
|
|
215
218
|
case 'bulk_select_latest':
|
|
216
|
-
if (!uiState.showInfoModal) {
|
|
217
|
-
stateManager.bulkSelectLatest(
|
|
219
|
+
if (!uiState.showInfoModal && !uiState.showThemeModal) {
|
|
220
|
+
stateManager.bulkSelectLatest(filteredStates);
|
|
218
221
|
}
|
|
219
222
|
break;
|
|
220
223
|
case 'bulk_unselect_all':
|
|
221
|
-
if (!uiState.showInfoModal) {
|
|
222
|
-
stateManager.bulkUnselectAll(
|
|
224
|
+
if (!uiState.showInfoModal && !uiState.showThemeModal) {
|
|
225
|
+
stateManager.bulkUnselectAll(filteredStates);
|
|
223
226
|
}
|
|
224
227
|
break;
|
|
225
228
|
case 'toggle_info_modal':
|
|
226
229
|
if (!uiState.showInfoModal) {
|
|
227
230
|
// Opening modal - load package info asynchronously
|
|
228
231
|
stateManager.toggleInfoModal();
|
|
229
|
-
const currentState =
|
|
232
|
+
const currentState = filteredStates[uiState.currentRow];
|
|
230
233
|
stateManager.setModalLoading(true);
|
|
231
234
|
renderInterface();
|
|
232
235
|
// Fetch metadata asynchronously
|
|
@@ -249,6 +252,20 @@ class InteractiveUI {
|
|
|
249
252
|
renderInterface();
|
|
250
253
|
}
|
|
251
254
|
break;
|
|
255
|
+
case 'enter_filter_mode':
|
|
256
|
+
stateManager.enterFilterMode();
|
|
257
|
+
break;
|
|
258
|
+
case 'exit_filter_mode':
|
|
259
|
+
stateManager.exitFilterMode();
|
|
260
|
+
break;
|
|
261
|
+
case 'filter_input':
|
|
262
|
+
stateManager.appendToFilterQuery(action.char);
|
|
263
|
+
// Re-calculate filtered states after input
|
|
264
|
+
break;
|
|
265
|
+
case 'filter_backspace':
|
|
266
|
+
stateManager.deleteFromFilterQuery();
|
|
267
|
+
// Re-calculate filtered states after backspace
|
|
268
|
+
break;
|
|
252
269
|
case 'resize':
|
|
253
270
|
const heightChanged = stateManager.updateTerminalHeight(action.height);
|
|
254
271
|
if (heightChanged) {
|
|
@@ -260,6 +277,30 @@ class InteractiveUI {
|
|
|
260
277
|
stateManager.setInitialRender(true);
|
|
261
278
|
}
|
|
262
279
|
break;
|
|
280
|
+
case 'toggle_theme_modal':
|
|
281
|
+
stateManager.toggleThemeModal();
|
|
282
|
+
break;
|
|
283
|
+
case 'theme_navigate_up': {
|
|
284
|
+
const themeManager = stateManager.getThemeManager();
|
|
285
|
+
const currentIndex = themes_1.themeNames.indexOf(themeManager.getPreviewTheme());
|
|
286
|
+
if (currentIndex > 0) {
|
|
287
|
+
const themeNames = Object.keys(themes_1.themes);
|
|
288
|
+
stateManager.previewTheme(themeNames[currentIndex - 1]);
|
|
289
|
+
}
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case 'theme_navigate_down': {
|
|
293
|
+
const themeManager = stateManager.getThemeManager();
|
|
294
|
+
const currentIndex = themes_1.themeNames.indexOf(themeManager.getPreviewTheme());
|
|
295
|
+
if (currentIndex < themes_1.themeNames.length - 1) {
|
|
296
|
+
const themeNames = Object.keys(themes_1.themes);
|
|
297
|
+
stateManager.previewTheme(themeNames[currentIndex + 1]);
|
|
298
|
+
}
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case 'theme_confirm':
|
|
302
|
+
stateManager.confirmTheme();
|
|
303
|
+
break;
|
|
263
304
|
case 'cancel':
|
|
264
305
|
handleCancel();
|
|
265
306
|
return;
|
|
@@ -269,6 +310,9 @@ class InteractiveUI {
|
|
|
269
310
|
}
|
|
270
311
|
};
|
|
271
312
|
const handleConfirm = (selectedStates) => {
|
|
313
|
+
// Reset terminal colors
|
|
314
|
+
process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
|
|
315
|
+
ui_1.CursorUtils.show();
|
|
272
316
|
// Clean up listeners
|
|
273
317
|
if (process.stdin.setRawMode) {
|
|
274
318
|
process.stdin.setRawMode(false);
|
|
@@ -279,6 +323,9 @@ class InteractiveUI {
|
|
|
279
323
|
resolve(selectedStates);
|
|
280
324
|
};
|
|
281
325
|
const handleCancel = () => {
|
|
326
|
+
// Reset terminal colors
|
|
327
|
+
process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
|
|
328
|
+
ui_1.CursorUtils.show();
|
|
282
329
|
// Clean up listeners
|
|
283
330
|
if (process.stdin.setRawMode) {
|
|
284
331
|
process.stdin.setRawMode(false);
|
|
@@ -291,16 +338,39 @@ class InteractiveUI {
|
|
|
291
338
|
const inputHandler = new ui_1.InputHandler(stateManager, handleAction, handleConfirm, handleCancel);
|
|
292
339
|
const renderInterface = () => {
|
|
293
340
|
const uiState = stateManager.getUIState();
|
|
294
|
-
|
|
341
|
+
const filteredStates = stateManager.getFilteredStates(states);
|
|
342
|
+
// Apply terminal background color
|
|
343
|
+
const bgCode = (0, themes_colors_1.getTerminalBgColorCode)();
|
|
344
|
+
process.stdout.write(bgCode);
|
|
345
|
+
if (uiState.forceFullRender) {
|
|
295
346
|
console.clear();
|
|
347
|
+
ui_1.CursorUtils.hide();
|
|
296
348
|
}
|
|
297
349
|
else {
|
|
298
|
-
|
|
299
|
-
|
|
350
|
+
ui_1.CursorUtils.moveToHome();
|
|
351
|
+
}
|
|
352
|
+
// If theme modal is open, render only the theme selector
|
|
353
|
+
if (uiState.showThemeModal) {
|
|
354
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
355
|
+
const terminalHeight = this.getTerminalHeight();
|
|
356
|
+
const themeManager = stateManager.getThemeManager();
|
|
357
|
+
// Render header
|
|
358
|
+
const headerLines = [];
|
|
359
|
+
headerLines.push(' ' + chalk_1.default.bold.magenta('🚀 inup'));
|
|
360
|
+
headerLines.push('');
|
|
361
|
+
headerLines.push(' ' +
|
|
362
|
+
chalk_1.default.bold.white('T ') +
|
|
363
|
+
chalk_1.default.gray('/ Esc Exit theme selector'));
|
|
364
|
+
headerLines.push('');
|
|
365
|
+
headerLines.forEach((line) => console.log(line));
|
|
366
|
+
const modalLines = this.renderer.renderThemeSelectorModal(themeManager.getCurrentTheme(), themeManager.getPreviewTheme(), terminalWidth, terminalHeight);
|
|
367
|
+
modalLines.forEach((line) => console.log(line));
|
|
368
|
+
// Clear any remaining lines from previous render
|
|
369
|
+
ui_1.CursorUtils.clearToEndOfScreen();
|
|
370
|
+
stateManager.markRendered([]);
|
|
300
371
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const selectedState = states[uiState.infoModalRow];
|
|
372
|
+
else if (uiState.showInfoModal && uiState.infoModalRow >= 0 && uiState.infoModalRow < filteredStates.length) {
|
|
373
|
+
const selectedState = filteredStates[uiState.infoModalRow];
|
|
304
374
|
const terminalWidth = process.stdout.columns || 80;
|
|
305
375
|
const terminalHeight = this.getTerminalHeight();
|
|
306
376
|
// Render header
|
|
@@ -323,20 +393,21 @@ class InteractiveUI {
|
|
|
323
393
|
modalLines.forEach((line) => console.log(line));
|
|
324
394
|
}
|
|
325
395
|
// Clear any remaining lines from previous render
|
|
326
|
-
|
|
396
|
+
ui_1.CursorUtils.clearToEndOfScreen();
|
|
327
397
|
stateManager.markRendered([]);
|
|
328
398
|
}
|
|
329
399
|
else {
|
|
330
400
|
// Normal list view (flat rendering - no grouping)
|
|
331
|
-
const
|
|
401
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
402
|
+
const lines = this.renderer.renderInterface(filteredStates, uiState.currentRow, uiState.scrollOffset, uiState.maxVisibleItems, uiState.forceFullRender, [], // No renderable items - use flat rendering
|
|
332
403
|
dependencyTypeLabel, // Show which dependency type we're upgrading
|
|
333
|
-
this.packageManager // Pass package manager info for header
|
|
334
|
-
);
|
|
404
|
+
this.packageManager, // Pass package manager info for header
|
|
405
|
+
uiState.filterMode, uiState.filterQuery, states.length, terminalWidth);
|
|
335
406
|
// Print all lines
|
|
336
407
|
lines.forEach((line) => console.log(line));
|
|
337
408
|
// Clear any remaining lines from previous render
|
|
338
|
-
if (!uiState.
|
|
339
|
-
|
|
409
|
+
if (!uiState.forceFullRender) {
|
|
410
|
+
ui_1.CursorUtils.clearToEndOfScreen();
|
|
340
411
|
}
|
|
341
412
|
stateManager.markRendered(lines);
|
|
342
413
|
}
|
|
@@ -368,6 +439,8 @@ class InteractiveUI {
|
|
|
368
439
|
renderInterface();
|
|
369
440
|
}
|
|
370
441
|
catch (error) {
|
|
442
|
+
// Reset terminal colors
|
|
443
|
+
process.stdout.write((0, themes_colors_1.getTerminalResetCode)());
|
|
371
444
|
// Fallback to simple interface if raw mode fails
|
|
372
445
|
console.log(chalk_1.default.yellow('Raw mode not available, using fallback interface...'));
|
|
373
446
|
resolve(states);
|
|
@@ -387,6 +460,7 @@ class InteractiveUI {
|
|
|
387
460
|
if (process.stdin.setRawMode) {
|
|
388
461
|
process.stdin.setRawMode(true);
|
|
389
462
|
}
|
|
463
|
+
ui_1.CursorUtils.hide();
|
|
390
464
|
process.stdin.resume();
|
|
391
465
|
process.stdin.on('keypress', (str, key) => inputHandler.handleKeypress(str, key));
|
|
392
466
|
}
|
|
@@ -38,15 +38,16 @@ exports.clearJsdelivrPackageCache = clearJsdelivrPackageCache;
|
|
|
38
38
|
exports.closeJsdelivrPool = closeJsdelivrPool;
|
|
39
39
|
const undici_1 = require("undici");
|
|
40
40
|
const semver = __importStar(require("semver"));
|
|
41
|
-
const
|
|
41
|
+
const config_1 = require("../config");
|
|
42
42
|
const npm_registry_1 = require("./npm-registry");
|
|
43
43
|
// Create a persistent connection pool for jsDelivr CDN with optimal settings
|
|
44
44
|
// This enables connection reuse and HTTP/1.1 keep-alive for blazing fast requests
|
|
45
45
|
const jsdelivrPool = new undici_1.Pool('https://cdn.jsdelivr.net', {
|
|
46
|
-
connections:
|
|
46
|
+
connections: config_1.MAX_CONCURRENT_REQUESTS, // Maximum concurrent connections
|
|
47
47
|
pipelining: 10, // Enable request pipelining for even better performance
|
|
48
|
-
keepAliveTimeout:
|
|
49
|
-
keepAliveMaxTimeout:
|
|
48
|
+
keepAliveTimeout: config_1.REQUEST_TIMEOUT, // Keep connections alive for 60 seconds
|
|
49
|
+
keepAliveMaxTimeout: config_1.REQUEST_TIMEOUT, // Maximum keep-alive timeout
|
|
50
|
+
connectTimeout: config_1.REQUEST_TIMEOUT, // 60 seconds connect timeout
|
|
50
51
|
});
|
|
51
52
|
const packageCache = new Map();
|
|
52
53
|
/**
|
|
@@ -58,15 +59,15 @@ const packageCache = new Map();
|
|
|
58
59
|
*/
|
|
59
60
|
async function fetchPackageJsonFromJsdelivr(packageName, versionTag) {
|
|
60
61
|
try {
|
|
61
|
-
const url = `${
|
|
62
|
+
const url = `${config_1.JSDELIVR_CDN_URL}/${encodeURIComponent(packageName)}@${versionTag}/package.json`;
|
|
62
63
|
const { statusCode, body } = await (0, undici_1.request)(url, {
|
|
63
64
|
dispatcher: jsdelivrPool,
|
|
64
65
|
method: 'GET',
|
|
65
66
|
headers: {
|
|
66
67
|
accept: 'application/json',
|
|
67
68
|
},
|
|
68
|
-
headersTimeout:
|
|
69
|
-
bodyTimeout:
|
|
69
|
+
headersTimeout: config_1.REQUEST_TIMEOUT,
|
|
70
|
+
bodyTimeout: config_1.REQUEST_TIMEOUT,
|
|
70
71
|
});
|
|
71
72
|
if (statusCode !== 200) {
|
|
72
73
|
// Consume body to prevent memory leaks
|
|
@@ -84,7 +85,7 @@ async function fetchPackageJsonFromJsdelivr(packageName, versionTag) {
|
|
|
84
85
|
}
|
|
85
86
|
/**
|
|
86
87
|
* Fetches package data from jsdelivr CDN with fallback to npm registry.
|
|
87
|
-
* Makes simultaneous requests for @latest
|
|
88
|
+
* Makes simultaneous requests for @latest, @major version, and current version.
|
|
88
89
|
* @param packageName - The npm package name
|
|
89
90
|
* @param currentVersion - The current version to extract major from (optional)
|
|
90
91
|
* @returns Package data with latest version and all versions
|
|
@@ -92,26 +93,31 @@ async function fetchPackageJsonFromJsdelivr(packageName, versionTag) {
|
|
|
92
93
|
async function fetchPackageFromJsdelivr(packageName, currentVersion) {
|
|
93
94
|
// Check cache first
|
|
94
95
|
const cached = packageCache.get(packageName);
|
|
95
|
-
if (cached && Date.now() - cached.timestamp <
|
|
96
|
+
if (cached && Date.now() - cached.timestamp < config_1.CACHE_TTL) {
|
|
96
97
|
return cached.data;
|
|
97
98
|
}
|
|
98
99
|
try {
|
|
100
|
+
// Coerce the current version in case it's a range like ^1.1.5
|
|
101
|
+
const coercedVersion = currentVersion ? semver.coerce(currentVersion)?.version : null;
|
|
99
102
|
// Determine major version from current version if provided
|
|
100
|
-
// Need to coerce the version first in case it's a range like ^1.1.5
|
|
101
103
|
const majorVersion = currentVersion
|
|
102
104
|
? semver.major(semver.coerce(currentVersion) || '0.0.0').toString()
|
|
103
105
|
: null;
|
|
104
|
-
// Prepare requests: always fetch @latest,
|
|
106
|
+
// Prepare requests: always fetch @latest, @major if we have a current version, and @currentVersion
|
|
105
107
|
const requests = [
|
|
106
108
|
fetchPackageJsonFromJsdelivr(packageName, 'latest'),
|
|
107
109
|
];
|
|
108
110
|
if (majorVersion) {
|
|
109
111
|
requests.push(fetchPackageJsonFromJsdelivr(packageName, majorVersion));
|
|
110
112
|
}
|
|
113
|
+
if (coercedVersion) {
|
|
114
|
+
requests.push(fetchPackageJsonFromJsdelivr(packageName, coercedVersion));
|
|
115
|
+
}
|
|
111
116
|
// Execute all requests simultaneously
|
|
112
117
|
const results = await Promise.all(requests);
|
|
113
118
|
const latestResult = results[0];
|
|
114
119
|
const majorResult = results[1];
|
|
120
|
+
const currentResult = results[2];
|
|
115
121
|
if (!latestResult) {
|
|
116
122
|
// jsdelivr doesn't have this package, fallback to npm registry
|
|
117
123
|
const npmData = await (0, npm_registry_1.getAllPackageData)([packageName]);
|
|
@@ -124,40 +130,14 @@ async function fetchPackageFromJsdelivr(packageName, currentVersion) {
|
|
|
124
130
|
return data;
|
|
125
131
|
}
|
|
126
132
|
const latestVersion = latestResult.version;
|
|
127
|
-
// If we have a major version result, we can build a minimal version list
|
|
128
|
-
// This is much faster than fetching all versions from npm
|
|
129
|
-
if (majorResult) {
|
|
130
|
-
const allVersions = [latestVersion];
|
|
131
|
-
// Add the major version result if different from latest
|
|
132
|
-
if (majorResult.version !== latestVersion) {
|
|
133
|
-
allVersions.push(majorResult.version);
|
|
134
|
-
}
|
|
135
|
-
// Add the current version if it's valid and not already in the list
|
|
136
|
-
if (currentVersion && semver.valid(currentVersion)) {
|
|
137
|
-
const coerced = semver.coerce(currentVersion);
|
|
138
|
-
if (coerced && !allVersions.includes(coerced.version)) {
|
|
139
|
-
allVersions.push(coerced.version);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
const result = {
|
|
143
|
-
latestVersion,
|
|
144
|
-
allVersions: allVersions.sort(semver.rcompare),
|
|
145
|
-
};
|
|
146
|
-
// Cache the result
|
|
147
|
-
packageCache.set(packageName, {
|
|
148
|
-
data: result,
|
|
149
|
-
timestamp: Date.now(),
|
|
150
|
-
});
|
|
151
|
-
return result;
|
|
152
|
-
}
|
|
153
|
-
// No major version provided, just return latest with minimal version list
|
|
154
133
|
const allVersions = [latestVersion];
|
|
155
|
-
// Add the
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
134
|
+
// Add the major version result if different from latest
|
|
135
|
+
if (majorResult && majorResult.version !== latestVersion) {
|
|
136
|
+
allVersions.push(majorResult.version);
|
|
137
|
+
}
|
|
138
|
+
// Add the current version result if different from latest and major
|
|
139
|
+
if (currentResult && !allVersions.includes(currentResult.version)) {
|
|
140
|
+
allVersions.push(currentResult.version);
|
|
161
141
|
}
|
|
162
142
|
const result = {
|
|
163
143
|
latestVersion,
|