@reliverse/dler 2.0.6 → 2.0.7
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.
- package/package.json +16 -12
- package/src/cli.ts +0 -8
- package/src/cmds/build/cmd.ts +0 -568
- package/src/cmds/clean/cmd.ts +0 -166
- package/src/cmds/clean/impl.ts +0 -900
- package/src/cmds/clean/presets.ts +0 -158
- package/src/cmds/clean/types.ts +0 -71
- package/src/cmds/init/cmd.ts +0 -68
- package/src/cmds/init/impl/config.ts +0 -105
- package/src/cmds/init/impl/generators.ts +0 -220
- package/src/cmds/init/impl/prompts.ts +0 -137
- package/src/cmds/init/impl/types.ts +0 -25
- package/src/cmds/init/impl/utils.ts +0 -17
- package/src/cmds/init/impl/validators.ts +0 -55
- package/src/cmds/integrate/cmd.ts +0 -82
- package/src/cmds/integrate/impl.ts +0 -204
- package/src/cmds/integrate/integrations/base.ts +0 -69
- package/src/cmds/integrate/integrations/nextjs.ts +0 -227
- package/src/cmds/integrate/integrations/registry.ts +0 -45
- package/src/cmds/integrate/integrations/ultracite.ts +0 -53
- package/src/cmds/integrate/types.ts +0 -48
- package/src/cmds/integrate/utils/biome.ts +0 -173
- package/src/cmds/integrate/utils/context.ts +0 -148
- package/src/cmds/integrate/utils/temp.ts +0 -47
- package/src/cmds/perf/analysis/bundle.ts +0 -311
- package/src/cmds/perf/analysis/filesystem.ts +0 -324
- package/src/cmds/perf/analysis/monorepo.ts +0 -439
- package/src/cmds/perf/benchmarks/command.ts +0 -230
- package/src/cmds/perf/benchmarks/memory.ts +0 -249
- package/src/cmds/perf/benchmarks/runner.ts +0 -220
- package/src/cmds/perf/cmd.ts +0 -285
- package/src/cmds/perf/impl.ts +0 -411
- package/src/cmds/perf/reporters/console.ts +0 -331
- package/src/cmds/perf/reporters/html.ts +0 -984
- package/src/cmds/perf/reporters/json.ts +0 -42
- package/src/cmds/perf/types.ts +0 -220
- package/src/cmds/perf/utils/cache.ts +0 -234
- package/src/cmds/perf/utils/formatter.ts +0 -190
- package/src/cmds/perf/utils/stats.ts +0 -153
- package/src/cmds/publish/cmd.ts +0 -213
- package/src/cmds/shell/cmd.ts +0 -61
- package/src/cmds/tsc/cache.ts +0 -237
- package/src/cmds/tsc/cmd.ts +0 -139
- package/src/cmds/tsc/impl.ts +0 -855
- package/src/cmds/tsc/types.ts +0 -66
- package/tsconfig.json +0 -9
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// apps/dler/src/cmds/perf/reporters/json.ts
|
|
2
|
-
|
|
3
|
-
import { writeFileSync } from "node:fs";
|
|
4
|
-
import { logger } from "@reliverse/dler-logger";
|
|
5
|
-
import type { PerfReport } from "../types";
|
|
6
|
-
|
|
7
|
-
export class JsonReporter {
|
|
8
|
-
private outputPath?: string;
|
|
9
|
-
|
|
10
|
-
constructor(outputPath?: string) {
|
|
11
|
-
this.outputPath = outputPath;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
report(report: PerfReport): void {
|
|
15
|
-
const json = JSON.stringify(report, null, 2);
|
|
16
|
-
|
|
17
|
-
if (this.outputPath) {
|
|
18
|
-
try {
|
|
19
|
-
writeFileSync(this.outputPath, json, "utf-8");
|
|
20
|
-
logger.success(`📄 JSON report saved to: ${this.outputPath}`);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
logger.error(`Failed to save JSON report: ${error}`);
|
|
23
|
-
}
|
|
24
|
-
} else {
|
|
25
|
-
console.log(json);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
static save(report: PerfReport, outputPath: string): void {
|
|
30
|
-
const reporter = new JsonReporter(outputPath);
|
|
31
|
-
reporter.report(report);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
static print(report: PerfReport): void {
|
|
35
|
-
const reporter = new JsonReporter();
|
|
36
|
-
reporter.report(report);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export const createJsonReporter = (outputPath?: string): JsonReporter => {
|
|
41
|
-
return new JsonReporter(outputPath);
|
|
42
|
-
};
|
package/src/cmds/perf/types.ts
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
// apps/dler/src/cmds/perf/types.ts
|
|
2
|
-
|
|
3
|
-
export interface PerfOptions {
|
|
4
|
-
target?: string;
|
|
5
|
-
type?: string;
|
|
6
|
-
runs?: number;
|
|
7
|
-
warmup?: number;
|
|
8
|
-
concurrency?: number;
|
|
9
|
-
compare?: boolean;
|
|
10
|
-
output?: string;
|
|
11
|
-
save?: boolean;
|
|
12
|
-
verbose?: boolean;
|
|
13
|
-
cwd?: string;
|
|
14
|
-
ignore?: string | string[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type PerfAnalysisType =
|
|
18
|
-
| "command"
|
|
19
|
-
| "bundle"
|
|
20
|
-
| "file"
|
|
21
|
-
| "monorepo"
|
|
22
|
-
| "auto";
|
|
23
|
-
export type PerfOutputFormat = "console" | "json" | "html" | "all";
|
|
24
|
-
|
|
25
|
-
export interface BenchmarkResult {
|
|
26
|
-
command: string;
|
|
27
|
-
runs: number;
|
|
28
|
-
warmup: number;
|
|
29
|
-
concurrency: number;
|
|
30
|
-
measurements: Measurement[];
|
|
31
|
-
statistics: Statistics;
|
|
32
|
-
memory: MemoryStats;
|
|
33
|
-
executionTime: number;
|
|
34
|
-
success: boolean;
|
|
35
|
-
error?: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface Measurement {
|
|
39
|
-
run: number;
|
|
40
|
-
duration: number;
|
|
41
|
-
memory: MemoryUsage;
|
|
42
|
-
success: boolean;
|
|
43
|
-
error?: string;
|
|
44
|
-
stdout?: string;
|
|
45
|
-
stderr?: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface Statistics {
|
|
49
|
-
min: number;
|
|
50
|
-
max: number;
|
|
51
|
-
mean: number;
|
|
52
|
-
median: number;
|
|
53
|
-
p95: number;
|
|
54
|
-
p99: number;
|
|
55
|
-
variance: number;
|
|
56
|
-
standardDeviation: number;
|
|
57
|
-
coefficientOfVariation: number;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface MemoryUsage {
|
|
61
|
-
rss: number;
|
|
62
|
-
heapTotal: number;
|
|
63
|
-
heapUsed: number;
|
|
64
|
-
external: number;
|
|
65
|
-
arrayBuffers: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface MemoryStats {
|
|
69
|
-
peak: MemoryUsage;
|
|
70
|
-
average: MemoryUsage;
|
|
71
|
-
growth: number;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface BundleAnalysisResult {
|
|
75
|
-
target: string;
|
|
76
|
-
totalSize: number;
|
|
77
|
-
fileCount: number;
|
|
78
|
-
largestFiles: FileSize[];
|
|
79
|
-
modules: ModuleInfo[];
|
|
80
|
-
duplicates: DuplicateInfo[];
|
|
81
|
-
compressionPotential: number;
|
|
82
|
-
analysisTime: number;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface FileSize {
|
|
86
|
-
path: string;
|
|
87
|
-
size: number;
|
|
88
|
-
percentage: number;
|
|
89
|
-
type: string;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface ModuleInfo {
|
|
93
|
-
name: string;
|
|
94
|
-
size: number;
|
|
95
|
-
percentage: number;
|
|
96
|
-
dependencies: string[];
|
|
97
|
-
isExternal: boolean;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export interface DuplicateInfo {
|
|
101
|
-
name: string;
|
|
102
|
-
count: number;
|
|
103
|
-
totalSize: number;
|
|
104
|
-
locations: string[];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export interface FileSystemAnalysisResult {
|
|
108
|
-
target: string;
|
|
109
|
-
totalFiles: number;
|
|
110
|
-
totalSize: number;
|
|
111
|
-
directoryCount: number;
|
|
112
|
-
maxDepth: number;
|
|
113
|
-
largestFiles: FileSize[];
|
|
114
|
-
largestDirectories: DirectorySize[];
|
|
115
|
-
fileTypes: FileTypeDistribution[];
|
|
116
|
-
compressionPotential: number;
|
|
117
|
-
analysisTime: number;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export interface DirectorySize {
|
|
121
|
-
path: string;
|
|
122
|
-
size: number;
|
|
123
|
-
fileCount: number;
|
|
124
|
-
depth: number;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export interface FileTypeDistribution {
|
|
128
|
-
extension: string;
|
|
129
|
-
count: number;
|
|
130
|
-
totalSize: number;
|
|
131
|
-
percentage: number;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface MonorepoAnalysisResult {
|
|
135
|
-
packages: PackageInfo[];
|
|
136
|
-
dependencies: DependencyGraph;
|
|
137
|
-
circularDependencies: CircularDependency[];
|
|
138
|
-
criticalPath: string[];
|
|
139
|
-
buildOrder: string[];
|
|
140
|
-
bottlenecks: Bottleneck[];
|
|
141
|
-
suggestedConcurrency: number;
|
|
142
|
-
analysisTime: number;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export interface PackageInfo {
|
|
146
|
-
name: string;
|
|
147
|
-
path: string;
|
|
148
|
-
dependencies: string[];
|
|
149
|
-
dependents: string[];
|
|
150
|
-
buildTime?: number;
|
|
151
|
-
size?: number;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface DependencyGraph {
|
|
155
|
-
nodes: string[];
|
|
156
|
-
edges: DependencyEdge[];
|
|
157
|
-
levels: string[][];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export interface DependencyEdge {
|
|
161
|
-
from: string;
|
|
162
|
-
to: string;
|
|
163
|
-
type: "dependency" | "devDependency" | "peerDependency";
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export interface CircularDependency {
|
|
167
|
-
packages: string[];
|
|
168
|
-
cycle: string[];
|
|
169
|
-
severity: "low" | "medium" | "high";
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export interface Bottleneck {
|
|
173
|
-
package: string;
|
|
174
|
-
type: "slow-build" | "many-dependencies" | "circular-dependency";
|
|
175
|
-
impact: number;
|
|
176
|
-
suggestion: string;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export interface PerfReport {
|
|
180
|
-
timestamp: number;
|
|
181
|
-
options: PerfOptions;
|
|
182
|
-
benchmark?: BenchmarkResult;
|
|
183
|
-
bundleAnalysis?: BundleAnalysisResult;
|
|
184
|
-
fileSystemAnalysis?: FileSystemAnalysisResult;
|
|
185
|
-
monorepoAnalysis?: MonorepoAnalysisResult;
|
|
186
|
-
baseline?: BaselineComparison;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export interface BaselineComparison {
|
|
190
|
-
exists: boolean;
|
|
191
|
-
improvement?: number;
|
|
192
|
-
regression?: number;
|
|
193
|
-
changes?: ChangeSummary;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export interface ChangeSummary {
|
|
197
|
-
duration?: number;
|
|
198
|
-
memory?: number;
|
|
199
|
-
size?: number;
|
|
200
|
-
files?: number;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export interface CacheEntry {
|
|
204
|
-
timestamp: number;
|
|
205
|
-
report: PerfReport;
|
|
206
|
-
hash: string;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export interface CacheOptions {
|
|
210
|
-
enabled: boolean;
|
|
211
|
-
cacheDir: string;
|
|
212
|
-
maxAge: number;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export type AnalysisResult =
|
|
216
|
-
| BundleAnalysisResult
|
|
217
|
-
| FileSystemAnalysisResult
|
|
218
|
-
| MonorepoAnalysisResult;
|
|
219
|
-
|
|
220
|
-
export type OutputFormat = PerfOutputFormat;
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
// apps/dler/src/cmds/perf/utils/cache.ts
|
|
2
|
-
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { join, resolve } from "node:path";
|
|
6
|
-
import type { CacheEntry, CacheOptions, PerfReport } from "../types";
|
|
7
|
-
|
|
8
|
-
export class PerfCache {
|
|
9
|
-
private options: CacheOptions;
|
|
10
|
-
private cacheDir: string;
|
|
11
|
-
|
|
12
|
-
constructor(options: CacheOptions) {
|
|
13
|
-
this.options = options;
|
|
14
|
-
this.cacheDir = resolve(options.cacheDir);
|
|
15
|
-
this.ensureCacheDir();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
private ensureCacheDir(): void {
|
|
19
|
-
if (!existsSync(this.cacheDir)) {
|
|
20
|
-
mkdirSync(this.cacheDir, { recursive: true });
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
private generateHash(report: PerfReport): string {
|
|
25
|
-
const content = JSON.stringify({
|
|
26
|
-
target: report.options.target,
|
|
27
|
-
type: report.options.type,
|
|
28
|
-
// Exclude timestamp and other volatile fields
|
|
29
|
-
benchmark: report.benchmark
|
|
30
|
-
? {
|
|
31
|
-
command: report.benchmark.command,
|
|
32
|
-
runs: report.benchmark.runs,
|
|
33
|
-
concurrency: report.benchmark.concurrency,
|
|
34
|
-
}
|
|
35
|
-
: undefined,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return createHash("sha256").update(content).digest("hex").substring(0, 16);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private getCachePath(hash: string): string {
|
|
42
|
-
return join(this.cacheDir, `${hash}.json`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private isExpired(entry: CacheEntry): boolean {
|
|
46
|
-
if (!this.options.enabled) return true;
|
|
47
|
-
|
|
48
|
-
const age = Date.now() - entry.timestamp;
|
|
49
|
-
return age > this.options.maxAge;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async save(report: PerfReport): Promise<void> {
|
|
53
|
-
if (!this.options.enabled) return;
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const hash = this.generateHash(report);
|
|
57
|
-
const entry: CacheEntry = {
|
|
58
|
-
timestamp: Date.now(),
|
|
59
|
-
report,
|
|
60
|
-
hash,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const cachePath = this.getCachePath(hash);
|
|
64
|
-
writeFileSync(cachePath, JSON.stringify(entry, null, 2));
|
|
65
|
-
} catch (error) {
|
|
66
|
-
// Silently fail cache operations
|
|
67
|
-
console.warn("Failed to save performance cache:", error);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async load(target: string, type?: string): Promise<PerfReport | null> {
|
|
72
|
-
if (!this.options.enabled) return null;
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
// Find all cache files
|
|
76
|
-
const cacheFiles = Array.from(
|
|
77
|
-
new Bun.Glob("*.json").scanSync({ cwd: this.cacheDir }),
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
for (const file of cacheFiles) {
|
|
81
|
-
const cachePath = join(this.cacheDir, file);
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
const content = readFileSync(cachePath, "utf-8");
|
|
85
|
-
const entry: CacheEntry = JSON.parse(content);
|
|
86
|
-
|
|
87
|
-
if (this.isExpired(entry)) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Check if this matches our target
|
|
92
|
-
if (
|
|
93
|
-
entry.report.options.target === target &&
|
|
94
|
-
(!type || entry.report.options.type === type)
|
|
95
|
-
) {
|
|
96
|
-
return entry.report;
|
|
97
|
-
}
|
|
98
|
-
} catch {
|
|
99
|
-
// Skip invalid cache files
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return null;
|
|
105
|
-
} catch (error) {
|
|
106
|
-
// Silently fail cache operations
|
|
107
|
-
console.warn("Failed to load performance cache:", error);
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async findBaseline(
|
|
113
|
-
target: string,
|
|
114
|
-
type?: string,
|
|
115
|
-
): Promise<PerfReport | null> {
|
|
116
|
-
return this.load(target, type);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async listBaselines(): Promise<
|
|
120
|
-
Array<{ target: string; type?: string; timestamp: number; hash: string }>
|
|
121
|
-
> {
|
|
122
|
-
if (!this.options.enabled) return [];
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
const cacheFiles = Array.from(
|
|
126
|
-
new Bun.Glob("*.json").scanSync({ cwd: this.cacheDir }),
|
|
127
|
-
);
|
|
128
|
-
const baselines: Array<{
|
|
129
|
-
target: string;
|
|
130
|
-
type?: string;
|
|
131
|
-
timestamp: number;
|
|
132
|
-
hash: string;
|
|
133
|
-
}> = [];
|
|
134
|
-
|
|
135
|
-
for (const file of cacheFiles) {
|
|
136
|
-
const cachePath = join(this.cacheDir, file);
|
|
137
|
-
|
|
138
|
-
try {
|
|
139
|
-
const content = readFileSync(cachePath, "utf-8");
|
|
140
|
-
const entry: CacheEntry = JSON.parse(content);
|
|
141
|
-
|
|
142
|
-
if (!this.isExpired(entry)) {
|
|
143
|
-
baselines.push({
|
|
144
|
-
target: entry.report.options.target ?? "unknown",
|
|
145
|
-
type: entry.report.options.type,
|
|
146
|
-
timestamp: entry.timestamp,
|
|
147
|
-
hash: entry.hash,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
} catch {
|
|
151
|
-
// Skip invalid cache files
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return baselines.sort((a, b) => b.timestamp - a.timestamp);
|
|
157
|
-
} catch (error) {
|
|
158
|
-
console.warn("Failed to list performance baselines:", error);
|
|
159
|
-
return [];
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async clear(): Promise<void> {
|
|
164
|
-
if (!this.options.enabled) return;
|
|
165
|
-
|
|
166
|
-
try {
|
|
167
|
-
const cacheFiles = Array.from(
|
|
168
|
-
new Bun.Glob("*.json").scanSync({ cwd: this.cacheDir }),
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
for (const file of cacheFiles) {
|
|
172
|
-
const cachePath = join(this.cacheDir, file);
|
|
173
|
-
try {
|
|
174
|
-
Bun.write(cachePath, "");
|
|
175
|
-
} catch {
|
|
176
|
-
// Ignore deletion errors
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
} catch (error) {
|
|
180
|
-
console.warn("Failed to clear performance cache:", error);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async cleanup(): Promise<void> {
|
|
185
|
-
if (!this.options.enabled) return;
|
|
186
|
-
|
|
187
|
-
try {
|
|
188
|
-
const cacheFiles = Array.from(
|
|
189
|
-
new Bun.Glob("*.json").scanSync({ cwd: this.cacheDir }),
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
for (const file of cacheFiles) {
|
|
193
|
-
const cachePath = join(this.cacheDir, file);
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
const content = readFileSync(cachePath, "utf-8");
|
|
197
|
-
const entry: CacheEntry = JSON.parse(content);
|
|
198
|
-
|
|
199
|
-
if (this.isExpired(entry)) {
|
|
200
|
-
Bun.write(cachePath, "");
|
|
201
|
-
}
|
|
202
|
-
} catch {
|
|
203
|
-
// Skip invalid cache files
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
} catch (error) {
|
|
208
|
-
console.warn("Failed to cleanup performance cache:", error);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
getCacheSize(): number {
|
|
213
|
-
try {
|
|
214
|
-
const cacheFiles = Array.from(
|
|
215
|
-
new Bun.Glob("*.json").scanSync({ cwd: this.cacheDir }),
|
|
216
|
-
);
|
|
217
|
-
return cacheFiles.length;
|
|
218
|
-
} catch {
|
|
219
|
-
return 0;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export const createPerfCache = (
|
|
225
|
-
options: Partial<CacheOptions> = {},
|
|
226
|
-
): PerfCache => {
|
|
227
|
-
const defaultOptions: CacheOptions = {
|
|
228
|
-
enabled: true,
|
|
229
|
-
cacheDir: ".dler-cache/perf",
|
|
230
|
-
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
return new PerfCache({ ...defaultOptions, ...options });
|
|
234
|
-
};
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
// apps/dler/src/cmds/perf/utils/formatter.ts
|
|
2
|
-
|
|
3
|
-
export const formatDuration = (ms: number): string => {
|
|
4
|
-
if (ms < 1000) {
|
|
5
|
-
return `${ms.toFixed(2)}ms`;
|
|
6
|
-
}
|
|
7
|
-
if (ms < 60000) {
|
|
8
|
-
return `${(ms / 1000).toFixed(2)}s`;
|
|
9
|
-
}
|
|
10
|
-
const minutes = Math.floor(ms / 60000);
|
|
11
|
-
const seconds = ((ms % 60000) / 1000).toFixed(2);
|
|
12
|
-
return `${minutes}m ${seconds}s`;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const formatBytes = (bytes: number): string => {
|
|
16
|
-
if (bytes === 0) return "0 B";
|
|
17
|
-
|
|
18
|
-
const k = 1024;
|
|
19
|
-
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
20
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
21
|
-
|
|
22
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const formatPercentage = (value: number, total: number): string => {
|
|
26
|
-
if (total === 0) return "0.00%";
|
|
27
|
-
return `${((value / total) * 100).toFixed(2)}%`;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const formatNumber = (num: number): string => {
|
|
31
|
-
if (num < 1000) return num.toString();
|
|
32
|
-
if (num < 1000000) return `${(num / 1000).toFixed(1)}K`;
|
|
33
|
-
if (num < 1000000000) return `${(num / 1000000).toFixed(1)}M`;
|
|
34
|
-
return `${(num / 1000000000).toFixed(1)}B`;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const formatMemory = (bytes: number): string => {
|
|
38
|
-
return formatBytes(bytes);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const formatImprovement = (improvement: number): string => {
|
|
42
|
-
const sign = improvement > 0 ? "+" : "";
|
|
43
|
-
return `${sign}${improvement.toFixed(2)}%`;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export const formatRegression = (regression: number): string => {
|
|
47
|
-
return `+${regression.toFixed(2)}%`;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const formatConfidenceInterval = (
|
|
51
|
-
lower: number,
|
|
52
|
-
upper: number,
|
|
53
|
-
formatter = formatDuration,
|
|
54
|
-
): string => {
|
|
55
|
-
return `${formatter(lower)} - ${formatter(upper)}`;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export const formatProgress = (current: number, total: number): string => {
|
|
59
|
-
const percentage = total === 0 ? 0 : (current / total) * 100;
|
|
60
|
-
const barLength = 20;
|
|
61
|
-
const filled = Math.floor((percentage / 100) * barLength);
|
|
62
|
-
const bar = "█".repeat(filled) + "░".repeat(barLength - filled);
|
|
63
|
-
return `[${bar}] ${percentage.toFixed(1)}% (${current}/${total})`;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export const formatTable = (headers: string[], rows: string[][]): string => {
|
|
67
|
-
if (rows.length === 0) return "";
|
|
68
|
-
|
|
69
|
-
// Calculate column widths
|
|
70
|
-
const widths = headers.map((header, i) => {
|
|
71
|
-
const maxRowWidth = Math.max(...rows.map((row) => row[i]?.length ?? 0));
|
|
72
|
-
return Math.max(header.length, maxRowWidth);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Create separator
|
|
76
|
-
const separator = "─".repeat(widths.reduce((sum, w) => sum + w + 3, 0) - 1);
|
|
77
|
-
|
|
78
|
-
// Format header
|
|
79
|
-
const headerRow = headers
|
|
80
|
-
.map((header, i) => header.padEnd(widths[i]!))
|
|
81
|
-
.join(" │ ");
|
|
82
|
-
|
|
83
|
-
// Format rows
|
|
84
|
-
const dataRows = rows.map((row) =>
|
|
85
|
-
row.map((cell, i) => (cell ?? "").padEnd(widths[i]!)).join(" │ "),
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
return [headerRow, separator, ...dataRows].join("\n");
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
export const formatDurationBar = (
|
|
92
|
-
value: number,
|
|
93
|
-
max: number,
|
|
94
|
-
width = 20,
|
|
95
|
-
): string => {
|
|
96
|
-
const percentage = max === 0 ? 0 : (value / max) * 100;
|
|
97
|
-
const filled = Math.floor((percentage / 100) * width);
|
|
98
|
-
const bar = "█".repeat(filled) + "░".repeat(width - filled);
|
|
99
|
-
return `${bar} ${formatDuration(value)}`;
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
export const formatSizeBar = (
|
|
103
|
-
value: number,
|
|
104
|
-
max: number,
|
|
105
|
-
width = 20,
|
|
106
|
-
): string => {
|
|
107
|
-
const percentage = max === 0 ? 0 : (value / max) * 100;
|
|
108
|
-
const filled = Math.floor((percentage / 100) * width);
|
|
109
|
-
const bar = "█".repeat(filled) + "░".repeat(width - filled);
|
|
110
|
-
return `${bar} ${formatBytes(value)}`;
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
export const formatRelativeChange = (
|
|
114
|
-
baseline: number,
|
|
115
|
-
current: number,
|
|
116
|
-
): string => {
|
|
117
|
-
if (baseline === 0) return "N/A";
|
|
118
|
-
|
|
119
|
-
const change = ((current - baseline) / baseline) * 100;
|
|
120
|
-
const sign = change > 0 ? "+" : "";
|
|
121
|
-
const color = change > 0 ? "🔴" : change < 0 ? "🟢" : "⚪";
|
|
122
|
-
|
|
123
|
-
return `${color} ${sign}${change.toFixed(2)}%`;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
export const truncatePath = (path: string, maxLength = 50): string => {
|
|
127
|
-
if (path.length <= maxLength) return path;
|
|
128
|
-
|
|
129
|
-
const start = path.substring(0, Math.floor(maxLength / 2) - 2);
|
|
130
|
-
const end = path.substring(path.length - Math.floor(maxLength / 2) + 2);
|
|
131
|
-
|
|
132
|
-
return `${start}...${end}`;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
export const formatFileType = (extension: string): string => {
|
|
136
|
-
const typeMap: Record<string, string> = {
|
|
137
|
-
".js": "JavaScript",
|
|
138
|
-
".ts": "TypeScript",
|
|
139
|
-
".jsx": "React JSX",
|
|
140
|
-
".tsx": "React TSX",
|
|
141
|
-
".json": "JSON",
|
|
142
|
-
".css": "CSS",
|
|
143
|
-
".scss": "SCSS",
|
|
144
|
-
".sass": "Sass",
|
|
145
|
-
".less": "Less",
|
|
146
|
-
".html": "HTML",
|
|
147
|
-
".svg": "SVG",
|
|
148
|
-
".png": "PNG",
|
|
149
|
-
".jpg": "JPEG",
|
|
150
|
-
".jpeg": "JPEG",
|
|
151
|
-
".gif": "GIF",
|
|
152
|
-
".webp": "WebP",
|
|
153
|
-
".woff": "WOFF",
|
|
154
|
-
".woff2": "WOFF2",
|
|
155
|
-
".ttf": "TrueType",
|
|
156
|
-
".eot": "EOT",
|
|
157
|
-
".map": "Source Map",
|
|
158
|
-
".d.ts": "TypeScript Declarations",
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
return typeMap[extension] ?? extension.toUpperCase();
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
export const formatSeverity = (severity: "low" | "medium" | "high"): string => {
|
|
165
|
-
const icons = {
|
|
166
|
-
low: "🟡",
|
|
167
|
-
medium: "🟠",
|
|
168
|
-
high: "🔴",
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
return `${icons[severity]} ${severity.toUpperCase()}`;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
export const formatBottleneckType = (
|
|
175
|
-
type: "slow-build" | "many-dependencies" | "circular-dependency",
|
|
176
|
-
): string => {
|
|
177
|
-
const icons = {
|
|
178
|
-
"slow-build": "⏱️",
|
|
179
|
-
"many-dependencies": "🔗",
|
|
180
|
-
"circular-dependency": "🔄",
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
const labels = {
|
|
184
|
-
"slow-build": "Slow Build",
|
|
185
|
-
"many-dependencies": "Many Dependencies",
|
|
186
|
-
"circular-dependency": "Circular Dependency",
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
return `${icons[type]} ${labels[type]}`;
|
|
190
|
-
};
|