apisurf
Version:
Analyze API surface changes between npm package versions to catch breaking changes
67 lines (66 loc) • 3.32 kB
JavaScript
import { Command } from 'commander';
import chalk from 'chalk';
import { formatOutput } from '../utilities/formatOutput.js';
import { analyzeDiff } from '../analyzers/analyzeDiff.js';
export const diffCommand = new Command('diff')
.description('Check for breaking changes by comparing package API surface between git branches or npm package versions')
.argument('[packagename]', 'NPM package name to compare versions')
.argument('[fromversion]', 'Base version to compare from')
.argument('[toversion]', 'Target version to compare to')
.option('--base <branch>', 'Base branch to compare against (for git mode)', 'main')
.option('--head <branch>', 'Head branch to compare (for git mode, defaults to current branch)')
.option('--packages <pattern>', 'Glob pattern for packages to check (for monorepos in git mode)')
.option('--registry <url>', 'NPM registry URL (defaults to public npm, respects .npmrc)')
.option('--format <format>', 'Output format: console, json, md, html, report', 'report')
.option('--logfile <filename>', 'JSON file to log full API surfaces for both versions')
.option('--verbose', 'Enable verbose output including npm notices')
.action(async (packagename, fromversion, toversion, options) => {
try {
// Convert commander options to DiffOptions
const diffOptions = {
base: options.base,
head: options.head,
packages: options.packages,
format: options.format,
npmPackage: packagename,
fromVersion: fromversion,
toVersion: toversion,
registry: options.registry,
logfile: options.logfile,
verbose: options.verbose
};
// Validate options
if (diffOptions.npmPackage) {
if (!diffOptions.fromVersion || !diffOptions.toVersion) {
console.error('Error: NPM mode requires all three arguments: <packagename> <fromversion> <toversion>');
process.exit(1);
}
if (diffOptions.format === 'console' || diffOptions.format === 'html' || diffOptions.format === 'report') {
console.log(`Analyzing ${chalk.cyan(diffOptions.npmPackage)} api surface changes: ${chalk.yellow(diffOptions.fromVersion)} to ${chalk.green(diffOptions.toVersion)}`);
console.log();
}
}
else {
if (diffOptions.format === 'console' || diffOptions.format === 'html' || diffOptions.format === 'report') {
console.log('Analyzing api surface changes...');
console.log();
}
}
const result = await analyzeDiff(diffOptions);
const output = formatOutput(result, diffOptions.format, diffOptions.verbose);
// For markdown and json formats, output directly without any additional formatting
if (diffOptions.format === 'md' || diffOptions.format === 'json') {
process.stdout.write(output + '\n');
}
else {
console.log(output);
}
if (result.hasBreakingChanges) {
process.exit(1);
}
}
catch (error) {
console.error('Error during diff analysis:', error instanceof Error ? error.message : String(error));
process.exit(1);
}
});