inup 1.4.12 → 1.5.1
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/LICENSE +21 -0
- package/README.md +39 -30
- package/dist/cli.js +29 -14
- package/dist/config/project-config.js +6 -0
- package/dist/core/package-detector.js +3 -2
- package/dist/core/upgrade-runner.js +6 -3
- package/dist/features/changelog/clients/github-client.js +134 -0
- package/dist/features/changelog/clients/npm-registry-client.js +53 -0
- package/dist/features/changelog/index.js +19 -0
- package/dist/features/changelog/parsers/changelog-parser.js +68 -0
- package/dist/features/changelog/parsers/github-release-html-parser.js +61 -0
- package/dist/features/changelog/parsers/package-metadata.js +34 -0
- package/dist/features/changelog/parsers/repository-ref.js +26 -0
- package/dist/features/changelog/services/changelog-service.js +30 -0
- package/dist/features/changelog/services/package-metadata-service.js +108 -0
- package/dist/features/changelog/services/release-notes-service.js +180 -0
- package/dist/features/changelog/types/changelog.types.js +3 -0
- package/dist/interactive-ui.js +242 -114
- package/dist/services/background-audit.js +60 -0
- package/dist/services/index.js +3 -1
- package/dist/services/vulnerability-checker.js +133 -0
- package/dist/ui/controllers/index.js +8 -0
- package/dist/ui/controllers/package-info-modal-controller.js +237 -0
- package/dist/ui/controllers/vulnerability-audit-controller.js +82 -0
- package/dist/ui/index.js +3 -0
- package/dist/ui/input-handler.js +40 -9
- package/dist/ui/modal/index.js +22 -0
- package/dist/ui/modal/layout.js +84 -0
- package/dist/ui/modal/package-info-sections.js +327 -0
- package/dist/ui/modal/package-info.js +147 -0
- package/dist/ui/modal/theme-selector.js +46 -0
- package/dist/ui/modal/types.js +3 -0
- package/dist/ui/presenters/index.js +11 -0
- package/dist/ui/presenters/vulnerability.js +76 -0
- package/dist/ui/renderer/index.js +9 -11
- package/dist/ui/renderer/package-list.js +135 -62
- package/dist/ui/state/filter-manager.js +17 -2
- package/dist/ui/state/modal-manager.js +48 -6
- package/dist/ui/state/state-manager.js +42 -7
- package/dist/ui/utils/cursor.js +18 -0
- package/dist/ui/utils/index.js +8 -1
- package/dist/ui/utils/terminal-input.js +125 -0
- package/dist/ui/utils/text.js +75 -0
- package/dist/ui/utils/version.js +3 -2
- package/dist/utils/git.js +33 -0
- package/dist/utils/index.js +1 -0
- package/package.json +22 -19
- package/dist/services/changelog-fetcher.js +0 -215
- package/dist/ui/renderer/modal.js +0 -190
- package/dist/ui/renderer/theme-selector.js +0 -83
|
@@ -11,6 +11,11 @@ exports.renderPackagesTable = renderPackagesTable;
|
|
|
11
11
|
const chalk_1 = __importDefault(require("chalk"));
|
|
12
12
|
const utils_1 = require("../utils");
|
|
13
13
|
const themes_colors_1 = require("../themes-colors");
|
|
14
|
+
const vulnerability_1 = require("../presenters/vulnerability");
|
|
15
|
+
function padLineToWidth(line, terminalWidth) {
|
|
16
|
+
const padding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(line));
|
|
17
|
+
return line + ' '.repeat(padding);
|
|
18
|
+
}
|
|
14
19
|
/**
|
|
15
20
|
* Get type badge for dependency type (theme-aware)
|
|
16
21
|
*/
|
|
@@ -34,7 +39,7 @@ function getTypeBadge(type) {
|
|
|
34
39
|
* @param isCurrentRow Whether this is the current/highlighted row
|
|
35
40
|
* @param terminalWidth Terminal width for dynamic truncation (default 80)
|
|
36
41
|
*/
|
|
37
|
-
function renderPackageLine(state, index, isCurrentRow, terminalWidth = 80) {
|
|
42
|
+
function renderPackageLine(state, index, isCurrentRow, terminalWidth = 80, options = {}) {
|
|
38
43
|
const prefix = isCurrentRow ? (0, themes_colors_1.getThemeColor)('success')('❯ ') : ' ';
|
|
39
44
|
// Package name with special formatting for scoped packages (@author/package)
|
|
40
45
|
let packageName;
|
|
@@ -44,14 +49,18 @@ function renderPackageLine(state, index, isCurrentRow, terminalWidth = 80) {
|
|
|
44
49
|
const author = parts[0]; // @author
|
|
45
50
|
const packagePart = parts.slice(1).join('/'); // package name
|
|
46
51
|
if (isCurrentRow) {
|
|
47
|
-
packageName =
|
|
52
|
+
packageName =
|
|
53
|
+
chalk_1.default.bold((0, themes_colors_1.getThemeColor)('packageAuthor')(author)) +
|
|
54
|
+
(0, themes_colors_1.getThemeColor)('packageName')('/' + packagePart);
|
|
48
55
|
}
|
|
49
56
|
else {
|
|
50
57
|
packageName = chalk_1.default.bold.white(author) + chalk_1.default.white('/' + packagePart);
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
60
|
else {
|
|
54
|
-
packageName = isCurrentRow
|
|
61
|
+
packageName = isCurrentRow
|
|
62
|
+
? (0, themes_colors_1.getThemeColor)('packageName')(state.name)
|
|
63
|
+
: chalk_1.default.white(state.name);
|
|
55
64
|
}
|
|
56
65
|
}
|
|
57
66
|
else {
|
|
@@ -130,18 +139,26 @@ function renderPackageLine(state, index, isCurrentRow, terminalWidth = 80) {
|
|
|
130
139
|
const displayName = truncatedName !== state.name ? truncatedName : packageName;
|
|
131
140
|
// Package name with dashes and badge at the end
|
|
132
141
|
const typeBadge = getTypeBadge(state.type);
|
|
142
|
+
const shouldShowVulnerability = (0, vulnerability_1.shouldDisplayVulnerabilityForDependency)(state.type, options);
|
|
143
|
+
const vulnBadge = shouldShowVulnerability ? (0, vulnerability_1.getVulnerabilityBadge)(state.vulnerability) : '';
|
|
144
|
+
const vulnBadgeWidth = vulnBadge ? utils_1.VersionUtils.getVisualLength(vulnBadge) + 1 : 0; // +1 for space
|
|
133
145
|
const nameLength = utils_1.VersionUtils.getVisualLength(truncatedName);
|
|
134
|
-
const namePadding = Math.max(0, packageNameWidth - nameLength - 1 - badgeWidth); // -1 for space after package name
|
|
135
|
-
const nameDashes = shouldShowDashes(namePadding)
|
|
136
|
-
|
|
146
|
+
const namePadding = Math.max(0, packageNameWidth - nameLength - 1 - badgeWidth - vulnBadgeWidth); // -1 for space after package name
|
|
147
|
+
const nameDashes = shouldShowDashes(namePadding)
|
|
148
|
+
? dashColor('-').repeat(namePadding)
|
|
149
|
+
: ' '.repeat(namePadding);
|
|
150
|
+
// Place badges at the end of dashes: name ------⚠[D]
|
|
151
|
+
const vulnSuffix = vulnBadge ? ` ${vulnBadge}` : '';
|
|
137
152
|
const packageNameSection = typeBadge
|
|
138
|
-
? `${displayName} ${nameDashes}${typeBadge}`
|
|
139
|
-
: `${displayName} ${nameDashes}`;
|
|
153
|
+
? `${displayName} ${nameDashes}${vulnSuffix}${typeBadge}`
|
|
154
|
+
: `${displayName} ${nameDashes}${vulnSuffix}`;
|
|
140
155
|
// Current version section with dashes only if needed
|
|
141
156
|
const currentSection = `${currentDot} ${currentVersion}`;
|
|
142
157
|
const currentSectionLength = utils_1.VersionUtils.getVisualLength(currentSection) + 1; // +1 for space before padding
|
|
143
158
|
const currentPadding = Math.max(0, currentColumnWidth - currentSectionLength);
|
|
144
|
-
const currentPaddingText = shouldShowDashes(currentPadding)
|
|
159
|
+
const currentPaddingText = shouldShowDashes(currentPadding)
|
|
160
|
+
? dashColor('-').repeat(currentPadding)
|
|
161
|
+
: ' '.repeat(currentPadding);
|
|
145
162
|
const currentWithPadding = currentSection + ' ' + currentPaddingText;
|
|
146
163
|
// Range version section with dashes only if needed
|
|
147
164
|
let rangeSection = '';
|
|
@@ -149,7 +166,9 @@ function renderPackageLine(state, index, isCurrentRow, terminalWidth = 80) {
|
|
|
149
166
|
rangeSection = `${rangeDot} ${rangeVersionText}`;
|
|
150
167
|
const rangeSectionLength = utils_1.VersionUtils.getVisualLength(rangeSection) + 1; // +1 for space before padding
|
|
151
168
|
const rangePadding = Math.max(0, rangeColumnWidth - rangeSectionLength);
|
|
152
|
-
const rangePaddingText = shouldShowDashes(rangePadding)
|
|
169
|
+
const rangePaddingText = shouldShowDashes(rangePadding)
|
|
170
|
+
? dashColor('-').repeat(rangePadding)
|
|
171
|
+
: ' '.repeat(rangePadding);
|
|
153
172
|
rangeSection += ' ' + rangePaddingText;
|
|
154
173
|
}
|
|
155
174
|
else {
|
|
@@ -162,7 +181,9 @@ function renderPackageLine(state, index, isCurrentRow, terminalWidth = 80) {
|
|
|
162
181
|
latestSection = `${latestDot} ${latestVersionText}`;
|
|
163
182
|
const latestSectionLength = utils_1.VersionUtils.getVisualLength(latestSection) + 1; // +1 for space before padding
|
|
164
183
|
const latestPadding = Math.max(0, latestColumnWidth - latestSectionLength);
|
|
165
|
-
const latestPaddingText = shouldShowDashes(latestPadding)
|
|
184
|
+
const latestPaddingText = shouldShowDashes(latestPadding)
|
|
185
|
+
? dashColor('-').repeat(latestPadding)
|
|
186
|
+
: ' '.repeat(latestPadding);
|
|
166
187
|
latestSection += ' ' + latestPaddingText;
|
|
167
188
|
}
|
|
168
189
|
else {
|
|
@@ -189,7 +210,7 @@ function renderSpacer() {
|
|
|
189
210
|
/**
|
|
190
211
|
* Render the main interface
|
|
191
212
|
*/
|
|
192
|
-
function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, activeFilterLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter, terminalWidth = 80, loadingProgress) {
|
|
213
|
+
function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, activeFilterLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter, terminalWidth = 80, loadingProgress, auditProgress, options = {}) {
|
|
193
214
|
const output = [];
|
|
194
215
|
// Header section (same for initial and incremental render)
|
|
195
216
|
if (packageManager) {
|
|
@@ -204,20 +225,33 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
204
225
|
// Each character in "inup" gets a different color
|
|
205
226
|
const inupColors = [chalk_1.default.red, chalk_1.default.yellow, chalk_1.default.blue, chalk_1.default.magenta];
|
|
206
227
|
const coloredInup = inupColors.map((color, i) => color.bold('inup'[i])).join('');
|
|
207
|
-
const headerLine = ' ' +
|
|
228
|
+
const headerLine = ' ' +
|
|
229
|
+
chalk_1.default.bold(pmColor('🚀')) +
|
|
230
|
+
' ' +
|
|
231
|
+
coloredInup +
|
|
232
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')(` (${packageManager.displayName})`);
|
|
208
233
|
// Show filter state (always show, including "All")
|
|
209
234
|
const fullHeaderLine = activeFilterLabel
|
|
210
|
-
? headerLine +
|
|
235
|
+
? headerLine +
|
|
236
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')(' - ') +
|
|
237
|
+
(0, themes_colors_1.getThemeColor)('primary')(activeFilterLabel)
|
|
211
238
|
: headerLine;
|
|
212
239
|
// Pad to terminal width to clear any leftover characters
|
|
213
240
|
const headerPadding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(fullHeaderLine));
|
|
214
241
|
output.push(fullHeaderLine + ' '.repeat(headerPadding));
|
|
215
242
|
}
|
|
216
243
|
else {
|
|
217
|
-
const headerLine = ' ' +
|
|
244
|
+
const headerLine = ' ' +
|
|
245
|
+
chalk_1.default.bold.blue('🚀 ') +
|
|
246
|
+
chalk_1.default.bold.red('i') +
|
|
247
|
+
chalk_1.default.bold.yellow('n') +
|
|
248
|
+
chalk_1.default.bold.blue('u') +
|
|
249
|
+
chalk_1.default.bold.magenta('p');
|
|
218
250
|
// Show filter state (always show, including "All")
|
|
219
251
|
const fullHeaderLine = activeFilterLabel
|
|
220
|
-
? headerLine +
|
|
252
|
+
? headerLine +
|
|
253
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')(' - ') +
|
|
254
|
+
(0, themes_colors_1.getThemeColor)('primary')(activeFilterLabel)
|
|
221
255
|
: headerLine;
|
|
222
256
|
// Pad to terminal width to clear any leftover characters
|
|
223
257
|
const headerPadding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(fullHeaderLine));
|
|
@@ -226,14 +260,20 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
226
260
|
output.push('');
|
|
227
261
|
if (filterMode) {
|
|
228
262
|
// Show filter input with cursor when actively filtering
|
|
229
|
-
const filterDisplay = ' ' +
|
|
263
|
+
const filterDisplay = ' ' +
|
|
264
|
+
chalk_1.default.bold.white('Search: ') +
|
|
265
|
+
(0, themes_colors_1.getThemeColor)('primary')(filterQuery || '') +
|
|
266
|
+
(0, themes_colors_1.getThemeColor)('border')('█');
|
|
230
267
|
// Pad to terminal width to clear any leftover characters from backspace
|
|
231
268
|
const padding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(filterDisplay));
|
|
232
269
|
output.push(filterDisplay + ' '.repeat(padding));
|
|
233
270
|
}
|
|
234
271
|
else if (filterQuery) {
|
|
235
272
|
// Show applied filter when not in filter mode but filter is active
|
|
236
|
-
const filterDisplay = ' ' +
|
|
273
|
+
const filterDisplay = ' ' +
|
|
274
|
+
chalk_1.default.bold.white('Search: ') +
|
|
275
|
+
(0, themes_colors_1.getThemeColor)('primary')(filterQuery) +
|
|
276
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')(' (press / to edit)');
|
|
237
277
|
const padding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(filterDisplay));
|
|
238
278
|
output.push(filterDisplay + ' '.repeat(padding));
|
|
239
279
|
}
|
|
@@ -255,6 +295,9 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
255
295
|
chalk_1.default.bold.white('I ') +
|
|
256
296
|
(0, themes_colors_1.getThemeColor)('textSecondary')('Info') +
|
|
257
297
|
' ' +
|
|
298
|
+
chalk_1.default.bold.white('S ') +
|
|
299
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Vulnerable') +
|
|
300
|
+
' ' +
|
|
258
301
|
chalk_1.default.bold.white('M ') +
|
|
259
302
|
(0, themes_colors_1.getThemeColor)('textSecondary')('Minor') +
|
|
260
303
|
' ' +
|
|
@@ -275,67 +318,97 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
275
318
|
if (filterMode) {
|
|
276
319
|
// In filter mode, show Enter to apply and ESC to clear
|
|
277
320
|
if (totalPackages === 0) {
|
|
278
|
-
statusLine =
|
|
279
|
-
'
|
|
280
|
-
|
|
321
|
+
statusLine =
|
|
322
|
+
(0, themes_colors_1.getThemeColor)('warning')(`No matches found`) +
|
|
323
|
+
' ' +
|
|
324
|
+
chalk_1.default.bold.white('Esc ') +
|
|
325
|
+
chalk_1.default.gray('Clear');
|
|
281
326
|
}
|
|
282
327
|
else if (totalVisualItems > maxVisibleItems) {
|
|
283
|
-
statusLine =
|
|
284
|
-
'
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
328
|
+
statusLine =
|
|
329
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} matches`) +
|
|
330
|
+
' ' +
|
|
331
|
+
chalk_1.default.bold.white('Enter ') +
|
|
332
|
+
chalk_1.default.gray('Apply') +
|
|
333
|
+
' ' +
|
|
334
|
+
chalk_1.default.bold.white('Esc ') +
|
|
335
|
+
chalk_1.default.gray('Clear');
|
|
288
336
|
}
|
|
289
337
|
else {
|
|
290
|
-
statusLine =
|
|
291
|
-
'
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
338
|
+
statusLine =
|
|
339
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')(`Showing all ${chalk_1.default.white(totalPackages)} matches`) +
|
|
340
|
+
' ' +
|
|
341
|
+
chalk_1.default.bold.white('Enter ') +
|
|
342
|
+
chalk_1.default.gray('Apply') +
|
|
343
|
+
' ' +
|
|
344
|
+
chalk_1.default.bold.white('Esc ') +
|
|
345
|
+
chalk_1.default.gray('Clear');
|
|
295
346
|
}
|
|
296
347
|
}
|
|
297
348
|
else if (totalPackages < totalBeforeFilter) {
|
|
298
349
|
// Filter is applied but not in filter mode
|
|
299
350
|
if (totalVisualItems > maxVisibleItems) {
|
|
300
|
-
statusLine =
|
|
301
|
-
'
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
351
|
+
statusLine =
|
|
352
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} matches`) +
|
|
353
|
+
' ' +
|
|
354
|
+
chalk_1.default.bold.white('D/P/O ') +
|
|
355
|
+
chalk_1.default.gray('Filter') +
|
|
356
|
+
' ' +
|
|
357
|
+
chalk_1.default.bold.white('M ') +
|
|
358
|
+
chalk_1.default.gray('Minor') +
|
|
359
|
+
' ' +
|
|
360
|
+
chalk_1.default.bold.white('L ') +
|
|
361
|
+
chalk_1.default.gray('All') +
|
|
362
|
+
' ' +
|
|
363
|
+
chalk_1.default.bold.white('U ') +
|
|
364
|
+
chalk_1.default.gray('None') +
|
|
365
|
+
' ' +
|
|
366
|
+
chalk_1.default.bold.white('Esc ') +
|
|
367
|
+
chalk_1.default.gray('Clear');
|
|
311
368
|
}
|
|
312
369
|
else {
|
|
313
|
-
statusLine =
|
|
314
|
-
'
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
370
|
+
statusLine =
|
|
371
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')(`Showing all ${chalk_1.default.white(totalPackages)} matches`) +
|
|
372
|
+
' ' +
|
|
373
|
+
chalk_1.default.bold.white('D/P/O ') +
|
|
374
|
+
chalk_1.default.gray('Filter') +
|
|
375
|
+
' ' +
|
|
376
|
+
chalk_1.default.bold.white('M ') +
|
|
377
|
+
chalk_1.default.gray('Minor') +
|
|
378
|
+
' ' +
|
|
379
|
+
chalk_1.default.bold.white('L ') +
|
|
380
|
+
chalk_1.default.gray('All') +
|
|
381
|
+
' ' +
|
|
382
|
+
chalk_1.default.bold.white('U ') +
|
|
383
|
+
chalk_1.default.gray('None') +
|
|
384
|
+
' ' +
|
|
385
|
+
chalk_1.default.bold.white('Esc ') +
|
|
386
|
+
chalk_1.default.gray('Clear');
|
|
324
387
|
}
|
|
325
388
|
}
|
|
326
389
|
else {
|
|
327
390
|
// No filter applied
|
|
328
391
|
if (totalVisualItems > maxVisibleItems) {
|
|
329
|
-
statusLine =
|
|
330
|
-
|
|
331
|
-
|
|
392
|
+
statusLine =
|
|
393
|
+
chalk_1.default.gray(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} packages`) +
|
|
394
|
+
' ' +
|
|
395
|
+
chalk_1.default.bold.white('Enter ') +
|
|
396
|
+
chalk_1.default.gray('Confirm');
|
|
332
397
|
}
|
|
333
398
|
else {
|
|
334
|
-
statusLine =
|
|
335
|
-
|
|
336
|
-
|
|
399
|
+
statusLine =
|
|
400
|
+
chalk_1.default.gray(`Showing all ${chalk_1.default.white(totalPackages)} packages`) +
|
|
401
|
+
' ' +
|
|
402
|
+
chalk_1.default.bold.white('Enter ') +
|
|
403
|
+
chalk_1.default.gray('Confirm');
|
|
337
404
|
}
|
|
338
405
|
}
|
|
406
|
+
if (auditProgress && auditProgress.total > 0) {
|
|
407
|
+
const auditLabel = auditProgress.isRunning
|
|
408
|
+
? `Audit ${auditProgress.completed}/${auditProgress.total}`
|
|
409
|
+
: `Audit ${auditProgress.total}/${auditProgress.total}`;
|
|
410
|
+
statusLine += ' ' + (0, themes_colors_1.getThemeColor)('textSecondary')(auditLabel);
|
|
411
|
+
}
|
|
339
412
|
// Pad status line to terminal width to clear any leftover characters
|
|
340
413
|
const statusLineFull = ' ' + statusLine;
|
|
341
414
|
const statusPadding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(statusLineFull));
|
|
@@ -353,7 +426,7 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
353
426
|
output.push(renderSpacer());
|
|
354
427
|
}
|
|
355
428
|
else if (item.type === 'package') {
|
|
356
|
-
const line = renderPackageLine(item.state, item.originalIndex, item.originalIndex === currentRow, terminalWidth);
|
|
429
|
+
const line = renderPackageLine(item.state, item.originalIndex, item.originalIndex === currentRow, terminalWidth, options);
|
|
357
430
|
output.push(line);
|
|
358
431
|
}
|
|
359
432
|
}
|
|
@@ -361,7 +434,7 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
361
434
|
else {
|
|
362
435
|
// Fallback to flat rendering (legacy mode)
|
|
363
436
|
for (let i = scrollOffset; i < Math.min(scrollOffset + maxVisibleItems, states.length); i++) {
|
|
364
|
-
const line = renderPackageLine(states[i], i, i === currentRow, terminalWidth);
|
|
437
|
+
const line = renderPackageLine(states[i], i, i === currentRow, terminalWidth, options);
|
|
365
438
|
output.push(line);
|
|
366
439
|
}
|
|
367
440
|
}
|
|
@@ -374,7 +447,7 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
374
447
|
const loadingPadding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(loadingLine));
|
|
375
448
|
output.push(loadingLine + ' '.repeat(loadingPadding));
|
|
376
449
|
}
|
|
377
|
-
return output;
|
|
450
|
+
return output.map((line) => padLineToWidth(line, terminalWidth));
|
|
378
451
|
}
|
|
379
452
|
/**
|
|
380
453
|
* Render packages table
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FilterManager = void 0;
|
|
4
|
+
const vulnerability_1 = require("../presenters/vulnerability");
|
|
4
5
|
class FilterManager {
|
|
5
6
|
constructor() {
|
|
6
7
|
this.state = {
|
|
@@ -10,6 +11,7 @@ class FilterManager {
|
|
|
10
11
|
showDevDependencies: true,
|
|
11
12
|
showPeerDependencies: true,
|
|
12
13
|
showOptionalDependencies: true,
|
|
14
|
+
showOnlyVulnerable: false,
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
17
|
getState() {
|
|
@@ -60,6 +62,12 @@ class FilterManager {
|
|
|
60
62
|
break;
|
|
61
63
|
}
|
|
62
64
|
}
|
|
65
|
+
toggleVulnerableFilter() {
|
|
66
|
+
this.state.showOnlyVulnerable = !this.state.showOnlyVulnerable;
|
|
67
|
+
}
|
|
68
|
+
isVulnerableFilterActive() {
|
|
69
|
+
return this.state.showOnlyVulnerable;
|
|
70
|
+
}
|
|
63
71
|
getActiveFilterLabel() {
|
|
64
72
|
const activeTypes = [];
|
|
65
73
|
if (this.state.showDependencies)
|
|
@@ -72,9 +80,10 @@ class FilterManager {
|
|
|
72
80
|
activeTypes.push('Optional');
|
|
73
81
|
if (activeTypes.length === 0)
|
|
74
82
|
return 'None';
|
|
75
|
-
|
|
83
|
+
const label = activeTypes.join(', ');
|
|
84
|
+
return this.state.showOnlyVulnerable ? label + ' (vulnerable only)' : label;
|
|
76
85
|
}
|
|
77
|
-
getFilteredStates(allStates) {
|
|
86
|
+
getFilteredStates(allStates, options = {}) {
|
|
78
87
|
let filtered = allStates;
|
|
79
88
|
// Apply text filter
|
|
80
89
|
if (this.state.filterQuery) {
|
|
@@ -96,6 +105,12 @@ class FilterManager {
|
|
|
96
105
|
return true;
|
|
97
106
|
}
|
|
98
107
|
});
|
|
108
|
+
// Apply vulnerability filter
|
|
109
|
+
if (this.state.showOnlyVulnerable) {
|
|
110
|
+
filtered = filtered.filter((state) => (0, vulnerability_1.shouldDisplayVulnerabilityForDependency)(state.type, options) &&
|
|
111
|
+
!!state.vulnerability &&
|
|
112
|
+
state.vulnerability.count > 0);
|
|
113
|
+
}
|
|
99
114
|
return filtered;
|
|
100
115
|
}
|
|
101
116
|
}
|
|
@@ -7,6 +7,8 @@ class ModalManager {
|
|
|
7
7
|
showInfoModal: false,
|
|
8
8
|
infoModalRow: -1,
|
|
9
9
|
isLoadingModalInfo: false,
|
|
10
|
+
infoModalScrollOffset: 0,
|
|
11
|
+
infoModalSessionId: 0,
|
|
10
12
|
};
|
|
11
13
|
}
|
|
12
14
|
getState() {
|
|
@@ -21,24 +23,64 @@ class ModalManager {
|
|
|
21
23
|
isLoading() {
|
|
22
24
|
return this.state.isLoadingModalInfo;
|
|
23
25
|
}
|
|
26
|
+
getScrollOffset() {
|
|
27
|
+
return this.state.infoModalScrollOffset;
|
|
28
|
+
}
|
|
29
|
+
getSessionId() {
|
|
30
|
+
return this.state.infoModalSessionId;
|
|
31
|
+
}
|
|
32
|
+
clampScrollOffset(maxOffset) {
|
|
33
|
+
const nextOffset = Math.max(0, Math.min(this.state.infoModalScrollOffset, maxOffset));
|
|
34
|
+
if (nextOffset === this.state.infoModalScrollOffset) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
this.state.infoModalScrollOffset = nextOffset;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
resetScroll() {
|
|
41
|
+
this.state.infoModalScrollOffset = 0;
|
|
42
|
+
}
|
|
43
|
+
scrollModalUp() {
|
|
44
|
+
if (this.state.infoModalScrollOffset > 0) {
|
|
45
|
+
this.state.infoModalScrollOffset--;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
scrollModalDown(maxOffset) {
|
|
51
|
+
if (this.state.infoModalScrollOffset < maxOffset) {
|
|
52
|
+
this.state.infoModalScrollOffset++;
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
24
57
|
toggleInfoModal(currentRow) {
|
|
25
58
|
if (this.state.showInfoModal) {
|
|
26
59
|
// Close the modal
|
|
27
60
|
this.closeInfoModal();
|
|
61
|
+
return this.state.infoModalSessionId;
|
|
28
62
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
63
|
+
// Open the modal for the current package
|
|
64
|
+
this.state.showInfoModal = true;
|
|
65
|
+
this.state.infoModalRow = currentRow;
|
|
66
|
+
this.state.infoModalScrollOffset = 0;
|
|
67
|
+
this.state.isLoadingModalInfo = false;
|
|
68
|
+
this.state.infoModalSessionId += 1;
|
|
69
|
+
return this.state.infoModalSessionId;
|
|
34
70
|
}
|
|
35
71
|
closeInfoModal() {
|
|
36
72
|
this.state.showInfoModal = false;
|
|
37
73
|
this.state.infoModalRow = -1;
|
|
38
74
|
this.state.isLoadingModalInfo = false;
|
|
75
|
+
this.state.infoModalScrollOffset = 0;
|
|
76
|
+
this.state.infoModalSessionId += 1;
|
|
39
77
|
}
|
|
40
|
-
setModalLoading(isLoading) {
|
|
78
|
+
setModalLoading(isLoading, sessionId) {
|
|
79
|
+
if (sessionId !== undefined && sessionId !== this.state.infoModalSessionId) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
41
82
|
this.state.isLoadingModalInfo = isLoading;
|
|
83
|
+
return true;
|
|
42
84
|
}
|
|
43
85
|
}
|
|
44
86
|
exports.ModalManager = ModalManager;
|
|
@@ -42,6 +42,7 @@ class StateManager {
|
|
|
42
42
|
showInfoModal: modalState.showInfoModal,
|
|
43
43
|
infoModalRow: modalState.infoModalRow,
|
|
44
44
|
isLoadingModalInfo: modalState.isLoadingModalInfo,
|
|
45
|
+
infoModalScrollOffset: modalState.infoModalScrollOffset,
|
|
45
46
|
filterMode: filterState.filterMode,
|
|
46
47
|
filterQuery: filterState.filterQuery,
|
|
47
48
|
showThemeModal: themeState.showThemeModal,
|
|
@@ -151,16 +152,40 @@ class StateManager {
|
|
|
151
152
|
// Modal delegation
|
|
152
153
|
toggleInfoModal() {
|
|
153
154
|
const currentRow = this.navigationManager.getCurrentRow();
|
|
154
|
-
this.modalManager.toggleInfoModal(currentRow);
|
|
155
|
+
const sessionId = this.modalManager.toggleInfoModal(currentRow);
|
|
155
156
|
this.renderState.forceFullRender = true;
|
|
157
|
+
return sessionId;
|
|
156
158
|
}
|
|
157
159
|
closeInfoModal() {
|
|
158
160
|
this.modalManager.closeInfoModal();
|
|
159
161
|
this.renderState.forceFullRender = true;
|
|
160
162
|
}
|
|
161
|
-
setModalLoading(isLoading) {
|
|
162
|
-
this.modalManager.setModalLoading(isLoading);
|
|
163
|
-
|
|
163
|
+
setModalLoading(isLoading, sessionId) {
|
|
164
|
+
const updated = this.modalManager.setModalLoading(isLoading, sessionId);
|
|
165
|
+
if (updated) {
|
|
166
|
+
this.renderState.forceFullRender = true;
|
|
167
|
+
}
|
|
168
|
+
return updated;
|
|
169
|
+
}
|
|
170
|
+
getInfoModalSessionId() {
|
|
171
|
+
return this.modalManager.getSessionId();
|
|
172
|
+
}
|
|
173
|
+
resetInfoModalScroll() {
|
|
174
|
+
this.modalManager.resetScroll();
|
|
175
|
+
}
|
|
176
|
+
scrollInfoModalUp() {
|
|
177
|
+
return this.modalManager.scrollModalUp();
|
|
178
|
+
// Don't force full render — modal viewport handles its own overwrite
|
|
179
|
+
}
|
|
180
|
+
scrollInfoModalDown(maxOffset) {
|
|
181
|
+
return this.modalManager.scrollModalDown(maxOffset);
|
|
182
|
+
// Don't force full render — modal viewport handles its own overwrite
|
|
183
|
+
}
|
|
184
|
+
getInfoModalScrollOffset() {
|
|
185
|
+
return this.modalManager.getScrollOffset();
|
|
186
|
+
}
|
|
187
|
+
clampInfoModalScrollOffset(maxOffset) {
|
|
188
|
+
return this.modalManager.clampScrollOffset(maxOffset);
|
|
164
189
|
}
|
|
165
190
|
// Filter delegation
|
|
166
191
|
enterFilterMode(preserveQuery = false) {
|
|
@@ -190,8 +215,8 @@ class StateManager {
|
|
|
190
215
|
this.navigationManager.setCurrentRow(0);
|
|
191
216
|
this.navigationManager.setScrollOffset(0);
|
|
192
217
|
}
|
|
193
|
-
getFilteredStates(allStates) {
|
|
194
|
-
return this.filterManager.getFilteredStates(allStates);
|
|
218
|
+
getFilteredStates(allStates, options) {
|
|
219
|
+
return this.filterManager.getFilteredStates(allStates, options);
|
|
195
220
|
}
|
|
196
221
|
toggleDependencyTypeFilter(type) {
|
|
197
222
|
this.filterManager.toggleDependencyType(type);
|
|
@@ -200,6 +225,14 @@ class StateManager {
|
|
|
200
225
|
this.navigationManager.setScrollOffset(0);
|
|
201
226
|
// Use incremental render (no blink)
|
|
202
227
|
}
|
|
228
|
+
toggleVulnerableFilter() {
|
|
229
|
+
this.filterManager.toggleVulnerableFilter();
|
|
230
|
+
this.navigationManager.setCurrentRow(0);
|
|
231
|
+
this.navigationManager.setScrollOffset(0);
|
|
232
|
+
}
|
|
233
|
+
isVulnerableFilterActive() {
|
|
234
|
+
return this.filterManager.isVulnerableFilterActive();
|
|
235
|
+
}
|
|
203
236
|
getActiveFilterLabel() {
|
|
204
237
|
return this.filterManager.getActiveFilterLabel();
|
|
205
238
|
}
|
|
@@ -223,7 +256,9 @@ class StateManager {
|
|
|
223
256
|
this.renderState.forceFullRender = isInitial;
|
|
224
257
|
}
|
|
225
258
|
resetForResize(totalFilteredItems) {
|
|
226
|
-
const totalItems = totalFilteredItems ||
|
|
259
|
+
const totalItems = totalFilteredItems ||
|
|
260
|
+
this.renderState.renderableItems.length ||
|
|
261
|
+
this.displayState.maxVisibleItems;
|
|
227
262
|
this.navigationManager.resetForResize(totalItems);
|
|
228
263
|
this.renderState.forceFullRender = true;
|
|
229
264
|
}
|
package/dist/ui/utils/cursor.js
CHANGED
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ConsoleUtils = exports.CursorUtils = void 0;
|
|
7
7
|
exports.CursorUtils = {
|
|
8
|
+
/**
|
|
9
|
+
* Switch to the terminal alternate screen buffer.
|
|
10
|
+
*/
|
|
11
|
+
enterAlternateScreen() {
|
|
12
|
+
process.stdout.write('\x1b[?1049h');
|
|
13
|
+
},
|
|
14
|
+
/**
|
|
15
|
+
* Return to the terminal primary screen buffer.
|
|
16
|
+
*/
|
|
17
|
+
exitAlternateScreen() {
|
|
18
|
+
process.stdout.write('\x1b[?1049l');
|
|
19
|
+
},
|
|
8
20
|
/**
|
|
9
21
|
* Hide the cursor in the terminal
|
|
10
22
|
*/
|
|
@@ -23,6 +35,12 @@ exports.CursorUtils = {
|
|
|
23
35
|
moveToHome() {
|
|
24
36
|
process.stdout.write('\x1b[H');
|
|
25
37
|
},
|
|
38
|
+
/**
|
|
39
|
+
* Clear the full screen and move the cursor to the top-left corner.
|
|
40
|
+
*/
|
|
41
|
+
clearScreen() {
|
|
42
|
+
process.stdout.write('\x1b[2J\x1b[H');
|
|
43
|
+
},
|
|
26
44
|
/**
|
|
27
45
|
* Clear display from cursor to end of screen
|
|
28
46
|
*/
|
package/dist/ui/utils/index.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ConsoleUtils = exports.CursorUtils = exports.VersionUtils = void 0;
|
|
3
|
+
exports.wrapPlainText = exports.truncatePlainText = exports.stripAnsi = exports.getVisualLength = exports.TerminalInput = exports.ConsoleUtils = exports.CursorUtils = exports.VersionUtils = void 0;
|
|
4
4
|
var version_1 = require("./version");
|
|
5
5
|
Object.defineProperty(exports, "VersionUtils", { enumerable: true, get: function () { return version_1.VersionUtils; } });
|
|
6
6
|
var cursor_1 = require("./cursor");
|
|
7
7
|
Object.defineProperty(exports, "CursorUtils", { enumerable: true, get: function () { return cursor_1.CursorUtils; } });
|
|
8
8
|
Object.defineProperty(exports, "ConsoleUtils", { enumerable: true, get: function () { return cursor_1.ConsoleUtils; } });
|
|
9
|
+
var terminal_input_1 = require("./terminal-input");
|
|
10
|
+
Object.defineProperty(exports, "TerminalInput", { enumerable: true, get: function () { return terminal_input_1.TerminalInput; } });
|
|
11
|
+
var text_1 = require("./text");
|
|
12
|
+
Object.defineProperty(exports, "getVisualLength", { enumerable: true, get: function () { return text_1.getVisualLength; } });
|
|
13
|
+
Object.defineProperty(exports, "stripAnsi", { enumerable: true, get: function () { return text_1.stripAnsi; } });
|
|
14
|
+
Object.defineProperty(exports, "truncatePlainText", { enumerable: true, get: function () { return text_1.truncatePlainText; } });
|
|
15
|
+
Object.defineProperty(exports, "wrapPlainText", { enumerable: true, get: function () { return text_1.wrapPlainText; } });
|
|
9
16
|
//# sourceMappingURL=index.js.map
|