Skip to content

Commit

Permalink
refactor(betterer 🔧): use Promises.withResolvers instead of custom defer
Browse files Browse the repository at this point in the history
  • Loading branch information
phenomnomnominal committed Sep 15, 2024
1 parent c763729 commit b202aea
Show file tree
Hide file tree
Showing 11 changed files with 23 additions and 128 deletions.
8 changes: 8 additions & 0 deletions packages/betterer/src/reporters/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class BettererReporterΩ implements BettererReporter {
}

async contextStart(context: BettererContext, lifecycle: Promise<BettererContextSummary>): Promise<void> {
defaultLifecycleCatch(lifecycle);
await Promise.all(this._reporters.map((r) => r.contextStart?.(context, lifecycle)));
}

Expand All @@ -26,6 +27,7 @@ export class BettererReporterΩ implements BettererReporter {
}

async suiteStart(suite: BettererSuite, lifecycle: Promise<BettererSuiteSummary>): Promise<void> {
defaultLifecycleCatch(lifecycle);
await Promise.all(this._reporters.map((r) => r.suiteStart?.(suite, lifecycle)));
}

Expand All @@ -38,6 +40,7 @@ export class BettererReporterΩ implements BettererReporter {
}

async runStart(run: BettererRun, lifecycle: Promise<BettererRunSummary>): Promise<void> {
defaultLifecycleCatch(lifecycle);
await Promise.all(this._reporters.map((r) => r.runStart?.(run, lifecycle)));
}

Expand All @@ -49,3 +52,8 @@ export class BettererReporterΩ implements BettererReporter {
await Promise.all(this._reporters.map((r) => r.runError?.(run, error)));
}
}

function defaultLifecycleCatch(lifecycle: Promise<unknown>): void {
// Just in case no-one handles this error in a reporter:
lifecycle.catch(() => void 0);
}
3 changes: 1 addition & 2 deletions packages/betterer/src/run/run-obsolete.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { BettererResult } from '../results/index.js';
import type { BettererRun, BettererRunSummary } from './types.js';

import { defer } from '../utils.js';
import { BettererRunSummaryΩ } from './run-summary.js';

