Skip to content

Commit f2aa36a

Browse files
build(ci): switch to typescript-eslint strict type checked shared con… (#146)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
1 parent 5e33e43 commit f2aa36a

File tree

10 files changed

+221
-173
lines changed

10 files changed

+221
-173
lines changed

.eslintrc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
"extends": [
88
"eslint:recommended",
99
"airbnb-base",
10-
"plugin:@typescript-eslint/recommended",
11-
"plugin:@typescript-eslint/stylistic"
10+
"plugin:@typescript-eslint/strict-type-checked",
11+
"plugin:@typescript-eslint/stylistic-type-checked"
1212
],
1313
"parser": "@typescript-eslint/parser",
1414
"parserOptions": {

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export interface Options {
107107
signal?: AbortSignal;
108108

109109
/**
110-
* Throw if a task fails (events will not work if true)
110+
* Throw if a task fails (events will not work if true) @default false
111111
*/
112112
throws?: boolean;
113113

@@ -166,7 +166,6 @@ function has been executed.
166166
- `result?: TaskResult`: the result object
167167
- `async run()`: run the current task and write the results in `Task.result` object property
168168
- `async warmup()`: warmup the current task
169-
- `setResult(result: Partial<TaskResult>)`: change the result object values
170169
- `reset()`: reset the task to make the `Task.runs` a zero-value and remove the `Task.result` object property
171170

172171
FnOptions:

src/bench.ts

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable operator-linebreak */
12
import pLimit from 'p-limit';
23
import {
34
defaultMinimumIterations,
@@ -11,7 +12,6 @@ import type {
1112
AddEventListenerOptionsArgument,
1213
BenchEvents,
1314
BenchEventsMap,
14-
EventListener,
1515
Fn,
1616
FnOptions,
1717
Hook,
@@ -49,7 +49,7 @@ export default class Bench extends EventTarget {
4949

5050
signal?: AbortSignal;
5151

52-
throws: boolean;
52+
throws = false;
5353

5454
warmupTime = defaultMinimumWarmupTime;
5555

@@ -74,7 +74,7 @@ export default class Bench extends EventTarget {
7474
this.time = options.time ?? this.time;
7575
this.iterations = options.iterations ?? this.iterations;
7676
this.signal = options.signal;
77-
this.throws = options.throws ?? false;
77+
this.throws = options.throws ?? this.throws;
7878
// eslint-disable-next-line @typescript-eslint/no-empty-function
7979
this.setup = options.setup ?? (() => {});
8080
// eslint-disable-next-line @typescript-eslint/no-empty-function
@@ -91,9 +91,11 @@ export default class Bench extends EventTarget {
9191
}
9292
}
9393

94-
private runTask(task: Task) {
95-
if (this.signal?.aborted) return task;
96-
return task.run();
94+
private async runTask(task: Task): Promise<Task> {
95+
if (this.signal?.aborted) {
96+
return task;
97+
}
98+
return await task.run();
9799
}
98100

99101
/**
@@ -142,7 +144,7 @@ export default class Bench extends EventTarget {
142144
/**
143145
* reset each task and remove its result
144146
*/
145-
reset() {
147+
reset(): void {
146148
this.dispatchEvent(createBenchEvent('reset'));
147149
for (const task of this._tasks.values()) {
148150
task.reset();
@@ -152,7 +154,7 @@ export default class Bench extends EventTarget {
152154
/**
153155
* add a benchmark task to the task map
154156
*/
155-
add(name: string, fn: Fn, opts: FnOptions = {}) {
157+
add(name: string, fn: Fn, opts: FnOptions = {}): this {
156158
const task = new Task(this, name, fn, opts);
157159
this._tasks.set(name, task);
158160
this.dispatchEvent(createBenchEvent('add', task));
@@ -162,7 +164,7 @@ export default class Bench extends EventTarget {
162164
/**
163165
* remove a benchmark task from the task map
164166
*/
165-
remove(name: string) {
167+
remove(name: string): this {
166168
const task = this.getTask(name);
167169
if (task) {
168170
this.dispatchEvent(createBenchEvent('remove', task));
@@ -171,44 +173,56 @@ export default class Bench extends EventTarget {
171173
return this;
172174
}
173175

174-
addEventListener<
175-
K extends BenchEvents,
176-
T extends EventListener = BenchEventsMap[K],
177-
>(type: K, listener: T, options?: AddEventListenerOptionsArgument): void {
176+
addEventListener<K extends BenchEvents>(
177+
type: K,
178+
listener: BenchEventsMap[K],
179+
options?: AddEventListenerOptionsArgument,
180+
): void {
178181
super.addEventListener(type, listener, options);
179182
}
180183

181-
removeEventListener<
182-
K extends BenchEvents,
183-
T extends EventListener = BenchEventsMap[K],
184-
>(type: K, listener: T, options?: RemoveEventListenerOptionsArgument) {
184+
removeEventListener<K extends BenchEvents>(
185+
type: K,
186+
listener: BenchEventsMap[K],
187+
options?: RemoveEventListenerOptionsArgument,
188+
): void {
185189
super.removeEventListener(type, listener, options);
186190
}
187191

188192
/**
189193
* table of the tasks results
190194
*/
191-
table(convert?: (task: Task) => Record<string, string | number> | undefined) {
195+
table(
196+
convert?: (task: Task) => Record<string, string | number> | undefined,
197+
): (Record<string, string | number> | undefined | null)[] {
192198
return this.tasks.map((task) => {
193199
if (task.result) {
194200
if (task.result.error) {
195201
throw task.result.error;
196202
}
197203
return (
204+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
198205
convert?.(task) || {
199206
'Task name': task.name,
207+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
200208
'Throughput average (ops/s)': task.result.error
201209
? 'NaN'
202210
: `${task.result.throughput.mean.toFixed(0)} \xb1 ${task.result.throughput.rme.toFixed(2)}%`,
211+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
203212
'Throughput median (ops/s)': task.result.error
204213
? 'NaN'
205-
: `${task.result.throughput.p50?.toFixed(0)}${Number.parseInt(task.result.throughput.mad!.toFixed(0), 10) > 0 ? ` \xb1 ${task.result.throughput.mad!.toFixed(0)}` : ''}`,
214+
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
215+
`${task.result.throughput.p50!.toFixed(0)}${Number.parseInt(task.result.throughput.mad!.toFixed(0), 10) > 0 ? ` \xb1 ${task.result.throughput.mad!.toFixed(0)}` : ''}`,
216+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
206217
'Latency average (ns)': task.result.error
207218
? 'NaN'
208219
: `${(task.result.latency.mean * 1e6).toFixed(2)} \xb1 ${task.result.latency.rme.toFixed(2)}%`,
220+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
209221
'Latency median (ns)': task.result.error
210222
? 'NaN'
211-
: `${(task.result.latency.p50! * 1e6).toFixed(2)}${Number.parseFloat((task.result.latency.mad! * 1e6).toFixed(2)) > 0 ? ` \xb1 ${(task.result.latency.mad! * 1e6).toFixed(2)}` : ''}`,
223+
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
224+
`${(task.result.latency.p50! * 1e6).toFixed(2)}${Number.parseFloat((task.result.latency.mad! * 1e6).toFixed(2)) > 0 ? ` \xb1 ${(task.result.latency.mad! * 1e6).toFixed(2)}` : ''}`,
225+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
212226
Samples: task.result.error
213227
? 'NaN'
214228
: task.result.latency.samples.length,

src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Student t-distribution two-tailed critical values for 95% confidence level.
33
*/
4-
export const tTable: Record<string, number> = Object.freeze({
4+
export const tTable: Readonly<Record<string, number>> = Object.freeze({
55
1: 12.706204736432102,
66
2: 4.3026527299112765,
77
3: 3.182446305284264,

src/task.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type Bench from './bench';
33
import { createBenchEvent } from './event';
44
import type {
55
AddEventListenerOptionsArgument,
6-
EventListener,
76
Fn,
87
FnOptions,
98
RemoveEventListenerOptionsArgument,
@@ -44,7 +43,7 @@ export default class Task extends EventTarget {
4443
/**
4544
* The result object
4645
*/
47-
result?: TaskResult;
46+
result?: Readonly<TaskResult>;
4847

4948
/**
5049
* Task options
@@ -134,7 +133,7 @@ export default class Task extends EventTarget {
134133
/**
135134
* run the current task and write the results in `Task.result` object property
136135
*/
137-
async run() {
136+
async run(): Promise<Task> {
138137
if (this.result?.error) {
139138
return this;
140139
}
@@ -209,7 +208,7 @@ export default class Task extends EventTarget {
209208
/**
210209
* warmup the current task
211210
*/
212-
async warmup() {
211+
async warmup(): Promise<void> {
213212
if (this.result?.error) {
214213
return;
215214
}
@@ -229,32 +228,36 @@ export default class Task extends EventTarget {
229228
}
230229
}
231230

232-
addEventListener<
233-
K extends TaskEvents,
234-
T extends EventListener = TaskEventsMap[K],
235-
>(type: K, listener: T, options?: AddEventListenerOptionsArgument) {
231+
addEventListener<K extends TaskEvents>(
232+
type: K,
233+
listener: TaskEventsMap[K],
234+
options?: AddEventListenerOptionsArgument,
235+
): void {
236236
super.addEventListener(type, listener, options);
237237
}
238238

239-
removeEventListener<
240-
K extends TaskEvents,
241-
T extends EventListener = TaskEventsMap[K],
242-
>(type: K, listener: T, options?: RemoveEventListenerOptionsArgument) {
239+
removeEventListener<K extends TaskEvents>(
240+
type: K,
241+
listener: TaskEventsMap[K],
242+
options?: RemoveEventListenerOptionsArgument,
243+
): void {
243244
super.removeEventListener(type, listener, options);
244245
}
245246

246247
/**
247248
* change the result object values
248249
*/
249-
setResult(result: Partial<TaskResult>) {
250-
this.result = { ...this.result, ...result } as TaskResult;
251-
Object.freeze(this.result);
250+
private setResult(result: Partial<TaskResult>): void {
251+
this.result = Object.freeze({
252+
...this.result,
253+
...result,
254+
}) as Readonly<TaskResult>;
252255
}
253256

254257
/**
255258
* reset the task to make the `Task.runs` a zero-value and remove the `Task.result` object property
256259
*/
257-
reset() {
260+
reset(): void {
258261
this.dispatchEvent(createBenchEvent('reset', this));
259262
this.runs = 0;
260263
this.result = undefined;

src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type Task from '../src/task';
33
/**
44
* the task function
55
*/
6+
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
67
export type Fn = (...arg: unknown[]) => unknown | Promise<unknown>;
78

89
export interface FnOptions {
@@ -333,7 +334,7 @@ export interface Options {
333334
signal?: AbortSignal;
334335

335336
/**
336-
* Throw if a task fails (events will not work if true)
337+
* Throw if a task fails (events will not work if true) @default false
337338
*/
338339
throws?: boolean;
339340

src/utils.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type AsyncFunctionType<A extends unknown[], R> = (...args: A) => PromiseLike<R>;
2828
* @returns true if the function is an async function
2929
*/
3030
const isAsyncFunction = (
31-
fn: Fn,
31+
fn: Fn | undefined | null,
3232
// eslint-disable-next-line @typescript-eslint/no-empty-function
3333
): fn is AsyncFunctionType<unknown[], unknown> => fn?.constructor === (async () => {}).constructor;
3434

@@ -38,7 +38,7 @@ const isAsyncFunction = (
3838
* @param fn - the function to check
3939
* @returns true if the function is an async function or returns a promise
4040
*/
41-
export const isFnAsyncResource = (fn: Fn): boolean => {
41+
export const isFnAsyncResource = (fn: Fn | undefined | null): boolean => {
4242
if (fn == null) {
4343
return false;
4444
}
@@ -51,7 +51,7 @@ export const isFnAsyncResource = (fn: Fn): boolean => {
5151
if (promiseLike) {
5252
// silence promise rejection
5353
try {
54-
// eslint-disable-next-line @typescript-eslint/no-empty-function
54+
// eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unnecessary-condition
5555
(fnCall as Promise<unknown>).then(() => {})?.catch(() => {});
5656
} catch {
5757
// ignore
@@ -114,7 +114,9 @@ const quantileSorted = (samples: number[], q: number) => {
114114
const baseIndex = Math.floor(base);
115115
if (samples[baseIndex + 1] != null) {
116116
return (
117+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
117118
samples[baseIndex]!
119+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
118120
+ (base - baseIndex) * (samples[baseIndex + 1]! - samples[baseIndex]!)
119121
);
120122
}
@@ -145,6 +147,7 @@ const absoluteDeviation = (
145147
const absoluteDeviations: number[] = [];
146148

147149
for (const sample of samples) {
150+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
148151
absoluteDeviations.push(Math.abs(sample - aggValue!));
149152
}
150153

@@ -165,13 +168,16 @@ export const getStatisticsSorted = (samples: number[]): Statistics => {
165168
const sd = Math.sqrt(vr);
166169
const sem = sd / Math.sqrt(samples.length);
167170
const df = samples.length - 1;
171+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/no-non-null-assertion
168172
const critical = tTable[(Math.round(df) || 1).toString()] || tTable.infinity!;
169173
const moe = sem * critical;
170174
const rme = (moe / mean) * 100;
171175
const p50 = medianSorted(samples);
172176
return {
173177
samples,
178+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
174179
min: samples[0]!,
180+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
175181
max: samples[df]!,
176182
mean,
177183
variance: vr,

0 commit comments

Comments
 (0)