pnpm-catalog-updates 0.5.6 โ†’ 0.6.5

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 (220) hide show
  1. package/bin/pcu.js +1 -1
  2. package/dist/index.js +9559 -32
  3. package/dist/index.js.map +1 -1
  4. package/package.json +61 -103
  5. package/src/cli/commands/checkCommand.ts +227 -0
  6. package/src/cli/commands/initCommand.ts +394 -0
  7. package/src/cli/commands/securityCommand.ts +569 -0
  8. package/src/cli/commands/updateCommand.ts +245 -0
  9. package/src/cli/formatters/outputFormatter.ts +830 -0
  10. package/src/cli/formatters/progressBar.ts +700 -0
  11. package/src/cli/index.ts +565 -0
  12. package/src/cli/interactive/interactivePrompts.ts +517 -0
  13. package/src/cli/options/globalOptions.ts +380 -0
  14. package/src/cli/options/index.ts +5 -0
  15. package/src/cli/themes/colorTheme.ts +379 -0
  16. package/src/cli/validators/commandValidator.ts +395 -0
  17. package/src/cli/validators/index.ts +5 -0
  18. package/src/index.ts +4 -0
  19. package/LICENSE +0 -21
  20. package/README.ja.md +0 -582
  21. package/README.md +0 -690
  22. package/README.zh-CN.md +0 -630
  23. package/dist/application/services/CatalogUpdateService.d.ts +0 -209
  24. package/dist/application/services/CatalogUpdateService.d.ts.map +0 -1
  25. package/dist/application/services/CatalogUpdateService.js +0 -836
  26. package/dist/application/services/CatalogUpdateService.js.map +0 -1
  27. package/dist/application/services/WorkspaceService.d.ts +0 -139
  28. package/dist/application/services/WorkspaceService.d.ts.map +0 -1
  29. package/dist/application/services/WorkspaceService.js +0 -340
  30. package/dist/application/services/WorkspaceService.js.map +0 -1
  31. package/dist/cli/commands/CheckCommand.d.ts +0 -40
  32. package/dist/cli/commands/CheckCommand.d.ts.map +0 -1
  33. package/dist/cli/commands/CheckCommand.js +0 -177
  34. package/dist/cli/commands/CheckCommand.js.map +0 -1
  35. package/dist/cli/commands/InitCommand.d.ts +0 -53
  36. package/dist/cli/commands/InitCommand.d.ts.map +0 -1
  37. package/dist/cli/commands/InitCommand.js +0 -338
  38. package/dist/cli/commands/InitCommand.js.map +0 -1
  39. package/dist/cli/commands/SecurityCommand.d.ts +0 -113
  40. package/dist/cli/commands/SecurityCommand.d.ts.map +0 -1
  41. package/dist/cli/commands/SecurityCommand.js +0 -410
  42. package/dist/cli/commands/SecurityCommand.js.map +0 -1
  43. package/dist/cli/commands/UpdateCommand.d.ts +0 -44
  44. package/dist/cli/commands/UpdateCommand.d.ts.map +0 -1
  45. package/dist/cli/commands/UpdateCommand.js +0 -189
  46. package/dist/cli/commands/UpdateCommand.js.map +0 -1
  47. package/dist/cli/formatters/OutputFormatter.d.ts +0 -116
  48. package/dist/cli/formatters/OutputFormatter.d.ts.map +0 -1
  49. package/dist/cli/formatters/OutputFormatter.js +0 -664
  50. package/dist/cli/formatters/OutputFormatter.js.map +0 -1
  51. package/dist/cli/formatters/ProgressBar.d.ts +0 -195
  52. package/dist/cli/formatters/ProgressBar.d.ts.map +0 -1
  53. package/dist/cli/formatters/ProgressBar.js +0 -622
  54. package/dist/cli/formatters/ProgressBar.js.map +0 -1
  55. package/dist/cli/index.d.ts +0 -12
  56. package/dist/cli/index.d.ts.map +0 -1
  57. package/dist/cli/index.js +0 -492
  58. package/dist/cli/index.js.map +0 -1
  59. package/dist/cli/interactive/InteractivePrompts.d.ts +0 -85
  60. package/dist/cli/interactive/InteractivePrompts.d.ts.map +0 -1
  61. package/dist/cli/interactive/InteractivePrompts.js +0 -434
  62. package/dist/cli/interactive/InteractivePrompts.js.map +0 -1
  63. package/dist/cli/options/GlobalOptions.d.ts +0 -117
  64. package/dist/cli/options/GlobalOptions.d.ts.map +0 -1
  65. package/dist/cli/options/GlobalOptions.js +0 -278
  66. package/dist/cli/options/GlobalOptions.js.map +0 -1
  67. package/dist/cli/options/index.d.ts +0 -5
  68. package/dist/cli/options/index.d.ts.map +0 -1
  69. package/dist/cli/options/index.js +0 -5
  70. package/dist/cli/options/index.js.map +0 -1
  71. package/dist/cli/themes/ColorTheme.d.ts +0 -211
  72. package/dist/cli/themes/ColorTheme.d.ts.map +0 -1
  73. package/dist/cli/themes/ColorTheme.js +0 -267
  74. package/dist/cli/themes/ColorTheme.js.map +0 -1
  75. package/dist/cli/validators/CommandValidator.d.ts +0 -60
  76. package/dist/cli/validators/CommandValidator.d.ts.map +0 -1
  77. package/dist/cli/validators/CommandValidator.js +0 -319
  78. package/dist/cli/validators/CommandValidator.js.map +0 -1
  79. package/dist/cli/validators/index.d.ts +0 -5
  80. package/dist/cli/validators/index.d.ts.map +0 -1
  81. package/dist/cli/validators/index.js +0 -5
  82. package/dist/cli/validators/index.js.map +0 -1
  83. package/dist/common/config/Config.d.ts +0 -142
  84. package/dist/common/config/Config.d.ts.map +0 -1
  85. package/dist/common/config/Config.js +0 -382
  86. package/dist/common/config/Config.js.map +0 -1
  87. package/dist/common/config/ConfigLoader.d.ts +0 -49
  88. package/dist/common/config/ConfigLoader.d.ts.map +0 -1
  89. package/dist/common/config/ConfigLoader.js +0 -180
  90. package/dist/common/config/ConfigLoader.js.map +0 -1
  91. package/dist/common/config/PackageFilterConfig.d.ts +0 -56
  92. package/dist/common/config/PackageFilterConfig.d.ts.map +0 -1
  93. package/dist/common/config/PackageFilterConfig.js +0 -94
  94. package/dist/common/config/PackageFilterConfig.js.map +0 -1
  95. package/dist/common/config/index.d.ts +0 -8
  96. package/dist/common/config/index.d.ts.map +0 -1
  97. package/dist/common/config/index.js +0 -8
  98. package/dist/common/config/index.js.map +0 -1
  99. package/dist/common/error-handling/ErrorTracker.d.ts +0 -48
  100. package/dist/common/error-handling/ErrorTracker.d.ts.map +0 -1
  101. package/dist/common/error-handling/ErrorTracker.js +0 -93
  102. package/dist/common/error-handling/ErrorTracker.js.map +0 -1
  103. package/dist/common/error-handling/UserFriendlyErrorHandler.d.ts +0 -74
  104. package/dist/common/error-handling/UserFriendlyErrorHandler.d.ts.map +0 -1
  105. package/dist/common/error-handling/UserFriendlyErrorHandler.js +0 -703
  106. package/dist/common/error-handling/UserFriendlyErrorHandler.js.map +0 -1
  107. package/dist/common/error-handling/index.d.ts +0 -11
  108. package/dist/common/error-handling/index.d.ts.map +0 -1
  109. package/dist/common/error-handling/index.js +0 -9
  110. package/dist/common/error-handling/index.js.map +0 -1
  111. package/dist/common/logger/Logger.d.ts +0 -110
  112. package/dist/common/logger/Logger.d.ts.map +0 -1
  113. package/dist/common/logger/Logger.js +0 -289
  114. package/dist/common/logger/Logger.js.map +0 -1
  115. package/dist/common/logger/index.d.ts +0 -6
  116. package/dist/common/logger/index.d.ts.map +0 -1
  117. package/dist/common/logger/index.js +0 -6
  118. package/dist/common/logger/index.js.map +0 -1
  119. package/dist/common/types/cli.d.ts +0 -265
  120. package/dist/common/types/cli.d.ts.map +0 -1
  121. package/dist/common/types/cli.js +0 -5
  122. package/dist/common/types/cli.js.map +0 -1
  123. package/dist/common/types/core.d.ts +0 -270
  124. package/dist/common/types/core.d.ts.map +0 -1
  125. package/dist/common/types/core.js +0 -32
  126. package/dist/common/types/core.js.map +0 -1
  127. package/dist/common/types/index.d.ts +0 -8
  128. package/dist/common/types/index.d.ts.map +0 -1
  129. package/dist/common/types/index.js +0 -8
  130. package/dist/common/types/index.js.map +0 -1
  131. package/dist/common/utils/VersionChecker.d.ts +0 -54
  132. package/dist/common/utils/VersionChecker.d.ts.map +0 -1
  133. package/dist/common/utils/VersionChecker.js +0 -180
  134. package/dist/common/utils/VersionChecker.js.map +0 -1
  135. package/dist/common/utils/async.d.ts +0 -74
  136. package/dist/common/utils/async.d.ts.map +0 -1
  137. package/dist/common/utils/async.js +0 -228
  138. package/dist/common/utils/async.js.map +0 -1
  139. package/dist/common/utils/format.d.ts +0 -32
  140. package/dist/common/utils/format.d.ts.map +0 -1
  141. package/dist/common/utils/format.js +0 -121
  142. package/dist/common/utils/format.js.map +0 -1
  143. package/dist/common/utils/git.d.ts +0 -44
  144. package/dist/common/utils/git.d.ts.map +0 -1
  145. package/dist/common/utils/git.js +0 -147
  146. package/dist/common/utils/git.js.map +0 -1
  147. package/dist/common/utils/index.d.ts +0 -12
  148. package/dist/common/utils/index.d.ts.map +0 -1
  149. package/dist/common/utils/index.js +0 -12
  150. package/dist/common/utils/index.js.map +0 -1
  151. package/dist/common/utils/string.d.ts +0 -56
  152. package/dist/common/utils/string.d.ts.map +0 -1
  153. package/dist/common/utils/string.js +0 -134
  154. package/dist/common/utils/string.js.map +0 -1
  155. package/dist/common/utils/validation.d.ts +0 -88
  156. package/dist/common/utils/validation.d.ts.map +0 -1
  157. package/dist/common/utils/validation.js +0 -308
  158. package/dist/common/utils/validation.js.map +0 -1
  159. package/dist/domain/entities/Catalog.d.ts +0 -117
  160. package/dist/domain/entities/Catalog.d.ts.map +0 -1
  161. package/dist/domain/entities/Catalog.js +0 -240
  162. package/dist/domain/entities/Catalog.js.map +0 -1
  163. package/dist/domain/entities/Package.d.ts +0 -143
  164. package/dist/domain/entities/Package.d.ts.map +0 -1
  165. package/dist/domain/entities/Package.js +0 -272
  166. package/dist/domain/entities/Package.js.map +0 -1
  167. package/dist/domain/entities/Workspace.d.ts +0 -95
  168. package/dist/domain/entities/Workspace.d.ts.map +0 -1
  169. package/dist/domain/entities/Workspace.js +0 -173
  170. package/dist/domain/entities/Workspace.js.map +0 -1
  171. package/dist/domain/repositories/WorkspaceRepository.d.ts +0 -41
  172. package/dist/domain/repositories/WorkspaceRepository.d.ts.map +0 -1
  173. package/dist/domain/repositories/WorkspaceRepository.js +0 -8
  174. package/dist/domain/repositories/WorkspaceRepository.js.map +0 -1
  175. package/dist/domain/value-objects/CatalogCollection.d.ts +0 -106
  176. package/dist/domain/value-objects/CatalogCollection.d.ts.map +0 -1
  177. package/dist/domain/value-objects/CatalogCollection.js +0 -230
  178. package/dist/domain/value-objects/CatalogCollection.js.map +0 -1
  179. package/dist/domain/value-objects/PackageCollection.d.ts +0 -122
  180. package/dist/domain/value-objects/PackageCollection.d.ts.map +0 -1
  181. package/dist/domain/value-objects/PackageCollection.js +0 -263
  182. package/dist/domain/value-objects/PackageCollection.js.map +0 -1
  183. package/dist/domain/value-objects/Version.d.ts +0 -141
  184. package/dist/domain/value-objects/Version.d.ts.map +0 -1
  185. package/dist/domain/value-objects/Version.js +0 -268
  186. package/dist/domain/value-objects/Version.js.map +0 -1
  187. package/dist/domain/value-objects/WorkspaceConfig.d.ts +0 -144
  188. package/dist/domain/value-objects/WorkspaceConfig.d.ts.map +0 -1
  189. package/dist/domain/value-objects/WorkspaceConfig.js +0 -357
  190. package/dist/domain/value-objects/WorkspaceConfig.js.map +0 -1
  191. package/dist/domain/value-objects/WorkspaceId.d.ts +0 -51
  192. package/dist/domain/value-objects/WorkspaceId.d.ts.map +0 -1
  193. package/dist/domain/value-objects/WorkspaceId.js +0 -104
  194. package/dist/domain/value-objects/WorkspaceId.js.map +0 -1
  195. package/dist/domain/value-objects/WorkspacePath.d.ts +0 -75
  196. package/dist/domain/value-objects/WorkspacePath.d.ts.map +0 -1
  197. package/dist/domain/value-objects/WorkspacePath.js +0 -128
  198. package/dist/domain/value-objects/WorkspacePath.js.map +0 -1
  199. package/dist/index.d.ts +0 -25
  200. package/dist/index.d.ts.map +0 -1
  201. package/dist/infrastructure/cache/Cache.d.ts +0 -161
  202. package/dist/infrastructure/cache/Cache.d.ts.map +0 -1
  203. package/dist/infrastructure/cache/Cache.js +0 -398
  204. package/dist/infrastructure/cache/Cache.js.map +0 -1
  205. package/dist/infrastructure/cache/index.d.ts +0 -6
  206. package/dist/infrastructure/cache/index.d.ts.map +0 -1
  207. package/dist/infrastructure/cache/index.js +0 -6
  208. package/dist/infrastructure/cache/index.js.map +0 -1
  209. package/dist/infrastructure/external-services/NpmRegistryService.d.ts +0 -145
  210. package/dist/infrastructure/external-services/NpmRegistryService.d.ts.map +0 -1
  211. package/dist/infrastructure/external-services/NpmRegistryService.js +0 -466
  212. package/dist/infrastructure/external-services/NpmRegistryService.js.map +0 -1
  213. package/dist/infrastructure/file-system/FileSystemService.d.ts +0 -120
  214. package/dist/infrastructure/file-system/FileSystemService.d.ts.map +0 -1
  215. package/dist/infrastructure/file-system/FileSystemService.js +0 -663
  216. package/dist/infrastructure/file-system/FileSystemService.js.map +0 -1
  217. package/dist/infrastructure/repositories/FileWorkspaceRepository.d.ts +0 -57
  218. package/dist/infrastructure/repositories/FileWorkspaceRepository.d.ts.map +0 -1
  219. package/dist/infrastructure/repositories/FileWorkspaceRepository.js +0 -179
  220. package/dist/infrastructure/repositories/FileWorkspaceRepository.js.map +0 -1
