pnpm-catalog-updates 1.0.3 → 1.1.0

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
@@ -5,10 +5,26 @@
5
5
  * Provides detailed information about available updates.
6
6
  */
7
7
 
8
- import type { CatalogUpdateService, CheckOptions } from '@pcu/core'
9
- import { ConfigLoader } from '@pcu/utils'
10
- import { type OutputFormat, OutputFormatter } from '../formatters/outputFormatter.js'
8
+ import type {
9
+ CatalogUpdateInfo,
10
+ CatalogUpdateService,
11
+ CheckOptions,
12
+ OutdatedDependencyInfo,
13
+ OutdatedReport,
14
+ } from '@pcu/core'
15
+ import { countUpdateTypesFromCatalogs } from '@pcu/core'
16
+ import { CommandExitError, t } from '@pcu/utils'
17
+ import type { OutputFormat } from '../formatters/outputFormatter.js'
11
18
  import { StyledText, ThemeManager } from '../themes/colorTheme.js'
19
+ import { cliOutput } from '../utils/cliOutput.js'
20
+ import {
21
+ getEffectivePatterns,
22
+ getEffectiveTarget,
23
+ handleCommandError,
24
+ initializeCommand,
25
+ mergeWithConfig,
26
+ } from '../utils/commandHelpers.js'
27
+ import { errorsOnly, validateCheckOptions } from '../validators/index.js'
12
28
 
