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