Added strict mode to check version ranges

This commit is contained in:
Hein 2025-10-10 13:42:04 +02:00
parent 2ffa2bd0ca
commit 3ca78de94c
2 changed files with 74 additions and 23 deletions

View File

@ -52,9 +52,16 @@ const cli = async () => {
default: 'text', default: 'text',
type:'string' type:'string'
}) })
.option('strict', {
alias: 's',
describe: 'Strict mode: only update packages with version ranges (~, ^, >=) if they are incompatible',
type: 'boolean',
default: false,
})
.example('$0 --check-versions', 'Show only version differences') .example('$0 --check-versions', 'Show only version differences')
.example('$0 --check-missing', 'Show missing dependencies') .example('$0 --check-missing', 'Show missing dependencies')
.example('$0 --update --dry-run', 'Show what would be updated') .example('$0 --update --dry-run', 'Show what would be updated')
.example('$0 --update --strict', 'Update only incompatible versions within ranges')
.example('$0 --packages ./packages,./other-packages', 'Check multiple package directories') .example('$0 --packages ./packages,./other-packages', 'Check multiple package directories')
.example('$0 --packages ./pkg1/package.json,./pkg2/package.json', 'Check specific package.json files') .example('$0 --packages ./pkg1/package.json,./pkg2/package.json', 'Check specific package.json files')
.example('$0 --packages ./packages,./other/package.json', 'Mix of directories and files') .example('$0 --packages ./packages,./other/package.json', 'Mix of directories and files')
@ -135,6 +142,7 @@ const cli = async () => {
format: argv.format as any, format: argv.format as any,
checkVersions: argv.checkVersions, checkVersions: argv.checkVersions,
checkMissing: argv.checkMissing, checkMissing: argv.checkMissing,
strict: argv.strict,
}); });
} catch (error:any) { } catch (error:any) {
console.error(chalk.red('Error during execution:')); console.error(chalk.red('Error during execution:'));

View File

@ -16,6 +16,7 @@ interface RunOptions {
format?: "text" | "json"; format?: "text" | "json";
checkVersions?: boolean; checkVersions?: boolean;
checkMissing?: boolean; checkMissing?: boolean;
strict?: boolean;
} }
interface VersionInfo { interface VersionInfo {
@ -75,6 +76,7 @@ class DependencyChecker {
private packageJsonFiles: string[]; private packageJsonFiles: string[];
private dependencyMap: Map<string, DependencyInfo>; private dependencyMap: Map<string, DependencyInfo>;
private workspacePackages: Set<string>; private workspacePackages: Set<string>;
private strictMode: boolean;
constructor(appPackageJsonPath: string, packagesInput: string) { constructor(appPackageJsonPath: string, packagesInput: string) {
this.appPackageJsonPath = appPackageJsonPath; this.appPackageJsonPath = appPackageJsonPath;
@ -82,6 +84,7 @@ class DependencyChecker {
this.packageJsonFiles = []; this.packageJsonFiles = [];
this.dependencyMap = new Map(); this.dependencyMap = new Map();
this.workspacePackages = new Set(); this.workspacePackages = new Set();
this.strictMode = false;
} }
private findWorkspacePackages(): void { private findWorkspacePackages(): void {
@ -147,6 +150,21 @@ class DependencyChecker {
return this.workspacePackages.has(packageName); return this.workspacePackages.has(packageName);
} }
private hasVersionRange(version: string): boolean {
return /^[~^<>=]+/.test(version);
}
private isVersionCompatible(rangeVersion: string, targetVersion: string): boolean {
try {
const cleanTargetVersion = this.getSemverVersion(targetVersion);
if (!cleanTargetVersion) return false;
return semver.satisfies(cleanTargetVersion, rangeVersion);
} catch {
return false;
}
}
private shouldIncludeDependency( private shouldIncludeDependency(
depName: string, depName: string,
version: string, version: string,
@ -590,30 +608,52 @@ class DependencyChecker {
if (appDependencies[dep]) { if (appDependencies[dep]) {
const appVersion = appDependencies[dep]; const appVersion = appDependencies[dep];
// Extract just the version numbers for comparison
const cleanCurrentVersion = version.replace(/^[~^<>=]+\s*/g, ""); // In strict mode, check if versions are compatible within range constraints
const cleanAppVersion = appVersion.replace(/^[~^<>=]+\s*/g, ""); if (this.strictMode && this.hasVersionRange(version)) {
if (!this.isVersionCompatible(version, appVersion)) {
if (cleanCurrentVersion !== cleanAppVersion) { // Only update if the app version doesn't satisfy the range
// Extract the version prefix (operators and spaces) const cleanAppVersion = appVersion.replace(/^[~^<>=]+\s*/g, "");
const versionPrefix = version.match(/^[~^<>=]+\s*/)?.[0] || ''; const versionPrefix = version.match(/^[~^<>=]+\s*/)?.[0] || '';
const newVersion = versionPrefix + cleanAppVersion;
// Create new version string with original prefix but updated version number
const newVersion = versionPrefix + cleanAppVersion; if (!dryRun) {
packageJson[section]![dep] = newVersion;
if (!dryRun) { }
packageJson[section]![dep] = newVersion;
updates.push({
package: packageJson.name,
dependency: dep,
from: version,
to: newVersion,
type: section,
});
hasUpdates = true;
}
} else {
// Original behavior for non-strict mode
const cleanCurrentVersion = version.replace(/^[~^<>=]+\s*/g, "");
const cleanAppVersion = appVersion.replace(/^[~^<>=]+\s*/g, "");
if (cleanCurrentVersion !== cleanAppVersion) {
const versionPrefix = version.match(/^[~^<>=]+\s*/)?.[0] || '';
const newVersion = versionPrefix + cleanAppVersion;
if (!dryRun) {
packageJson[section]![dep] = newVersion;
}
updates.push({
package: packageJson.name,
dependency: dep,
from: version,
to: newVersion,
type: section,
});
hasUpdates = true;
} }
updates.push({
package: packageJson.name,
dependency: dep,
from: version,
to: newVersion,
type: section,
});
hasUpdates = true;
} }
} }
}); });
@ -768,8 +808,11 @@ class DependencyChecker {
format = "text", format = "text",
checkVersions = false, checkVersions = false,
checkMissing = false, checkMissing = false,
strict = false,
} = options; } = options;
this.strictMode = strict;
if (checkMissing) { if (checkMissing) {
this.findPackageJsonFiles(); this.findPackageJsonFiles();
this.checkMissingDependencies(); this.checkMissingDependencies();