Skip to content

Commit

Permalink
feat: Add "tap" method
Browse files Browse the repository at this point in the history
  • Loading branch information
iainjreid committed Nov 28, 2023
1 parent 58c6dc7 commit f8f91e2
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 22 deletions.
29 changes: 28 additions & 1 deletion lib/compose.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Promise } from '@emphori/promise';
import assert from 'node:assert';
import { describe, it } from 'node:test';
import { Composition, UnaryComposableFunction, UnreachableFunctionWarning, compose, reject, resolve } from './compose.js';
import { Composition, UnaryComposableFunction, UnreachableFunctionWarning, compose, reject, resolve, tap } from './compose.js';

describe('Maintaining safe compositions', () => {
const composition1: Composition<any, [string, string], string, never> =
Expand Down Expand Up @@ -174,6 +174,33 @@ describe('Scoping compositions', () => {
});
});

describe('resolve', () => {
it('should return a resolved Promise', () => {
return resolve('1').then((val): any => {
return assert.equal(val, '1');
});
});
});

describe('reject', () => {
it('should return a rejected Promise', () => {
return reject('1').catch((val): any => {
return assert.equal(val, '1');
});
});
});

describe('tap', () => {
const composition: Composition<void, [string, string], string, never> =
compose(safeTarget).then(tap(() => resolve('GoodbyeWorld')));

it('should not affect the return value of the Promise', () => {
return composition('Hello', 'World').then((val) => {
return assert.equal(val, 'HelloWorld');
});
});
});

/**
* The block below confirms that compositions that will never fail are properly
* typed.
Expand Down
52 changes: 31 additions & 21 deletions lib/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,38 @@ export interface Composition<C1, I1 extends any[], R1, E1> extends ComposableFun
* @param fn - The function to compose
*/
export function compose<C1, I1 extends any[], R1, E1 = unknown>(fn: ComposableFunction<C1, I1, R1, E1>): Composition<C1, I1, R1, E1> {
return Object.setPrototypeOf(function (this: C1, ...args: I1) {
return fn.apply(this, args);
}, compose);
return Object.setPrototypeOf(function (this: C1) {
return fn.apply(this, arguments as any as I1);
}, composable);
}

Object.defineProperty(compose, 'then', {
value: function (this: any, fn: any): any {
const run = this;
return compose(function (...args) {
return run.apply(this, args).then((val: any) => fn.call(this, val));
});
},
});
function composable () {}

Object.defineProperty(compose, 'catch', {
value: function (this: any, fn: any): any {
const run = this;
return compose(function (...args) {
return run.apply(this, args).catch((val: any) => fn.call(this, val));
});
},
});
composable.then = function (this: any, fn: any): any {
const run = this;
return compose(function () {
return run.apply(this, arguments).then((val: any) => fn.call(this, val));
});
}

composable.catch = function (this: any, fn: any): any {
const run = this;
return compose(function () {
return run.apply(this, arguments).catch((val: any) => fn.call(this, val));
});
}

// export const resolve: typeof Promise.resolve = Promise.resolve.bind(Promise);
// export const reject: typeof Promise.reject = Promise.reject.bind(Promise);

export const resolve: typeof Promise.resolve = Promise.resolve.bind(Promise);
export const reject: typeof Promise.reject = Promise.reject.bind(Promise);
// export const resolve = <T>(_: T) => Promise.resolve<T>(_);
// export const reject = <T>(_: T) => Promise.reject<T>(_);

export function resolve<T>(_: T) { return Promise.resolve<T>(_) }
export function reject<T>(_: T) { return Promise.reject<T>(_) }

export function tap<C1, I1, E1>(fn: ComposableFunction<C1, [I1], any, E1>) {
return function (this: C1, val: I1) {
return fn.call(this, val).then(() => val);
}
}

0 comments on commit f8f91e2

Please sign in to comment.