@reliverse/dler 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +3 -0
  3. package/dist/cmds/build/cmd.d.ts +2 -0
  4. package/dist/cmds/build/cmd.js +564 -0
  5. package/dist/cmds/clean/cmd.d.ts +2 -0
  6. package/dist/cmds/clean/cmd.js +146 -0
  7. package/dist/cmds/clean/impl.d.ts +2 -0
  8. package/dist/cmds/clean/impl.js +627 -0
  9. package/dist/cmds/clean/presets.d.ts +10 -0
  10. package/dist/cmds/clean/presets.js +112 -0
  11. package/dist/cmds/clean/types.d.ts +62 -0
  12. package/dist/cmds/clean/types.js +0 -0
  13. package/dist/cmds/init/cmd.d.ts +3 -0
  14. package/dist/cmds/init/cmd.js +56 -0
  15. package/dist/cmds/init/impl/config.d.ts +45 -0
  16. package/dist/cmds/init/impl/config.js +99 -0
  17. package/dist/cmds/init/impl/generators.d.ts +6 -0
  18. package/dist/cmds/init/impl/generators.js +178 -0
  19. package/dist/cmds/init/impl/prompts.d.ts +2 -0
  20. package/dist/cmds/init/impl/prompts.js +98 -0
  21. package/dist/cmds/init/impl/types.d.ts +22 -0
  22. package/dist/cmds/init/impl/types.js +0 -0
  23. package/dist/cmds/init/impl/utils.d.ts +4 -0
  24. package/dist/cmds/init/impl/utils.js +11 -0
  25. package/dist/cmds/init/impl/validators.d.ts +4 -0
  26. package/dist/cmds/init/impl/validators.js +42 -0
  27. package/dist/cmds/integrate/cmd.d.ts +3 -0
  28. package/dist/cmds/integrate/cmd.js +70 -0
  29. package/dist/cmds/integrate/impl.d.ts +7 -0
  30. package/dist/cmds/integrate/impl.js +127 -0
  31. package/dist/cmds/integrate/integrations/base.d.ts +13 -0
  32. package/dist/cmds/integrate/integrations/base.js +41 -0
  33. package/dist/cmds/integrate/integrations/nextjs.d.ts +16 -0
  34. package/dist/cmds/integrate/integrations/nextjs.js +167 -0
  35. package/dist/cmds/integrate/integrations/registry.d.ts +7 -0
  36. package/dist/cmds/integrate/integrations/registry.js +31 -0
  37. package/dist/cmds/integrate/integrations/ultracite.d.ts +11 -0
  38. package/dist/cmds/integrate/integrations/ultracite.js +40 -0
  39. package/dist/cmds/integrate/types.d.ts +39 -0
  40. package/dist/cmds/integrate/types.js +0 -0
  41. package/dist/cmds/integrate/utils/biome.d.ts +4 -0
  42. package/dist/cmds/integrate/utils/biome.js +140 -0
  43. package/dist/cmds/integrate/utils/context.d.ts +3 -0
  44. package/dist/cmds/integrate/utils/context.js +111 -0
  45. package/dist/cmds/integrate/utils/temp.d.ts +3 -0
  46. package/dist/cmds/integrate/utils/temp.js +36 -0
  47. package/dist/cmds/perf/analysis/bundle.d.ts +20 -0
  48. package/dist/cmds/perf/analysis/bundle.js +225 -0
  49. package/dist/cmds/perf/analysis/filesystem.d.ts +27 -0
  50. package/dist/cmds/perf/analysis/filesystem.js +246 -0
  51. package/dist/cmds/perf/analysis/monorepo.d.ts +29 -0
  52. package/dist/cmds/perf/analysis/monorepo.js +307 -0
  53. package/dist/cmds/perf/benchmarks/command.d.ts +21 -0
  54. package/dist/cmds/perf/benchmarks/command.js +162 -0
  55. package/dist/cmds/perf/benchmarks/memory.d.ts +41 -0
  56. package/dist/cmds/perf/benchmarks/memory.js +169 -0
  57. package/dist/cmds/perf/benchmarks/runner.d.ts +22 -0
  58. package/dist/cmds/perf/benchmarks/runner.js +157 -0
  59. package/dist/cmds/perf/cmd.d.ts +2 -0
  60. package/dist/cmds/perf/cmd.js +238 -0
  61. package/dist/cmds/perf/impl.d.ts +24 -0
  62. package/dist/cmds/perf/impl.js +304 -0
  63. package/dist/cmds/perf/reporters/console.d.ts +12 -0
  64. package/dist/cmds/perf/reporters/console.js +257 -0
  65. package/dist/cmds/perf/reporters/html.d.ts +27 -0
  66. package/dist/cmds/perf/reporters/html.js +881 -0
  67. package/dist/cmds/perf/reporters/json.d.ts +9 -0
  68. package/dist/cmds/perf/reporters/json.js +32 -0
  69. package/dist/cmds/perf/types.d.ts +184 -0
  70. package/dist/cmds/perf/types.js +0 -0
  71. package/dist/cmds/perf/utils/cache.d.ts +23 -0
  72. package/dist/cmds/perf/utils/cache.js +171 -0
  73. package/dist/cmds/perf/utils/formatter.d.ts +17 -0
  74. package/dist/cmds/perf/utils/formatter.js +134 -0
  75. package/dist/cmds/perf/utils/stats.d.ts +15 -0
  76. package/dist/cmds/perf/utils/stats.js +101 -0
  77. package/dist/cmds/publish/cmd.d.ts +3 -0
  78. package/dist/cmds/publish/cmd.js +189 -0
  79. package/dist/cmds/shell/cmd.d.ts +3 -0
  80. package/dist/cmds/shell/cmd.js +50 -0
  81. package/dist/cmds/tsc/cache.d.ts +27 -0
  82. package/dist/cmds/tsc/cache.js +160 -0
  83. package/dist/cmds/tsc/cmd.d.ts +2 -0
  84. package/dist/cmds/tsc/cmd.js +111 -0
  85. package/dist/cmds/tsc/impl.d.ts +41 -0
  86. package/dist/cmds/tsc/impl.js +572 -0
  87. package/dist/cmds/tsc/types.d.ts +57 -0
  88. package/dist/cmds/tsc/types.js +0 -0
  89. package/package.json +4 -11
  90. package/src/cli.ts +8 -0
  91. package/src/cmds/build/cmd.ts +582 -0
  92. package/src/cmds/clean/cmd.ts +166 -0
  93. package/src/cmds/clean/impl.ts +900 -0
  94. package/src/cmds/clean/presets.ts +158 -0
  95. package/src/cmds/clean/types.ts +71 -0
  96. package/src/cmds/init/cmd.ts +68 -0
  97. package/src/cmds/init/impl/config.ts +105 -0
  98. package/src/cmds/init/impl/generators.ts +220 -0
  99. package/src/cmds/init/impl/prompts.ts +137 -0
  100. package/src/cmds/init/impl/types.ts +25 -0
  101. package/src/cmds/init/impl/utils.ts +17 -0
  102. package/src/cmds/init/impl/validators.ts +55 -0
  103. package/src/cmds/integrate/cmd.ts +82 -0
  104. package/src/cmds/integrate/impl.ts +204 -0
  105. package/src/cmds/integrate/integrations/base.ts +69 -0
  106. package/src/cmds/integrate/integrations/nextjs.ts +227 -0
  107. package/src/cmds/integrate/integrations/registry.ts +45 -0
  108. package/src/cmds/integrate/integrations/ultracite.ts +53 -0
  109. package/src/cmds/integrate/types.ts +48 -0
  110. package/src/cmds/integrate/utils/biome.ts +173 -0
  111. package/src/cmds/integrate/utils/context.ts +148 -0
  112. package/src/cmds/integrate/utils/temp.ts +47 -0
  113. package/src/cmds/perf/analysis/bundle.ts +311 -0
  114. package/src/cmds/perf/analysis/filesystem.ts +324 -0
  115. package/src/cmds/perf/analysis/monorepo.ts +439 -0
  116. package/src/cmds/perf/benchmarks/command.ts +230 -0
  117. package/src/cmds/perf/benchmarks/memory.ts +249 -0
  118. package/src/cmds/perf/benchmarks/runner.ts +220 -0
  119. package/src/cmds/perf/cmd.ts +285 -0
  120. package/src/cmds/perf/impl.ts +411 -0
  121. package/src/cmds/perf/reporters/console.ts +331 -0
  122. package/src/cmds/perf/reporters/html.ts +984 -0
  123. package/src/cmds/perf/reporters/json.ts +42 -0
  124. package/src/cmds/perf/types.ts +220 -0
  125. package/src/cmds/perf/utils/cache.ts +234 -0
  126. package/src/cmds/perf/utils/formatter.ts +190 -0
  127. package/src/cmds/perf/utils/stats.ts +153 -0
  128. package/src/cmds/publish/cmd.ts +215 -0
  129. package/src/cmds/shell/cmd.ts +61 -0
  130. package/src/cmds/tsc/cache.ts +237 -0
  131. package/src/cmds/tsc/cmd.ts +139 -0
  132. package/src/cmds/tsc/impl.ts +855 -0
  133. package/src/cmds/tsc/types.ts +66 -0
  134. package/tsconfig.json +9 -0
  135. package/cli.js +0 -1316
