imp(core): extracted IxBuilder from http route builder
ADD
packages/core/src/+internal/fp/IxBuilder.ts
+export class IxBuilder<I, O, A> {
+ readonly _A: A | undefined;
+ readonly _L: O | undefined;
+ readonly _U: I | undefined;
+
+ constructor(readonly spec: A) {}
+
+ run(): A {
+ return this.spec;
+ }
+
+ map<B>(f: (a: A) => B): IxBuilder<I, O, B> {
+ return new IxBuilder(f(this.spec));
+ }
+
+ ichain<Z, B>(f: (a: A) => IxBuilder<O, Z, B>): IxBuilder<I, Z, B> {
+ return new IxBuilder(f(this.spec).run());
+ }
+}
+
+export const map = <I, O, A, B>
+ (fa: IxBuilder<I, O, A>, f: (a: A) => B): IxBuilder<I, O, B> =>
+ fa.map(f);
+
+export const iof = <I, A>
+ (a: A): IxBuilder<I, I, A> =>
+ new IxBuilder(a);
+
+export const ichain = <I, O, Z, A, B>
+ (fa: IxBuilder<I, O, A>, f: (a: A) => IxBuilder<O, Z, B>): IxBuilder<I, Z, B> =>
+ fa.ichain(f);
+
+export const ichainCurry = <I, O, Z, A, B>
+ (f: (a: A) => IxBuilder<O, Z, B>) =>
+ (fa: IxBuilder<I, O, A>): IxBuilder<I, Z, B> =>
+ fa.ichain(f);

MODIFY
packages/core/src/+internal/fp/index.ts
packages/core/src/+internal/fp/index.ts
export * from './compose';
+export * from './IxBuilder';

ADD
packages/core/src/+internal/fp/spec/IxBuilder.spec.ts
+import { iof, ichain, map } from '../IxBuilder';
+
+describe('IxBuilder', () => {
+ test('maps values', () => {
+ expect(iof('a')
+ .map(x => x + 'b')
+ .map(x => x + 'c')
+ .run()).toBe('abc');
+ });
+
+ test('chains builders', () => {
+ expect(iof('a')
+ .ichain(x => iof(x + 'b'))
+ .ichain(x => iof(x + 'c'))
+ .run()).toBe('abc');
+ });
+});
+
+test('static #iof creates builder', () => {
+ expect(
+ iof('a').run()
+ ).toBe('a');
+});
+
+test('static #ichan chains builders', () => {
+ expect(
+ ichain(iof('a'), x => iof(x + 'b')).run()
+ ).toBe('ab');
+});
+
+test('static #map maps values', () => {
+ expect(
+ map(iof('a'), x => x + 'b').run()
+ ).toBe('ab');
+});

MODIFY
packages/core/src/router/router.ixbuilder.ts
packages/core/src/router/router.ixbuilder.ts
+import { IxBuilder, ichainCurry } from '../+internal/fp/IxBuilder';
import { RouteEffect } from './router.interface';
import { HttpMethod } from '../http.interface';
import { HttpMiddlewareEffect, HttpEffect } from '../effects/http-effects.interface';
@@ -13,28 +14,6 @@ type MetaApplied = 'MetaApplied';
type RouteEffectSpec = Partial<RouteEffect>;
-export class IxRouteBuilder<I, O, A> {
- readonly _A: A | undefined;
- readonly _L: O | undefined;
- readonly _U: I | undefined;
-
- constructor(readonly spec: A) {}
-
- run(): A {
- return this.spec;
- }
-
- ichain<Z, B>(f: (a: A) => IxRouteBuilder<O, Z, B>): IxRouteBuilder<I, Z, B> {
- return new IxRouteBuilder(f(this.spec).run());
- }
-}
-
-export const ichain = <I, O, Z, A, B>
- (f: (a: A) => IxRouteBuilder<O, Z, B>) =>
- (fa: IxRouteBuilder<I, O, A>): IxRouteBuilder<I, Z, B> => {
- return fa.ichain(f);
-};
-
type Arity<A, B> = (a: A) => B;
function pipe<A, B>(
@@ -114,8 +93,8 @@ function pipe<A, B, C, D, E, F, G, H, I, J, K> (
): RouteEffect;
function pipe(
...fns: Array<Arity<
- IxRouteBuilder<any, any, any>,
- IxRouteBuilder<any, any, any>
+ IxBuilder<any, any, any>,
+ IxBuilder<any, any, any>
>>
): RouteEffect {
return fns.reduce(
@@ -125,27 +104,27 @@ function pipe(
}
const route =
- new IxRouteBuilder<Ready, Empty, RouteEffectSpec>({});
+ new IxBuilder<Ready, Empty, RouteEffectSpec>({});
-const matchPath = (path: string) => ichain((spec: RouteEffectSpec) =>
- new IxRouteBuilder<Empty, PathApplied, RouteEffectSpec>({ ...spec, path }));
+const matchPath = (path: string) => ichainCurry((spec: RouteEffectSpec) =>
+ new IxBuilder<Empty, PathApplied, RouteEffectSpec>({ ...spec, path }));
-const matchType = (method: HttpMethod) => ichain((spec: RouteEffectSpec) =>
- new IxRouteBuilder<PathApplied, TypeApplied, RouteEffectSpec>({ ...spec, method }));
+const matchType = (method: HttpMethod) => ichainCurry((spec: RouteEffectSpec) =>
+ new IxBuilder<PathApplied, TypeApplied, RouteEffectSpec>({ ...spec, method }));
-const use = (middleware: HttpMiddlewareEffect) => ichain((spec: RouteEffectSpec) =>
- new IxRouteBuilder<TypeApplied | MiddlewareApplied, MiddlewareApplied, RouteEffectSpec>({
+const use = (middleware: HttpMiddlewareEffect) => ichainCurry((spec: RouteEffectSpec) =>
+ new IxBuilder<TypeApplied | MiddlewareApplied, MiddlewareApplied, RouteEffectSpec>({
...spec,
middleware: spec.middleware
? combineMiddlewares(spec.middleware, middleware)
: middleware
}));
-const useEffect = (effect: HttpEffect) => ichain((spec: RouteEffectSpec) =>
- new IxRouteBuilder<TypeApplied | MiddlewareApplied, EffectApplied, RouteEffectSpec>({ ...spec, effect }));
+const useEffect = (effect: HttpEffect) => ichainCurry((spec: RouteEffectSpec) =>
+ new IxBuilder<TypeApplied | MiddlewareApplied, EffectApplied, RouteEffectSpec>({ ...spec, effect }));
-const applyMeta = (meta: Record<string, any>) => ichain((spec: RouteEffectSpec) =>
- new IxRouteBuilder<EffectApplied | MetaApplied, MetaApplied, RouteEffectSpec>({
+const applyMeta = (meta: Record<string, any>) => ichainCurry((spec: RouteEffectSpec) =>
+ new IxBuilder<EffectApplied | MetaApplied, MetaApplied, RouteEffectSpec>({
...spec,
meta: { ...spec.meta, ...meta },
}));

imp(core): extracted IxBuilder from http route builder