crapifyme
Version:
Ultra-fast developer productivity CLI tools - remove comments, logs, and more
230 lines ⢠10.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.depsCommand = void 0;
const commander_1 = require("commander");
const shared_1 = require("../../shared");
const logic_1 = require("./logic");
const types_1 = require("./types");
exports.depsCommand = new commander_1.Command('deps')
.description('Analyze and optimize project dependencies')
.argument('[path]', 'Project directory to analyze', '.')
.option('--security-only', 'Only perform security vulnerability analysis', false)
.option('--size-only', 'Only perform bundle size analysis', false)
.option('--outdated-only', 'Only check for outdated dependencies', false)
.option('--unused-only', 'Only check for unused dependencies', false)
.option('--duplicates-only', 'Only check for duplicate dependencies', false)
.option('--include-gzip', 'Include gzipped size information', true)
.option('--no-include-gzip', 'Exclude gzipped size information')
.option('--include-peer', 'Include peer dependencies in analysis', false)
.option('--include-optional', 'Include optional dependencies in analysis', false)
.option('--pm <manager>', 'Package manager to use (npm|yarn|pnpm|auto)', 'auto')
.option('--workspaces', 'Analyze workspaces if available', false)
.option('--timeout <ms>', 'Request timeout in milliseconds', parseInt, 120000)
.option('--output <format>', 'Output format (table|json|tree|summary)', 'table')
.option('--no-security', 'Skip security vulnerability checks')
.option('--no-bundle-size', 'Skip bundle size analysis')
.action(async (projectPath, options, command) => {
const globalOptions = command.parent?.opts() || {};
const logger = new shared_1.Logger(globalOptions.verbose, globalOptions.quiet, globalOptions.json);
if (!globalOptions.force) {
const vcsResult = (0, shared_1.detectVersionControl)();
if (!vcsResult.detected) {
logger.error('No version control system detected in this project or its parent directories.');
logger.error('This tool analyzes your dependencies, which may involve network requests and package information.');
logger.error('Use --force to proceed without version control.');
process.exit(shared_1.ExitCode.Error);
}
if (globalOptions.verbose) {
logger.info(`Version control detected: ${vcsResult.type} at ${vcsResult.path}`);
}
}
try {
const analysisTypes = determineAnalysisTypes(options);
if (!globalOptions.quiet) {
process.stdout.write('Starting deps analysis');
const animateTimer = setInterval(() => {
process.stdout.write('.');
}, 500);
setTimeout(() => {
clearInterval(animateTimer);
process.stdout.write('\n');
}, 1000);
}
if (globalOptions.verbose) {
logger.info(`Analysis types: ${analysisTypes.join(', ')}`);
}
if (globalOptions.dryRun) {
logger.info('DRY RUN - Analysis will be performed but no modifications will be made');
}
const processor = new logic_1.DepsProcessor({
packageManager: options.pm === 'auto' ? undefined : options.pm,
includeDevDependencies: options.includeDev,
includePeerDependencies: options.includePeer,
includeOptionalDependencies: options.includeOptional,
checkSecurity: options.security,
analyzeBundleSize: options.bundleSize,
checkUnused: analysisTypes.includes(types_1.AnalysisType.UNUSED),
workspaces: options.workspaces,
timeout: options.timeout,
verbose: globalOptions.verbose
}, projectPath);
const result = await processor.analyzeProject(analysisTypes);
const stats = {
filesAnalyzed: 1,
dependenciesScanned: result.analysis.summary.total.production + result.analysis.summary.total.development,
vulnerabilitiesFound: result.analysis.security.vulnerabilities.length,
outdatedPackages: result.analysis.summary.outdated,
unusedPackages: result.analysis.unusedDependencies.length,
sizeSavingsIdentified: 0,
errors: result.errors.map(e => ({ message: e.message, type: e.type }))
};
if (globalOptions.json) {
if (options.output === 'summary') {
logger.json(stats);
}
else {
logger.json({
analysis: {
...result.analysis,
duplicateDependencies: Object.fromEntries(result.analysis.duplicateDependencies)
},
stats,
errors: result.errors,
warnings: result.warnings,
processingTime: result.processingTime
});
}
}
else {
await displayResults(result, options.output, logger, stats);
}
if (result.errors.length > 0) {
logger.error(`Analysis completed with ${result.errors.length} error${result.errors.length === 1 ? '' : 's'}`);
result.errors.forEach(error => logger.error(`${error.type}: ${error.message}`));
}
if (result.warnings.length > 0 && globalOptions.verbose) {
logger.warn(`${result.warnings.length} warning${result.warnings.length === 1 ? '' : 's'} found:`);
result.warnings.forEach(warning => logger.warn(`${warning.type}: ${warning.message}`));
}
if (globalOptions.verbose) {
logger.info(`Analysis completed in ${result.processingTime}ms`);
}
const hasIssues = stats.vulnerabilitiesFound > 0 || stats.outdatedPackages > 0 || stats.unusedPackages > 0;
const exitCode = result.errors.length > 0
? shared_1.ExitCode.Error
: hasIssues
? shared_1.ExitCode.IssuesFound
: shared_1.ExitCode.Success;
process.exit(exitCode);
}
catch (error) {
const errorMessage = error.message;
if (errorMessage.includes('No package.json found')) {
logger.error('No package.json found in current directory or any parent directory');
logger.info("Make sure you're running this command from within a Node.js project");
}
else if (errorMessage.includes('No supported package manager detected')) {
logger.error('No package manager lock file found (package-lock.json, yarn.lock, pnpm-lock.yaml)');
logger.info('Run `npm install`, `yarn install`, or `pnpm install` to generate lock files first');
}
else {
logger.error('Fatal error during dependency analysis', error);
}
process.exit(shared_1.ExitCode.Error);
}
});
function determineAnalysisTypes(options) {
const types = [];
if (options.securityOnly)
return [types_1.AnalysisType.SECURITY];
if (options.sizeOnly)
return [types_1.AnalysisType.SIZE];
if (options.outdatedOnly)
return [types_1.AnalysisType.OUTDATED];
if (options.unusedOnly)
return [types_1.AnalysisType.UNUSED];
if (options.duplicatesOnly)
return [types_1.AnalysisType.DUPLICATES];
return [types_1.AnalysisType.FULL];
}
async function displayResults(result, format, logger, stats) {
switch (format) {
case types_1.OutputFormat.SUMMARY:
displaySummary(result.analysis, logger, stats);
break;
case types_1.OutputFormat.TREE:
displayTree(result.analysis);
break;
case types_1.OutputFormat.JSON:
console.log(JSON.stringify({
analysis: {
...result.analysis,
duplicateDependencies: Object.fromEntries(result.analysis.duplicateDependencies)
},
stats,
errors: result.errors,
warnings: result.warnings,
processingTime: result.processingTime
}, null, 2));
break;
case types_1.OutputFormat.TABLE:
default:
const processor = new logic_1.DepsProcessor();
const report = await processor.generateReport(result.analysis);
console.log(report);
break;
}
}
function displaySummary(analysis, logger, stats) {
logger.info(`š¦ Dependencies Scanned: ${stats.dependenciesScanned}`);
if (stats.vulnerabilitiesFound > 0) {
logger.warn(`šØ Security Issues: ${stats.vulnerabilitiesFound}`);
}
if (stats.outdatedPackages > 0) {
logger.warn(`š Outdated Packages: ${stats.outdatedPackages}`);
}
if (stats.unusedPackages > 0) {
logger.warn(`š Unused Packages: ${stats.unusedPackages}`);
}
if (analysis.bundle?.totalSize) {
logger.info(`š Total Bundle Size: ${analysis.bundle.totalSize.formatted.raw} (${analysis.bundle.totalSize.formatted.gzip} gzipped)`);
}
if (stats.vulnerabilitiesFound === 0 &&
stats.outdatedPackages === 0 &&
stats.unusedPackages === 0) {
logger.success('ā
No issues found! Your dependencies look good.');
}
}
function displayTree(analysis) {
const { production, development } = analysis.dependencies;
console.log('\nš¦ DEPENDENCY TREE\n');
if (production.length > 0) {
console.log('š Production Dependencies:');
production.slice(0, 20).forEach((dep, index) => {
const isLast = index === Math.min(production.length - 1, 19);
const prefix = isLast ? 'āāā ' : 'āāā ';
const version = dep.currentVersion;
const outdated = dep.isOutdated ? ' (outdated)' : '';
const size = dep.size ? ` [${dep.size.formatted.gzip}]` : '';
console.log(`${prefix}${dep.name}@${version}${outdated}${size}`);
});
if (production.length > 20) {
console.log(` ... and ${production.length - 20} more`);
}
console.log('');
}
if (development.length > 0) {
console.log('š§ Development Dependencies:');
development.slice(0, 10).forEach((dep, index) => {
const isLast = index === Math.min(development.length - 1, 9);
const prefix = isLast ? 'āāā ' : 'āāā ';
const version = dep.currentVersion;
const outdated = dep.isOutdated ? ' (outdated)' : '';
console.log(`${prefix}${dep.name}@${version}${outdated}`);
});
if (development.length > 10) {
console.log(` ... and ${development.length - 10} more`);
}
}
}
//# sourceMappingURL=index.js.map