@@ -0,0 +1,246 @@
1
+ import { existsSync, statSync } from "node:fs";
2
+ import { extname, join, resolve } from "node:path";
3
+ import { logger } from "@reliverse/dler-logger";
4
+ import { formatBytes } from "../utils/formatter.js";
5
+ export class FileSystemAnalyzer {
6
+ options;
7
+ fileCount = 0;
8
+ totalSize = 0;
9
+ directoryCount = 0;
10
+ maxDepth = 0;
11
+ files = [];
12
+ directories = [];
13
+ fileTypes = /* @__PURE__ */ new Map();
14
+ constructor(options) {
15
+ this.options = options;
16
+ }
17
+ async analyze() {
18
+ const startTime = Date.now();
19
+ const { target, verbose } = this.options;
20
+ if (verbose) {
21
+ logger.info(`\u{1F50D} Analyzing filesystem: ${target}`);
22
+ }
23
+ const targetPath = resolve(target);
24
+ if (!existsSync(targetPath)) {
25
+ throw new Error(`Target not found: ${target}`);
26
+ }
27
+ const stat = statSync(targetPath);
28
+ if (stat.isFile()) {
29
+ await this.analyzeFile(targetPath, 0);
30
+ } else {
31
+ await this.analyzeDirectory(targetPath, 0);
32
+ }
33
+ this.files.sort((a, b) => b.size - a.size);
34
+ this.directories.sort((a, b) => b.size - a.size);
35
+ const fileTypeDistribution = Array.from(
36
+ this.fileTypes.entries()
37
+ ).map(([extension, info]) => ({
38
+ extension,
39
+ count: info.count,
40
+ totalSize: info.totalSize,
41
+ percentage: info.totalSize / this.totalSize * 100
42
+ })).sort((a, b) => b.totalSize - a.totalSize);
43
+ const compressionPotential = this.calculateCompressionPotential();
44
+ const analysisTime = Date.now() - startTime;
45
+ if (verbose) {
46
+ logger.info(` Analysis completed in ${analysisTime}ms`);
47
+ logger.info(
48
+ ` Files: ${this.fileCount}, Directories: ${this.directoryCount}, Size: ${formatBytes(this.totalSize)}`
49
+ );
50
+ }
51
+ return {
52
+ target,
53
+ totalFiles: this.fileCount,
54
+ totalSize: this.totalSize,
55
+ directoryCount: this.directoryCount,
56
+ maxDepth: this.maxDepth,
57
+ largestFiles: this.files.slice(0, 20),
58
+ // Top 20
59
+ largestDirectories: this.directories.slice(0, 20),
60
+ // Top 20
61
+ fileTypes: fileTypeDistribution,
62
+ compressionPotential,
63
+ analysisTime
64
+ };
65
+ }
66
+ async analyzeFile(filePath, depth) {
67
+ try {
68
+ const stat = statSync(filePath);
69
+ const ext = extname(filePath);
70
+ if (this.shouldExclude(filePath)) {
71
+ return;
72
+ }
73
+ this.fileCount++;
74
+ this.totalSize += stat.size;
75
+ this.maxDepth = Math.max(this.maxDepth, depth);
76
+ this.files.push({
77
+ path: filePath,
78
+ size: stat.size,
79
+ percentage: 0,
80
+ // Will be calculated later
81
+ type: this.getFileType(ext)
82
+ });
83
+ const extension = ext || "no-extension";
84
+ const existing = this.fileTypes.get(extension);
85
+ if (existing) {
86
+ existing.count++;
87
+ existing.totalSize += stat.size;
88
+ } else {
89
+ this.fileTypes.set(extension, {
90
+ count: 1,
91
+ totalSize: stat.size
92
+ });
93
+ }
94
+ } catch (error) {
95
+ if (this.options.verbose) {
96
+ logger.warn(`Cannot access file ${filePath}:`, error);
97
+ }
98
+ }
99
+ }
100
+ async analyzeDirectory(dirPath, depth) {
101
+ try {
102
+ this.directoryCount++;
103
+ this.maxDepth = Math.max(this.maxDepth, depth);
104
+ if (this.shouldExclude(dirPath)) {
105
+ return;
106
+ }
107
+ let dirSize = 0;
108
+ let dirFileCount = 0;
109
+ const glob = new Bun.Glob("**/*");
110
+ const matches = glob.scanSync({
111
+ cwd: dirPath,
112
+ onlyFiles: false,
113
+ dot: this.options.includeHidden ?? false
114
+ });
115
+ for (const match of matches) {
116
+ const fullPath = join(dirPath, match);
117
+ try {
118
+ const stat = statSync(fullPath);
119
+ if (stat.isFile()) {
120
+ await this.analyzeFile(fullPath, depth + 1);
121
+ dirSize += stat.size;
122
+ dirFileCount++;
123
+ } else if (stat.isDirectory()) {
124
+ await this.analyzeDirectory(fullPath, depth + 1);
125
+ }
126
+ } catch (error) {
127
+ if (this.options.verbose) {
128
+ logger.warn(`Cannot access ${fullPath}:`, error);
129
+ }
130
+ }
131
+ }
132
+ this.directories.push({
133
+ path: dirPath,
134
+ size: dirSize,
135
+ fileCount: dirFileCount,
136
+ depth
137
+ });
138
+ } catch (error) {
139
+ if (this.options.verbose) {
140
+ logger.warn(`Cannot access directory ${dirPath}:`, error);
141
+ }
142
+ }
143
+ }
144
+ shouldExclude(path) {
145
+ const { excludePatterns = [] } = this.options;
146
+ for (const pattern of excludePatterns) {
147
+ if (path.includes(pattern)) {
148
+ return true;
149
+ }
150
+ }
151
+ const defaultExclusions = [
152
+ "node_modules",
153
+ ".git",
154
+ ".next",
155
+ ".nuxt",
156
+ ".expo",
157
+ "dist",
158
+ "build",
159
+ "coverage",
160
+ ".cache",
161
+ ".turbo"
162
+ ];
163
+ for (const exclusion of defaultExclusions) {
164
+ if (path.includes(exclusion)) {
165
+ return true;
166
+ }
167
+ }
168
+ return false;
169
+ }
170
+ getFileType(extension) {
171
+ const typeMap = {
172
+ ".js": "JavaScript",
173
+ ".mjs": "ES Module",
174
+ ".cjs": "CommonJS",
175
+ ".ts": "TypeScript",
176
+ ".jsx": "React JSX",
177
+ ".tsx": "React TSX",
178
+ ".json": "JSON",
179
+ ".css": "CSS",
180
+ ".scss": "SCSS",
181
+ ".sass": "Sass",
182
+ ".less": "Less",
183
+ ".html": "HTML",
184
+ ".svg": "SVG",
185
+ ".png": "PNG",
186
+ ".jpg": "JPEG",
187
+ ".jpeg": "JPEG",
188
+ ".gif": "GIF",
189
+ ".webp": "WebP",
190
+ ".woff": "WOFF",
191
+ ".woff2": "WOFF2",
192
+ ".ttf": "TrueType",
193
+ ".eot": "EOT",
194
+ ".map": "Source Map",
195
+ ".d.ts": "TypeScript Declarations",
196
+ ".md": "Markdown",
197
+ ".txt": "Text",
198
+ ".yml": "YAML",
199
+ ".yaml": "YAML",
200
+ ".xml": "XML",
201
+ ".pdf": "PDF",
202
+ ".zip": "ZIP",
203
+ ".tar": "TAR",
204
+ ".gz": "GZIP"
205
+ };
206
+ return typeMap[extension] ?? "Unknown";
207
+ }
208
+ calculateCompressionPotential() {
209
+ if (this.totalSize === 0) return 0;
210
+ let compressibleSize = 0;
211
+ for (const [extension, info] of this.fileTypes) {
212
+ const compressibleExtensions = [
213
+ ".js",
214
+ ".mjs",
215
+ ".cjs",
216
+ ".ts",
217
+ ".jsx",
218
+ ".tsx",
219
+ ".json",
220
+ ".css",
221
+ ".scss",
222
+ ".sass",
223
+ ".less",
224
+ ".html",
225
+ ".svg",
226
+ ".md",
227
+ ".txt",
228
+ ".yml",
229
+ ".yaml",
230
+ ".xml"
231
+ ];
232
+ if (compressibleExtensions.includes(extension)) {
233
+ compressibleSize += info.totalSize;
234
+ }
235
+ }
236
+ const estimatedCompression = compressibleSize * 0.7;
237
+ return estimatedCompression / this.totalSize * 100;
238
+ }
239
+ }
240
+ export const analyzeFileSystem = async (options) => {
241
+ const analyzer = new FileSystemAnalyzer(options);
242
+ return analyzer.analyze();
243
+ };
244
+ export const createFileSystemAnalyzer = (options) => {
245
+ return new FileSystemAnalyzer(options);
246
+ };
@@ -0,0 +1,29 @@
1
+ import type { MonorepoAnalysisResult } from "../types.js";
2
+ export interface MonorepoAnalysisOptions {
3
+ cwd?: string;
4
+ ignore?: string | string[];
5
+ verbose?: boolean;
6
+ includeDevDependencies?: boolean;
7
+ analyzeBuildOrder?: boolean;
8
+ }
9
+ export declare class MonorepoAnalyzer {
10
+ private options;
11
+ private packages;
12
+ private dependencyGraph;
13
+ constructor(options: MonorepoAnalysisOptions);
14
+ analyze(): Promise<MonorepoAnalysisResult>;
15
+ private findMonorepoRoot;
16
+ private discoverPackages;
17
+ private resolvePackageInfo;
18
+ private buildDependencyGraph;
19
+ private calculateLevels;
20
+ private findCircularDependencies;
21
+ private detectCycle;
22
+ private calculateCycleSeverity;
23
+ private calculateBuildOrder;
24
+ private findCriticalPath;
25
+ private identifyBottlenecks;
26
+ private suggestOptimalConcurrency;
27
+ }
28
+ export declare const analyzeMonorepo: (options: MonorepoAnalysisOptions) => Promise<MonorepoAnalysisResult>;
29
+ export declare const createMonorepoAnalyzer: (options: MonorepoAnalysisOptions) => MonorepoAnalyzer;
@@ -0,0 +1,307 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { logger } from "@reliverse/dler-logger";
4
+ import { createIgnoreFilter } from "@reliverse/dler-matcher";
5
+ import {
6
+ getWorkspacePatterns,
7
+ hasWorkspaces,
8
+ readPackageJSON
9
+ } from "@reliverse/dler-pkg-tsc";
10
+ export class MonorepoAnalyzer {
11
+ options;
12
+ packages = [];
13
+ dependencyGraph = {
14
+ nodes: [],
15
+ edges: [],
16
+ levels: []
17
+ };
18
+ constructor(options) {
19
+ this.options = options;
20
+ }
21
+ async analyze() {
22
+ const startTime = Date.now();
23
+ const { cwd, verbose } = this.options;
24
+ if (verbose) {
25
+ logger.info("\u{1F50D} Analyzing monorepo structure...");
26
+ }
27
+ const monorepoRoot = await this.findMonorepoRoot(cwd);
28
+ if (!monorepoRoot) {
29
+ throw new Error(
30
+ 'No monorepo found. Ensure package.json has "workspaces" field.'
31
+ );
32
+ }
33
+ if (verbose) {
34
+ logger.info(` Monorepo root: ${monorepoRoot}`);
35
+ }
36
+ this.packages = await this.discoverPackages(monorepoRoot);
37
+ if (verbose) {
38
+ logger.info(` Found ${this.packages.length} packages`);
39
+ }
40
+ this.dependencyGraph = await this.buildDependencyGraph();
41
+ const circularDependencies = this.findCircularDependencies();
42
+ const buildOrder = this.calculateBuildOrder();
43
+ const criticalPath = this.findCriticalPath();
44
+ const bottlenecks = this.identifyBottlenecks();
45
+ const suggestedConcurrency = this.suggestOptimalConcurrency();
46
+ const analysisTime = Date.now() - startTime;
47
+ if (verbose) {
48
+ logger.info(` Analysis completed in ${analysisTime}ms`);
49
+ }
50
+ return {
51
+ packages: this.packages,
52
+ dependencies: this.dependencyGraph,
53
+ circularDependencies,
54
+ criticalPath,
55
+ buildOrder,
56
+ bottlenecks,
57
+ suggestedConcurrency,
58
+ analysisTime
59
+ };
60
+ }
61
+ async findMonorepoRoot(startDir) {
62
+ let currentDir = resolve(startDir ?? process.cwd());
63
+ while (currentDir !== "/") {
64
+ const pkgPath = join(currentDir, "package.json");
65
+ if (existsSync(pkgPath)) {
66
+ const pkg = await readPackageJSON(currentDir);
67
+ if (pkg && hasWorkspaces(pkg)) {
68
+ return currentDir;
69
+ }
70
+ }
71
+ const parentDir = resolve(currentDir, "..");
72
+ if (parentDir === currentDir) break;
73
+ currentDir = parentDir;
74
+ }
75
+ return null;
76
+ }
77
+ async discoverPackages(monorepoRoot) {
78
+ const rootPkg = await readPackageJSON(monorepoRoot);
79
+ if (!rootPkg) {
80
+ throw new Error("Could not read root package.json");
81
+ }
82
+ const patterns = getWorkspacePatterns(rootPkg);
83
+ if (!patterns.length) {
84
+ throw new Error("No workspace patterns found in package.json");
85
+ }
86
+ const packages = [];
87
+ const seenPaths = /* @__PURE__ */ new Set();
88
+ for (const pattern of patterns) {
89
+ const glob = new Bun.Glob(pattern);
90
+ const matches = glob.scanSync({ cwd: monorepoRoot, onlyFiles: false });
91
+ for (const match of matches) {
92
+ const packagePath = resolve(monorepoRoot, match);
93
+ if (seenPaths.has(packagePath)) continue;
94
+ seenPaths.add(packagePath);
95
+ const pkgInfo = await this.resolvePackageInfo(packagePath);
96
+ if (pkgInfo) {
97
+ packages.push(pkgInfo);
98
+ }
99
+ }
100
+ }
101
+ if (this.options.ignore) {
102
+ const ignoreFilter = createIgnoreFilter(this.options.ignore);
103
+ return ignoreFilter(packages);
104
+ }
105
+ return packages;
106
+ }
107
+ async resolvePackageInfo(packagePath) {
108
+ const pkgJsonPath = join(packagePath, "package.json");
109
+ if (!existsSync(pkgJsonPath)) return null;
110
+ try {
111
+ const pkg = await readPackageJSON(packagePath);
112
+ if (!pkg?.name) return null;
113
+ const dependencies = [
114
+ ...Object.keys(pkg.dependencies ?? {}),
115
+ ...this.options.includeDevDependencies ? Object.keys(pkg.devDependencies ?? {}) : [],
116
+ ...Object.keys(pkg.peerDependencies ?? {})
117
+ ];
118
+ return {
119
+ name: pkg.name,
120
+ path: packagePath,
121
+ dependencies,
122
+ dependents: [],
123
+ // Will be filled later
124
+ buildTime: 0,
125
+ // Would need to measure actual build time
126
+ size: 0
127
+ // Would need to calculate package size
128
+ };
129
+ } catch {
130
+ return null;
131
+ }
132
+ }
133
+ async buildDependencyGraph() {
134
+ const nodes = this.packages.map((pkg) => pkg.name);
135
+ const edges = [];
136
+ for (const pkg of this.packages) {
137
+ for (const dep of pkg.dependencies) {
138
+ const depPkg = this.packages.find((p) => p.name === dep);
139
+ if (depPkg) {
140
+ edges.push({
141
+ from: pkg.name,
142
+ to: dep,
143
+ type: "dependency"
144
+ });
145
+ depPkg.dependents.push(pkg.name);
146
+ }
147
+ }
148
+ }
149
+ const levels = this.calculateLevels(nodes, edges);
150
+ return {
151
+ nodes,
152
+ edges,
153
+ levels
154
+ };
155
+ }
156
+ calculateLevels(nodes, edges) {
157
+ const inDegree = /* @__PURE__ */ new Map();
158
+ const graph = /* @__PURE__ */ new Map();
159
+ for (const node of nodes) {
160
+ inDegree.set(node, 0);
161
+ graph.set(node, []);
162
+ }
163
+ for (const edge of edges) {
164
+ const current = inDegree.get(edge.to) ?? 0;
165
+ inDegree.set(edge.to, current + 1);
166
+ const neighbors = graph.get(edge.from) ?? [];
167
+ neighbors.push(edge.to);
168
+ graph.set(edge.from, neighbors);
169
+ }
170
+ const levels = [];
171
+ const queue = [];
172
+ for (const [node, degree] of inDegree) {
173
+ if (degree === 0) {
174
+ queue.push(node);
175
+ }
176
+ }
177
+ while (queue.length > 0) {
178
+ const currentLevel = [];
179
+ const nextQueue = [];
180
+ for (const node of queue) {
181
+ currentLevel.push(node);
182
+ const neighbors = graph.get(node) ?? [];
183
+ for (const neighbor of neighbors) {
184
+ const degree = inDegree.get(neighbor) ?? 0;
185
+ inDegree.set(neighbor, degree - 1);
186
+ if (degree - 1 === 0) {
187
+ nextQueue.push(neighbor);
188
+ }
189
+ }
190
+ }
191
+ levels.push(currentLevel);
192
+ queue.length = 0;
193
+ queue.push(...nextQueue);
194
+ }
195
+ return levels;
196
+ }
197
+ findCircularDependencies() {
198
+ const circular = [];
199
+ const visited = /* @__PURE__ */ new Set();
200
+ const recursionStack = /* @__PURE__ */ new Set();
201
+ for (const pkg of this.packages) {
202
+ if (!visited.has(pkg.name)) {
203
+ const cycle = this.detectCycle(pkg.name, visited, recursionStack, []);
204
+ if (cycle.length > 0) {
205
+ circular.push({
206
+ packages: cycle,
207
+ cycle,
208
+ severity: this.calculateCycleSeverity(cycle)
209
+ });
210
+ }
211
+ }
212
+ }
213
+ return circular;
214
+ }
215
+ detectCycle(node, visited, recursionStack, path) {
216
+ visited.add(node);
217
+ recursionStack.add(node);
218
+ path.push(node);
219
+ const pkg = this.packages.find((p) => p.name === node);
220
+ if (pkg) {
221
+ for (const dep of pkg.dependencies) {
222
+ const depPkg = this.packages.find((p) => p.name === dep);
223
+ if (depPkg) {
224
+ if (!visited.has(dep)) {
225
+ const cycle = this.detectCycle(dep, visited, recursionStack, [
226
+ ...path
227
+ ]);
228
+ if (cycle.length > 0) {
229
+ return cycle;
230
+ }
231
+ } else if (recursionStack.has(dep)) {
232
+ const cycleStart = path.indexOf(dep);
233
+ return path.slice(cycleStart);
234
+ }
235
+ }
236
+ }
237
+ }
238
+ recursionStack.delete(node);
239
+ return [];
240
+ }
241
+ calculateCycleSeverity(cycle) {
242
+ if (cycle.length <= 2) return "low";
243
+ if (cycle.length <= 4) return "medium";
244
+ return "high";
245
+ }
246
+ calculateBuildOrder() {
247
+ const order = [];
248
+ for (const level of this.dependencyGraph.levels) {
249
+ order.push(...level);
250
+ }
251
+ return order;
252
+ }
253
+ findCriticalPath() {
254
+ const dependentCounts = /* @__PURE__ */ new Map();
255
+ for (const pkg of this.packages) {
256
+ dependentCounts.set(pkg.name, pkg.dependents.length);
257
+ }
258
+ return Array.from(dependentCounts.entries()).sort(([, a], [, b]) => b - a).map(([name]) => name);
259
+ }
260
+ identifyBottlenecks() {
261
+ const bottlenecks = [];
262
+ for (const pkg of this.packages) {
263
+ if (pkg.dependencies.length > 10) {
264
+ bottlenecks.push({
265
+ package: pkg.name,
266
+ type: "many-dependencies",
267
+ impact: pkg.dependencies.length,
268
+ suggestion: `Consider splitting ${pkg.name} - it has ${pkg.dependencies.length} dependencies`
269
+ });
270
+ }
271
+ }
272
+ const circularDeps = this.findCircularDependencies();
273
+ for (const circular of circularDeps) {
274
+ bottlenecks.push({
275
+ package: circular.packages[0],
276
+ type: "circular-dependency",
277
+ impact: circular.packages.length,
278
+ suggestion: `Resolve circular dependency: ${circular.cycle.join(" \u2192 ")}`
279
+ });
280
+ }
281
+ for (const pkg of this.packages) {
282
+ if (pkg.dependents.length > 5) {
283
+ bottlenecks.push({
284
+ package: pkg.name,
285
+ type: "slow-build",
286
+ impact: pkg.dependents.length,
287
+ suggestion: `Optimize ${pkg.name} - it blocks ${pkg.dependents.length} other packages`
288
+ });
289
+ }
290
+ }
291
+ return bottlenecks.sort((a, b) => b.impact - a.impact);
292
+ }
293
+ suggestOptimalConcurrency() {
294
+ const maxLevel = this.dependencyGraph.levels.length;
295
+ const avgLevelSize = this.packages.length / maxLevel;
296
+ const cpuCores = require("node:os").cpus().length;
297
+ const suggested = Math.min(Math.ceil(avgLevelSize), cpuCores);
298
+ return Math.max(1, suggested);
299
+ }
300
+ }
301
+ export const analyzeMonorepo = async (options) => {
302
+ const analyzer = new MonorepoAnalyzer(options);
303
+ return analyzer.analyze();
304
+ };
305
+ export const createMonorepoAnalyzer = (options) => {
306
+ return new MonorepoAnalyzer(options);
307
+ };
@@ -0,0 +1,21 @@
1
+ import type { Measurement, MemoryUsage } from "../types.js";
2
+ export interface CommandExecutionOptions {
3
+ cwd?: string;
4
+ timeout?: number;
5
+ env?: Record<string, string>;
6
+ }
7
+ export interface CommandResult {
8
+ success: boolean;
9
+ duration: number;
10
+ memory: MemoryUsage;
11
+ stdout: string;
12
+ stderr: string;
13
+ error?: string;
14
+ exitCode: number;
15
+ }
16
+ export declare const executeCommand: (command: string, options?: CommandExecutionOptions) => Promise<CommandResult>;
17
+ export declare const executeCommandWithMemoryTracking: (command: string, options?: CommandExecutionOptions) => Promise<Measurement>;
18
+ export declare const isDlerCommand: (command: string) => boolean;
19
+ export declare const isBunCommand: (command: string) => boolean;
20
+ export declare const isNodeCommand: (command: string) => boolean;
21
+ export declare const getCommandType: (command: string) => "dler" | "bun" | "node" | "external";