flexi-bench 0.0.0-alpha.4 → 0.2.0

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/dist/benchmark.js CHANGED
@@ -1,42 +1,40 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.Benchmark = void 0;
13
4
  const benchmark_console_reporter_1 = require("./reporters/benchmark-console-reporter");
14
5
  const variation_1 = require("./variation");
6
+ const api_types_1 = require("./api-types");
15
7
  const child_process_1 = require("child_process");
16
8
  const results_1 = require("./results");
17
9
  const performance_observer_1 = require("./performance-observer");
18
10
  const shared_api_1 = require("./shared-api");
19
11
  class Benchmark extends shared_api_1.BenchmarkBase {
12
+ name;
13
+ variations = [];
14
+ iterations;
15
+ timeout;
16
+ reporter;
17
+ watcher;
18
+ errorStrategy = api_types_1.ErrorStrategy.Continue;
20
19
  constructor(name, options) {
21
20
  super();
22
21
  this.name = name;
23
- this.variations = [];
24
- if (options === null || options === void 0 ? void 0 : options.action) {
22
+ if (options?.action) {
25
23
  this.action = options.action;
26
24
  }
27
- if (options === null || options === void 0 ? void 0 : options.setup) {
25
+ if (options?.setup) {
28
26
  this.setupMethods.push(options.setup);
29
27
  }
30
- if (options === null || options === void 0 ? void 0 : options.teardown) {
28
+ if (options?.teardown) {
31
29
  this.teardownMethods.push(options.teardown);
32
30
  }
33
- if (options === null || options === void 0 ? void 0 : options.iterations) {
31
+ if (options?.iterations) {
34
32
  this.iterations = options.iterations;
35
33
  }
36
- if (options === null || options === void 0 ? void 0 : options.timeout) {
34
+ if (options?.timeout) {
37
35
  this.timeout = options.timeout;
38
36
  }
39
- this.reporter = (options === null || options === void 0 ? void 0 : options.reporter) || new benchmark_console_reporter_1.BenchmarkConsoleReporter();
37
+ this.reporter = options?.reporter || new benchmark_console_reporter_1.BenchmarkConsoleReporter();
40
38
  }
41
39
  withVariation(nameOrVariation, builder) {
42
40
  if (nameOrVariation instanceof variation_1.Variation) {
@@ -83,117 +81,129 @@ class Benchmark extends shared_api_1.BenchmarkBase {
83
81
  this.watcher = new performance_observer_1.PerformanceWatcher(options);
84
82
  return this;
85
83
  }
86
- run() {
87
- return __awaiter(this, void 0, void 0, function* () {
88
- var _a, _b;
89
- this.validate();
90
- let results = [];
91
- if (this.variations.length === 0) {
92
- this.variations.push(new variation_1.Variation('default'));
84
+ async run() {
85
+ this.validate();
86
+ let results = [];
87
+ if (this.variations.length === 0) {
88
+ this.variations.push(new variation_1.Variation('default'));
89
+ }
90
+ const totalIterations = this.iterations
91
+ ? this.variations.length * this.iterations
92
+ : undefined;
93
+ const startTime = performance.now();
94
+ let totalCompletedIterations = 0;
95
+ for (let variationIndex = 0; variationIndex < this.variations.length; variationIndex++) {
96
+ const variation = this.variations[variationIndex];
97
+ const variationStartTime = performance.now();
98
+ const iterationResults = [];
99
+ // SETUP
100
+ const oldEnv = { ...process.env };
101
+ process.env = {
102
+ ...process.env,
103
+ ...variation.environment,
104
+ };
105
+ for (const setup of this.setupMethods) {
106
+ await setup(variation);
93
107
  }
94
- const totalIterations = this.iterations
95
- ? this.variations.length * this.iterations
96
- : undefined;
97
- const startTime = performance.now();
98
- let totalCompletedIterations = 0;
99
- for (let variationIndex = 0; variationIndex < this.variations.length; variationIndex++) {
100
- const variation = this.variations[variationIndex];
101
- const timings = [];
102
- // SETUP
103
- const oldEnv = Object.assign({}, process.env);
104
- process.env = Object.assign(Object.assign({}, process.env), variation.environment);
105
- for (const setup of this.setupMethods) {
106
- yield setup(variation);
107
- }
108
- for (const setup of variation.setupMethods) {
109
- yield setup(variation);
110
- }
111
- // ACT
112
- const benchmarkThis = this;
113
- yield new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
114
- let completedIterations = 0;
115
- let timeout = benchmarkThis.timeout
116
- ? setTimeout(() => {
117
- running = false;
118
- if ((benchmarkThis === null || benchmarkThis === void 0 ? void 0 : benchmarkThis.iterations) &&
119
- completedIterations < benchmarkThis.iterations) {
120
- reject('Timeout');
121
- }
122
- resolve();
123
- }, benchmarkThis.timeout)
124
- : null;
125
- let running = true;
126
- while (running) {
127
- for (const setup of this.setupEachMethods.concat(variation.setupEachMethods)) {
128
- yield setup(variation);
129
- }
130
- const a = performance.now();
131
- if (variation.action) {
132
- yield runAction(variation.action, variation);
133
- }
134
- else if (this.action) {
135
- yield runAction(this.action, variation);
136
- }
137
- const b = performance.now();
138
- for (const teardown of this.teardownEachMethods.concat(variation.teardownEachMethods)) {
139
- yield teardown(variation);
140
- }
141
- const duration = b - a;
142
- completedIterations++;
143
- totalCompletedIterations++;
144
- timings.push(duration);
145
- if (this.reporter.progress &&
146
- totalIterations &&
147
- benchmarkThis.iterations) {
148
- this.reporter.progress(variation.name, totalCompletedIterations / totalIterations, {
149
- timeElapsed: performance.now() - startTime,
150
- totalIterations,
151
- completedIterations: totalCompletedIterations,
152
- timeout: benchmarkThis.timeout,
153
- });
108
+ for (const setup of variation.setupMethods) {
109
+ await setup(variation);
110
+ }
111
+ // ACT
112
+ const benchmarkThis = this;
113
+ await new Promise(async (resolve, reject) => {
114
+ let completedIterations = 0;
115
+ let timeout = benchmarkThis.timeout
116
+ ? setTimeout(() => {
117
+ running = false;
118
+ if (benchmarkThis?.iterations &&
119
+ completedIterations < benchmarkThis.iterations) {
120
+ reject('Timeout');
154
121
  }
155
- if ((benchmarkThis === null || benchmarkThis === void 0 ? void 0 : benchmarkThis.iterations) &&
156
- completedIterations >= benchmarkThis.iterations) {
157
- running = false;
158
- if (timeout) {
159
- clearTimeout(timeout);
160
- }
161
- resolve();
122
+ resolve();
123
+ }, benchmarkThis.timeout)
124
+ : null;
125
+ let running = true;
126
+ while (running) {
127
+ for (const setup of this.setupEachMethods.concat(variation.setupEachMethods)) {
128
+ await setup(variation);
129
+ }
130
+ const result = await runAndMeasureAction(benchmarkThis, variation);
131
+ const errorStrategy = variation.errorStrategy ?? benchmarkThis.errorStrategy;
132
+ if (errorStrategy === api_types_1.ErrorStrategy.Abort &&
133
+ result instanceof Error) {
134
+ reject(result);
135
+ return;
136
+ }
137
+ for (const teardown of this.teardownEachMethods.concat(variation.teardownEachMethods)) {
138
+ await teardown(variation);
139
+ }
140
+ completedIterations++;
141
+ totalCompletedIterations++;
142
+ iterationResults.push(result);
143
+ if (this.reporter.progress &&
144
+ totalIterations &&
145
+ benchmarkThis.iterations) {
146
+ this.reporter.progress(variation.name, totalCompletedIterations / totalIterations, {
147
+ timeElapsed: performance.now() - startTime,
148
+ totalIterations,
149
+ completedIterations: totalCompletedIterations,
150
+ timeout: benchmarkThis.timeout,
151
+ });
152
+ }
153
+ if (benchmarkThis?.iterations &&
154
+ completedIterations >= benchmarkThis.iterations) {
155
+ running = false;
156
+ if (timeout) {
157
+ clearTimeout(timeout);
162
158
  }
159
+ resolve();
163
160
  }
164
- }));
165
- if (this.reporter.progress && !totalIterations) {
166
- this.reporter.progress(variation.name, variationIndex / this.variations.length, {
167
- timeElapsed: performance.now() - startTime,
168
- timeout: this.timeout,
169
- completedIterations: totalCompletedIterations,
170
- });
171
161
  }
172
- // TEARDOWN
173
- for (const teardown of variation.teardownMethods) {
174
- yield teardown(variation);
175
- }
176
- for (const teardown of this.teardownMethods) {
177
- yield teardown(variation);
178
- }
179
- process.env = oldEnv;
180
- // REPORT
181
- const result = (0, results_1.calculateResultsFromDurations)(variation.name, timings);
182
- // PerformanceObserver needs a chance to flush
183
- if (this.watcher) {
184
- const measures = yield this.watcher.getMeasures();
185
- for (const key in measures) {
186
- (_a = result.subresults) !== null && _a !== void 0 ? _a : (result.subresults = []);
187
- result.subresults.push((0, results_1.calculateResultsFromDurations)(key, measures[key]));
188
- }
189
- this.watcher.clearMeasures();
162
+ });
163
+ if (this.reporter.progress && !totalIterations) {
164
+ this.reporter.progress(variation.name, variationIndex / this.variations.length, {
165
+ timeElapsed: performance.now() - startTime,
166
+ timeout: this.timeout,
167
+ completedIterations: totalCompletedIterations,
168
+ });
169
+ }
170
+ // TEARDOWN
171
+ for (const teardown of variation.teardownMethods) {
172
+ await teardown(variation);
173
+ }
174
+ for (const teardown of this.teardownMethods) {
175
+ await teardown(variation);
176
+ }
177
+ process.env = oldEnv;
178
+ // REPORT
179
+ const variationEndTime = performance.now();
180
+ const result = (0, results_1.calculateResultsFromDurations)(variation.name, iterationResults, {
181
+ iterations: iterationResults.length,
182
+ totalDuration: variationEndTime - variationStartTime,
183
+ benchmarkName: this.name,
184
+ variationName: variation.name,
185
+ });
186
+ // PerformanceObserver needs a chance to flush
187
+ if (this.watcher) {
188
+ const measures = await this.watcher.getMeasures();
189
+ for (const key in measures) {
190
+ result.subresults ??= [];
191
+ result.subresults.push((0, results_1.calculateResultsFromDurations)(key, measures[key], {
192
+ benchmarkName: this.name,
193
+ variationName: variation.name,
194
+ }));
190
195
  }
191
- results.push(result);
196
+ this.watcher.clearMeasures();
192
197
  }
193
- (_b = this.watcher) === null || _b === void 0 ? void 0 : _b.disconnect();
194
- this.reporter.report(this, results);
195
- return results;
196
- });
198
+ results.push(result);
199
+ }
200
+ this.watcher?.disconnect();
201
+ this.reporter.report(this, results);
202
+ if (this.errorStrategy === api_types_1.ErrorStrategy.DelayedThrow &&
203
+ results.some((r) => r.failed)) {
204
+ throw new api_types_1.AggregateBenchmarkError(results);
205
+ }
206
+ return results;
197
207
  }
198
208
  validate() {
199
209
  if (!this.timeout && !this.iterations) {
@@ -224,26 +234,35 @@ class Benchmark extends shared_api_1.BenchmarkBase {
224
234
  }
225
235
  }
226
236
  exports.Benchmark = Benchmark;
227
- function runAction(action, variation) {
228
- return __awaiter(this, void 0, void 0, function* () {
229
- if (typeof action === 'string') {
230
- return new Promise((resolve, reject) => {
231
- const child = (0, child_process_1.spawn)(action, variation.cliArgs, {
232
- shell: true,
233
- windowsHide: true,
234
- });
235
- child.on('exit', (code) => {
236
- if (code === 0) {
237
- resolve();
238
- }
239
- else {
240
- reject(`Action failed with code ${code}`);
241
- }
242
- });
237
+ async function runAndMeasureAction(benchmark, variation) {
238
+ try {
239
+ const a = performance.now();
240
+ await runAction((variation.action ?? benchmark.action), variation);
241
+ const b = performance.now();
242
+ return b - a;
243
+ }
244
+ catch (e) {
245
+ return e instanceof Error ? e : new Error('Unknown error during action.');
246
+ }
247
+ }
248
+ async function runAction(action, variation) {
249
+ if (typeof action === 'string') {
250
+ return new Promise((resolve, reject) => {
251
+ const child = (0, child_process_1.spawn)(action, variation.cliArgs, {
252
+ shell: true,
253
+ windowsHide: true,
243
254
  });
244
- }
245
- else {
246
- return action(variation);
247
- }
248
- });
255
+ child.on('exit', (code) => {
256
+ if (code === 0) {
257
+ resolve();
258
+ }
259
+ else {
260
+ reject(`Action failed with code ${code}`);
261
+ }
262
+ });
263
+ });
264
+ }
265
+ else {
266
+ return action(variation);
267
+ }
249
268
  }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  export * from './reporters/benchmark-console-reporter';
2
2
  export * from './reporters/markdown-benchmark-reporter';
3
+ export * from './reporters/markdown-suite-reporter';
3
4
  export * from './reporters/suite-console-reporter';
5
+ export * from './reporters/noop-reporter';
6
+ export * from './reporters/composite-reporter';
7
+ export * from './reporters/json-suite-reporter';
4
8
  export * from './api-types';
5
9
  export * from './benchmark';
6
10
  export * from './variation';
7
11
  export * from './suite';
8
12
  export * from './performance-observer';
9
13
  export * from './benchmark-runner';
14
+ export * from './results';
package/dist/index.js CHANGED
@@ -16,10 +16,15 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./reporters/benchmark-console-reporter"), exports);
18
18
  __exportStar(require("./reporters/markdown-benchmark-reporter"), exports);
19
+ __exportStar(require("./reporters/markdown-suite-reporter"), exports);
19
20
  __exportStar(require("./reporters/suite-console-reporter"), exports);
21
+ __exportStar(require("./reporters/noop-reporter"), exports);
22
+ __exportStar(require("./reporters/composite-reporter"), exports);
23
+ __exportStar(require("./reporters/json-suite-reporter"), exports);
20
24
  __exportStar(require("./api-types"), exports);
21
25
  __exportStar(require("./benchmark"), exports);
22
26
  __exportStar(require("./variation"), exports);
23
27
  __exportStar(require("./suite"), exports);
24
28
  __exportStar(require("./performance-observer"), exports);
25
29
  __exportStar(require("./benchmark-runner"), exports);
30
+ __exportStar(require("./results"), exports);
@@ -1,27 +1,17 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.PerformanceWatcher = void 0;
13
4
  const node_perf_hooks_1 = require("node:perf_hooks");
14
5
  class PerformanceWatcher {
6
+ observer;
7
+ measures = {};
15
8
  constructor(opts = {}) {
16
- this.measures = {};
17
9
  this.observer = new node_perf_hooks_1.PerformanceObserver((list) => {
18
- var _a;
19
- var _b;
20
10
  for (const entry of list.getEntries()) {
21
11
  if (entry.entryType === 'measure' &&
22
12
  (!opts.measureFilter || opts.measureFilter(entry))) {
23
- const label = normalizeLabel(entry.name, opts === null || opts === void 0 ? void 0 : opts.label);
24
- (_a = (_b = this.measures)[label]) !== null && _a !== void 0 ? _a : (_b[label] = []);
13
+ const label = normalizeLabel(entry.name, opts?.label);
14
+ this.measures[label] ??= [];
25
15
  this.measures[label].push(entry.duration);
26
16
  }
27
17
  }
@@ -33,10 +23,8 @@ class PerformanceWatcher {
33
23
  // not fire until the next tick so we need that to happen before the measures are
34
24
  // retrieved. Since this method is async, it must be awaited, which actually gives
35
25
  // the observer time to collect the measures.
36
- getMeasures() {
37
- return __awaiter(this, void 0, void 0, function* () {
38
- return this.measures;
39
- });
26
+ async getMeasures() {
27
+ return this.measures;
40
28
  }
41
29
  clearMeasures() {
42
30
  for (const key in this.measures) {
@@ -44,8 +32,7 @@ class PerformanceWatcher {
44
32
  }
45
33
  }
46
34
  disconnect() {
47
- var _a;
48
- (_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
35
+ this.observer?.disconnect();
49
36
  delete this.observer;
50
37
  }
51
38
  }
@@ -3,8 +3,11 @@ import { Benchmark } from '../benchmark';
3
3
  import { SingleBar } from 'cli-progress';
4
4
  import { Result } from '../results';
5
5
  export declare class BenchmarkConsoleReporter implements BenchmarkReporter {
6
+ private noColor;
6
7
  bar: SingleBar;
7
- constructor();
8
+ constructor(opts?: {
9
+ noColor?: boolean;
10
+ });
8
11
  progress(name: string, percent: number, context: ProgressContext): void;
9
12
  report(benchmark: Benchmark, results: Result[]): void;
10
13
  }
@@ -2,27 +2,40 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BenchmarkConsoleReporter = void 0;
4
4
  const cli_progress_1 = require("cli-progress");
5
+ function getNoColorOption(explicitNoColor) {
6
+ if (explicitNoColor !== undefined) {
7
+ return explicitNoColor;
8
+ }
9
+ return process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== '';
10
+ }
5
11
  class BenchmarkConsoleReporter {
6
- constructor() {
12
+ noColor;
13
+ bar;
14
+ constructor(opts) {
15
+ this.noColor = getNoColorOption(opts?.noColor);
7
16
  this.bar = new cli_progress_1.SingleBar({
8
- format: 'Running variation {label}: {bar} {percentage}% | {value}/{total} - ETA: {eta}s',
9
- barCompleteChar: '\u2588',
10
- barIncompleteChar: '\u2591',
17
+ format: this.noColor
18
+ ? 'Running variation {label}: [{bar}] {percentage}% | {value}/{total} - ETA: {eta}s'
19
+ : 'Running variation {label}: {bar} {percentage}% | {value}/{total} - ETA: {eta}s',
20
+ barCompleteChar: this.noColor ? '#' : '\u2588',
21
+ barIncompleteChar: this.noColor ? '-' : '\u2591',
11
22
  hideCursor: true,
12
23
  stopOnComplete: true,
13
24
  clearOnComplete: true,
14
25
  });
15
26
  }
16
27
  progress(name, percent, context) {
17
- var _a;
18
28
  if (!this.bar.isActive) {
19
- this.bar.start((_a = context.totalIterations) !== null && _a !== void 0 ? _a : 100, 0);
29
+ this.bar.start(context.totalIterations ?? 100, 0);
20
30
  }
21
31
  this.bar.update(context.completedIterations, { label: name });
22
32
  }
23
33
  report(benchmark, results) {
34
+ const tableEntries = results.map(({ raw, ...rest }) => ({
35
+ ...rest,
36
+ }));
24
37
  console.log(`Benchmark: ${benchmark.name}`);
25
- console.table(results);
38
+ console.table(tableEntries);
26
39
  }
27
40
  }
28
41
  exports.BenchmarkConsoleReporter = BenchmarkConsoleReporter;
@@ -0,0 +1,21 @@
1
+ import { SuiteReporter } from '../api-types';
2
+ import { Result } from '../results';
3
+ /**
4
+ * A reporter that chains multiple suite reporters together.
5
+ * Useful when you want to output results to multiple destinations
6
+ * (e.g., console and file) simultaneously.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * suite.withReporter(new CompositeReporter([
11
+ * new SuiteConsoleReporter(),
12
+ * new MarkdownSuiteReporter({ outputFile: 'results.md' }),
13
+ * new JsonSuiteReporter({ outputFile: 'results.json' }),
14
+ * ]))
15
+ * ```
16
+ */
17
+ export declare class CompositeReporter implements SuiteReporter {
18
+ private reporters;
19
+ constructor(reporters: SuiteReporter[]);
20
+ report: (results: Record<string, Result[]>) => void;
21
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CompositeReporter = void 0;
4
+ /**
5
+ * A reporter that chains multiple suite reporters together.
6
+ * Useful when you want to output results to multiple destinations
7
+ * (e.g., console and file) simultaneously.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * suite.withReporter(new CompositeReporter([
12
+ * new SuiteConsoleReporter(),
13
+ * new MarkdownSuiteReporter({ outputFile: 'results.md' }),
14
+ * new JsonSuiteReporter({ outputFile: 'results.json' }),
15
+ * ]))
16
+ * ```
17
+ */
18
+ class CompositeReporter {
19
+ reporters;
20
+ constructor(reporters) {
21
+ this.reporters = reporters;
22
+ }
23
+ report = (results) => {
24
+ for (const reporter of this.reporters) {
25
+ reporter.report(results);
26
+ }
27
+ };
28
+ }
29
+ exports.CompositeReporter = CompositeReporter;
@@ -0,0 +1,26 @@
1
+ import { SuiteReporter } from '../api-types';
2
+ import { Result } from '../results';
3
+ export interface JsonSuiteReporterOptions {
4
+ outputFile: string;
5
+ pretty?: boolean;
6
+ includeMetadata?: boolean;
7
+ }
8
+ /**
9
+ * A reporter that outputs benchmark results as JSON.
10
+ * Useful for CI/CD integration and programmatic analysis.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * suite.withReporter(new JsonSuiteReporter({
15
+ * outputFile: 'results.json',
16
+ * pretty: true,
17
+ * }))
18
+ * ```
19
+ */
20
+ export declare class JsonSuiteReporter implements SuiteReporter {
21
+ private outputFile;
22
+ private pretty;
23
+ private includeMetadata;
24
+ constructor(opts: JsonSuiteReporterOptions);
25
+ report: (results: Record<string, Result[]>) => void;
26
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonSuiteReporter = void 0;
4
+ const fs_1 = require("fs");
5
+ /**
6
+ * A reporter that outputs benchmark results as JSON.
7
+ * Useful for CI/CD integration and programmatic analysis.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * suite.withReporter(new JsonSuiteReporter({
12
+ * outputFile: 'results.json',
13
+ * pretty: true,
14
+ * }))
15
+ * ```
16
+ */
17
+ class JsonSuiteReporter {
18
+ outputFile;
19
+ pretty;
20
+ includeMetadata;
21
+ constructor(opts) {
22
+ this.outputFile = opts.outputFile;
23
+ this.pretty = opts.pretty ?? false;
24
+ this.includeMetadata = opts.includeMetadata ?? true;
25
+ }
26
+ report = (results) => {
27
+ const output = this.includeMetadata
28
+ ? {
29
+ timestamp: new Date().toISOString(),
30
+ platform: process.platform,
31
+ nodeVersion: process.version,
32
+ results,
33
+ }
34
+ : results;
35
+ (0, fs_1.writeFileSync)(this.outputFile, JSON.stringify(output, null, this.pretty ? 2 : undefined));
36
+ };
37
+ }
38
+ exports.JsonSuiteReporter = JsonSuiteReporter;
@@ -3,10 +3,22 @@ import { Benchmark } from '../benchmark';
3
3
  import { Result } from '../results';
4
4
  export declare class MarkdownBenchmarkReporter implements BenchmarkReporter {
5
5
  outputFile: string;
6
- fields: Array<keyof Omit<Result, 'subresults' | 'label'>>;
6
+ fields: Array<keyof Omit<Result, 'subresults' | 'label' | 'raw'>>;
7
+ append: boolean;
8
+ private isFirstReport;
9
+ private accumulatedResults;
7
10
  constructor(opts: {
8
11
  outputFile: string;
9
12
  fields?: MarkdownBenchmarkReporter['fields'];
13
+ append?: boolean;
10
14
  });
15
+ private formatDuration;
11
16
  report: (benchmark: Benchmark, results: Result[]) => void;
17
+ private generateBenchmarkContent;
18
+ private generateResultsTable;
19
+ private generateComparison;
20
+ /**
21
+ * Clears the output file. Useful when re-running benchmarks.
22
+ */
23
+ clear(): void;
12
24
  }