13
29
  export interface CheckCommandOptions {
14
30
  workspace?: string
@@ -20,6 +36,9 @@ export interface CheckCommandOptions {
20
36
  exclude?: string[]
21
37
  verbose?: boolean
22
38
  color?: boolean
39
+ exitCode?: boolean
40
+ /** Skip security vulnerability checks */
41
+ noSecurity?: boolean
23
42
  }
24
43
 
25
44
  export class CheckCommand {
@@ -30,45 +49,30 @@ export class CheckCommand {
30
49
  */
31
50
  async execute(options: CheckCommandOptions = {}): Promise<void> {
32
51
  try {
33
- // Initialize theme
34
- ThemeManager.setTheme('default')
35
-
36
- if (options.verbose) {
37
- console.log(StyledText.iconAnalysis('Checking for outdated catalog dependencies'))
38
- console.log(StyledText.muted(`Workspace: ${options.workspace || process.cwd()}`))
39
-
40
- if (options.catalog) {
41
- console.log(StyledText.muted(`Catalog: ${options.catalog}`))
42
- }
43
-
44
- if (options.target && options.target !== 'latest') {
45
- console.log(StyledText.muted(`Target: ${options.target}`))
46
- }
47
-
48
- console.log('')
49
- }
50
-
51
- // Load configuration file first
52
- const config = ConfigLoader.loadConfig(options.workspace || process.cwd())
53
-
54
- // Use format from CLI options first, then config file, then default
55
- const effectiveFormat = options.format || config.defaults?.format || 'table'
56
-
57
- // Create output formatter with effective format
58
- const formatter = new OutputFormatter(
59
- effectiveFormat as OutputFormat,
60
- options.color !== false
61
- )
62
-
63
- // Merge CLI options with configuration file settings
52
+ // Initialize command with shared helper (theme, config, formatter)
53
+ const { config, formatter } = await initializeCommand(options, {
54
+ showVerboseInfo: true,
55
+ verboseInfo: {
56
+ [t('command.check.catalogLabel', { catalog: '' }).replace(': ', '')]:
57
+ options.catalog || undefined,
58
+ [t('command.check.targetLabel', { target: '' }).replace(': ', '')]:
59
+ options.target && options.target !== 'latest' ? options.target : undefined,
60
+ },
61
+ })
62
+
63
+ // Build check options using shared helpers
64
64
  const checkOptions: CheckOptions = {
65
65
  workspacePath: options.workspace,
66
66
  catalogName: options.catalog,
67
- target: options.target || config.defaults?.target || 'latest',
68
- includePrerelease: options.prerelease ?? config.defaults?.includePrerelease ?? false,
69
- // CLI include/exclude options take priority over config file
70
- include: options.include?.length ? options.include : config.include,
71
- exclude: options.exclude?.length ? options.exclude : config.exclude,
67
+ target: getEffectiveTarget(options.target, config.defaults?.target),
68
+ includePrerelease: mergeWithConfig(
69
+ options.prerelease,
70
+ config.defaults?.includePrerelease,
71
+ false
72
+ ),
73
+ include: getEffectivePatterns(options.include, config.include),
74
+ exclude: getEffectivePatterns(options.exclude, config.exclude),
75
+ noSecurity: options.noSecurity,
72
76
  }
73
77
 
74
78
  // Execute check
@@ -76,117 +80,106 @@ export class CheckCommand {
76
80
 
77
81
  // Format and display results
78
82
  const formattedOutput = formatter.formatOutdatedReport(report)
79
- console.log(formattedOutput)
83
+ cliOutput.print(formattedOutput)
80
84
 
81
85
  // Show summary
82
86
  if (options.verbose || options.format === 'table') {
83
87
  this.showSummary(report, options)
84
88
  }
85
89
 
86
- // Always exit with 0 since this is just a check command
87
- // and finding updates is not an error condition
88
- process.exit(0)
89
- } catch (error) {
90
- console.error(StyledText.iconError('Error checking dependencies:'))
91
- console.error(StyledText.error(String(error)))
90
+ // Exit with code 1 if --exit-code is set and updates are available (for CI/CD)
91
+ if (options.exitCode && report.hasUpdates) {
92
+ throw CommandExitError.failure('Updates available')
93
+ }
92
94
 
93
- if (options.verbose && error instanceof Error) {
94
- console.error(StyledText.muted('Stack trace:'))
95
- console.error(StyledText.muted(error.stack || 'No stack trace available'))
95
+ // Otherwise exit with 0 since this is just a check command
96
+ throw CommandExitError.success()
97
+ } catch (error) {
98
+ // Re-throw CommandExitError as-is (success or controlled exit)
99
+ if (error instanceof CommandExitError) {
100
+ throw error
96
101
  }
97
102
 
98
- process.exit(1)
103
+ // QUAL-007: Use unified error handling
104
+ handleCommandError(error, {
105
+ verbose: options.verbose,
106
+ errorMessage: 'Check dependencies failed',
107
+ context: { options },
108
+ errorDisplayKey: 'command.check.errorChecking',
109
+ })
110
+ throw CommandExitError.failure('Check command failed')
99
111
  }
100
112
  }
101
113
 
102
114
  /**
103
115
  * Show command summary
104
116
  */
105
- private showSummary(report: any, _options: CheckCommandOptions): void {
117
+ private showSummary(report: OutdatedReport, _options: CheckCommandOptions): void {
106
118
  const lines: string[] = []
107
119
  const theme = ThemeManager.getTheme()
108
120
 
109
121
  if (!report.hasUpdates) {
110
- lines.push(StyledText.iconSuccess('All catalog dependencies are up to date!'))
122
+ lines.push(StyledText.iconSuccess(t('info.noUpdatesFound')))
111
123
  } else {
112
- lines.push(StyledText.iconInfo('Summary:'))
113
- lines.push(` • ${report.totalOutdated} outdated dependencies found`)
114
- lines.push(` • ${report.catalogs.length} catalogs checked`)
124
+ lines.push(StyledText.iconInfo(`${t('command.check.summary')}:`))
125
+ lines.push(` • ${t('info.foundOutdated', { count: report.totalOutdated })}`)
126
+ lines.push(` • ${t('command.check.catalogsChecked', { count: report.catalogs.length })}`)
115
127
 
116
128
  const totalPackages = report.catalogs.reduce(
117
- (sum: number, cat: any) => sum + cat.totalPackages,
129
+ (sum: number, cat: CatalogUpdateInfo) => sum + cat.totalPackages,
118
130
  0
119
131
  )
120
- lines.push(` • ${totalPackages} total catalog entries`)
132
+ lines.push(` • ${t('command.check.totalCatalogEntries', { count: totalPackages })}`)
121
133
 
122
134
  // Show breakdown by update type
123
- const updateTypes = { major: 0, minor: 0, patch: 0 }
124
-
125
- for (const catalog of report.catalogs) {
126
- for (const dep of catalog.outdatedDependencies) {
127
- updateTypes[dep.updateType as keyof typeof updateTypes]++
128
- }
129
- }
135
+ const updateTypes = countUpdateTypesFromCatalogs(report.catalogs)
130
136
 
131
137
  if (updateTypes.major > 0) {
132
- lines.push(theme.major(` • ${updateTypes.major} major updates`))
138
+ lines.push(
139
+ theme.major(` • ${t('command.check.majorUpdates', { count: updateTypes.major })}`)
140
+ )
133
141
  }
134
142
  if (updateTypes.minor > 0) {
135
- lines.push(theme.minor(` • ${updateTypes.minor} minor updates`))
143
+ lines.push(
144
+ theme.minor(` • ${t('command.check.minorUpdates', { count: updateTypes.minor })}`)
145
+ )
136
146
  }
137
147
  if (updateTypes.patch > 0) {
138
- lines.push(theme.patch(` • ${updateTypes.patch} patch updates`))
148
+ lines.push(
149
+ theme.patch(` • ${t('command.check.patchUpdates', { count: updateTypes.patch })}`)
150
+ )
139
151
  }
140
152
 
141
153
  // Security updates
142
- const securityUpdates = report.catalogs.reduce((sum: number, cat: any) => {
143
- return sum + cat.outdatedDependencies.filter((dep: any) => dep.isSecurityUpdate).length
154
+ const securityUpdates = report.catalogs.reduce((sum: number, cat: CatalogUpdateInfo) => {
155
+ return (
156
+ sum +
157
+ cat.outdatedDependencies.filter((dep: OutdatedDependencyInfo) => dep.isSecurityUpdate)
158
+ .length
159
+ )
144
160
  }, 0)
145
161
 
146
162
  if (securityUpdates > 0) {
147
- lines.push(StyledText.iconSecurity(`${securityUpdates} security updates`))
163
+ lines.push(StyledText.iconSecurity(t('info.securityUpdates', { count: securityUpdates })))
148
164
  }
149
165
 
150
166
  lines.push('')
151
- lines.push(StyledText.iconUpdate('Run with --update to apply updates'))
167
+ lines.push(StyledText.iconUpdate(t('info.runWithUpdate')))
152
168
 
153
169
  if (updateTypes.major > 0) {
154
- lines.push(StyledText.iconWarning('Major updates may contain breaking changes'))
170
+ lines.push(StyledText.iconWarning(t('info.majorWarning')))
155
171
  }
156
172
  }
157
173
 
158
- console.log(lines.join('\n'))
174
+ cliOutput.print(lines.join('\n'))
159
175
  }
160
176
 
161
177
  /**
162
178
  * Validate command options
179
+ * QUAL-002: Uses unified validator from validators/
163
180
  */
164
181
  static validateOptions(options: CheckCommandOptions): string[] {
165
- const errors: string[] = []
166
-
167
- // Validate format
168
- if (options.format && !['table', 'json', 'yaml', 'minimal'].includes(options.format)) {
169
- errors.push('Invalid format. Must be one of: table, json, yaml, minimal')
170
- }
171
-
172
- // Validate target
173
- if (
174
- options.target &&
175
- !['latest', 'greatest', 'minor', 'patch', 'newest'].includes(options.target)
176
- ) {
177
- errors.push('Invalid target. Must be one of: latest, greatest, minor, patch, newest')
178
- }
179
-
180
- // Validate include/exclude patterns
181
- if (options.include?.some((pattern) => !pattern.trim())) {
182
- errors.push('Include patterns cannot be empty')
183
- }
184
-
185
- if (options.exclude?.some((pattern) => !pattern.trim())) {
186
- errors.push('Exclude patterns cannot be empty')
187
- }
188
-
189
- return errors
182
+ return errorsOnly(validateCheckOptions)(options)
190
183
  }
191
184
 
192
185
  /**