pnpm-catalog-updates 1.0.3 → 1.1.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.
Files changed (51) hide show
  1. package/README.md +15 -0
  2. package/dist/index.js +22031 -10684
  3. package/dist/index.js.map +1 -1
  4. package/package.json +7 -2
  5. package/src/cli/__tests__/commandRegistrar.test.ts +248 -0
  6. package/src/cli/commandRegistrar.ts +785 -0
  7. package/src/cli/commands/__tests__/aiCommand.test.ts +161 -0
  8. package/src/cli/commands/__tests__/analyzeCommand.test.ts +283 -0
  9. package/src/cli/commands/__tests__/checkCommand.test.ts +435 -0
  10. package/src/cli/commands/__tests__/graphCommand.test.ts +312 -0
  11. package/src/cli/commands/__tests__/initCommand.test.ts +317 -0
  12. package/src/cli/commands/__tests__/rollbackCommand.test.ts +400 -0
  13. package/src/cli/commands/__tests__/securityCommand.test.ts +467 -0
  14. package/src/cli/commands/__tests__/themeCommand.test.ts +166 -0
  15. package/src/cli/commands/__tests__/updateCommand.test.ts +720 -0
  16. package/src/cli/commands/__tests__/workspaceCommand.test.ts +286 -0
  17. package/src/cli/commands/aiCommand.ts +163 -0
  18. package/src/cli/commands/analyzeCommand.ts +219 -0
  19. package/src/cli/commands/checkCommand.ts +91 -98
  20. package/src/cli/commands/graphCommand.ts +475 -0
  21. package/src/cli/commands/initCommand.ts +64 -54
  22. package/src/cli/commands/rollbackCommand.ts +334 -0
  23. package/src/cli/commands/securityCommand.ts +165 -100
  24. package/src/cli/commands/themeCommand.ts +148 -0
  25. package/src/cli/commands/updateCommand.ts +215 -263
  26. package/src/cli/commands/workspaceCommand.ts +73 -0
  27. package/src/cli/constants/cliChoices.ts +93 -0
  28. package/src/cli/formatters/__tests__/__snapshots__/outputFormatter.test.ts.snap +557 -0
  29. package/src/cli/formatters/__tests__/ciFormatter.test.ts +526 -0
  30. package/src/cli/formatters/__tests__/outputFormatter.test.ts +448 -0
  31. package/src/cli/formatters/__tests__/progressBar.test.ts +709 -0
  32. package/src/cli/formatters/ciFormatter.ts +964 -0
  33. package/src/cli/formatters/colorUtils.ts +145 -0
  34. package/src/cli/formatters/outputFormatter.ts +615 -332
  35. package/src/cli/formatters/progressBar.ts +43 -52
  36. package/src/cli/formatters/versionFormatter.ts +132 -0
  37. package/src/cli/handlers/aiAnalysisHandler.ts +205 -0
  38. package/src/cli/handlers/changelogHandler.ts +113 -0
  39. package/src/cli/handlers/index.ts +9 -0
  40. package/src/cli/handlers/installHandler.ts +130 -0
  41. package/src/cli/index.ts +175 -726
  42. package/src/cli/interactive/InteractiveOptionsCollector.ts +387 -0
  43. package/src/cli/interactive/interactivePrompts.ts +189 -83
  44. package/src/cli/interactive/optionUtils.ts +89 -0
  45. package/src/cli/themes/colorTheme.ts +43 -16
  46. package/src/cli/utils/cliOutput.ts +118 -0
  47. package/src/cli/utils/commandHelpers.ts +249 -0
  48. package/src/cli/validators/commandValidator.ts +321 -336
  49. package/src/cli/validators/index.ts +37 -2
  50. package/src/cli/options/globalOptions.ts +0 -437
  51. package/src/cli/options/index.ts +0 -5
@@ -4,6 +4,7 @@
4
4
  * Provides consistent color schemes and styling across the CLI
5
5
  */
6
6
 
7
+ import { t } from '@pcu/utils'
7
8
  import chalk from 'chalk'
8
9
 
