check-dependency-version-consistency
Version:
Ensures dependencies are on consistent versions across a monorepo.
67 lines (66 loc) • 3.35 kB
JavaScript
import { Command, Argument } from 'commander';
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { CDVC } from './cdvc.js';
import { DEPENDENCY_TYPE } from './types.js';
import { DEFAULT_DEP_TYPES } from './defaults.js';
const __dirname = dirname(fileURLToPath(import.meta.url));
function getCurrentPackageVersion() {
const packageJson = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf8'));
if (!packageJson.version) {
throw new Error('Could not find package.json `version`');
}
return packageJson.version;
}
/**
* Used for collecting repeated CLI options into an array.
* Example: --foo bar --foo baz => ['bar', 'baz']
*/
function collect(value, previous) {
return [...previous, value];
}
/**
* Used for collecting both repeated and CSV CLI options into an array.
* Example: --foo bar,baz,buz --foo biz => ['bar', 'baz', 'buz', 'biz']
* */
function collectCSV(value, previous) {
return [...previous, ...value.split(',')];
}
// Setup CLI.
export function run() {
const program = new Command();
program
.description('CLI tool which checks that dependencies are on consistent versions across a monorepo / npm/pnpm/Yarn workspace.')
.version(getCurrentPackageVersion())
.addArgument(new Argument('[path]', 'path to workspace root').default('.'))
.option('--dep-type <dependency-type>', `Type of dependency to check (choices: ${Object.keys(DEPENDENCY_TYPE).join(', ')}) (default: ${DEFAULT_DEP_TYPES.join(', ')}) (option can be repeated)`, collectCSV, [])
.option('--fix', 'Whether to autofix inconsistencies (using highest version present)', false)
.option('--ignore-dep <dependency-name>', 'Dependency to ignore (option can be repeated)', collect, [])
.option('--ignore-dep-pattern <dependency-name-pattern>', 'RegExp of dependency names to ignore (option can be repeated)', collect, [])
.option('--ignore-package <package-name>', 'Workspace package to ignore (option can be repeated)', collect, [])
.option('--ignore-package-pattern <package-name-pattern>', 'RegExp of package names to ignore (option can be repeated)', collect, [])
.option('--ignore-path <path>', 'Workspace-relative path of packages to ignore (option can be repeated)', collect, [])
.option('--ignore-path-pattern <path-pattern>', 'RegExp of workspace-relative path of packages to ignore (option can be repeated)', collect, [])
.action((path, options) => {
const cdvc = new CDVC(path, options);
if (options.fix) {
// Show output for dependencies we fixed.
if (cdvc.hasMismatchingDependenciesFixable) {
console.log(cdvc.toFixedSummary());
}
// Show output for dependencies that still have mismatches.
if (cdvc.hasMismatchingDependenciesNotFixable) {
console.log(cdvc.toMismatchSummary());
process.exitCode = 1;
}
}
else if (cdvc.hasMismatchingDependencies) {
// Show output for dependencies that have mismatches.
console.log(cdvc.toMismatchSummary());
process.exitCode = 1;
}
})
.parse(process.argv);
return program;
}