Skip to content

Commit 7ac0855

Browse files
committed
feat(cli): add tree-shaking analysis command and use case to CLI
Introduced a new `tree-shaking` command to analyze tree-shaking optimization opportunities for monorepo packages. Implemented `AnalyzeTreeShakingUseCase` to identify issues like re-export chains, large barrels, and wildcard exports, providing actionable recommendations. Updated DI bindings to integrate the new use case and command while adhering to Explicit Architecture principles.
1 parent 666690a commit 7ac0855

File tree

5 files changed

+476
-0
lines changed

5 files changed

+476
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Tree Shaking Command
3+
*
4+
* CLI command for analyzing and optimizing tree-shaking in monorepo packages.
5+
* Following explicit architecture guidelines for command organization.
6+
*/
7+
8+
import type { Command } from "commander";
9+
10+
import { inject, injectable } from "inversify";
11+
12+
import type { CommandInterface } from "@/commands/interfaces/command.interface";
13+
import type { AnalyzeTreeShakingUseCase } from "@/core/application/use-cases/analyze-tree-shaking.use-case";
14+
15+
import { TYPES } from "@/di/types";
16+
17+
@injectable()
18+
export class TreeShakingCommand implements CommandInterface {
19+
readonly name = "tree-shaking";
20+
readonly description = "Analyze and optimize tree-shaking for monorepo packages";
21+
22+
constructor(
23+
@inject(TYPES.AnalyzeTreeShakingUseCase)
24+
private readonly analyzeTreeShakingUseCase: AnalyzeTreeShakingUseCase,
25+
) {}
26+
27+
register(program: Command): void {
28+
program
29+
.command(this.name)
30+
.description(this.description)
31+
.option("-p, --packages <path>", "path to packages directory", "packages")
32+
.option("-n, --package-name <name>", "analyze specific package only")
33+
.option("--fix", "attempt to fix tree-shaking issues automatically", false)
34+
.option("--json", "output results in JSON format", false)
35+
.option("--threshold <score>", "minimum tree-shaking score threshold", "80")
36+
.action(
37+
async (options: {
38+
packages?: string;
39+
packageName?: string;
40+
fix?: boolean;
41+
json?: boolean;
42+
threshold?: string;
43+
}) => {
44+
const analyses = await this.analyzeTreeShakingUseCase.execute({
45+
fix: options.fix,
46+
packageName: options.packageName,
47+
packagesPath: options.packages,
48+
});
49+
50+
// Handle JSON output
51+
if (options.json) {
52+
console.log(JSON.stringify(analyses, null, 2));
53+
54+
return;
55+
}
56+
57+
// Check threshold and exit with the appropriate code
58+
const threshold = Number.parseInt(options.threshold ?? "80", 10);
59+
const failingPackages = analyses.filter((a) => a.treeShakingScore < threshold);
60+
61+
if (failingPackages.length > 0) {
62+
console.error(
63+
`\n❌ ${failingPackages.length} package(s) below threshold (${threshold})`,
64+
);
65+
process.exit(1);
66+
} else {
67+
console.log(`\n✅ All packages meet tree-shaking threshold (${threshold})`);
68+
}
69+
},
70+
);
71+
}
72+
}

0 commit comments

Comments
 (0)