modestbench 0.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.
- package/CHANGELOG.md +45 -0
- package/LICENSE.md +55 -0
- package/README.md +699 -0
- package/dist/bootstrap.cjs +37 -0
- package/dist/bootstrap.cjs.map +1 -0
- package/dist/bootstrap.d.cts +17 -0
- package/dist/bootstrap.d.cts.map +1 -0
- package/dist/bootstrap.d.ts +17 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +33 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/cli/commands/history.cjs +459 -0
- package/dist/cli/commands/history.cjs.map +1 -0
- package/dist/cli/commands/history.d.cts +34 -0
- package/dist/cli/commands/history.d.cts.map +1 -0
- package/dist/cli/commands/history.d.ts +34 -0
- package/dist/cli/commands/history.d.ts.map +1 -0
- package/dist/cli/commands/history.js +422 -0
- package/dist/cli/commands/history.js.map +1 -0
- package/dist/cli/commands/init.cjs +566 -0
- package/dist/cli/commands/init.cjs.map +1 -0
- package/dist/cli/commands/init.d.cts +26 -0
- package/dist/cli/commands/init.d.cts.map +1 -0
- package/dist/cli/commands/init.d.ts +26 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +562 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/run.cjs +285 -0
- package/dist/cli/commands/run.cjs.map +1 -0
- package/dist/cli/commands/run.d.cts +37 -0
- package/dist/cli/commands/run.d.cts.map +1 -0
- package/dist/cli/commands/run.d.ts +37 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +248 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/index.cjs +523 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +58 -0
- package/dist/cli/index.d.cts.map +1 -0
- package/dist/cli/index.d.ts +58 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +515 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/manager.cjs +370 -0
- package/dist/config/manager.cjs.map +1 -0
- package/dist/config/manager.d.cts +46 -0
- package/dist/config/manager.d.cts.map +1 -0
- package/dist/config/manager.d.ts +46 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +333 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/schema.cjs +182 -0
- package/dist/config/schema.cjs.map +1 -0
- package/dist/config/schema.d.cts +51 -0
- package/dist/config/schema.d.cts.map +1 -0
- package/dist/config/schema.d.ts +51 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +145 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/constants.cjs +22 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +10 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +19 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/benchmark-schema.cjs +135 -0
- package/dist/core/benchmark-schema.cjs.map +1 -0
- package/dist/core/benchmark-schema.d.cts +139 -0
- package/dist/core/benchmark-schema.d.cts.map +1 -0
- package/dist/core/benchmark-schema.d.ts +139 -0
- package/dist/core/benchmark-schema.d.ts.map +1 -0
- package/dist/core/benchmark-schema.js +132 -0
- package/dist/core/benchmark-schema.js.map +1 -0
- package/dist/core/engine.cjs +669 -0
- package/dist/core/engine.cjs.map +1 -0
- package/dist/core/engine.d.cts +128 -0
- package/dist/core/engine.d.cts.map +1 -0
- package/dist/core/engine.d.ts +128 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +632 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/engines/accurate-engine.cjs +292 -0
- package/dist/core/engines/accurate-engine.cjs.map +1 -0
- package/dist/core/engines/accurate-engine.d.cts +63 -0
- package/dist/core/engines/accurate-engine.d.cts.map +1 -0
- package/dist/core/engines/accurate-engine.d.ts +63 -0
- package/dist/core/engines/accurate-engine.d.ts.map +1 -0
- package/dist/core/engines/accurate-engine.js +288 -0
- package/dist/core/engines/accurate-engine.js.map +1 -0
- package/dist/core/engines/index.cjs +21 -0
- package/dist/core/engines/index.cjs.map +1 -0
- package/dist/core/engines/index.d.cts +16 -0
- package/dist/core/engines/index.d.cts.map +1 -0
- package/dist/core/engines/index.d.ts +16 -0
- package/dist/core/engines/index.d.ts.map +1 -0
- package/dist/core/engines/index.js +16 -0
- package/dist/core/engines/index.js.map +1 -0
- package/dist/core/engines/tinybench-engine.cjs +286 -0
- package/dist/core/engines/tinybench-engine.cjs.map +1 -0
- package/dist/core/engines/tinybench-engine.d.cts +18 -0
- package/dist/core/engines/tinybench-engine.d.cts.map +1 -0
- package/dist/core/engines/tinybench-engine.d.ts +18 -0
- package/dist/core/engines/tinybench-engine.d.ts.map +1 -0
- package/dist/core/engines/tinybench-engine.js +282 -0
- package/dist/core/engines/tinybench-engine.js.map +1 -0
- package/dist/core/error-manager.cjs +303 -0
- package/dist/core/error-manager.cjs.map +1 -0
- package/dist/core/error-manager.d.cts +77 -0
- package/dist/core/error-manager.d.cts.map +1 -0
- package/dist/core/error-manager.d.ts +77 -0
- package/dist/core/error-manager.d.ts.map +1 -0
- package/dist/core/error-manager.js +299 -0
- package/dist/core/error-manager.js.map +1 -0
- package/dist/core/loader.cjs +287 -0
- package/dist/core/loader.cjs.map +1 -0
- package/dist/core/loader.d.cts +55 -0
- package/dist/core/loader.d.cts.map +1 -0
- package/dist/core/loader.d.ts +55 -0
- package/dist/core/loader.d.ts.map +1 -0
- package/dist/core/loader.js +250 -0
- package/dist/core/loader.js.map +1 -0
- package/dist/core/stats-utils.cjs +99 -0
- package/dist/core/stats-utils.cjs.map +1 -0
- package/dist/core/stats-utils.d.cts +50 -0
- package/dist/core/stats-utils.d.cts.map +1 -0
- package/dist/core/stats-utils.d.ts +50 -0
- package/dist/core/stats-utils.d.ts.map +1 -0
- package/dist/core/stats-utils.js +94 -0
- package/dist/core/stats-utils.js.map +1 -0
- package/dist/index.cjs +64 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/progress/manager.cjs +325 -0
- package/dist/progress/manager.cjs.map +1 -0
- package/dist/progress/manager.d.cts +125 -0
- package/dist/progress/manager.d.cts.map +1 -0
- package/dist/progress/manager.d.ts +125 -0
- package/dist/progress/manager.d.ts.map +1 -0
- package/dist/progress/manager.js +321 -0
- package/dist/progress/manager.js.map +1 -0
- package/dist/reporters/csv.cjs +250 -0
- package/dist/reporters/csv.cjs.map +1 -0
- package/dist/reporters/csv.d.cts +92 -0
- package/dist/reporters/csv.d.cts.map +1 -0
- package/dist/reporters/csv.d.ts +92 -0
- package/dist/reporters/csv.d.ts.map +1 -0
- package/dist/reporters/csv.js +246 -0
- package/dist/reporters/csv.js.map +1 -0
- package/dist/reporters/human.cjs +516 -0
- package/dist/reporters/human.cjs.map +1 -0
- package/dist/reporters/human.d.cts +86 -0
- package/dist/reporters/human.d.cts.map +1 -0
- package/dist/reporters/human.d.ts +86 -0
- package/dist/reporters/human.d.ts.map +1 -0
- package/dist/reporters/human.js +509 -0
- package/dist/reporters/human.js.map +1 -0
- package/dist/reporters/index.cjs +17 -0
- package/dist/reporters/index.cjs.map +1 -0
- package/dist/reporters/index.d.cts +10 -0
- package/dist/reporters/index.d.cts.map +1 -0
- package/dist/reporters/index.d.ts +10 -0
- package/dist/reporters/index.d.ts.map +1 -0
- package/dist/reporters/index.js +10 -0
- package/dist/reporters/index.js.map +1 -0
- package/dist/reporters/json.cjs +215 -0
- package/dist/reporters/json.cjs.map +1 -0
- package/dist/reporters/json.d.cts +79 -0
- package/dist/reporters/json.d.cts.map +1 -0
- package/dist/reporters/json.d.ts +79 -0
- package/dist/reporters/json.d.ts.map +1 -0
- package/dist/reporters/json.js +211 -0
- package/dist/reporters/json.js.map +1 -0
- package/dist/reporters/registry.cjs +255 -0
- package/dist/reporters/registry.cjs.map +1 -0
- package/dist/reporters/registry.d.cts +155 -0
- package/dist/reporters/registry.d.cts.map +1 -0
- package/dist/reporters/registry.d.ts +155 -0
- package/dist/reporters/registry.d.ts.map +1 -0
- package/dist/reporters/registry.js +249 -0
- package/dist/reporters/registry.js.map +1 -0
- package/dist/reporters/simple.cjs +328 -0
- package/dist/reporters/simple.cjs.map +1 -0
- package/dist/reporters/simple.d.cts +51 -0
- package/dist/reporters/simple.d.cts.map +1 -0
- package/dist/reporters/simple.d.ts +51 -0
- package/dist/reporters/simple.d.ts.map +1 -0
- package/dist/reporters/simple.js +321 -0
- package/dist/reporters/simple.js.map +1 -0
- package/dist/schema/modestbench-config.schema.json +162 -0
- package/dist/storage/history.cjs +456 -0
- package/dist/storage/history.cjs.map +1 -0
- package/dist/storage/history.d.cts +99 -0
- package/dist/storage/history.d.cts.map +1 -0
- package/dist/storage/history.d.ts +99 -0
- package/dist/storage/history.d.ts.map +1 -0
- package/dist/storage/history.js +452 -0
- package/dist/storage/history.js.map +1 -0
- package/dist/types/cli.cjs +21 -0
- package/dist/types/cli.cjs.map +1 -0
- package/dist/types/cli.d.cts +296 -0
- package/dist/types/cli.d.cts.map +1 -0
- package/dist/types/cli.d.ts +296 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +18 -0
- package/dist/types/cli.js.map +1 -0
- package/dist/types/core.cjs +14 -0
- package/dist/types/core.cjs.map +1 -0
- package/dist/types/core.d.cts +380 -0
- package/dist/types/core.d.cts.map +1 -0
- package/dist/types/core.d.ts +380 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/types/core.js +13 -0
- package/dist/types/core.js.map +1 -0
- package/dist/types/index.cjs +27 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +11 -0
- package/dist/types/index.d.cts.map +1 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +11 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/interfaces.cjs +10 -0
- package/dist/types/interfaces.cjs.map +1 -0
- package/dist/types/interfaces.d.cts +381 -0
- package/dist/types/interfaces.d.cts.map +1 -0
- package/dist/types/interfaces.d.ts +381 -0
- package/dist/types/interfaces.d.ts.map +1 -0
- package/dist/types/interfaces.js +9 -0
- package/dist/types/interfaces.js.map +1 -0
- package/dist/types/utility.cjs +92 -0
- package/dist/types/utility.cjs.map +1 -0
- package/dist/types/utility.d.cts +330 -0
- package/dist/types/utility.d.cts.map +1 -0
- package/dist/types/utility.d.ts +330 -0
- package/dist/types/utility.d.ts.map +1 -0
- package/dist/types/utility.js +78 -0
- package/dist/types/utility.js.map +1 -0
- package/package.json +211 -0
- package/src/bootstrap.ts +35 -0
- package/src/cli/commands/history.ts +569 -0
- package/src/cli/commands/init.ts +658 -0
- package/src/cli/commands/run.ts +346 -0
- package/src/cli/index.ts +642 -0
- package/src/config/manager.ts +387 -0
- package/src/config/schema.ts +188 -0
- package/src/constants.ts +21 -0
- package/src/core/benchmark-schema.ts +185 -0
- package/src/core/engine.ts +888 -0
- package/src/core/engines/accurate-engine.ts +408 -0
- package/src/core/engines/index.ts +16 -0
- package/src/core/engines/tinybench-engine.ts +335 -0
- package/src/core/error-manager.ts +372 -0
- package/src/core/loader.ts +324 -0
- package/src/core/stats-utils.ts +135 -0
- package/src/index.ts +46 -0
- package/src/progress/manager.ts +415 -0
- package/src/reporters/csv.ts +368 -0
- package/src/reporters/human.ts +707 -0
- package/src/reporters/index.ts +10 -0
- package/src/reporters/json.ts +302 -0
- package/src/reporters/registry.ts +349 -0
- package/src/reporters/simple.ts +459 -0
- package/src/storage/history.ts +600 -0
- package/src/types/cli.ts +312 -0
- package/src/types/core.ts +414 -0
- package/src/types/index.ts +18 -0
- package/src/types/interfaces.ts +451 -0
- package/src/types/utility.ts +446 -0
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModestBench Init Command
|
|
3
|
+
*
|
|
4
|
+
* Initialize a new benchmark project with configuration files, directory
|
|
5
|
+
* structure, and optional example benchmark files.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
access,
|
|
10
|
+
appendFile,
|
|
11
|
+
mkdir,
|
|
12
|
+
readFile,
|
|
13
|
+
writeFile,
|
|
14
|
+
} from 'node:fs/promises';
|
|
15
|
+
import { join, resolve } from 'node:path';
|
|
16
|
+
import { createInterface } from 'node:readline';
|
|
17
|
+
|
|
18
|
+
import type { CliContext } from '../index.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Init command options interface
|
|
22
|
+
*/
|
|
23
|
+
interface InitOptions {
|
|
24
|
+
configType: 'js' | 'json' | 'ts' | 'yaml';
|
|
25
|
+
cwd: string;
|
|
26
|
+
examples: boolean;
|
|
27
|
+
force?: boolean | undefined;
|
|
28
|
+
quiet?: boolean | undefined;
|
|
29
|
+
type: 'advanced' | 'basic' | 'library';
|
|
30
|
+
verbose?: boolean | undefined;
|
|
31
|
+
yes?: boolean | undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Project templates for different initialization types
|
|
36
|
+
*/
|
|
37
|
+
const PROJECT_TEMPLATES = {
|
|
38
|
+
advanced: {
|
|
39
|
+
configOptions: {
|
|
40
|
+
iterations: 1000,
|
|
41
|
+
outputDir: './benchmark-results',
|
|
42
|
+
pattern: 'benchmarks/**/*.bench.{js,ts}',
|
|
43
|
+
reporters: ['human', 'json'],
|
|
44
|
+
time: 10000,
|
|
45
|
+
warmup: 50,
|
|
46
|
+
},
|
|
47
|
+
description: 'Feature-rich setup with multiple reporters and configuration',
|
|
48
|
+
directories: ['benchmarks', 'benchmark-results'],
|
|
49
|
+
name: 'Advanced Project',
|
|
50
|
+
},
|
|
51
|
+
basic: {
|
|
52
|
+
configOptions: {
|
|
53
|
+
iterations: 100,
|
|
54
|
+
pattern: 'benchmarks/**/*.bench.{js,ts}',
|
|
55
|
+
reporters: ['human'],
|
|
56
|
+
time: 5000,
|
|
57
|
+
},
|
|
58
|
+
description: 'Simple benchmark setup for small projects',
|
|
59
|
+
directories: ['benchmarks'],
|
|
60
|
+
name: 'Basic Project',
|
|
61
|
+
},
|
|
62
|
+
library: {
|
|
63
|
+
configOptions: {
|
|
64
|
+
bail: false,
|
|
65
|
+
iterations: 5000,
|
|
66
|
+
outputDir: './benchmark-results',
|
|
67
|
+
pattern: 'benchmarks/**/*.bench.{js,ts}',
|
|
68
|
+
reporters: ['human', 'json'],
|
|
69
|
+
time: 15000,
|
|
70
|
+
warmup: 100,
|
|
71
|
+
},
|
|
72
|
+
description: 'Optimized for library performance testing',
|
|
73
|
+
directories: ['benchmarks', 'benchmarks/suites', 'benchmark-results'],
|
|
74
|
+
name: 'Library Project',
|
|
75
|
+
},
|
|
76
|
+
} as const;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Example benchmark files
|
|
80
|
+
*/
|
|
81
|
+
const EXAMPLE_BENCHMARKS = {
|
|
82
|
+
arrayMethods: {
|
|
83
|
+
content: `/**
|
|
84
|
+
* Array Methods Performance Benchmark
|
|
85
|
+
*
|
|
86
|
+
* Compares performance of different array iteration methods.
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
export default {
|
|
90
|
+
name: 'Array Methods',
|
|
91
|
+
|
|
92
|
+
setup() {
|
|
93
|
+
// Setup data for benchmarks
|
|
94
|
+
this.smallArray = Array.from({ length: 100 }, (_, i) => i);
|
|
95
|
+
this.largeArray = Array.from({ length: 10000 }, (_, i) => i);
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
benchmarks: {
|
|
99
|
+
'for loop (small array)': {
|
|
100
|
+
fn() {
|
|
101
|
+
let sum = 0;
|
|
102
|
+
for (let i = 0; i < this.smallArray.length; i++) {
|
|
103
|
+
sum += this.smallArray[i];
|
|
104
|
+
}
|
|
105
|
+
return sum;
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
'forEach (small array)': {
|
|
110
|
+
fn() {
|
|
111
|
+
let sum = 0;
|
|
112
|
+
this.smallArray.forEach(n => sum += n);
|
|
113
|
+
return sum;
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
'reduce (small array)': {
|
|
118
|
+
fn() {
|
|
119
|
+
return this.smallArray.reduce((sum, n) => sum + n, 0);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
'for loop (large array)': {
|
|
124
|
+
fn() {
|
|
125
|
+
let sum = 0;
|
|
126
|
+
for (let i = 0; i < this.largeArray.length; i++) {
|
|
127
|
+
sum += this.largeArray[i];
|
|
128
|
+
}
|
|
129
|
+
return sum;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
'forEach (large array)': {
|
|
134
|
+
fn() {
|
|
135
|
+
let sum = 0;
|
|
136
|
+
this.largeArray.forEach(n => sum += n);
|
|
137
|
+
return sum;
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
'reduce (large array)': {
|
|
142
|
+
fn() {
|
|
143
|
+
return this.largeArray.reduce((sum, n) => sum + n, 0);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
`,
|
|
149
|
+
filename: 'array-methods.bench.js',
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
example: {
|
|
153
|
+
content: `/**
|
|
154
|
+
* Example Benchmark File
|
|
155
|
+
*
|
|
156
|
+
* This is a simple example demonstrating basic benchmarking setup.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
export default {
|
|
160
|
+
name: 'Example Benchmarks',
|
|
161
|
+
|
|
162
|
+
benchmarks: {
|
|
163
|
+
'simple addition': {
|
|
164
|
+
fn() {
|
|
165
|
+
return 1 + 1;
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
'array creation': {
|
|
170
|
+
fn() {
|
|
171
|
+
return Array.from({ length: 100 }, (_, i) => i);
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
'string manipulation': {
|
|
176
|
+
fn() {
|
|
177
|
+
return 'Hello, World!'.toUpperCase();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
`,
|
|
183
|
+
filename: 'example.bench.js',
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
stringOperations: {
|
|
187
|
+
content: `/**
|
|
188
|
+
* String Operations Performance Benchmark
|
|
189
|
+
*
|
|
190
|
+
* Tests various string manipulation techniques.
|
|
191
|
+
*/
|
|
192
|
+
|
|
193
|
+
export default {
|
|
194
|
+
name: 'String Operations',
|
|
195
|
+
|
|
196
|
+
setup() {
|
|
197
|
+
this.baseString = 'Hello, World!';
|
|
198
|
+
this.longString = 'Lorem ipsum '.repeat(1000);
|
|
199
|
+
this.template = 'Hello, {name}!';
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
benchmarks: {
|
|
203
|
+
'string concatenation': {
|
|
204
|
+
fn() {
|
|
205
|
+
return this.baseString + ' How are you?';
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
'template literals': {
|
|
210
|
+
fn() {
|
|
211
|
+
return \`\${this.baseString} How are you?\`;
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
'string replace': {
|
|
216
|
+
fn() {
|
|
217
|
+
return this.template.replace('{name}', 'ModestBench');
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
'string includes': {
|
|
222
|
+
fn() {
|
|
223
|
+
return this.longString.includes('ipsum');
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
'regex test': {
|
|
228
|
+
fn() {
|
|
229
|
+
return /ipsum/.test(this.longString);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
`,
|
|
235
|
+
filename: 'string-operations.bench.js',
|
|
236
|
+
},
|
|
237
|
+
} as const;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Prompt user for confirmation with Y/n default to Yes
|
|
241
|
+
*/
|
|
242
|
+
const promptUser = async (question: string): Promise<boolean> => {
|
|
243
|
+
const rl = createInterface({
|
|
244
|
+
input: process.stdin,
|
|
245
|
+
output: process.stdout,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return new Promise((resolve) => {
|
|
249
|
+
rl.question(question, (answer) => {
|
|
250
|
+
rl.close();
|
|
251
|
+
const normalized = answer.trim().toLowerCase();
|
|
252
|
+
// Default to Yes if empty or starts with 'y'
|
|
253
|
+
resolve(normalized === '' || normalized === 'y' || normalized === 'yes');
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Handle init command
|
|
260
|
+
*/
|
|
261
|
+
export const handleInitCommand = async (
|
|
262
|
+
context: CliContext,
|
|
263
|
+
options: InitOptions,
|
|
264
|
+
): Promise<number> => {
|
|
265
|
+
try {
|
|
266
|
+
const template = PROJECT_TEMPLATES[options.type];
|
|
267
|
+
|
|
268
|
+
if (!options.quiet) {
|
|
269
|
+
console.log(`Initializing ${template.name}...`);
|
|
270
|
+
console.log(template.description);
|
|
271
|
+
console.log();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Check if project already exists
|
|
275
|
+
if (!options.force) {
|
|
276
|
+
const hasConflicts = await checkForConflicts(options);
|
|
277
|
+
if (hasConflicts) {
|
|
278
|
+
console.error('Project files already exist. Use --force to overwrite.');
|
|
279
|
+
return 1; // Already initialized
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Create directory structure
|
|
284
|
+
await createDirectories(template.directories, options);
|
|
285
|
+
|
|
286
|
+
// Create configuration file
|
|
287
|
+
await createConfigFile(template.configOptions, options);
|
|
288
|
+
|
|
289
|
+
// Create example benchmarks if requested
|
|
290
|
+
if (options.examples) {
|
|
291
|
+
await createExampleBenchmarks(options);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Create additional files
|
|
295
|
+
await createAdditionalFiles(options);
|
|
296
|
+
|
|
297
|
+
if (!options.quiet) {
|
|
298
|
+
console.log('✅ Project initialized successfully!');
|
|
299
|
+
console.log();
|
|
300
|
+
console.log('Next steps:');
|
|
301
|
+
if (options.examples) {
|
|
302
|
+
console.log(' 1. Run example benchmarks: modestbench run');
|
|
303
|
+
} else {
|
|
304
|
+
console.log(
|
|
305
|
+
' 1. Create your first benchmark file in the benchmarks/ directory',
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
console.log(' 2. Customize configuration in your config file');
|
|
309
|
+
console.log(' 3. Add your own benchmark suites');
|
|
310
|
+
console.log();
|
|
311
|
+
console.log(
|
|
312
|
+
'Documentation: https://github.com/your-org/modestbench#readme',
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return 0;
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.error(
|
|
319
|
+
'Init command failed:',
|
|
320
|
+
error instanceof Error ? error.message : String(error),
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
if (options.verbose && error instanceof Error && error.stack) {
|
|
324
|
+
console.error('Stack trace:');
|
|
325
|
+
console.error(error.stack);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return 5; // Runtime error
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Check for existing files that would conflict
|
|
334
|
+
*/
|
|
335
|
+
const checkForConflicts = async (options: InitOptions): Promise<boolean> => {
|
|
336
|
+
const filesToCheck = [
|
|
337
|
+
'modestbench.config.' + options.configType,
|
|
338
|
+
'benchmarks',
|
|
339
|
+
];
|
|
340
|
+
|
|
341
|
+
for (const file of filesToCheck) {
|
|
342
|
+
try {
|
|
343
|
+
await access(resolve(options.cwd, file));
|
|
344
|
+
return true; // File exists, conflict detected
|
|
345
|
+
} catch {
|
|
346
|
+
// File doesn't exist, no conflict
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return false;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Handle .gitignore file creation or modification
|
|
355
|
+
*/
|
|
356
|
+
const handleGitignore = async (options: InitOptions): Promise<void> => {
|
|
357
|
+
const gitignorePath = resolve(options.cwd, '.gitignore');
|
|
358
|
+
const modestbenchEntry = '.modestbench/';
|
|
359
|
+
|
|
360
|
+
// Default .gitignore content for new files
|
|
361
|
+
const defaultGitignoreContent = `# ModestBench
|
|
362
|
+
benchmark-results/
|
|
363
|
+
.modestbench/
|
|
364
|
+
|
|
365
|
+
# Dependencies
|
|
366
|
+
node_modules/
|
|
367
|
+
|
|
368
|
+
# Environment
|
|
369
|
+
.env
|
|
370
|
+
.env.local
|
|
371
|
+
|
|
372
|
+
# Logs
|
|
373
|
+
*.log
|
|
374
|
+
npm-debug.log*
|
|
375
|
+
yarn-debug.log*
|
|
376
|
+
yarn-error.log*
|
|
377
|
+
|
|
378
|
+
# OS
|
|
379
|
+
.DS_Store
|
|
380
|
+
Thumbs.db
|
|
381
|
+
`;
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
// Check if .gitignore exists
|
|
385
|
+
let gitignoreExists = false;
|
|
386
|
+
try {
|
|
387
|
+
await access(gitignorePath);
|
|
388
|
+
gitignoreExists = true;
|
|
389
|
+
} catch {
|
|
390
|
+
// File doesn't exist
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (!gitignoreExists) {
|
|
394
|
+
// Create new .gitignore with full content
|
|
395
|
+
await writeFile(gitignorePath, defaultGitignoreContent, 'utf8');
|
|
396
|
+
if (options.verbose) {
|
|
397
|
+
console.log(' ✓ .gitignore');
|
|
398
|
+
}
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// File exists, check if .modestbench/ is already present
|
|
403
|
+
const existingContent = await readFile(gitignorePath, 'utf8');
|
|
404
|
+
|
|
405
|
+
// Check if .modestbench/ is already in the file
|
|
406
|
+
const hasModestbenchEntry = existingContent
|
|
407
|
+
.split('\n')
|
|
408
|
+
.some((line) => line.trim() === modestbenchEntry);
|
|
409
|
+
|
|
410
|
+
if (hasModestbenchEntry) {
|
|
411
|
+
// Already has the entry, nothing to do
|
|
412
|
+
if (options.verbose) {
|
|
413
|
+
console.log(' ✓ .gitignore (already contains .modestbench/)');
|
|
414
|
+
}
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Determine if we should prompt or auto-add
|
|
419
|
+
let shouldAdd = false;
|
|
420
|
+
|
|
421
|
+
if (options.yes || options.quiet) {
|
|
422
|
+
// Auto-accept in non-interactive mode
|
|
423
|
+
shouldAdd = true;
|
|
424
|
+
} else {
|
|
425
|
+
// Prompt the user
|
|
426
|
+
console.log();
|
|
427
|
+
console.log(
|
|
428
|
+
'The .modestbench/ directory stores benchmark history and should typically',
|
|
429
|
+
);
|
|
430
|
+
console.log('not be committed to version control.');
|
|
431
|
+
console.log();
|
|
432
|
+
|
|
433
|
+
shouldAdd = await promptUser(
|
|
434
|
+
'Would you like to add .modestbench/ to .gitignore? (Y/n) ',
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (shouldAdd) {
|
|
439
|
+
// Append .modestbench/ to existing .gitignore
|
|
440
|
+
let contentToAppend = '';
|
|
441
|
+
|
|
442
|
+
// Ensure file ends with newline
|
|
443
|
+
if (!existingContent.endsWith('\n')) {
|
|
444
|
+
contentToAppend += '\n';
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Add a blank line if the file doesn't end with one
|
|
448
|
+
if (!existingContent.endsWith('\n\n') && existingContent.trim() !== '') {
|
|
449
|
+
contentToAppend += '\n';
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Add comment and entry
|
|
453
|
+
contentToAppend += '# ModestBench history\n';
|
|
454
|
+
contentToAppend += modestbenchEntry + '\n';
|
|
455
|
+
|
|
456
|
+
await appendFile(gitignorePath, contentToAppend, 'utf8');
|
|
457
|
+
|
|
458
|
+
if (options.verbose || !options.quiet) {
|
|
459
|
+
console.log(' ✓ Added .modestbench/ to .gitignore');
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
if (options.verbose) {
|
|
463
|
+
console.log(' ⊘ Skipped adding .modestbench/ to .gitignore');
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
} catch (error) {
|
|
467
|
+
// Non-critical, just warn
|
|
468
|
+
console.warn(
|
|
469
|
+
'Warning: Could not create/modify .gitignore file:',
|
|
470
|
+
error instanceof Error ? error.message : String(error),
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Create additional project files
|
|
477
|
+
*/
|
|
478
|
+
const createAdditionalFiles = async (options: InitOptions): Promise<void> => {
|
|
479
|
+
if (!options.quiet) {
|
|
480
|
+
console.log('Creating additional files...');
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Handle .gitignore
|
|
484
|
+
await handleGitignore(options);
|
|
485
|
+
|
|
486
|
+
// Create README.md
|
|
487
|
+
const readmeContent = `# Benchmark Project
|
|
488
|
+
|
|
489
|
+
This project uses [ModestBench](https://github.com/your-org/modestbench) for performance testing.
|
|
490
|
+
|
|
491
|
+
## Getting Started
|
|
492
|
+
|
|
493
|
+
Run all benchmarks:
|
|
494
|
+
\`\`\`bash
|
|
495
|
+
modestbench run
|
|
496
|
+
\`\`\`
|
|
497
|
+
|
|
498
|
+
Run specific benchmarks:
|
|
499
|
+
\`\`\`bash
|
|
500
|
+
modestbench run "benchmarks/array-*.bench.js"
|
|
501
|
+
\`\`\`
|
|
502
|
+
|
|
503
|
+
View benchmark history:
|
|
504
|
+
\`\`\`bash
|
|
505
|
+
modestbench history list
|
|
506
|
+
\`\`\`
|
|
507
|
+
|
|
508
|
+
## Configuration
|
|
509
|
+
|
|
510
|
+
See \`modestbench.config.*\` for benchmark configuration options.
|
|
511
|
+
|
|
512
|
+
## Writing Benchmarks
|
|
513
|
+
|
|
514
|
+
Create new benchmark files in the \`benchmarks/\` directory. See the examples for the expected format.
|
|
515
|
+
`;
|
|
516
|
+
|
|
517
|
+
try {
|
|
518
|
+
const readmePath = resolve(options.cwd, 'README.md');
|
|
519
|
+
await writeFile(readmePath, readmeContent, 'utf8');
|
|
520
|
+
if (options.verbose) {
|
|
521
|
+
console.log(' ✓ README.md');
|
|
522
|
+
}
|
|
523
|
+
} catch {
|
|
524
|
+
// Non-critical, just warn
|
|
525
|
+
console.warn('Warning: Could not create README.md file');
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Create configuration file
|
|
531
|
+
*/
|
|
532
|
+
const createConfigFile = async (
|
|
533
|
+
configOptions: any,
|
|
534
|
+
options: InitOptions,
|
|
535
|
+
): Promise<void> => {
|
|
536
|
+
const filename = `modestbench.config.${options.configType}`;
|
|
537
|
+
const filePath = resolve(options.cwd, filename);
|
|
538
|
+
|
|
539
|
+
if (!options.quiet) {
|
|
540
|
+
console.log(`Creating configuration file: ${filename}`);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
let content: string;
|
|
544
|
+
|
|
545
|
+
switch (options.configType) {
|
|
546
|
+
case 'js':
|
|
547
|
+
content = `export default ${JSON.stringify(configOptions, null, 2)};\n`;
|
|
548
|
+
break;
|
|
549
|
+
|
|
550
|
+
case 'json':
|
|
551
|
+
content = JSON.stringify(configOptions, null, 2);
|
|
552
|
+
break;
|
|
553
|
+
|
|
554
|
+
case 'ts':
|
|
555
|
+
content = `import type { ModestBenchConfig } from 'modestbench';
|
|
556
|
+
|
|
557
|
+
const config: ModestBenchConfig = ${JSON.stringify(configOptions, null, 2)};
|
|
558
|
+
|
|
559
|
+
export default config;
|
|
560
|
+
`;
|
|
561
|
+
break;
|
|
562
|
+
|
|
563
|
+
case 'yaml':
|
|
564
|
+
// Simple YAML generation (could use a proper YAML library)
|
|
565
|
+
content = generateSimpleYaml(configOptions);
|
|
566
|
+
break;
|
|
567
|
+
|
|
568
|
+
default:
|
|
569
|
+
throw new Error(`Unsupported config format: ${options.configType}`);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
try {
|
|
573
|
+
await writeFile(filePath, content, 'utf8');
|
|
574
|
+
if (options.verbose) {
|
|
575
|
+
console.log(` ✓ ${filename}`);
|
|
576
|
+
}
|
|
577
|
+
} catch (error) {
|
|
578
|
+
throw new Error(
|
|
579
|
+
`Failed to create config file: ${error instanceof Error ? error.message : String(error)}`,
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Create directory structure
|
|
586
|
+
*/
|
|
587
|
+
const createDirectories = async (
|
|
588
|
+
directories: readonly string[],
|
|
589
|
+
options: InitOptions,
|
|
590
|
+
): Promise<void> => {
|
|
591
|
+
if (!options.quiet) {
|
|
592
|
+
console.log('Creating directories...');
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
for (const dir of directories) {
|
|
596
|
+
const dirPath = resolve(options.cwd, dir);
|
|
597
|
+
try {
|
|
598
|
+
await mkdir(dirPath, { recursive: true });
|
|
599
|
+
if (options.verbose) {
|
|
600
|
+
console.log(` ✓ ${dir}/`);
|
|
601
|
+
}
|
|
602
|
+
} catch (error) {
|
|
603
|
+
throw new Error(
|
|
604
|
+
`Failed to create directory ${dir}: ${error instanceof Error ? error.message : String(error)}`,
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Create example benchmark files
|
|
612
|
+
*/
|
|
613
|
+
const createExampleBenchmarks = async (options: InitOptions): Promise<void> => {
|
|
614
|
+
if (!options.quiet) {
|
|
615
|
+
console.log('Creating example benchmarks...');
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const benchmarksDir = resolve(options.cwd, 'benchmarks');
|
|
619
|
+
|
|
620
|
+
for (const [name, example] of Object.entries(EXAMPLE_BENCHMARKS)) {
|
|
621
|
+
const filePath = join(benchmarksDir, example.filename);
|
|
622
|
+
|
|
623
|
+
try {
|
|
624
|
+
await writeFile(filePath, example.content, 'utf8');
|
|
625
|
+
if (options.verbose) {
|
|
626
|
+
console.log(` ✓ ${example.filename}`);
|
|
627
|
+
}
|
|
628
|
+
} catch (error) {
|
|
629
|
+
throw new Error(
|
|
630
|
+
`Failed to create example ${name}: ${error instanceof Error ? error.message : String(error)}`,
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Generate simple YAML from object (basic implementation)
|
|
638
|
+
*/
|
|
639
|
+
const generateSimpleYaml = (obj: any, indent = 0): string => {
|
|
640
|
+
const spaces = ' '.repeat(indent);
|
|
641
|
+
let yaml = '';
|
|
642
|
+
|
|
643
|
+
for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
|
|
644
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
645
|
+
yaml += `${spaces}${key}:\n${generateSimpleYaml(value, indent + 2)}`;
|
|
646
|
+
} else if (Array.isArray(value)) {
|
|
647
|
+
yaml += `${spaces}${key}:\n`;
|
|
648
|
+
for (const item of value) {
|
|
649
|
+
yaml += `${spaces} - ${item}\n`;
|
|
650
|
+
}
|
|
651
|
+
} else {
|
|
652
|
+
const formattedValue = typeof value === 'string' ? `"${value}"` : value;
|
|
653
|
+
yaml += `${spaces}${key}: ${formattedValue}\n`;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return yaml;
|
|
658
|
+
};
|