@@ -1,836 +0,0 @@
1
- /**
2
- * Catalog Update Service
3
- *
4
- * Core application service that handles catalog dependency updates.
5
- * Orchestrates domain objects and infrastructure services to provide
6
- * high-level use cases for checking and updating catalog dependencies.
7
- */
8
- import { WorkspacePath } from '../../domain/value-objects/WorkspacePath.js';
9
- import { Version } from '../../domain/value-objects/Version.js';
10
- import { NpmRegistryService } from '../../infrastructure/external-services/NpmRegistryService.js';
11
- import { ConfigLoader } from '../../common/config/ConfigLoader.js';
12
- import { UserFriendlyErrorHandler } from '../../common/error-handling/UserFriendlyErrorHandler.js';
13
- import { ProgressBar } from '../../cli/formatters/ProgressBar.js';
14
- export class CatalogUpdateService {
15
- workspaceRepository;
16
- registryService;
17
- constructor(workspaceRepository, registryService) {
18
- this.workspaceRepository = workspaceRepository;
19
- this.registryService = registryService;
20
- }
21
- /**
22
- * Create a new CatalogUpdateService with advanced configuration
23
- */
24
- static createWithConfig(workspaceRepository, workspacePath) {
25
- const config = ConfigLoader.loadConfig(workspacePath || process.cwd());
26
- // Create registry service with advanced configuration
27
- const advancedConfig = {};
28
- if (config.advanced?.concurrency !== undefined) {
29
- advancedConfig.concurrency = config.advanced.concurrency;
30
- }
31
- if (config.advanced?.timeout !== undefined) {
32
- advancedConfig.timeout = config.advanced.timeout;
33
- }
34
- if (config.advanced?.retries !== undefined) {
35
- advancedConfig.retries = config.advanced.retries;
36
- }
37
- if (config.advanced?.cacheValidityMinutes !== undefined) {
38
- advancedConfig.cacheValidityMinutes = config.advanced.cacheValidityMinutes;
39
- }
40
- const registryService = new NpmRegistryService('https://registry.npmjs.org/', advancedConfig);
41
- return new CatalogUpdateService(workspaceRepository, registryService);
42
- }
43
- /**
44
- * Check for outdated catalog dependencies
45
- */
46
- async checkOutdatedDependencies(options = {}) {
47
- const workspacePath = WorkspacePath.fromString(options.workspacePath || process.cwd());
48
- // Load configuration
49
- const config = ConfigLoader.loadConfig(workspacePath.toString());
50
- // Load workspace
51
- const workspace = await this.workspaceRepository.findByPath(workspacePath);
52
- if (!workspace) {
53
- throw new Error(`No pnpm workspace found at ${workspacePath.toString()}`);
54
- }
55
- const catalogs = workspace.getCatalogs();
56
- const catalogInfos = [];
57
- let totalOutdated = 0;
58
- // Filter catalogs if specific catalog requested
59
- const catalogsToCheck = options.catalogName
60
- ? [catalogs.get(options.catalogName)].filter(Boolean)
61
- : catalogs.getAll();
62
- if (catalogsToCheck.length === 0) {
63
- throw new Error(options.catalogName
64
- ? `Catalog "${options.catalogName}" not found`
65
- : 'No catalogs found in workspace');
66
- }
67
- // Calculate total packages across all catalogs
68
- let totalPackages = 0;
69
- const allPackagesToCheck = [];
70
- for (const catalog of catalogsToCheck) {
71
- if (!catalog)
72
- continue;
73
- const dependencies = catalog.getDependencies();
74
- const packageArray = Array.from(dependencies);
75
- const packagesToCheck = packageArray.filter(([packageName]) => {
76
- const packageConfig = ConfigLoader.getPackageConfig(packageName, config);
77
- return packageConfig.shouldUpdate;
78
- });
79
- // Add catalog info to each package for processing
80
- packagesToCheck.forEach(([packageName, range]) => {
81
- allPackagesToCheck.push([packageName, range, catalog]);
82
- });
83
- totalPackages += packagesToCheck.length;
84
- }
85
- // Create a single progress bar for all catalogs
86
- let progressBar = null;
87
- if (totalPackages > 0) {
88
- progressBar = new ProgressBar({
89
- text: 'ๆญฃๅœจๆฃ€ๆŸฅไพ่ต–ๅŒ…...',
90
- total: totalPackages,
91
- });
92
- progressBar.start(`ๆญฃๅœจๆฃ€ๆŸฅ ${totalPackages} ไธชไพ่ต–ๅŒ…...`);
93
- }
94
- let completed = 0;
95
- // Check each catalog for outdated dependencies
96
- for (const catalog of catalogsToCheck) {
97
- if (!catalog) {
98
- throw new Error(`Catalog "${catalogsToCheck[0]?.getName() || 'unknown'}" not found`);
99
- }
100
- const dependencies = catalog.getDependencies();
101
- // Convert to array for parallel processing
102
- const packageArray = Array.from(dependencies);
103
- // Filter packages that should be updated based on configuration
104
- const packagesToCheck = packageArray.filter(([packageName]) => {
105
- const packageConfig = ConfigLoader.getPackageConfig(packageName, config);
106
- return packageConfig.shouldUpdate;
107
- });
108
- // Process packages in parallel with concurrency control (pass progress info)
109
- const outdatedDependencies = await this.processPackagesInParallel(packagesToCheck, catalog, workspace, config, options, progressBar, completed, totalPackages);
110
- // Update completed count
111
- completed += packagesToCheck.length;
112
- const catalogInfo = {
113
- catalogName: catalog.getName(),
114
- outdatedDependencies,
115
- totalPackages: dependencies.size,
116
- outdatedCount: outdatedDependencies.length,
117
- };
118
- catalogInfos.push(catalogInfo);
119
- totalOutdated += outdatedDependencies.length;
120
- }
121
- // Complete the progress bar
122
- if (progressBar) {
123
- if (totalOutdated > 0) {
124
- progressBar.succeed(`โœ… ๆฃ€ๆŸฅๅฎŒๆˆ! ๅ‘็Žฐ ${totalOutdated} ไธชๅฏๆ›ดๆ–ฐ็š„ไพ่ต–ๅŒ…`);
125
- }
126
- else {
127
- progressBar.succeed('โœ… ๆฃ€ๆŸฅๅฎŒๆˆ! ๆ‰€ๆœ‰ไพ่ต–ๅŒ…้ƒฝๆ˜ฏๆœ€ๆ–ฐ็š„');
128
- }
129
- }
130
- return {
131
- workspace: {
132
- path: workspacePath.toString(),
133
- name: workspacePath.getDirectoryName(),
134
- },
135
- catalogs: catalogInfos,
136
- totalOutdated,
137
- hasUpdates: totalOutdated > 0,
138
- };
139
- }
140
- /**
141
- * Plan catalog dependency updates
142
- */
143
- async planUpdates(options) {
144
- const outdatedReport = await this.checkOutdatedDependencies(options);
145
- const updates = [];
146
- const conflicts = [];
147
- // Load configuration for package rules and monorepo settings
148
- const workspacePath = options.workspacePath || process.cwd();
149
- const config = ConfigLoader.loadConfig(workspacePath);
150
- // Convert outdated dependencies to planned updates
151
- for (const catalogInfo of outdatedReport.catalogs) {
152
- for (const outdated of catalogInfo.outdatedDependencies) {
153
- // Get package-specific configuration
154
- const packageConfig = ConfigLoader.getPackageConfig(outdated.packageName, config);
155
- const update = {
156
- catalogName: catalogInfo.catalogName,
157
- packageName: outdated.packageName,
158
- currentVersion: outdated.currentVersion,
159
- newVersion: outdated.latestVersion,
160
- updateType: outdated.updateType,
161
- reason: this.getUpdateReason(outdated),
162
- affectedPackages: outdated.affectedPackages,
163
- requireConfirmation: packageConfig.requireConfirmation,
164
- autoUpdate: packageConfig.autoUpdate,
165
- groupUpdate: packageConfig.groupUpdate,
166
- };
167
- updates.push(update);
168
- }
169
- }
170
- // Handle syncVersions - ensure packages in syncVersions list are synchronized across catalogs
171
- if (config.monorepo?.syncVersions && config.monorepo.syncVersions.length > 0) {
172
- const workspacePathObj = WorkspacePath.fromString(workspacePath);
173
- const workspace = await this.workspaceRepository.findByPath(workspacePathObj);
174
- if (workspace) {
175
- updates.push(...(await this.createSyncVersionUpdates(config.monorepo.syncVersions, workspace, updates)));
176
- }
177
- }
178
- // Detect conflicts (same package in multiple catalogs with different versions)
179
- const packageCatalogMap = new Map();
180
- for (const update of updates) {
181
- if (!packageCatalogMap.has(update.packageName)) {
182
- packageCatalogMap.set(update.packageName, []);
183
- }
184
- packageCatalogMap.get(update.packageName).push(update);
185
- }
186
- // Handle conflicts with catalogPriority
187
- for (const [packageName, packageUpdates] of packageCatalogMap) {
188
- if (packageUpdates.length > 1) {
189
- const uniqueVersions = new Set(packageUpdates.map((u) => u.newVersion));
190
- if (uniqueVersions.size > 1) {
191
- const resolvedConflict = this.resolveVersionConflict(packageName, packageUpdates, config.monorepo?.catalogPriority || ['default']);
192
- if (resolvedConflict) {
193
- conflicts.push(resolvedConflict);
194
- }
195
- }
196
- }
197
- }
198
- return {
199
- workspace: outdatedReport.workspace,
200
- updates,
201
- conflicts,
202
- totalUpdates: updates.length,
203
- hasConflicts: conflicts.length > 0,
204
- };
205
- }
206
- /**
207
- * Execute catalog dependency updates
208
- */
209
- async executeUpdates(plan, options) {
210
- const workspacePath = WorkspacePath.fromString(plan.workspace.path);
211
- // Load configuration for security settings
212
- const config = ConfigLoader.loadConfig(workspacePath.toString());
213
- // Load workspace
214
- const workspace = await this.workspaceRepository.findByPath(workspacePath);
215
- if (!workspace) {
216
- throw new Error(`Workspace not found at ${workspacePath.toString()}`);
217
- }
218
- const updatedDependencies = [];
219
- const skippedDependencies = [];
220
- const errors = [];
221
- // Track security updates for notification
222
- const securityUpdates = [];
223
- // Execute updates
224
- for (const update of plan.updates) {
225
- try {
226
- // Skip if conflicts exist and force is not enabled
227
- if (plan.hasConflicts && !options.force) {
228
- const hasConflict = plan.conflicts.some((c) => c.packageName === update.packageName);
229
- if (hasConflict) {
230
- skippedDependencies.push({
231
- catalogName: update.catalogName,
232
- packageName: update.packageName,
233
- currentVersion: update.currentVersion,
234
- reason: 'Version conflict - use --force to override',
235
- });
236
- continue;
237
- }
238
- }
239
- // Check if this is a security update and track it
240
- let isSecurityUpdate = false;
241
- if (config.security?.notifyOnSecurityUpdate) {
242
- try {
243
- const securityReport = await this.registryService.checkSecurityVulnerabilities(update.packageName, update.currentVersion);
244
- if (securityReport.hasVulnerabilities) {
245
- isSecurityUpdate = true;
246
- securityUpdates.push(`${update.packageName}@${update.currentVersion} โ†’ ${update.newVersion}`);
247
- }
248
- }
249
- catch (error) {
250
- UserFriendlyErrorHandler.handleSecurityCheckFailure(update.packageName, error, { operation: 'update' });
251
- }
252
- }
253
- // Perform the update
254
- workspace.updateCatalogDependency(update.catalogName, update.packageName, update.newVersion);
255
- updatedDependencies.push({
256
- catalogName: update.catalogName,
257
- packageName: update.packageName,
258
- fromVersion: update.currentVersion,
259
- toVersion: update.newVersion,
260
- updateType: update.updateType,
261
- });
262
- // Log security update notification
263
- if (isSecurityUpdate && config.security?.notifyOnSecurityUpdate) {
264
- console.log(`โœ… Security fix applied: ${update.packageName}@${update.currentVersion} โ†’ ${update.newVersion}`);
265
- }
266
- }
267
- catch (error) {
268
- errors.push({
269
- catalogName: update.catalogName,
270
- packageName: update.packageName,
271
- error: String(error),
272
- fatal: false,
273
- });
274
- }
275
- }
276
- // Save workspace if not in dry-run mode
277
- if (!options.dryRun && updatedDependencies.length > 0) {
278
- try {
279
- await this.workspaceRepository.save(workspace);
280
- // Show summary of security updates if any
281
- if (securityUpdates.length > 0 && config.security?.notifyOnSecurityUpdate) {
282
- console.log(`\n๐Ÿ”’ Security Updates Summary:`);
283
- console.log(` Applied ${securityUpdates.length} security fix(es):`);
284
- securityUpdates.forEach((update) => console.log(` โ€ข ${update}`));
285
- }
286
- // Show summary of synced version updates
287
- const syncUpdates = updatedDependencies.filter((u) => plan.updates.find((pu) => pu.packageName === u.packageName &&
288
- pu.catalogName === u.catalogName &&
289
- pu.reason.includes('Sync version')));
290
- if (syncUpdates.length > 0) {
291
- console.log(`\n๐Ÿ”„ Version Sync Summary:`);
292
- const syncedPackages = new Set(syncUpdates.map((u) => u.packageName));
293
- console.log(` Synchronized ${syncedPackages.size} package(s) across catalogs:`);
294
- // Group by package name
295
- const syncByPackage = new Map();
296
- syncUpdates.forEach((update) => {
297
- if (!syncByPackage.has(update.packageName)) {
298
- syncByPackage.set(update.packageName, []);
299
- }
300
- syncByPackage.get(update.packageName).push(update);
301
- });
302
- syncByPackage.forEach((updates, packageName) => {
303
- const catalogs = updates.map((u) => u.catalogName).join(', ');
304
- const version = updates[0]?.toVersion;
305
- console.log(` โ€ข ${packageName}@${version} in catalogs: ${catalogs}`);
306
- });
307
- }
308
- // Show catalog priority resolution if any
309
- if (plan.hasConflicts &&
310
- plan.conflicts.some((c) => c.recommendation.includes('Priority catalog'))) {
311
- console.log(`\n๐Ÿ“‹ Catalog Priority Resolutions:`);
312
- plan.conflicts
313
- .filter((c) => c.recommendation.includes('Priority catalog'))
314
- .forEach((conflict) => {
315
- console.log(` โ€ข ${conflict.packageName}: ${conflict.recommendation}`);
316
- });
317
- }
318
- }
319
- catch (error) {
320
- errors.push({
321
- catalogName: '',
322
- packageName: '',
323
- error: `Failed to save workspace: ${error}`,
324
- fatal: true,
325
- });
326
- }
327
- }
328
- return {
329
- success: errors.filter((e) => e.fatal).length === 0,
330
- workspace: plan.workspace,
331
- updatedDependencies,
332
- skippedDependencies,
333
- errors,
334
- totalUpdated: updatedDependencies.length,
335
- totalSkipped: skippedDependencies.length,
336
- totalErrors: errors.length,
337
- };
338
- }
339
- /**
340
- * Analyze the impact of updating a specific dependency
341
- */
342
- async analyzeImpact(catalogName, packageName, newVersion, workspacePath) {
343
- const wsPath = WorkspacePath.fromString(workspacePath || process.cwd());
344
- // Load workspace
345
- const workspace = await this.workspaceRepository.findByPath(wsPath);
346
- if (!workspace) {
347
- throw new Error(`No pnpm workspace found at ${wsPath.toString()}`);
348
- }
349
- const catalog = workspace.getCatalogs().get(catalogName);
350
- if (!catalog) {
351
- throw new Error(`Catalog "${catalogName}" not found`);
352
- }
353
- const currentRange = catalog.getDependencyVersion(packageName);
354
- if (!currentRange) {
355
- throw new Error(`Package "${packageName}" not found in catalog "${catalogName}"`);
356
- }
357
- const currentVersion = currentRange.toString();
358
- const proposedVersion = Version.fromString(newVersion);
359
- const currentVersionObj = currentRange.getMinVersion();
360
- if (!currentVersionObj) {
361
- throw new Error(`Cannot determine current version for ${packageName}`);
362
- }
363
- const updateType = currentVersionObj.getDifferenceType(proposedVersion);
364
- // Get affected packages
365
- const affectedPackagesCollection = workspace.getPackagesUsingCatalogDependency(catalogName, packageName);
366
- const packageImpacts = [];
367
- for (const pkg of affectedPackagesCollection.getAll()) {
368
- const catalogRefs = pkg
369
- .getCatalogReferences()
370
- .filter((ref) => ref.getCatalogName() === catalogName && ref.getPackageName() === packageName);
371
- for (const ref of catalogRefs) {
372
- const isBreakingChange = updateType === 'major';
373
- const compatibilityRisk = this.assessCompatibilityRisk(updateType);
374
- packageImpacts.push({
375
- packageName: pkg.getName(),
376
- packagePath: pkg.getPath().toString(),
377
- dependencyType: ref.getDependencyType(),
378
- isBreakingChange,
379
- compatibilityRisk,
380
- });
381
- }
382
- }
383
- // Check security impact
384
- const securityImpact = await this.analyzeSecurityImpact(packageName, currentVersion, newVersion);
385
- // Assess overall risk
386
- const riskLevel = this.assessOverallRisk(updateType, packageImpacts, securityImpact);
387
- // Generate recommendations
388
- const recommendations = this.generateRecommendations(updateType, securityImpact, packageImpacts);
389
- return {
390
- packageName,
391
- catalogName,
392
- currentVersion,
393
- proposedVersion: newVersion,
394
- updateType: updateType,
395
- affectedPackages: packageImpacts,
396
- riskLevel,
397
- securityImpact,
398
- recommendations,
399
- };
400
- }
401
- /**
402
- * Process packages in parallel with concurrency control and progress tracking
403
- */
404
- async processPackagesInParallel(packagesToCheck, catalog, workspace, config, options, progressBar, startingCompleted = 0, totalPackages = 0) {
405
- const concurrency = config.advanced?.concurrency || 8; // Increased from 5 to match NCU
406
- const outdatedDependencies = [];
407
- let completed = startingCompleted;
408
- // Process packages in chunks with true parallelism within each chunk
409
- const chunks = this.chunkArray(packagesToCheck, concurrency);
410
- for (const chunk of chunks) {
411
- const chunkResults = await Promise.all(chunk.map(async ([packageName, currentRange]) => {
412
- try {
413
- const result = await this.processPackageCheck(packageName, currentRange, catalog, workspace, config, options);
414
- // Update progress for successful package
415
- completed++;
416
- if (progressBar && totalPackages > 0) {
417
- progressBar.update(`ๆญฃๅœจๆฃ€ๆŸฅไพ่ต–ๅŒ…: ${packageName}`, completed, totalPackages);
418
- }
419
- return result;
420
- }
421
- catch (error) {
422
- // Update progress even for failed packages
423
- completed++;
424
- if (progressBar && totalPackages > 0) {
425
- progressBar.update(`่ทณ่ฟ‡ๅŒ… ${packageName} (ๆฃ€ๆŸฅๅคฑ่ดฅ)`, completed, totalPackages);
426
- }
427
- UserFriendlyErrorHandler.handlePackageQueryFailure(packageName, error, {
428
- operation: 'check',
429
- });
430
- return null;
431
- }
432
- }));
433
- // Add successful results to the array
434
- chunkResults.forEach((result) => {
435
- if (result) {
436
- outdatedDependencies.push(result);
437
- }
438
- });
439
- }
440
- return outdatedDependencies;
441
- }
442
- /**
443
- * Process a single package check (extracted from the main loop)
444
- */
445
- async processPackageCheck(packageName, currentRange, catalog, workspace, config, options) {
446
- // Get package-specific configuration
447
- const packageConfig = ConfigLoader.getPackageConfig(packageName, config);
448
- const effectiveTarget = packageConfig.target;
449
- // Defer security checks - only do them after we know the package needs updating
450
- const outdatedInfo = await this.checkPackageUpdate(packageName, currentRange, effectiveTarget, options.includePrerelease || config.defaults?.includePrerelease || false);
451
- if (!outdatedInfo) {
452
- return null; // Package doesn't need updating
453
- }
454
- // Now check for security vulnerabilities only for packages that need updating
455
- let hasSecurityVulnerabilities = false;
456
- if (config.security?.autoFixVulnerabilities) {
457
- try {
458
- const currentVersion = currentRange.getMinVersion()?.toString();
459
- if (currentVersion) {
460
- const securityReport = await this.registryService.checkSecurityVulnerabilities(packageName, currentVersion);
461
- hasSecurityVulnerabilities = securityReport.hasVulnerabilities;
462
- // Allow major updates for security fixes if configured
463
- if (hasSecurityVulnerabilities && config.security.allowMajorForSecurity) {
464
- // Re-check with 'latest' target if security fix requires it
465
- const securityFixInfo = await this.checkPackageUpdate(packageName, currentRange, 'latest', options.includePrerelease || config.defaults?.includePrerelease || false);
466
- if (securityFixInfo) {
467
- Object.assign(outdatedInfo, securityFixInfo);
468
- }
469
- }
470
- }
471
- }
472
- catch (error) {
473
- UserFriendlyErrorHandler.handleSecurityCheckFailure(packageName, error);
474
- }
475
- }
476
- // Get affected packages
477
- const affectedPackages = workspace
478
- .getPackagesUsingCatalogDependency(catalog.getName(), packageName)
479
- .getPackageNames();
480
- // Log security notifications if enabled
481
- if (hasSecurityVulnerabilities && config.security?.notifyOnSecurityUpdate) {
482
- console.warn(`๐Ÿ”’ Security vulnerability detected in ${packageName}@${outdatedInfo.currentVersion}`);
483
- }
484
- return {
485
- ...outdatedInfo,
486
- affectedPackages,
487
- isSecurityUpdate: hasSecurityVulnerabilities || outdatedInfo.isSecurityUpdate,
488
- };
489
- }
490
- /**
491
- * Split array into chunks for parallel processing
492
- */
493
- chunkArray(array, chunkSize) {
494
- const chunks = [];
495
- for (let i = 0; i < array.length; i += chunkSize) {
496
- chunks.push(array.slice(i, i + chunkSize));
497
- }
498
- return chunks;
499
- }
500
- /**
501
- * Check if a package needs updating
502
- */
503
- async checkPackageUpdate(packageName, currentRange, target, includePrerelease) {
504
- try {
505
- // Use lightweight version API for better performance
506
- const versionInfo = await this.registryService.getPackageVersions(packageName);
507
- let targetVersion;
508
- switch (target) {
509
- case 'latest':
510
- targetVersion = Version.fromString(versionInfo.latestVersion);
511
- break;
512
- case 'greatest':
513
- targetVersion = await this.registryService.getGreatestVersion(packageName);
514
- break;
515
- case 'newest':
516
- const newestVersions = await this.registryService.getNewestVersions(packageName, 1);
517
- if (!newestVersions[0]) {
518
- throw new Error(`No versions found for ${packageName}`);
519
- }
520
- targetVersion = newestVersions[0];
521
- break;
522
- case 'minor':
523
- case 'patch':
524
- targetVersion = await this.getConstrainedVersion(packageName, currentRange, target);
525
- break;
526
- default:
527
- targetVersion = Version.fromString(versionInfo.latestVersion);
528
- }
529
- // Skip prereleases unless explicitly requested
530
- if (!includePrerelease && targetVersion.isPrerelease()) {
531
- return null;
532
- }
533
- const currentVersion = currentRange.getMinVersion();
534
- if (!currentVersion) {
535
- return null;
536
- }
537
- // Check if update is needed
538
- if (!targetVersion.isNewerThan(currentVersion)) {
539
- return null;
540
- }
541
- const updateType = currentVersion.getDifferenceType(targetVersion);
542
- // Check for security vulnerabilities
543
- const securityReport = await this.registryService.checkSecurityVulnerabilities(packageName, currentVersion.toString());
544
- return {
545
- packageName,
546
- currentVersion: currentVersion.toString(),
547
- latestVersion: targetVersion.toString(),
548
- wantedVersion: targetVersion.toString(),
549
- updateType: updateType,
550
- isSecurityUpdate: securityReport.hasVulnerabilities,
551
- affectedPackages: [], // Will be filled by caller
552
- };
553
- }
554
- catch (error) {
555
- UserFriendlyErrorHandler.handlePackageQueryFailure(packageName, error, {
556
- operation: 'update-check',
557
- });
558
- return null;
559
- }
560
- }
561
- /**
562
- * Get version constrained by update type
563
- */
564
- async getConstrainedVersion(packageName, currentRange, constraint) {
565
- const currentVersion = currentRange.getMinVersion();
566
- if (!currentVersion) {
567
- throw new Error(`Cannot determine current version for ${packageName}`);
568
- }
569
- const versionInfo = await this.registryService.getPackageVersions(packageName);
570
- // Filter versions based on constraint
571
- const compatibleVersions = versionInfo.versions.filter((v) => {
572
- try {
573
- const version = Version.fromString(v);
574
- const diff = currentVersion.getDifferenceType(version);
575
- if (constraint === 'patch') {
576
- return diff === 'patch' || diff === 'same';
577
- }
578
- else if (constraint === 'minor') {
579
- return diff === 'minor' || diff === 'patch' || diff === 'same';
580
- }
581
- return false;
582
- }
583
- catch {
584
- return false;
585
- }
586
- });
587
- if (compatibleVersions.length === 0) {
588
- return currentVersion;
589
- }
590
- // Return the highest compatible version
591
- if (!compatibleVersions[0]) {
592
- throw new Error(`No compatible versions found for ${packageName}`);
593
- }
594
- return Version.fromString(compatibleVersions[0]);
595
- }
596
- /**
597
- * Generate update reason description
598
- */
599
- getUpdateReason(outdated) {
600
- if (outdated.isSecurityUpdate) {
601
- return 'Security update available';
602
- }
603
- switch (outdated.updateType) {
604
- case 'major':
605
- return 'Major version update available';
606
- case 'minor':
607
- return 'Minor version update available';
608
- case 'patch':
609
- return 'Patch version update available';
610
- default:
611
- return 'Update available';
612
- }
613
- }
614
- /**
615
- * Analyze security impact of version change
616
- */
617
- async analyzeSecurityImpact(packageName, currentVersion, newVersion) {
618
- try {
619
- const [currentSecurity, newSecurity] = await Promise.all([
620
- this.registryService.checkSecurityVulnerabilities(packageName, currentVersion),
621
- this.registryService.checkSecurityVulnerabilities(packageName, newVersion),
622
- ]);
623
- const fixedVulnerabilities = currentSecurity.vulnerabilities.length - newSecurity.vulnerabilities.length;
624
- const newVulnerabilities = Math.max(0, newSecurity.vulnerabilities.length - currentSecurity.vulnerabilities.length);
625
- let severityChange = 'same';
626
- if (fixedVulnerabilities > 0) {
627
- severityChange = 'better';
628
- }
629
- else if (newVulnerabilities > 0) {
630
- severityChange = 'worse';
631
- }
632
- return {
633
- hasVulnerabilities: currentSecurity.hasVulnerabilities || newSecurity.hasVulnerabilities,
634
- fixedVulnerabilities: Math.max(0, fixedVulnerabilities),
635
- newVulnerabilities,
636
- severityChange,
637
- };
638
- }
639
- catch {
640
- return {
641
- hasVulnerabilities: false,
642
- fixedVulnerabilities: 0,
643
- newVulnerabilities: 0,
644
- severityChange: 'same',
645
- };
646
- }
647
- }
648
- /**
649
- * Assess compatibility risk for update type
650
- */
651
- assessCompatibilityRisk(updateType) {
652
- switch (updateType) {
653
- case 'patch':
654
- return 'low';
655
- case 'minor':
656
- return 'medium';
657
- case 'major':
658
- return 'high';
659
- default:
660
- return 'medium';
661
- }
662
- }
663
- /**
664
- * Assess overall risk level
665
- */
666
- assessOverallRisk(updateType, packageImpacts, securityImpact) {
667
- // Security fixes reduce risk
668
- if (securityImpact.fixedVulnerabilities > 0) {
669
- return updateType === 'major' ? 'medium' : 'low';
670
- }
671
- // New vulnerabilities increase risk
672
- if (securityImpact.newVulnerabilities > 0) {
673
- return 'high';
674
- }
675
- // Base risk on update type and number of affected packages
676
- const affectedPackageCount = packageImpacts.length;
677
- if (updateType === 'major') {
678
- return affectedPackageCount > 5 ? 'high' : 'medium';
679
- }
680
- else if (updateType === 'minor') {
681
- return affectedPackageCount > 10 ? 'medium' : 'low';
682
- }
683
- else {
684
- return 'low';
685
- }
686
- }
687
- /**
688
- * Generate recommendations based on analysis
689
- */
690
- generateRecommendations(updateType, securityImpact, packageImpacts) {
691
- const recommendations = [];
692
- if (securityImpact.fixedVulnerabilities > 0) {
693
- recommendations.push('๐Ÿ”’ Security update recommended - fixes known vulnerabilities');
694
- }
695
- if (securityImpact.newVulnerabilities > 0) {
696
- recommendations.push('โš ๏ธ New vulnerabilities detected - review carefully before updating');
697
- }
698
- if (updateType === 'major') {
699
- recommendations.push('๐Ÿ“– Review changelog for breaking changes before updating');
700
- recommendations.push('๐Ÿงช Test thoroughly in development environment');
701
- }
702
- const breakingChangePackages = packageImpacts.filter((p) => p.isBreakingChange);
703
- if (breakingChangePackages.length > 0) {
704
- recommendations.push(`๐Ÿ”ง ${breakingChangePackages.length} package(s) may need code changes`);
705
- }
706
- if (packageImpacts.length > 5) {
707
- recommendations.push('๐Ÿ“ฆ Many packages affected - consider updating in batches');
708
- }
709
- if (recommendations.length === 0) {
710
- recommendations.push('โœ… Low risk update - safe to proceed');
711
- }
712
- return recommendations;
713
- }
714
- /**
715
- * Create sync version updates for packages that should be synchronized across catalogs
716
- */
717
- async createSyncVersionUpdates(syncVersions, workspace, existingUpdates) {
718
- const syncUpdates = [];
719
- const catalogs = workspace.getCatalogs();
720
- const allCatalogs = catalogs.getAll();
721
- for (const packageName of syncVersions) {
722
- // Check if this package exists in multiple catalogs
723
- const catalogsWithPackage = allCatalogs.filter((catalog) => catalog && catalog.getDependencyVersion(packageName));
724
- if (catalogsWithPackage.length <= 1) {
725
- continue; // No need to sync if package is only in one catalog
726
- }
727
- // Find the highest version from existing updates or determine target version
728
- let targetVersion = null;
729
- let targetUpdateType = 'patch';
730
- // Check if this package has any existing updates
731
- const existingUpdate = existingUpdates.find((u) => u.packageName === packageName);
732
- if (existingUpdate) {
733
- targetVersion = existingUpdate.newVersion;
734
- targetUpdateType = existingUpdate.updateType;
735
- }
736
- else {
737
- // Get latest version for this package using lightweight API
738
- try {
739
- const versionInfo = await this.registryService.getPackageVersions(packageName);
740
- targetVersion = versionInfo.latestVersion;
741
- }
742
- catch (error) {
743
- UserFriendlyErrorHandler.handlePackageQueryFailure(packageName, error, {
744
- operation: 'sync',
745
- });
746
- continue;
747
- }
748
- }
749
- if (!targetVersion)
750
- continue;
751
- // Create sync updates for all catalogs that need updating
752
- for (const catalog of catalogsWithPackage) {
753
- const currentRange = catalog.getDependencyVersion(packageName);
754
- if (!currentRange)
755
- continue;
756
- const currentVersion = currentRange.getMinVersion();
757
- if (!currentVersion)
758
- continue;
759
- const currentVersionString = currentVersion.toString();
760
- // Skip if already at target version
761
- if (currentVersionString === targetVersion)
762
- continue;
763
- // Check if this update already exists
764
- const existingUpdateForCatalog = existingUpdates.find((u) => u.packageName === packageName && u.catalogName === catalog.getName());
765
- if (existingUpdateForCatalog) {
766
- // Update the existing update to use the sync version
767
- existingUpdateForCatalog.newVersion = targetVersion;
768
- existingUpdateForCatalog.reason = `Sync version across catalogs: ${existingUpdateForCatalog.reason}`;
769
- }
770
- else {
771
- // Create new sync update
772
- const affectedPackages = workspace
773
- .getPackagesUsingCatalogDependency(catalog.getName(), packageName)
774
- .getPackageNames();
775
- const syncUpdate = {
776
- catalogName: catalog.getName(),
777
- packageName: packageName,
778
- currentVersion: currentVersionString,
779
- newVersion: targetVersion,
780
- updateType: targetUpdateType,
781
- reason: `Sync version with other catalogs`,
782
- affectedPackages,
783
- requireConfirmation: true, // Sync updates should be confirmed
784
- autoUpdate: false,
785
- groupUpdate: true,
786
- };
787
- syncUpdates.push(syncUpdate);
788
- }
789
- }
790
- }
791
- return syncUpdates;
792
- }
793
- /**
794
- * Resolve version conflicts using catalog priority
795
- */
796
- resolveVersionConflict(packageName, packageUpdates, catalogPriority) {
797
- // Find the highest priority catalog with an update for this package
798
- let priorityCatalog = null;
799
- for (const catalogName of catalogPriority) {
800
- const catalogUpdate = packageUpdates.find((u) => u.catalogName === catalogName);
801
- if (catalogUpdate) {
802
- priorityCatalog = catalogUpdate;
803
- break;
804
- }
805
- }
806
- // If no priority catalog found, use the first one
807
- if (!priorityCatalog) {
808
- priorityCatalog = packageUpdates[0] || null;
809
- }
810
- // Update all other catalogs to use the priority catalog's version
811
- const priorityVersion = priorityCatalog?.newVersion;
812
- if (priorityVersion && priorityCatalog) {
813
- for (const update of packageUpdates) {
814
- if (update.catalogName !== priorityCatalog.catalogName) {
815
- update.newVersion = priorityVersion;
816
- update.reason = `Using version from priority catalog (${priorityCatalog.catalogName}): ${update.reason}`;
817
- }
818
- }
819
- }
820
- // Create conflict record for reporting
821
- const uniqueVersions = new Set(packageUpdates.map((u) => u.newVersion));
822
- if (uniqueVersions.size > 1) {
823
- return {
824
- packageName,
825
- catalogs: packageUpdates.map((u) => ({
826
- catalogName: u.catalogName,
827
- currentVersion: u.currentVersion,
828
- proposedVersion: u.newVersion,
829
- })),
830
- recommendation: `Resolved using catalog priority. Priority catalog '${priorityCatalog?.catalogName}' version '${priorityVersion}' selected.`,
831
- };
832
- }
833
- return null;
834
- }
835
- }
836
- //# sourceMappingURL=CatalogUpdateService.js.map