9
10
  export interface ColorTheme {
@@ -289,27 +290,27 @@ export class StyledText {
289
290
  }
290
291
 
291
292
  static iconInfo(text?: string): string {
292
- return StyledText.icon('ℹ️', text)
293
+ return StyledText.icon('[i]', text)
293
294
  }
294
295
 
295
296
  static iconPackage(text?: string): string {
296
- return StyledText.icon('📦', text)
297
+ return StyledText.icon('[PKG]', text)
297
298
  }
298
299
 
299
300
  static iconCatalog(text?: string): string {
300
- return StyledText.icon('📋', text)
301
+ return StyledText.icon('[CAT]', text)
301
302
  }
302
303
 
303
304
  static iconUpdate(text?: string): string {
304
- return StyledText.icon('🔄', text)
305
+ return StyledText.icon('[UPD]', text)
305
306
  }
306
307
 
307
308
  static iconSecurity(text?: string): string {
308
- return StyledText.icon('🔒', text)
309
+ return StyledText.icon('[SEC]', text)
309
310
  }
310
311
 
311
312
  static iconAnalysis(text?: string): string {
312
- return StyledText.icon('🔍', text)
313
+ return StyledText.icon('[*]', text)
313
314
  }
314
315
 
315
316
  static iconCheck(text?: string): string {
@@ -317,27 +318,53 @@ export class StyledText {
317
318
  }
318
319
 
319
320
  static iconProgress(text?: string): string {
320
- return StyledText.icon('', text)
321
+ return StyledText.icon('[...]', text)
321
322
  }
322
323
 
323
324
  static iconComplete(text?: string): string {
324
- return StyledText.icon('🎉', text)
325
+ return StyledText.icon('[OK]', text)
325
326
  }
327
+
328
+ // Text formatting
329
+ static bold(text: string): string {
330
+ return chalk.bold(text)
331
+ }
332
+
333
+ static dim(text: string): string {
334
+ return chalk.dim(text)
335
+ }
336
+
337
+ static italic(text: string): string {
338
+ return chalk.italic(text)
339
+ }
340
+
341
+ static underline(text: string): string {
342
+ return chalk.underline(text)
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Chalk-like color function type
348
+ */
349
+ type ColorFunction = {
350
+ (text: string): string
351
+ bold: (text: string) => string
352
+ dim: (text: string) => string
326
353
  }
327
354
 
328
355
  /**
329
356
  * Table styling utilities
330
357
  */
331
358
  export class TableStyles {
332
- static createHeaderStyle(color: any) {
359
+ static createHeaderStyle(color: ColorFunction) {
333
360
  return (text: string) => color.bold(text)
334
361
  }
335
362
 
336
- static createBorderStyle(color: any) {
363
+ static createBorderStyle(color: ColorFunction) {
337
364
  return (text: string) => color.dim(text)
338
365
  }
339
366
 
340
- static createCellStyle(color: any) {
367
+ static createCellStyle(color: (text: string) => string) {
341
368
  return (text: string) => color(text)
342
369
  }
343
370
  }
@@ -349,7 +376,7 @@ export interface ThemeConfig {
349
376
  name: string
350
377
  colors: Partial<ColorTheme>
351
378
  icons: Record<string, string>
352
- styles: Record<string, any>
379
+ styles: Record<string, string | number | boolean>
353
380
  }
354
381
 
355
382
  /**
@@ -358,22 +385,22 @@ export interface ThemeConfig {
358
385
  export const themePresets = {
359
386
  development: {
360
387
  name: 'development',
361
- description: 'Bright colors for development environments',
388
+ description: t('theme.preset.development'),
362
389
  theme: 'modern',
363
390
  },
364
391
  production: {
365
392
  name: 'production',
366
- description: 'Subtle colors for production environments',
393
+ description: t('theme.preset.production'),
367
394
  theme: 'minimal',
368
395
  },
369
396
  presentation: {
370
397
  name: 'presentation',
371
- description: 'High contrast colors for presentations',
398
+ description: t('theme.preset.presentation'),
372
399
  theme: 'neon',
373
400
  },
374
401
  default: {
375
402
  name: 'default',
376
- description: 'Balanced colors for general use',
403
+ description: t('theme.preset.default'),
377
404
  theme: 'default',
378
405
  },
379
406
  }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * CLI Output Service
3
+ *
4
+ * Provides a unified interface for CLI output, making it easier to test
5
+ * and control output behavior. This separates user-facing output from
6
+ * internal logging (which should use the logger from @pcu/utils).
7
+ *
8
+ * Usage:
9
+ * - Use cliOutput for user-facing messages (formatted, styled)
10
+ * - Use logger from @pcu/utils for internal logging (debug, errors)
11
+ */
12
+
13
+ /**
14
+ * Interface for CLI output operations
15
+ * Allows mocking in tests without console hijacking
16
+ */
17
+ export interface ICliOutput {
18
+ /** Print standard output (user-facing messages) */
19
+ print(...args: unknown[]): void
20
+ /** Print error output (user-facing errors) */
21
+ error(...args: unknown[]): void
22
+ /** Print warning output (user-facing warnings) */
23
+ warn(...args: unknown[]): void
24
+ /** Print info output (alias for print) */
25
+ info(...args: unknown[]): void
26
+ }
27
+
28
+ /**
29
+ * Default CLI output implementation using console
30
+ */
31
+ class CliOutputImpl implements ICliOutput {
32
+ print(...args: unknown[]): void {
33
+ console.log(...args)
34
+ }
35
+
36
+ error(...args: unknown[]): void {
37
+ console.error(...args)
38
+ }
39
+
40
+ warn(...args: unknown[]): void {
41
+ console.warn(...args)
42
+ }
43
+
44
+ info(...args: unknown[]): void {
45
+ console.log(...args)
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Singleton instance for CLI output
51
+ * Can be replaced in tests via setCliOutput()
52
+ */
53
+ let cliOutputInstance: ICliOutput = new CliOutputImpl()
54
+
55
+ /**
56
+ * Get the current CLI output instance
57
+ */
58
+ export function getCliOutput(): ICliOutput {
59
+ return cliOutputInstance
60
+ }
61
+
62
+ /**
63
+ * Set a custom CLI output instance (useful for testing)
64
+ */
65
+ export function setCliOutput(output: ICliOutput): void {
66
+ cliOutputInstance = output
67
+ }
68
+
69
+ /**
70
+ * Reset CLI output to the default implementation
71
+ */
72
+ export function resetCliOutput(): void {
73
+ cliOutputInstance = new CliOutputImpl()
74
+ }
75
+
76
+ /**
77
+ * Default CLI output instance for convenience
78
+ */
79
+ export const cliOutput: ICliOutput = {
80
+ print: (...args: unknown[]) => cliOutputInstance.print(...args),
81
+ error: (...args: unknown[]) => cliOutputInstance.error(...args),
82
+ warn: (...args: unknown[]) => cliOutputInstance.warn(...args),
83
+ info: (...args: unknown[]) => cliOutputInstance.info(...args),
84
+ }
85
+
86
+ /**
87
+ * Create a mock CLI output for testing
88
+ * Returns the mock and arrays of captured output
89
+ */
90
+ export function createMockCliOutput(): {
91
+ mock: ICliOutput
92
+ prints: unknown[][]
93
+ errors: unknown[][]
94
+ warns: unknown[][]
95
+ infos: unknown[][]
96
+ clear: () => void
97
+ } {
98
+ const prints: unknown[][] = []
99
+ const errors: unknown[][] = []
100
+ const warns: unknown[][] = []
101
+ const infos: unknown[][] = []
102
+
103
+ const mock: ICliOutput = {
104
+ print: (...args: unknown[]) => prints.push(args),
105
+ error: (...args: unknown[]) => errors.push(args),
106
+ warn: (...args: unknown[]) => warns.push(args),
107
+ info: (...args: unknown[]) => infos.push(args),
108
+ }
109
+
110
+ const clear = () => {
111
+ prints.length = 0
112
+ errors.length = 0
113
+ warns.length = 0
114
+ infos.length = 0
115
+ }
116
+
117
+ return { mock, prints, errors, warns, infos, clear }
118
+ }
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Command Helpers
3
+ *
4
+ * Shared utilities for CLI command initialization and common patterns.
5
+ * Reduces code duplication across check, update, and other commands.
6
+ */
7
+
8
+ import type { PackageFilterConfig, TranslationKey } from '@pcu/utils'
9
+ import { ConfigLoader, Logger, logger, t } from '@pcu/utils'
10
+ import { type OutputFormat, OutputFormatter } from '../formatters/outputFormatter.js'
11
+ import { StyledText, ThemeManager } from '../themes/colorTheme.js'
12
+ import { cliOutput } from './cliOutput.js'
13
+
14
+ /**
15
+ * Common command options shared across multiple commands
16
+ */
17
+ export interface CommonCommandOptions {
18
+ workspace?: string
19
+ format?: OutputFormat
20
+ color?: boolean
21
+ verbose?: boolean
22
+ }
23
+
24
+ /**
25
+ * Command context created during initialization
26
+ */
27
+ export interface CommandContext {
28
+ config: PackageFilterConfig
29
+ formatter: OutputFormatter
30
+ workspacePath: string
31
+ }
32
+
33
+ /**
34
+ * Command initialization options
35
+ */
36
+ export interface InitOptions {
37
+ /** Theme to use (default: 'default') */
38
+ theme?: 'default' | 'minimal' | 'neon' | 'modern'
39
+ /** Whether to show verbose initialization info */
40
+ showVerboseInfo?: boolean
41
+ /** Additional info to show in verbose mode */
42
+ verboseInfo?: Record<string, string | undefined>
43
+ }
44
+
45
+ /**
46
+ * Initialize theme for a command
47
+ * Common pattern used in: checkCommand, updateCommand, securityCommand, etc.
48
+ */
49
+ export function initializeTheme(
50
+ theme: 'default' | 'minimal' | 'neon' | 'modern' = 'default'
51
+ ): void {
52
+ ThemeManager.setTheme(theme)
53
+ }
54
+
55
+ /**
56
+ * Load and merge configuration with CLI options
57
+ * Common pattern used in: checkCommand, updateCommand, watchCommand
58
+ */
59
+ export async function loadConfiguration(workspacePath?: string): Promise<PackageFilterConfig> {
60
+ const effectivePath = workspacePath || process.cwd()
61
+ return ConfigLoader.loadConfig(effectivePath)
62
+ }
63
+
64
+ /**
65
+ * Create an output formatter with common configuration
66
+ * Common pattern used in: checkCommand, updateCommand, analyzeCommand, workspaceCommand
67
+ */
68
+ export function createFormatter(
69
+ format: OutputFormat | undefined,
70
+ config: PackageFilterConfig,
71
+ colorEnabled: boolean = true
72
+ ): OutputFormatter {
73
+ const effectiveFormat = format || config.defaults?.format || 'table'
74
+ return new OutputFormatter(effectiveFormat as OutputFormat, colorEnabled)
75
+ }
76
+
77
+ /**
78
+ * Initialize a command with common setup
79
+ * Combines theme initialization, config loading, and formatter creation
80
+ */
81
+ export async function initializeCommand(
82
+ options: CommonCommandOptions,
83
+ initOptions: InitOptions = {}
84
+ ): Promise<CommandContext> {
85
+ // Initialize theme
86
+ initializeTheme(initOptions.theme)
87
+
88
+ // Set logger to debug level when verbose mode is enabled
89
+ if (options.verbose) {
90
+ Logger.setGlobalLevel('debug')
91
+ }
92
+
93
+ // Show verbose initialization info
94
+ if (initOptions.showVerboseInfo && options.verbose) {
95
+ showVerboseInfo(options, initOptions.verboseInfo)
96
+ }
97
+
98
+ // Load configuration
99
+ const workspacePath = options.workspace || process.cwd()
100
+ const config = await loadConfiguration(workspacePath)
101
+
102
+ // Create formatter
103
+ const formatter = createFormatter(options.format, config, options.color !== false)
104
+
105
+ return {
106
+ config,
107
+ formatter,
108
+ workspacePath,
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Show verbose initialization information
114
+ * QUAL-012: Use unified output helpers (cliOutput, StyledText)
115
+ */
116
+ function showVerboseInfo(
117
+ options: CommonCommandOptions,
118
+ additionalInfo?: Record<string, string | undefined>
119
+ ): void {
120
+ cliOutput.print(StyledText.iconAnalysis(t('info.checkingUpdates')))
121
+ cliOutput.print(
122
+ StyledText.muted(`${t('command.workspace.title')}: ${options.workspace || process.cwd()}`)
123
+ )
124
+
125
+ if (additionalInfo) {
126
+ for (const [key, value] of Object.entries(additionalInfo)) {
127
+ if (value !== undefined) {
128
+ cliOutput.print(StyledText.muted(`${key}: ${value}`))
129
+ }
130
+ }
131
+ }
132
+
133
+ cliOutput.print('')
134
+ }
135
+
136
+ /**
137
+ * Error handling options for commands
138
+ * QUAL-007: Unified error handling configuration
139
+ */
140
+ export interface ErrorHandlingOptions {
141
+ /** Whether to show verbose information (stack trace) */
142
+ verbose?: boolean
143
+ /** Progress bar to stop/fail on error */
144
+ progressBar?: { stop: () => void; fail: (msg: string) => void }
145
+ /** Custom error message for logging */
146
+ errorMessage?: string
147
+ /** Additional context for logging */
148
+ context?: Record<string, unknown>
149
+ /** Custom i18n key for failed progress message */
150
+ failedProgressKey?: string
151
+ /** Custom i18n key for error display */
152
+ errorDisplayKey?: string
153
+ }
154
+
155
+ /**
156
+ * Check if error is a user cancellation (e.g., Ctrl+C)
157
+ */
158
+ export function isUserCancellation(error: unknown): boolean {
159
+ return (
160
+ error instanceof Error &&
161
+ (error.name === 'ExitPromptError' || error.message.includes('force closed'))
162
+ )
163
+ }
164
+
165
+ /**
166
+ * Handle command error with consistent logging
167
+ * QUAL-007: Unified error handling pattern for all commands
168
+ *
169
+ * @returns true if error was handled as user cancellation (command should return gracefully)
170
+ */
171
+ export function handleCommandError(
172
+ error: Error | unknown,
173
+ options: ErrorHandlingOptions = {}
174
+ ): boolean {
175
+ const {
176
+ verbose = false,
177
+ progressBar,
178
+ errorMessage = 'Command failed',
179
+ context,
180
+ failedProgressKey = 'progress.operationFailed',
181
+ errorDisplayKey,
182
+ } = options
183
+
184
+ // Handle user cancellation gracefully (Ctrl+C)
185
+ if (isUserCancellation(error)) {
186
+ progressBar?.stop()
187
+ cliOutput.print(StyledText.iconWarning(t('cli.cancelled')))
188
+ return true
189
+ }
190
+
191
+ // Log error with context
192
+ logger.error(errorMessage, error instanceof Error ? error : undefined, context)
193
+
194
+ // Fail progress bar if provided
195
+ if (progressBar) {
196
+ progressBar.fail(t(failedProgressKey as TranslationKey))
197
+ }
198
+
199
+ // Display error to user
200
+ const displayKey = errorDisplayKey || 'cli.error'
201
+ cliOutput.error(StyledText.iconError(t(displayKey as TranslationKey)))
202
+ cliOutput.error(StyledText.error(String(error)))
203
+
204
+ // Show stack trace in verbose mode
205
+ if (verbose && error instanceof Error) {
206
+ cliOutput.error(StyledText.muted(t('common.stackTrace')))
207
+ cliOutput.error(StyledText.muted(error.stack || t('common.noStackTrace')))
208
+ }
209
+
210
+ return false
211
+ }
212
+
213
+ /**
214
+ * Merge CLI options with config defaults
215
+ * Returns the effective value prioritizing CLI > config > fallback
216
+ */
217
+ export function mergeWithConfig<T>(
218
+ cliValue: T | undefined,
219
+ configValue: T | undefined,
220
+ fallback: T
221
+ ): T {
222
+ return cliValue ?? configValue ?? fallback
223
+ }
224
+
225
+ /**
226
+ * Get effective target from options and config
227
+ */
228
+ export function getEffectiveTarget(
229
+ optionTarget: string | undefined,
230
+ configTarget: string | undefined
231
+ ): 'latest' | 'greatest' | 'minor' | 'patch' | 'newest' {
232
+ return (optionTarget || configTarget || 'latest') as
233
+ | 'latest'
234
+ | 'greatest'
235
+ | 'minor'
236
+ | 'patch'
237
+ | 'newest'
238
+ }
239
+
240
+ /**
241
+ * Get effective include/exclude patterns
242
+ * CLI options take priority over config file
243
+ */
244
+ export function getEffectivePatterns(
245
+ cliPatterns: string[] | undefined,
246
+ configPatterns: string[] | undefined
247
+ ): string[] | undefined {
248
+ return cliPatterns?.length ? cliPatterns : configPatterns
249
+ }