flexi-bench 0.0.0-alpha.2 → 0.0.0-alpha.4

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.
@@ -1,33 +1,33 @@
1
1
  import { Variation } from './variation';
2
- import { Reporter } from './api-types';
3
- import { ActionMethod } from './api-types';
4
- import { TeardownMethod } from './api-types';
5
- import { SetupMethod } from './api-types';
6
- export declare class Benchmark {
2
+ import { TeardownMethod, SetupMethod, Action, BenchmarkReporter } from './api-types';
3
+ import { Result } from './results';
4
+ import { PerformanceObserverOptions } from './performance-observer';
5
+ import { BenchmarkBase } from './shared-api';
6
+ export declare class Benchmark extends BenchmarkBase {
7
7
  name: string;
8
- private setupMethods;
9
- private teardownMethods;
10
- private action?;
11
8
  variations: Variation[];
12
9
  private iterations?;
13
10
  private timeout?;
14
11
  private reporter;
12
+ private watcher?;
15
13
  constructor(name: string, options?: {
16
14
  setup?: SetupMethod;
17
15
  teardown?: TeardownMethod;
18
- action?: ActionMethod;
16
+ action?: Action;
19
17
  iterations?: number;
20
18
  timeout?: number;
21
- reporter?: Reporter;
19
+ reporter?: BenchmarkReporter;
22
20
  });
23
21
  withVariation(name: string, builder: (variation: Variation) => Variation): this;
22
+ withVariation(variation: Variation): this;
24
23
  withVariations(variations: Variation[]): this;
25
- withSetup(setup: () => void): this;
26
- withTeardown(teardown: () => void): this;
27
- withAction(action: () => void): this;
24
+ withSetup(setup: SetupMethod): this;
25
+ withTeardown(teardown: TeardownMethod): this;
26
+ withAction(action: Action): this;
28
27
  withIterations(iterations: number): this;
29
28
  withTimeout(timeout: number): this;
30
- withReporter(reporter: Reporter): this;
31
- run(): Promise<void>;
29
+ withReporter(reporter: BenchmarkReporter): this;
30
+ withPerformanceObserver(options?: PerformanceObserverOptions): this;
31
+ run(): Promise<Result[]>;
32
32
  private validate;
33
33
  }
package/dist/benchmark.js CHANGED
@@ -10,13 +10,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Benchmark = void 0;
13
- const console_reporter_1 = require("./console-reporter");
13
+ const benchmark_console_reporter_1 = require("./reporters/benchmark-console-reporter");
14
14
  const variation_1 = require("./variation");
15
- class Benchmark {
15
+ const child_process_1 = require("child_process");
16
+ const results_1 = require("./results");
17
+ const performance_observer_1 = require("./performance-observer");
18
+ const shared_api_1 = require("./shared-api");
19
+ class Benchmark extends shared_api_1.BenchmarkBase {
16
20
  constructor(name, options) {
21
+ super();
17
22
  this.name = name;
18
- this.setupMethods = [];
19
- this.teardownMethods = [];
20
23
  this.variations = [];
21
24
  if (options === null || options === void 0 ? void 0 : options.action) {
22
25
  this.action = options.action;
@@ -33,10 +36,19 @@ class Benchmark {
33
36
  if (options === null || options === void 0 ? void 0 : options.timeout) {
34
37
  this.timeout = options.timeout;
35
38
  }
36
- this.reporter = (options === null || options === void 0 ? void 0 : options.reporter) || new console_reporter_1.ConsoleReporter();
39
+ this.reporter = (options === null || options === void 0 ? void 0 : options.reporter) || new benchmark_console_reporter_1.BenchmarkConsoleReporter();
37
40
  }
38
- withVariation(name, builder) {
39
- this.variations.push(builder(new variation_1.Variation(name)));
41
+ withVariation(nameOrVariation, builder) {
42
+ if (nameOrVariation instanceof variation_1.Variation) {
43
+ this.variations.push(nameOrVariation);
44
+ }
45
+ else if (builder) {
46
+ this.variations.push(builder(new variation_1.Variation(nameOrVariation)));
47
+ return this;
48
+ }
49
+ else {
50
+ throw new Error('`withVariation` must be called with either a Variation or a name and a builder function.');
51
+ }
40
52
  return this;
41
53
  }
42
54
  withVariations(variations) {
@@ -67,8 +79,13 @@ class Benchmark {
67
79
  this.reporter = reporter;
68
80
  return this;
69
81
  }
82
+ withPerformanceObserver(options) {
83
+ this.watcher = new performance_observer_1.PerformanceWatcher(options);
84
+ return this;
85
+ }
70
86
  run() {
71
87
  return __awaiter(this, void 0, void 0, function* () {
88
+ var _a, _b;
72
89
  this.validate();
73
90
  let results = [];
74
91
  if (this.variations.length === 0) {
@@ -107,14 +124,20 @@ class Benchmark {
107
124
  : null;
108
125
  let running = true;
109
126
  while (running) {
127
+ for (const setup of this.setupEachMethods.concat(variation.setupEachMethods)) {
128
+ yield setup(variation);
129
+ }
110
130
  const a = performance.now();
111
131
  if (variation.action) {
112
- yield variation.action(variation);
132
+ yield runAction(variation.action, variation);
113
133
  }
114
134
  else if (this.action) {
115
- yield this.action(variation);
135
+ yield runAction(this.action, variation);
116
136
  }
117
137
  const b = performance.now();
138
+ for (const teardown of this.teardownEachMethods.concat(variation.teardownEachMethods)) {
139
+ yield teardown(variation);
140
+ }
118
141
  const duration = b - a;
119
142
  completedIterations++;
120
143
  totalCompletedIterations++;
@@ -155,24 +178,38 @@ class Benchmark {
155
178
  }
156
179
  process.env = oldEnv;
157
180
  // REPORT
158
- const min = Math.min(...timings);
159
- const max = Math.max(...timings);
160
- const sum = timings.reduce((a, b) => a + b, 0);
161
- const average = sum / timings.length;
162
- const sortedTimings = [...timings].sort((a, b) => a - b);
163
- const p95 = sortedTimings[Math.floor(sortedTimings.length * 0.95)];
164
- results.push({
165
- label: variation.name,
166
- min,
167
- max,
168
- average,
169
- p95,
170
- });
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();
190
+ }
191
+ results.push(result);
171
192
  }
193
+ (_b = this.watcher) === null || _b === void 0 ? void 0 : _b.disconnect();
172
194
  this.reporter.report(this, results);
195
+ return results;
173
196
  });
174
197
  }
175
198
  validate() {
199
+ if (!this.timeout && !this.iterations) {
200
+ this.iterations = 5;
201
+ }
202
+ const missingActions = [];
203
+ for (const variation of this.variations) {
204
+ let action = variation.action || this.action;
205
+ if (!action) {
206
+ missingActions.push(variation.name);
207
+ continue;
208
+ }
209
+ if (typeof action !== 'string' && variation.cliArgs.length > 0) {
210
+ throw new Error(`Cannot use CLI args with a non-command action for ${this.name}:${variation.name}`);
211
+ }
212
+ }
176
213
  if (!this.action) {
177
214
  const missingActions = this.variations.filter((v) => !v.action);
178
215
  if (missingActions.length > 0) {
@@ -187,3 +224,26 @@ class Benchmark {
187
224
  }
188
225
  }
189
226
  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
+ });
243
+ });
244
+ }
245
+ else {
246
+ return action(variation);
247
+ }
248
+ });
249
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,9 @@
1
+ export * from './reporters/benchmark-console-reporter';
2
+ export * from './reporters/markdown-benchmark-reporter';
3
+ export * from './reporters/suite-console-reporter';
1
4
  export * from './api-types';
2
5
  export * from './benchmark';
3
6
  export * from './variation';
4
- export * from './console-reporter';
7
+ export * from './suite';
8
+ export * from './performance-observer';
9
+ export * from './benchmark-runner';
package/dist/index.js CHANGED
@@ -14,7 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./reporters/benchmark-console-reporter"), exports);
18
+ __exportStar(require("./reporters/markdown-benchmark-reporter"), exports);
19
+ __exportStar(require("./reporters/suite-console-reporter"), exports);
17
20
  __exportStar(require("./api-types"), exports);
18
21
  __exportStar(require("./benchmark"), exports);
19
22
  __exportStar(require("./variation"), exports);
20
- __exportStar(require("./console-reporter"), exports);
23
+ __exportStar(require("./suite"), exports);
24
+ __exportStar(require("./performance-observer"), exports);
25
+ __exportStar(require("./benchmark-runner"), exports);
@@ -0,0 +1,12 @@
1
+ export declare class PerformanceWatcher {
2
+ private observer?;
3
+ private measures;
4
+ constructor(opts?: PerformanceObserverOptions);
5
+ getMeasures(): Promise<Record<string, number[]>>;
6
+ clearMeasures(): void;
7
+ disconnect(): void;
8
+ }
9
+ export type PerformanceObserverOptions = {
10
+ measureFilter?: (entry: PerformanceEntry) => boolean;
11
+ label?: Record<string, string> | ((label: string) => string);
12
+ };
@@ -0,0 +1,60 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.PerformanceWatcher = void 0;
13
+ const node_perf_hooks_1 = require("node:perf_hooks");
14
+ class PerformanceWatcher {
15
+ constructor(opts = {}) {
16
+ this.measures = {};
17
+ this.observer = new node_perf_hooks_1.PerformanceObserver((list) => {
18
+ var _a;
19
+ var _b;
20
+ for (const entry of list.getEntries()) {
21
+ if (entry.entryType === 'measure' &&
22
+ (!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] = []);
25
+ this.measures[label].push(entry.duration);
26
+ }
27
+ }
28
+ });
29
+ this.observer.observe({ entryTypes: ['measure'] });
30
+ }
31
+ // This method is async to give the observer time to collect the measures...
32
+ // If the action being ran by the benchmark is synchronous, the observer will
33
+ // not fire until the next tick so we need that to happen before the measures are
34
+ // retrieved. Since this method is async, it must be awaited, which actually gives
35
+ // the observer time to collect the measures.
36
+ getMeasures() {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ return this.measures;
39
+ });
40
+ }
41
+ clearMeasures() {
42
+ for (const key in this.measures) {
43
+ delete this.measures[key];
44
+ }
45
+ }
46
+ disconnect() {
47
+ var _a;
48
+ (_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
49
+ delete this.observer;
50
+ }
51
+ }
52
+ exports.PerformanceWatcher = PerformanceWatcher;
53
+ function normalizeLabel(label, transform) {
54
+ if (transform) {
55
+ return typeof transform === 'function'
56
+ ? transform(label)
57
+ : transform[label];
58
+ }
59
+ return label;
60
+ }
@@ -0,0 +1,10 @@
1
+ import { BenchmarkReporter, ProgressContext } from '../api-types';
2
+ import { Benchmark } from '../benchmark';
3
+ import { SingleBar } from 'cli-progress';
4
+ import { Result } from '../results';
5
+ export declare class BenchmarkConsoleReporter implements BenchmarkReporter {
6
+ bar: SingleBar;
7
+ constructor();
8
+ progress(name: string, percent: number, context: ProgressContext): void;
9
+ report(benchmark: Benchmark, results: Result[]): void;
10
+ }
@@ -1,14 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConsoleReporter = void 0;
3
+ exports.BenchmarkConsoleReporter = void 0;
4
4
  const cli_progress_1 = require("cli-progress");
5
- class ConsoleReporter {
5
+ class BenchmarkConsoleReporter {
6
6
  constructor() {
7
7
  this.bar = new cli_progress_1.SingleBar({
8
- format: 'Running: {label}\n{bar} {percentage}% | {value}/{total} - ETA: {eta}s',
8
+ format: 'Running variation {label}: {bar} {percentage}% | {value}/{total} - ETA: {eta}s',
9
9
  barCompleteChar: '\u2588',
10
10
  barIncompleteChar: '\u2591',
11
11
  hideCursor: true,
12
+ stopOnComplete: true,
13
+ clearOnComplete: true,
12
14
  });
13
15
  }
14
16
  progress(name, percent, context) {
@@ -17,15 +19,10 @@ class ConsoleReporter {
17
19
  this.bar.start((_a = context.totalIterations) !== null && _a !== void 0 ? _a : 100, 0);
18
20
  }
19
21
  this.bar.update(context.completedIterations, { label: name });
20
- process.stdout.moveCursor(0, -1);
21
- // console.log(`Progress: ${name} ${Math.round(percent * 10000) / 100}%`);
22
22
  }
23
23
  report(benchmark, results) {
24
- this.bar.stop();
25
- process.stdout.moveCursor(0, -1);
26
- process.stdout.clearScreenDown();
27
24
  console.log(`Benchmark: ${benchmark.name}`);
28
25
  console.table(results);
29
26
  }
30
27
  }
31
- exports.ConsoleReporter = ConsoleReporter;
28
+ exports.BenchmarkConsoleReporter = BenchmarkConsoleReporter;
@@ -0,0 +1,12 @@
1
+ import { BenchmarkReporter } from '../api-types';
2
+ import { Benchmark } from '../benchmark';
3
+ import { Result } from '../results';
4
+ export declare class MarkdownBenchmarkReporter implements BenchmarkReporter {
5
+ outputFile: string;
6
+ fields: Array<keyof Omit<Result, 'subresults' | 'label'>>;
7
+ constructor(opts: {
8
+ outputFile: string;
9
+ fields?: MarkdownBenchmarkReporter['fields'];
10
+ });
11
+ report: (benchmark: Benchmark, results: Result[]) => void;
12
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MarkdownBenchmarkReporter = void 0;
4
+ const fs_1 = require("fs");
5
+ const markdown_factory_1 = require("markdown-factory");
6
+ class MarkdownBenchmarkReporter {
7
+ constructor(opts) {
8
+ var _a;
9
+ this.report = (benchmark, results) => {
10
+ (0, fs_1.writeFileSync)(this.outputFile, (0, markdown_factory_1.h1)(benchmark.name, results.some((r) => !!r.subresults)
11
+ ? (0, markdown_factory_1.lines)(results.map((r) => {
12
+ var _a;
13
+ const entries = [Object.assign(Object.assign({}, r), { label: 'total' })];
14
+ delete entries[0].subresults;
15
+ for (const subresult of (_a = r.subresults) !== null && _a !== void 0 ? _a : []) {
16
+ entries.push(subresult);
17
+ }
18
+ return (0, markdown_factory_1.h2)(r.label, (0, markdown_factory_1.table)(entries, [
19
+ { field: 'label', label: '' },
20
+ ...this.fields,
21
+ ]));
22
+ }))
23
+ : (0, markdown_factory_1.table)(results, [{ field: 'label', label: '' }, ...this.fields])));
24
+ };
25
+ this.outputFile = opts.outputFile;
26
+ this.fields = (_a = opts.fields) !== null && _a !== void 0 ? _a : ['min', 'average', 'p95', 'max'];
27
+ }
28
+ }
29
+ exports.MarkdownBenchmarkReporter = MarkdownBenchmarkReporter;
@@ -0,0 +1,4 @@
1
+ import { BenchmarkReporter, SuiteReporter } from '../api-types';
2
+ export declare class NoopReporter implements BenchmarkReporter, SuiteReporter {
3
+ report: () => void;
4
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoopReporter = void 0;
4
+ class NoopReporter {
5
+ constructor() {
6
+ this.report = () => { };
7
+ }
8
+ }
9
+ exports.NoopReporter = NoopReporter;
@@ -0,0 +1,5 @@
1
+ import { SuiteReporter } from '../api-types';
2
+ import { Result } from '../results';
3
+ export declare class SuiteConsoleReporter implements SuiteReporter {
4
+ report: (results: Record<string, Result[]>) => void;
5
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SuiteConsoleReporter = void 0;
4
+ class SuiteConsoleReporter {
5
+ constructor() {
6
+ this.report = (results) => {
7
+ console.log('Suite Results:');
8
+ for (const [name, result] of Object.entries(results)) {
9
+ console.log(`Benchmark: ${name}`);
10
+ console.table(result);
11
+ }
12
+ };
13
+ }
14
+ }
15
+ exports.SuiteConsoleReporter = SuiteConsoleReporter;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A measurement result.
3
+ */
4
+ export type Result = {
5
+ /**
6
+ * The label of the result. Typically the name of the benchmark or variation.
7
+ */
8
+ label: string;
9
+ /**
10
+ * The minimum duration.
11
+ */
12
+ min: number;
13
+ /**
14
+ * The maximum duration.
15
+ */
16
+ max: number;
17
+ /**
18
+ * The average duration.
19
+ */
20
+ average: number;
21
+ /**
22
+ * The 95th percentile duration.
23
+ */
24
+ p95: number;
25
+ /**
26
+ * The raw durations, in order. Used for custom reporters.
27
+ */
28
+ raw: number[];
29
+ /**
30
+ * Subresults, if any. Typically sourced from performance observer.
31
+ */
32
+ subresults?: Result[];
33
+ };
34
+ export declare function calculateResultsFromDurations(label: string, durations: number[]): Result;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateResultsFromDurations = calculateResultsFromDurations;
4
+ function calculateResultsFromDurations(label, durations) {
5
+ durations.sort((a, b) => a - b);
6
+ return {
7
+ label,
8
+ min: Math.min(...durations),
9
+ max: Math.max(...durations),
10
+ average: durations.reduce((acc, duration) => acc + duration, 0) / durations.length,
11
+ p95: durations[Math.floor(durations.length * 0.95)],
12
+ raw: durations,
13
+ };
14
+ }
@@ -0,0 +1,13 @@
1
+ import { Action, SetupMethod, TeardownMethod } from './api-types';
2
+ export declare class BenchmarkBase {
3
+ setupEachMethods: SetupMethod[];
4
+ setupMethods: SetupMethod[];
5
+ teardownMethods: TeardownMethod[];
6
+ teardownEachMethods: TeardownMethod[];
7
+ action?: Action;
8
+ withSetup(setup: SetupMethod): this;
9
+ withSetupEach(setup: SetupMethod): this;
10
+ withTeardown(teardown: TeardownMethod): this;
11
+ withTeardownEach(teardown: TeardownMethod): this;
12
+ withAction(action: Action): this;
13
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BenchmarkBase = void 0;
4
+ class BenchmarkBase {
5
+ constructor() {
6
+ this.setupEachMethods = [];
7
+ this.setupMethods = [];
8
+ this.teardownMethods = [];
9
+ this.teardownEachMethods = [];
10
+ }
11
+ withSetup(setup) {
12
+ this.setupMethods.push(setup);
13
+ return this;
14
+ }
15
+ withSetupEach(setup) {
16
+ this.setupEachMethods.push(setup);
17
+ return this;
18
+ }
19
+ withTeardown(teardown) {
20
+ this.teardownMethods.push(teardown);
21
+ return this;
22
+ }
23
+ withTeardownEach(teardown) {
24
+ this.teardownEachMethods.push(teardown);
25
+ return this;
26
+ }
27
+ withAction(action) {
28
+ this.action = action;
29
+ return this;
30
+ }
31
+ }
32
+ exports.BenchmarkBase = BenchmarkBase;
@@ -0,0 +1,21 @@
1
+ import { BenchmarkReporter, SuiteReporter } from './api-types';
2
+ import { Benchmark } from './benchmark';
3
+ import { Result } from './results';
4
+ import { Variation } from './variation';
5
+ export interface SuiteOptions {
6
+ reporter?: SuiteReporter;
7
+ }
8
+ export declare class Suite {
9
+ private name;
10
+ private benchmarks;
11
+ private variations;
12
+ private reporter;
13
+ private benchmarkReporter?;
14
+ constructor(name: string, options?: SuiteOptions);
15
+ addBenchmark(benchmark: Benchmark): this;
16
+ withVariation(variation: Variation): this;
17
+ withVariations(variations: Variation[]): this;
18
+ withReporter(reporter: SuiteReporter): this;
19
+ withBenchmarkReporter(reporter: BenchmarkReporter): this;
20
+ run(): Promise<Record<string, Result[]>>;
21
+ }
package/dist/suite.js ADDED
@@ -0,0 +1,58 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.Suite = void 0;
13
+ const suite_console_reporter_1 = require("./reporters/suite-console-reporter");
14
+ class Suite {
15
+ constructor(name, options) {
16
+ this.name = name;
17
+ this.benchmarks = [];
18
+ this.variations = [];
19
+ this.name = name;
20
+ this.benchmarks = [];
21
+ this.reporter = (options === null || options === void 0 ? void 0 : options.reporter) || new suite_console_reporter_1.SuiteConsoleReporter();
22
+ }
23
+ addBenchmark(benchmark) {
24
+ this.benchmarks.push(benchmark);
25
+ return this;
26
+ }
27
+ withVariation(variation) {
28
+ this.variations.push(variation);
29
+ return this;
30
+ }
31
+ withVariations(variations) {
32
+ this.variations.push(...variations);
33
+ return this;
34
+ }
35
+ withReporter(reporter) {
36
+ this.reporter = reporter;
37
+ return this;
38
+ }
39
+ withBenchmarkReporter(reporter) {
40
+ this.benchmarkReporter = reporter;
41
+ return this;
42
+ }
43
+ run() {
44
+ return __awaiter(this, void 0, void 0, function* () {
45
+ const results = {};
46
+ for (const benchmark of this.benchmarks) {
47
+ benchmark.withVariations(this.variations);
48
+ if (this.benchmarkReporter) {
49
+ benchmark.withReporter(this.benchmarkReporter);
50
+ }
51
+ results[benchmark.name] = yield benchmark.run();
52
+ }
53
+ this.reporter.report(results);
54
+ return results;
55
+ });
56
+ }
57
+ }
58
+ exports.Suite = Suite;
@@ -0,0 +1 @@
1
+ export declare function findCombinations<T>(variables: T[][]): T[][];
package/dist/utils.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findCombinations = findCombinations;
4
+ function findCombinations(variables) {
5
+ // Generates all possible combinations of the given variables.
6
+ // e.g. findCombinations([[1, 2], [3, 4]]) => [[1, 3], [1, 4], [2, 3], [2, 4]]
7
+ return variables.reduce((acc, values) => {
8
+ return acc.flatMap((accItem) => {
9
+ return values.map((value) => {
10
+ return [...accItem, value];
11
+ });
12
+ });
13
+ }, [[]]);
14
+ }