export class BettererRunObsoleteΩ implements BettererRun {
Expand All @@ -12,7 +11,7 @@ export class BettererRunObsoleteΩ implements BettererRun {
public readonly isOnly = false;
public readonly isRemoved: boolean;
public readonly isSkipped = false;
public readonly lifecycle = defer<BettererRunSummary>();
public readonly lifecycle = Promise.withResolvers<BettererRunSummary>();

constructor(
public readonly name: string,
Expand Down
3 changes: 1 addition & 2 deletions packages/betterer/src/run/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import { getTimeΔ } from '@betterer/time';

import { getGlobals } from '../globals.js';
import { BettererResultΩ } from '../results/index.js';
import { defer } from '../utils.js';
import { BettererRunSummaryΩ } from './run-summary.js';

export class BettererRunΩ implements BettererRun {
public readonly lifecycle = defer<BettererRunSummary>();
public readonly lifecycle = Promise.withResolvers<BettererRunSummary>();
public readonly isNew: boolean;
public readonly isObsolete = false;
public readonly isOnly: boolean;
Expand Down
4 changes: 2 additions & 2 deletions packages/betterer/src/runner/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import { BettererError } from '@betterer/errors';

import { BettererContextΩ } from '../context/index.js';
import { createGlobals, destroyGlobals, getGlobals } from '../globals.js';
import { defer, normalisedPath } from '../utils.js';
import { normalisedPath } from '../utils.js';
import { createWatcher, WATCHER_EVENTS } from './watcher.js';

const DEBOUNCE_TIME = 200;

export class BettererRunnerΩ implements BettererRunner {
public config: BettererConfig;
public readonly lifecycle = defer<BettererContextSummary>();
public readonly lifecycle = Promise.withResolvers<BettererContextSummary>();

private _reporterContextStart: Promise<void>;
private _isRunOnce = false;
Expand Down
3 changes: 1 addition & 2 deletions packages/betterer/src/suite/suite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ import { invariantΔ } from '@betterer/errors';
import { getGlobals } from '../globals.js';
import { BettererResultΩ } from '../results/index.js';
import { BettererRunΩ, BettererRunObsoleteΩ } from '../run/index.js';
import { defer } from '../utils.js';
import { BettererSuiteSummaryΩ } from './suite-summary.js';

const NEGATIVE_FILTER_TOKEN = '!';

export class BettererSuiteΩ implements BettererSuite {
public readonly lifecycle = defer<BettererSuiteSummary>();
public readonly lifecycle = Promise.withResolvers<BettererSuiteSummary>();

private constructor(
public filePaths: BettererFilePaths,
Expand Down
25 changes: 0 additions & 25 deletions packages/betterer/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import assert from 'node:assert';
import path from 'node:path';

export function isBoolean(value: unknown): value is boolean {
Expand Down Expand Up @@ -29,30 +28,6 @@ export function normalisedPath(filePath: string): string {
return filePath.split(path.sep).join(path.posix.sep);
}

type Resolve<T> = (value: T) => void;
type Reject = (error: Error) => void;

/** @knipignore */
export interface Defer<T> {
promise: Promise<T>;
resolve: Resolve<T>;
reject: Reject;
}

export function defer<T>(): Defer<T> {
let resolve: Resolve<T> | null = null;
let reject: Reject | null = null;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
// Catch here to avoid global unhandledRejection:
promise.catch(() => void 0);
assert(resolve);
assert(reject);
return { promise, resolve, reject };
}

const NEW_LINE = '\n';
const NEW_LINES = /\r\n|\r|\n/g;

Expand Down
3 changes: 3 additions & 0 deletions packages/fixture/src/polyfills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@

// `structuredClone` is needed by ESLint and doesn't exist in node.js v16:
import 'core-js/actual/structured-clone.js';

// `Promise.withResolvers` is only a proposal but it's super useful:
import 'core-js/proposals/promise-with-resolvers.js';
24 changes: 1 addition & 23 deletions test/watch/watch-debounced.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import type { BettererSuiteSummary } from '@betterer/betterer';

import { describe, expect, it } from 'vitest';

import assert from 'node:assert';

import { createFixture } from '../fixture.js';

describe('betterer.watch', () => {
Expand All @@ -28,7 +26,7 @@ export default {
const filePath = resolve('./src/file.ts');
const { cwd } = paths;

const suiteSummaryDefer = defer<BettererSuiteSummary>();
const suiteSummaryDefer = Promise.withResolvers<BettererSuiteSummary>();

const runner = await watch({
configPaths,
Expand Down Expand Up @@ -58,23 +56,3 @@ export default {
await cleanup();
});
});

type Resolve<T> = (value: T) => void;
type Reject = (error: Error) => void;
interface Defer<T> {
promise: Promise<T>;
resolve: Resolve<T>;
reject: Reject;
}

function defer<T>(): Defer<T> {
let resolve: Resolve<T> | null = null;
let reject: Reject | null = null;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
assert(resolve);
assert(reject);
return { promise, resolve, reject };
}
24 changes: 1 addition & 23 deletions test/watch/watch-ignored.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import type { BettererSuiteSummary } from '@betterer/betterer';

import { describe, expect, it } from 'vitest';

import assert from 'node:assert';

import { createFixture } from '../fixture.js';

describe('betterer.watch', () => {
Expand Down Expand Up @@ -35,7 +33,7 @@ ignored.ts
const nestedPath = resolve('./src/nested/ignored.ts');
const { cwd } = paths;

const suiteSummaryDefer = defer<BettererSuiteSummary>();
const suiteSummaryDefer = Promise.withResolvers<BettererSuiteSummary>();

const runner = await betterer.watch({
configPaths,
Expand Down Expand Up @@ -68,23 +66,3 @@ ignored.ts
await cleanup();
});
});

type Resolve<T> = (value: T) => void;
type Reject = (error: Error) => void;
interface Defer<T> {
promise: Promise<T>;
resolve: Resolve<T>;
reject: Reject;
}

function defer<T>(): Defer<T> {
let resolve: Resolve<T> | null = null;
let reject: Reject | null = null;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
assert(resolve);
assert(reject);
return { promise, resolve, reject };
}
26 changes: 2 additions & 24 deletions test/watch/watch-quit.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import assert from 'node:assert';

import { describe, expect, it } from 'vitest';

import { createFixture } from '../fixture.js';
Expand Down Expand Up @@ -27,8 +25,8 @@ export default {

const { cwd } = paths;

const suiteEndDefer = defer();
const contextEndDefer = defer();
const suiteEndDefer = Promise.withResolvers<void>();
const contextEndDefer = Promise.withResolvers<void>();

await betterer.watch({
configPaths,
Expand Down Expand Up @@ -62,23 +60,3 @@ export default {
await cleanup();
});
});

type Resolve<T> = (value: T) => void;
type Reject = (error: Error) => void;
interface Defer<T = void> {
promise: Promise<T>;
resolve: Resolve<T>;
reject: Reject;
}

function defer<T = void>(): Defer<T> {
let resolve: Resolve<T> | null = null;
let reject: Reject | null = null;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
assert(resolve);
assert(reject);
return { promise, resolve, reject };
}
28 changes: 3 additions & 25 deletions test/watch/watch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import type { BettererSuiteSummary } from '@betterer/betterer';

import { describe, expect, it } from 'vitest';

import assert from 'node:assert';

import { createFixture } from '../fixture.js';

describe('betterer.watch', () => {
Expand Down Expand Up @@ -32,9 +30,9 @@ export default {
await betterer({ configPaths, resultsPath, cwd, workers: false });

const suiteSummaryDefers = [
defer<BettererSuiteSummary>(),
defer<BettererSuiteSummary>(),
defer<BettererSuiteSummary>()
Promise.withResolvers<BettererSuiteSummary>(),
Promise.withResolvers<BettererSuiteSummary>(),
Promise.withResolvers<BettererSuiteSummary>()
];
const [worse, same, better] = suiteSummaryDefers;

Expand Down Expand Up @@ -83,23 +81,3 @@ export default {
await cleanup();
});
});

type Resolve<T> = (value: T) => void;
type Reject = (error: Error) => void;
interface Defer<T> {
promise: Promise<T>;
resolve: Resolve<T>;
reject: Reject;
}

function defer<T>(): Defer<T> {
let resolve: Resolve<T> | null = null;
let reject: Reject | null = null;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
assert(resolve);
assert(reject);
return { promise, resolve, reject };
}

0 comments on commit b202aea

Please sign in to comment.