Comparing version 0.16.3 to 0.17.0
@@ -8,3 +8,3 @@ import { konsole } from './Konsole'; | ||
if (t instanceof Observable) | ||
return t; | ||
return t.take(1); | ||
if (t instanceof Promise) | ||
@@ -15,8 +15,18 @@ return Observable.fromPromise<T>(t); | ||
export interface ActionRoute { | ||
type: 'action'; | ||
action: () => Observableable<any>; | ||
export type Action = () => Observableable<any>; | ||
export interface DoRoute { | ||
type: 'do'; | ||
action: Action; | ||
score: number; | ||
} | ||
export function isDoRoute(route: Route): route is DoRoute { | ||
return route.type === 'do'; | ||
} | ||
export function isNoRoute(route: Route): route is NoRoute { | ||
return route.type === 'no'; | ||
} | ||
export interface NoRoute { | ||
@@ -27,6 +37,20 @@ type: 'no'; | ||
export type Route = ActionRoute | NoRoute; | ||
export type Route = DoRoute | NoRoute; | ||
export type GetRoute$ <ROUTABLE> = (routable: ROUTABLE) => Observable<Route> | ||
export type RawRoute = Route | { | ||
type?: 'do'; | ||
action: Action; | ||
score?: number; | ||
} | { | ||
type?: 'no'; | ||
reason: string; | ||
} | ||
export type GetRouteRaw <ROUTABLE> = (routable: ROUTABLE) => Observableable<Route | RawRoute | Action>; | ||
export type GetRoute <ROUTABLE> = (routable: ROUTABLE) => Observableable<Route>; | ||
export type GetRoute$ <ROUTABLE> = (routable: ROUTABLE) => Observable<Route>; | ||
export type MapRoute <ROUTABLE> = (route: Route) => Observableable<GetRoute<ROUTABLE>>; | ||
export type Handler <ROUTABLE> = (routable: ROUTABLE) => Observableable<any>; | ||
@@ -50,284 +74,290 @@ | ||
export class Router <ROUTABLE> { | ||
constructor(public _getRoute$: GetRoute$<ROUTABLE>) {} | ||
export function doRoute ( | ||
action: () => Observableable<any>, | ||
score: number = 1 | ||
): DoRoute { | ||
return { | ||
type: 'do', | ||
action, | ||
score | ||
}; | ||
} | ||
static actionRoute ( | ||
action: () => Observableable<any>, | ||
score: number = 1 | ||
) { | ||
return { | ||
type: 'action', | ||
action, | ||
score | ||
} as ActionRoute; | ||
} | ||
export const defaultReason = "none"; | ||
static noRoute (reason: string = Router.defaultReason) { | ||
return { | ||
type: 'no', | ||
reason | ||
} as NoRoute; | ||
} | ||
export function noRoute ( | ||
reason: string = defaultReason | ||
): NoRoute { | ||
return { | ||
type: 'no', | ||
reason | ||
}; | ||
} | ||
static combineScore(score, otherScore) { | ||
return score * otherScore | ||
} | ||
export function normalizeRoute (rawRoute: RawRoute): Route { | ||
if (!rawRoute || (rawRoute as NoRoute).reason) | ||
return noRoute(rawRoute && (rawRoute as NoRoute).reason); | ||
if (typeof(rawRoute) === 'function') | ||
return doRoute(rawRoute); | ||
if ((rawRoute as DoRoute).action) | ||
return doRoute((rawRoute as DoRoute).action, (rawRoute as DoRoute).score); | ||
throw new Error('invalid route'); | ||
} | ||
static routeWithCombinedScore(route: ActionRoute, newScore: number) { | ||
const score = Router.combineScore(newScore, route.score); | ||
export const getNormalizedRoute = <ROUTABLE> (routable: ROUTABLE) => (getRoute: GetRouteRaw<ROUTABLE>) => getRoute | ||
? toObservable(getRoute(routable)) | ||
.map(normalizeRoute) | ||
: Observable.of(noRoute()); | ||
return route.score === score | ||
? route | ||
: { | ||
... route, | ||
score | ||
} as Route; | ||
} | ||
export function route$ <ROUTABLE> (routable: ROUTABLE, getRoute: GetRouteRaw<ROUTABLE>) { | ||
return Observable.of(getRoute) | ||
.flatMap(getNormalizedRoute(routable)) | ||
.do(route => konsole.log("route: returned a route", route)) | ||
.flatMap(route => isDoRoute(route) | ||
? toObservable(route.action()) | ||
.do(_ => konsole.log("route: called action")) | ||
.map(_ => true) | ||
: Observable.of(false) | ||
); | ||
} | ||
static route$ <ROUTABLE> (routable: ROUTABLE, router: Router<ROUTABLE>) { | ||
return router | ||
._getRoute$(routable) | ||
.do(route => konsole.log("route: returned a route", route)) | ||
.flatMap(route => route.type === 'action' | ||
? toObservable(route.action()) | ||
.do(_ => konsole.log("route: called action")) | ||
.map(_ => true) | ||
: Observable.of(false) | ||
); | ||
} | ||
export function no <ROUTABLE> ( | ||
reason?: string | ||
): GetRoute$<ROUTABLE> { | ||
return routable => Observable.of(noRoute(reason)); | ||
} | ||
static minRoute = Router.actionRoute( | ||
() => { | ||
console.warn("BestRouter.minRoute.action should never be called"); | ||
}, | ||
0 | ||
); | ||
export function getRouteDo <ROUTABLE> ( | ||
handler: Handler<ROUTABLE>, | ||
score?: number | ||
): GetRoute$<ROUTABLE> { | ||
return routable => Observable.of(doRoute(() => handler(routable), score)); | ||
} | ||
static defaultReason = "none"; | ||
export { getRouteDo as do } | ||
static getRouteNo$ <ROUTABLE> ( | ||
reason?: string | ||
): GetRoute$<ROUTABLE> { | ||
return routable => Observable.of(Router.noRoute(reason)); | ||
} | ||
export function first <ROUTABLE> ( | ||
... getRoutes: GetRouteRaw<ROUTABLE>[] | ||
): GetRoute$<ROUTABLE> { | ||
return routable => Observable.from(getRoutes) | ||
.concatMap(getNormalizedRoute(routable)) | ||
.filter(isDoRoute) | ||
.take(1) // so that we don't keep going through routers after we find one that matches; | ||
.defaultIfEmpty(noRoute('first')); | ||
} | ||
static getRouteDo$ <ROUTABLE> ( | ||
handler: Handler<ROUTABLE>, | ||
score?: number | ||
): GetRoute$<ROUTABLE> { | ||
return routable => Observable.of(Router.actionRoute(() => handler(routable), score)); | ||
} | ||
export function combinedScore(score, otherScore) { | ||
return score * otherScore | ||
} | ||
static getRouteFirst$ <ROUTABLE> ( | ||
... getRouters: ((routable: ROUTABLE) => Observableable<Router<ROUTABLE>>)[] | ||
): GetRoute$<ROUTABLE> { | ||
return routable => Observable.from(getRouters) | ||
.filter(getRouter => !!getRouter) | ||
.flatMap(getRouter => toObservable(getRouter(routable))) | ||
.map(Router.toRouter) | ||
.concatMap((router, i) => { | ||
konsole.log(`first: trying router #${i}`); | ||
return router | ||
._getRoute$(routable) | ||
.do(route => konsole.log(`first: router #${i} returned route`, route)); | ||
}) | ||
.filter(route => route.type === 'action') | ||
.take(1) // so that we don't keep going through routers after we find one that matches; | ||
.defaultIfEmpty(Router.noRoute('tryInOrder')); | ||
} | ||
export function routeWithCombinedScore(route: DoRoute, newScore: number) { | ||
const score = combinedScore(newScore, route.score); | ||
static getRouteBest$ <ROUTABLE> ( | ||
... getRouters: ((routable: ROUTABLE) => Observableable<Router<ROUTABLE>>)[] | ||
): GetRoute$<ROUTABLE> { | ||
return routable => new Observable<Route>(observer => { | ||
let bestRoute = Router.minRoute; | ||
return route.score === score | ||
? route | ||
: { | ||
... route, | ||
score | ||
} as Route; | ||
} | ||
const subscription = Observable.from(getRouters) | ||
.filter(getRouter => !!getRouter) | ||
.flatMap(getRouter => toObservable(getRouter(routable))) | ||
.map(Router.toRouter) | ||
.takeWhile(_ => bestRoute.score < 1) | ||
.concatMap(router => router._getRoute$(routable)) | ||
.filter(route => route.type === 'action') | ||
.subscribe( | ||
(route: ActionRoute) => { | ||
if (route.score > bestRoute.score) { | ||
bestRoute = route; | ||
if (bestRoute.score === 1) { | ||
observer.next(bestRoute); | ||
observer.complete(); | ||
} | ||
export const minRoute = doRoute( | ||
() => { | ||
console.warn("BestRouter.minRoute.action should never be called"); | ||
}, | ||
0 | ||
); | ||
export function best <ROUTABLE> ( | ||
... getRoutes: GetRouteRaw<ROUTABLE>[] | ||
): GetRoute<ROUTABLE> { | ||
return routable => new Observable<Route>(observer => { | ||
let bestRoute = minRoute; | ||
const subscription = Observable.from(getRoutes) | ||
.takeWhile(_ => bestRoute.score < 1) | ||
.concatMap(getNormalizedRoute(routable)) | ||
.filter(isDoRoute) | ||
.subscribe( | ||
(route: DoRoute) => { | ||
if (route.score > bestRoute.score) { | ||
bestRoute = route; | ||
if (bestRoute.score === 1) { | ||
observer.next(bestRoute); | ||
observer.complete(); | ||
} | ||
}, | ||
error => | ||
observer.error(error), | ||
() => { | ||
observer.next(bestRoute.score > 0 | ||
? bestRoute | ||
: Router.noRoute('tryInScoreOrder') | ||
); | ||
observer.complete(); | ||
} | ||
); | ||
}, | ||
error => | ||
observer.error(error), | ||
() => { | ||
observer.next(bestRoute.score > 0 | ||
? bestRoute | ||
: noRoute('best') | ||
); | ||
observer.complete(); | ||
} | ||
); | ||
return () => subscription.unsubscribe(); | ||
}); | ||
} | ||
return () => subscription.unsubscribe(); | ||
}); | ||
} | ||
static getRouteNoop$ <ROUTABLE> (handler: Handler<ROUTABLE>): GetRoute$<ROUTABLE> { | ||
return routable => toObservable(handler(routable)) | ||
.map(_ => Router.noRoute('noop')); | ||
} | ||
export function noop <ROUTABLE> (handler: Handler<ROUTABLE>): GetRouteRaw<ROUTABLE> { | ||
return routable => toObservable(handler(routable)) | ||
.map(_ => noRoute('noop')); | ||
} | ||
static isMatch <VALUE> (match: MatchResult<any>): match is Match<VALUE> { | ||
return ((match as any).reason === undefined); | ||
} | ||
export function isMatch <VALUE> (match: MatchResult<any>): match is Match<VALUE> { | ||
return ((match as any).reason === undefined); | ||
} | ||
static normalizeMatchResult <VALUE> (response: any): MatchResult<VALUE> { | ||
if (response == null || response === false) | ||
return { | ||
reason: Router.defaultReason | ||
} | ||
function normalizeMatchResult <VALUE> (response: any): MatchResult<VALUE> { | ||
if (response == null || response === false) | ||
return { | ||
reason: defaultReason | ||
} | ||
if (typeof(response) === 'object') { | ||
if (response.reason) { | ||
if (typeof(response.reason) !== 'string') | ||
throw new Error('The reason for NoMatch must be a string'); | ||
if (typeof(response) === 'object') { | ||
if (response.reason) { | ||
if (typeof(response.reason) !== 'string') | ||
throw new Error('The reason for NoMatch must be a string'); | ||
return { | ||
reason: response.reason | ||
} | ||
return { | ||
reason: response.reason | ||
} | ||
} | ||
if (response.value !== undefined) { | ||
if (response.score !== undefined && typeof(response.score) !== 'number') | ||
throw new Error('The score for Match must be a number'); | ||
if (response.value !== undefined) { | ||
if (response.score !== undefined && typeof(response.score) !== 'number') | ||
throw new Error('The score for Match must be a number'); | ||
return { | ||
value: response.value, | ||
score: response.score || 1 | ||
} | ||
return { | ||
value: response.value, | ||
score: response.score || 1 | ||
} | ||
} | ||
return { | ||
value: response, | ||
score: 1 | ||
} | ||
} | ||
static toRouter <ROUTABLE> (router: Router<ROUTABLE>): Router<ROUTABLE> { | ||
return router || new Router(Router.getRouteNo$()); | ||
return { | ||
value: response, | ||
score: 1 | ||
} | ||
} | ||
static getRouteIfMatches$ <ROUTABLE, VALUE> ( | ||
matcher: Matcher<ROUTABLE, VALUE>, | ||
getThenRouter: (routable: ROUTABLE, value: VALUE) => Observableable<Router<ROUTABLE>>, | ||
getElseRouter?: (routable: ROUTABLE, reason: string) => Observableable<Router<ROUTABLE>> | ||
): GetRoute$<ROUTABLE> { | ||
if (!getElseRouter) | ||
getElseRouter = (routable: ROUTABLE, reason: string) => new Router<ROUTABLE>(Router.getRouteNo$(reason)); | ||
return routable => toObservable(matcher(routable)) | ||
.map(response => Router.normalizeMatchResult<VALUE>(response)) | ||
.flatMap(matchResult => Router.isMatch(matchResult) | ||
? toObservable(getThenRouter(routable, matchResult.value)) | ||
.map(Router.toRouter) | ||
.flatMap(router => router._getRoute$(routable)) | ||
.map(route => route.type === 'action' | ||
? Router.routeWithCombinedScore(route, matchResult.score) | ||
: route | ||
) | ||
: toObservable(getElseRouter(routable, matchResult.reason)) | ||
.map(Router.toRouter) | ||
.flatMap(router => router._getRoute$(routable)) | ||
export function getNormalizedMatchResult$ <ROUTABLE, VALUE> (matcher: Matcher<ROUTABLE, VALUE>, routable: ROUTABLE) { | ||
return toObservable(matcher(routable)) | ||
.map(response => normalizeMatchResult<VALUE>(response)); | ||
} | ||
function getRouteIfMatches <ROUTABLE, VALUE> ( | ||
matcher: Matcher<ROUTABLE, VALUE>, | ||
getThenGetRoute: (value: VALUE) => Observableable<GetRoute<ROUTABLE>>, | ||
elseMapRoute: (route: NoRoute) => Observableable<GetRoute<ROUTABLE>> = route => routable => route | ||
): GetRoute<ROUTABLE> { | ||
return routable => getNormalizedMatchResult$(matcher, routable) | ||
.flatMap(matchResult => isMatch(matchResult) | ||
? toObservable(getThenGetRoute(matchResult.value)) | ||
.flatMap(getNormalizedRoute(routable)) | ||
.map(route => isDoRoute(route) | ||
? routeWithCombinedScore(route, matchResult.score) | ||
: route | ||
) | ||
: toObservable(elseMapRoute(noRoute(matchResult.reason))) | ||
.flatMap(getNormalizedRoute(routable)) | ||
); | ||
} | ||
} | ||
static predicateToMatcher <ROUTABLE> (predicate: Predicate<ROUTABLE>): Matcher<ROUTABLE, boolean> { | ||
return routable => toObservable(predicate(routable)) | ||
.map((response: any) => { | ||
if (response === true || response === false) | ||
export { getRouteIfMatches as ifGet } | ||
export function predicateToMatcher <ROUTABLE> (predicate: Predicate<ROUTABLE>): Matcher<ROUTABLE, boolean> { | ||
return routable => toObservable(predicate(routable)) | ||
.map((response: any) => { | ||
if (response === true || response === false) | ||
return response; | ||
if (typeof(response) === 'object') { | ||
if (response.reason) | ||
return response; | ||
if (typeof(response) === 'object') { | ||
if (response.reason) | ||
if (response.value !== undefined) { | ||
if (response.value === false) | ||
return false; | ||
if (response.value === true) | ||
return response; | ||
if (response.value !== undefined) { | ||
if (response.value === false) | ||
return false; | ||
if (response.value === true) | ||
return response; | ||
throw new Error('When returning a Match from a predicate, the value must be true or false'); | ||
} | ||
throw new Error('When returning a Match from a predicate, the value must be true or false'); | ||
} | ||
} | ||
throw new Error('A predicate may only return true, false, a Match of true or false, or a NoMatch'); | ||
}); | ||
} | ||
throw new Error('A predicate may only return true, false, a Match of true or false, or a NoMatch'); | ||
}); | ||
} | ||
static getRouteIfTrue$ <ROUTABLE> ( | ||
predicate: Predicate<ROUTABLE>, | ||
getThenRouter: (routable: ROUTABLE, value: boolean) => Observableable<Router<ROUTABLE>>, | ||
getElseRouter?: (routable: ROUTABLE, reason: string) => Observableable<Router<ROUTABLE>> | ||
): GetRoute$<ROUTABLE> { | ||
return Router.getRouteIfMatches$(Router.predicateToMatcher(predicate), getThenRouter, getElseRouter); | ||
} | ||
function getRouteIfTrue <ROUTABLE> ( | ||
predicate: Predicate<ROUTABLE>, | ||
thenGetRoute: GetRoute<ROUTABLE>, | ||
elseMapRoute: (route: NoRoute) => Observableable<GetRoute<ROUTABLE>> | ||
): GetRoute<ROUTABLE> { | ||
return getRouteIfMatches(predicateToMatcher(predicate), value => thenGetRoute, elseMapRoute); | ||
} | ||
static getRouteBefore$ <ROUTABLE> ( | ||
beforeHandler: Handler<ROUTABLE>, | ||
router: Router<ROUTABLE> | ||
): GetRoute$<ROUTABLE> { | ||
return routable => router | ||
._getRoute$(routable) | ||
.map(route => route.type === 'action' | ||
? { | ||
... route, | ||
action: () => toObservable(beforeHandler(routable)) | ||
.flatMap(_ => toObservable(route.action())) | ||
} | ||
: route | ||
); | ||
} | ||
export { getRouteIfTrue as if } | ||
static getRouteAfter$ <ROUTABLE> ( | ||
afterHandler: Handler<ROUTABLE>, | ||
router: Router<ROUTABLE> | ||
): GetRoute$<ROUTABLE> { | ||
return routable => router | ||
._getRoute$(routable) | ||
.map(route => route.type === 'action' | ||
? { | ||
... route, | ||
action: () => toObservable(route.action()) | ||
.flatMap(_ => toObservable(afterHandler(routable))) | ||
} | ||
: route | ||
); | ||
} | ||
export function map <ROUTABLE> ( | ||
getRoute: GetRoute<ROUTABLE>, | ||
mapper: MapRoute<ROUTABLE> | ||
): GetRoute$<ROUTABLE> { | ||
return routable => Observable.of(getRoute) | ||
.flatMap(getNormalizedRoute(routable)) | ||
.flatMap(route => toObservable(mapper(route))) | ||
.flatMap(getNormalizedRoute(routable)) | ||
} | ||
static getRouteDefault$ <ROUTABLE> ( | ||
mainRouter: Router<ROUTABLE>, | ||
getDefaultRouter: (routable: ROUTABLE, reason: string) => Observableable<Router<ROUTABLE>> | ||
): GetRoute$<ROUTABLE> { | ||
return routable => mainRouter._getRoute$(routable) | ||
.flatMap(route => route.type === 'action' | ||
? Observable.of(route) | ||
: toObservable(getDefaultRouter(routable, route.reason)) | ||
.map(Router.toRouter) | ||
.flatMap(router => router._getRoute$(routable)) | ||
); | ||
} | ||
export function before <ROUTABLE> ( | ||
beforeHandler: Handler<ROUTABLE>, | ||
getRoute: GetRoute<ROUTABLE> | ||
): GetRoute$<ROUTABLE> { | ||
return map(getRoute, route => routable => isDoRoute(route) | ||
? doRoute( | ||
() => toObservable(beforeHandler(routable)) | ||
.flatMap(_ => toObservable(route.action())), | ||
route.score | ||
) | ||
: route | ||
); | ||
} | ||
static getRouteSwitch$ <ROUTABLE> ( | ||
getKey: (routable: ROUTABLE) => Observableable<string>, | ||
getMapKeyToRouter: (routable: ROUTABLE) => Observableable<Record<string, Router<ROUTABLE>>> | ||
): GetRoute$<ROUTABLE> { | ||
return routable => toObservable(getKey(routable)) | ||
.flatMap(key => toObservable(getMapKeyToRouter(routable)) | ||
.map(mapKeyToRouter => mapKeyToRouter[key]) | ||
) | ||
.map(Router.toRouter) | ||
.flatMap(router => router._getRoute$(routable)); | ||
} | ||
export function after <ROUTABLE> ( | ||
afterHandler: Handler<ROUTABLE>, | ||
getRoute: GetRoute<ROUTABLE> | ||
): GetRoute$<ROUTABLE> { | ||
return map(getRoute, route => routable => isDoRoute(route) | ||
? doRoute( | ||
() => toObservable(route.action()) | ||
.flatMap(_ => toObservable(afterHandler(routable))), | ||
route.score | ||
) | ||
: route | ||
); | ||
} | ||
function getRouteDefault <ROUTABLE> ( | ||
getRoute: GetRoute<ROUTABLE>, | ||
defaultMapRoute: (route: NoRoute) => Observableable<GetRoute<ROUTABLE>> | ||
) { | ||
return map(getRoute, route => isNoRoute(route) | ||
? defaultMapRoute(route) | ||
: routable => route | ||
); | ||
} | ||
export { getRouteDefault as default } | ||
function getRouteSwitch <ROUTABLE> ( | ||
getKey: (routable: ROUTABLE) => Observableable<string>, | ||
mapKeyToGetRoute: Record<string, GetRoute<ROUTABLE>> | ||
) { | ||
return getRouteIfMatches(getKey, key => mapKeyToGetRoute[key]); | ||
} | ||
export { getRouteSwitch as switch } |
import { Observable } from 'rxjs'; | ||
export declare type Observableable<T> = T | Observable<T> | Promise<T>; | ||
export declare function toObservable<T>(t: Observableable<T>): Observable<T>; | ||
export interface ActionRoute { | ||
type: 'action'; | ||
action: () => Observableable<any>; | ||
export declare type Action = () => Observableable<any>; | ||
export interface DoRoute { | ||
type: 'do'; | ||
action: Action; | ||
score: number; | ||
} | ||
export declare function isDoRoute(route: Route): route is DoRoute; | ||
export declare function isNoRoute(route: Route): route is NoRoute; | ||
export interface NoRoute { | ||
@@ -13,4 +16,15 @@ type: 'no'; | ||
} | ||
export declare type Route = ActionRoute | NoRoute; | ||
export declare type Route = DoRoute | NoRoute; | ||
export declare type RawRoute = Route | { | ||
type?: 'do'; | ||
action: Action; | ||
score?: number; | ||
} | { | ||
type?: 'no'; | ||
reason: string; | ||
}; | ||
export declare type GetRouteRaw<ROUTABLE> = (routable: ROUTABLE) => Observableable<Route | RawRoute | Action>; | ||
export declare type GetRoute<ROUTABLE> = (routable: ROUTABLE) => Observableable<Route>; | ||
export declare type GetRoute$<ROUTABLE> = (routable: ROUTABLE) => Observable<Route>; | ||
export declare type MapRoute<ROUTABLE> = (route: Route) => Observableable<GetRoute<ROUTABLE>>; | ||
export declare type Handler<ROUTABLE> = (routable: ROUTABLE) => Observableable<any>; | ||
@@ -28,27 +42,30 @@ export interface Match<VALUE> { | ||
export declare type Predicate<ROUTABLE> = Matcher<ROUTABLE, boolean>; | ||
export declare class Router<ROUTABLE> { | ||
_getRoute$: GetRoute$<ROUTABLE>; | ||
constructor(_getRoute$: GetRoute$<ROUTABLE>); | ||
static actionRoute(action: () => Observableable<any>, score?: number): ActionRoute; | ||
static noRoute(reason?: string): NoRoute; | ||
static combineScore(score: any, otherScore: any): number; | ||
static routeWithCombinedScore(route: ActionRoute, newScore: number): Route; | ||
static route$<ROUTABLE>(routable: ROUTABLE, router: Router<ROUTABLE>): Observable<boolean>; | ||
static minRoute: ActionRoute; | ||
static defaultReason: string; | ||
static getRouteNo$<ROUTABLE>(reason?: string): GetRoute$<ROUTABLE>; | ||
static getRouteDo$<ROUTABLE>(handler: Handler<ROUTABLE>, score?: number): GetRoute$<ROUTABLE>; | ||
static getRouteFirst$<ROUTABLE>(...getRouters: ((routable: ROUTABLE) => Observableable<Router<ROUTABLE>>)[]): GetRoute$<ROUTABLE>; | ||
static getRouteBest$<ROUTABLE>(...getRouters: ((routable: ROUTABLE) => Observableable<Router<ROUTABLE>>)[]): GetRoute$<ROUTABLE>; | ||
static getRouteNoop$<ROUTABLE>(handler: Handler<ROUTABLE>): GetRoute$<ROUTABLE>; | ||
static isMatch<VALUE>(match: MatchResult<any>): match is Match<VALUE>; | ||
static normalizeMatchResult<VALUE>(response: any): MatchResult<VALUE>; | ||
static toRouter<ROUTABLE>(router: Router<ROUTABLE>): Router<ROUTABLE>; | ||
static getRouteIfMatches$<ROUTABLE, VALUE>(matcher: Matcher<ROUTABLE, VALUE>, getThenRouter: (routable: ROUTABLE, value: VALUE) => Observableable<Router<ROUTABLE>>, getElseRouter?: (routable: ROUTABLE, reason: string) => Observableable<Router<ROUTABLE>>): GetRoute$<ROUTABLE>; | ||
static predicateToMatcher<ROUTABLE>(predicate: Predicate<ROUTABLE>): Matcher<ROUTABLE, boolean>; | ||
static getRouteIfTrue$<ROUTABLE>(predicate: Predicate<ROUTABLE>, getThenRouter: (routable: ROUTABLE, value: boolean) => Observableable<Router<ROUTABLE>>, getElseRouter?: (routable: ROUTABLE, reason: string) => Observableable<Router<ROUTABLE>>): GetRoute$<ROUTABLE>; | ||
static getRouteBefore$<ROUTABLE>(beforeHandler: Handler<ROUTABLE>, router: Router<ROUTABLE>): GetRoute$<ROUTABLE>; | ||
static getRouteAfter$<ROUTABLE>(afterHandler: Handler<ROUTABLE>, router: Router<ROUTABLE>): GetRoute$<ROUTABLE>; | ||
static getRouteDefault$<ROUTABLE>(mainRouter: Router<ROUTABLE>, getDefaultRouter: (routable: ROUTABLE, reason: string) => Observableable<Router<ROUTABLE>>): GetRoute$<ROUTABLE>; | ||
static getRouteSwitch$<ROUTABLE>(getKey: (routable: ROUTABLE) => Observableable<string>, getMapKeyToRouter: (routable: ROUTABLE) => Observableable<Record<string, Router<ROUTABLE>>>): GetRoute$<ROUTABLE>; | ||
} | ||
export declare function doRoute(action: () => Observableable<any>, score?: number): DoRoute; | ||
export declare const defaultReason = "none"; | ||
export declare function noRoute(reason?: string): NoRoute; | ||
export declare function normalizeRoute(rawRoute: RawRoute): Route; | ||
export declare const getNormalizedRoute: <ROUTABLE>(routable: ROUTABLE) => (getRoute: GetRouteRaw<ROUTABLE>) => Observable<Route>; | ||
export declare function route$<ROUTABLE>(routable: ROUTABLE, getRoute: GetRouteRaw<ROUTABLE>): Observable<boolean>; | ||
export declare function no<ROUTABLE>(reason?: string): GetRoute$<ROUTABLE>; | ||
export declare function getRouteDo<ROUTABLE>(handler: Handler<ROUTABLE>, score?: number): GetRoute$<ROUTABLE>; | ||
export { getRouteDo as do }; | ||
export declare function first<ROUTABLE>(...getRoutes: GetRouteRaw<ROUTABLE>[]): GetRoute$<ROUTABLE>; | ||
export declare function combinedScore(score: any, otherScore: any): number; | ||
export declare function routeWithCombinedScore(route: DoRoute, newScore: number): Route; | ||
export declare const minRoute: DoRoute; | ||
export declare function best<ROUTABLE>(...getRoutes: GetRouteRaw<ROUTABLE>[]): GetRoute<ROUTABLE>; | ||
export declare function noop<ROUTABLE>(handler: Handler<ROUTABLE>): GetRouteRaw<ROUTABLE>; | ||
export declare function isMatch<VALUE>(match: MatchResult<any>): match is Match<VALUE>; | ||
export declare function getNormalizedMatchResult$<ROUTABLE, VALUE>(matcher: Matcher<ROUTABLE, VALUE>, routable: ROUTABLE): Observable<MatchResult<VALUE>>; | ||
declare function getRouteIfMatches<ROUTABLE, VALUE>(matcher: Matcher<ROUTABLE, VALUE>, getThenGetRoute: (value: VALUE) => Observableable<GetRoute<ROUTABLE>>, elseMapRoute?: (route: NoRoute) => Observableable<GetRoute<ROUTABLE>>): GetRoute<ROUTABLE>; | ||
export { getRouteIfMatches as ifGet }; | ||
export declare function predicateToMatcher<ROUTABLE>(predicate: Predicate<ROUTABLE>): Matcher<ROUTABLE, boolean>; | ||
declare function getRouteIfTrue<ROUTABLE>(predicate: Predicate<ROUTABLE>, thenGetRoute: GetRoute<ROUTABLE>, elseMapRoute: (route: NoRoute) => Observableable<GetRoute<ROUTABLE>>): GetRoute<ROUTABLE>; | ||
export { getRouteIfTrue as if }; | ||
export declare function map<ROUTABLE>(getRoute: GetRoute<ROUTABLE>, mapper: MapRoute<ROUTABLE>): GetRoute$<ROUTABLE>; | ||
export declare function before<ROUTABLE>(beforeHandler: Handler<ROUTABLE>, getRoute: GetRoute<ROUTABLE>): GetRoute$<ROUTABLE>; | ||
export declare function after<ROUTABLE>(afterHandler: Handler<ROUTABLE>, getRoute: GetRoute<ROUTABLE>): GetRoute$<ROUTABLE>; | ||
declare function getRouteDefault<ROUTABLE>(getRoute: GetRoute<ROUTABLE>, defaultMapRoute: (route: NoRoute) => Observableable<GetRoute<ROUTABLE>>): GetRoute$<ROUTABLE>; | ||
export { getRouteDefault as default }; | ||
declare function getRouteSwitch<ROUTABLE>(getKey: (routable: ROUTABLE) => Observableable<string>, mapKeyToGetRoute: Record<string, GetRoute<ROUTABLE>>): GetRoute<ROUTABLE>; | ||
export { getRouteSwitch as switch }; |
@@ -15,3 +15,3 @@ "use strict"; | ||
if (t instanceof rxjs_1.Observable) | ||
return t; | ||
return t.take(1); | ||
if (t instanceof Promise) | ||
@@ -22,209 +22,228 @@ return rxjs_1.Observable.fromPromise(t); | ||
exports.toObservable = toObservable; | ||
var Router = /** @class */ (function () { | ||
function Router(_getRoute$) { | ||
this._getRoute$ = _getRoute$; | ||
function isDoRoute(route) { | ||
return route.type === 'do'; | ||
} | ||
exports.isDoRoute = isDoRoute; | ||
function isNoRoute(route) { | ||
return route.type === 'no'; | ||
} | ||
exports.isNoRoute = isNoRoute; | ||
function doRoute(action, score) { | ||
if (score === void 0) { score = 1; } | ||
return { | ||
type: 'do', | ||
action: action, | ||
score: score | ||
}; | ||
} | ||
exports.doRoute = doRoute; | ||
exports.defaultReason = "none"; | ||
function noRoute(reason) { | ||
if (reason === void 0) { reason = exports.defaultReason; } | ||
return { | ||
type: 'no', | ||
reason: reason | ||
}; | ||
} | ||
exports.noRoute = noRoute; | ||
function normalizeRoute(rawRoute) { | ||
if (!rawRoute || rawRoute.reason) | ||
return noRoute(rawRoute && rawRoute.reason); | ||
if (typeof (rawRoute) === 'function') | ||
return doRoute(rawRoute); | ||
if (rawRoute.action) | ||
return doRoute(rawRoute.action, rawRoute.score); | ||
throw new Error('invalid route'); | ||
} | ||
exports.normalizeRoute = normalizeRoute; | ||
exports.getNormalizedRoute = function (routable) { return function (getRoute) { return getRoute | ||
? toObservable(getRoute(routable)) | ||
.map(normalizeRoute) | ||
: rxjs_1.Observable.of(noRoute()); }; }; | ||
function route$(routable, getRoute) { | ||
return rxjs_1.Observable.of(getRoute) | ||
.flatMap(exports.getNormalizedRoute(routable)) | ||
.do(function (route) { return Konsole_1.konsole.log("route: returned a route", route); }) | ||
.flatMap(function (route) { return isDoRoute(route) | ||
? toObservable(route.action()) | ||
.do(function (_) { return Konsole_1.konsole.log("route: called action"); }) | ||
.map(function (_) { return true; }) | ||
: rxjs_1.Observable.of(false); }); | ||
} | ||
exports.route$ = route$; | ||
function no(reason) { | ||
return function (routable) { return rxjs_1.Observable.of(noRoute(reason)); }; | ||
} | ||
exports.no = no; | ||
function getRouteDo(handler, score) { | ||
return function (routable) { return rxjs_1.Observable.of(doRoute(function () { return handler(routable); }, score)); }; | ||
} | ||
exports.getRouteDo = getRouteDo; | ||
exports.do = getRouteDo; | ||
function first() { | ||
var getRoutes = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
getRoutes[_i] = arguments[_i]; | ||
} | ||
Router.actionRoute = function (action, score) { | ||
if (score === void 0) { score = 1; } | ||
return function (routable) { return rxjs_1.Observable.from(getRoutes) | ||
.concatMap(exports.getNormalizedRoute(routable)) | ||
.filter(isDoRoute) | ||
.take(1) // so that we don't keep going through routers after we find one that matches; | ||
.defaultIfEmpty(noRoute('first')); }; | ||
} | ||
exports.first = first; | ||
function combinedScore(score, otherScore) { | ||
return score * otherScore; | ||
} | ||
exports.combinedScore = combinedScore; | ||
function routeWithCombinedScore(route, newScore) { | ||
var score = combinedScore(newScore, route.score); | ||
return route.score === score | ||
? route | ||
: __assign({}, route, { score: score }); | ||
} | ||
exports.routeWithCombinedScore = routeWithCombinedScore; | ||
exports.minRoute = doRoute(function () { | ||
console.warn("BestRouter.minRoute.action should never be called"); | ||
}, 0); | ||
function best() { | ||
var getRoutes = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
getRoutes[_i] = arguments[_i]; | ||
} | ||
return function (routable) { return new rxjs_1.Observable(function (observer) { | ||
var bestRoute = exports.minRoute; | ||
var subscription = rxjs_1.Observable.from(getRoutes) | ||
.takeWhile(function (_) { return bestRoute.score < 1; }) | ||
.concatMap(exports.getNormalizedRoute(routable)) | ||
.filter(isDoRoute) | ||
.subscribe(function (route) { | ||
if (route.score > bestRoute.score) { | ||
bestRoute = route; | ||
if (bestRoute.score === 1) { | ||
observer.next(bestRoute); | ||
observer.complete(); | ||
} | ||
} | ||
}, function (error) { | ||
return observer.error(error); | ||
}, function () { | ||
observer.next(bestRoute.score > 0 | ||
? bestRoute | ||
: noRoute('best')); | ||
observer.complete(); | ||
}); | ||
return function () { return subscription.unsubscribe(); }; | ||
}); }; | ||
} | ||
exports.best = best; | ||
function noop(handler) { | ||
return function (routable) { return toObservable(handler(routable)) | ||
.map(function (_) { return noRoute('noop'); }); }; | ||
} | ||
exports.noop = noop; | ||
function isMatch(match) { | ||
return (match.reason === undefined); | ||
} | ||
exports.isMatch = isMatch; | ||
function normalizeMatchResult(response) { | ||
if (response == null || response === false) | ||
return { | ||
type: 'action', | ||
action: action, | ||
score: score | ||
reason: exports.defaultReason | ||
}; | ||
}; | ||
Router.noRoute = function (reason) { | ||
if (reason === void 0) { reason = Router.defaultReason; } | ||
return { | ||
type: 'no', | ||
reason: reason | ||
}; | ||
}; | ||
Router.combineScore = function (score, otherScore) { | ||
return score * otherScore; | ||
}; | ||
Router.routeWithCombinedScore = function (route, newScore) { | ||
var score = Router.combineScore(newScore, route.score); | ||
return route.score === score | ||
? route | ||
: __assign({}, route, { score: score }); | ||
}; | ||
Router.route$ = function (routable, router) { | ||
return router | ||
._getRoute$(routable) | ||
.do(function (route) { return Konsole_1.konsole.log("route: returned a route", route); }) | ||
.flatMap(function (route) { return route.type === 'action' | ||
? toObservable(route.action()) | ||
.do(function (_) { return Konsole_1.konsole.log("route: called action"); }) | ||
.map(function (_) { return true; }) | ||
: rxjs_1.Observable.of(false); }); | ||
}; | ||
Router.getRouteNo$ = function (reason) { | ||
return function (routable) { return rxjs_1.Observable.of(Router.noRoute(reason)); }; | ||
}; | ||
Router.getRouteDo$ = function (handler, score) { | ||
return function (routable) { return rxjs_1.Observable.of(Router.actionRoute(function () { return handler(routable); }, score)); }; | ||
}; | ||
Router.getRouteFirst$ = function () { | ||
var getRouters = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
getRouters[_i] = arguments[_i]; | ||
if (typeof (response) === 'object') { | ||
if (response.reason) { | ||
if (typeof (response.reason) !== 'string') | ||
throw new Error('The reason for NoMatch must be a string'); | ||
return { | ||
reason: response.reason | ||
}; | ||
} | ||
return function (routable) { return rxjs_1.Observable.from(getRouters) | ||
.filter(function (getRouter) { return !!getRouter; }) | ||
.flatMap(function (getRouter) { return toObservable(getRouter(routable)); }) | ||
.map(Router.toRouter) | ||
.concatMap(function (router, i) { | ||
Konsole_1.konsole.log("first: trying router #" + i); | ||
return router | ||
._getRoute$(routable) | ||
.do(function (route) { return Konsole_1.konsole.log("first: router #" + i + " returned route", route); }); | ||
}) | ||
.filter(function (route) { return route.type === 'action'; }) | ||
.take(1) // so that we don't keep going through routers after we find one that matches; | ||
.defaultIfEmpty(Router.noRoute('tryInOrder')); }; | ||
}; | ||
Router.getRouteBest$ = function () { | ||
var getRouters = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
getRouters[_i] = arguments[_i]; | ||
} | ||
return function (routable) { return new rxjs_1.Observable(function (observer) { | ||
var bestRoute = Router.minRoute; | ||
var subscription = rxjs_1.Observable.from(getRouters) | ||
.filter(function (getRouter) { return !!getRouter; }) | ||
.flatMap(function (getRouter) { return toObservable(getRouter(routable)); }) | ||
.map(Router.toRouter) | ||
.takeWhile(function (_) { return bestRoute.score < 1; }) | ||
.concatMap(function (router) { return router._getRoute$(routable); }) | ||
.filter(function (route) { return route.type === 'action'; }) | ||
.subscribe(function (route) { | ||
if (route.score > bestRoute.score) { | ||
bestRoute = route; | ||
if (bestRoute.score === 1) { | ||
observer.next(bestRoute); | ||
observer.complete(); | ||
} | ||
} | ||
}, function (error) { | ||
return observer.error(error); | ||
}, function () { | ||
observer.next(bestRoute.score > 0 | ||
? bestRoute | ||
: Router.noRoute('tryInScoreOrder')); | ||
observer.complete(); | ||
}); | ||
return function () { return subscription.unsubscribe(); }; | ||
}); }; | ||
}; | ||
Router.getRouteNoop$ = function (handler) { | ||
return function (routable) { return toObservable(handler(routable)) | ||
.map(function (_) { return Router.noRoute('noop'); }); }; | ||
}; | ||
Router.isMatch = function (match) { | ||
return (match.reason === undefined); | ||
}; | ||
Router.normalizeMatchResult = function (response) { | ||
if (response == null || response === false) | ||
if (response.value !== undefined) { | ||
if (response.score !== undefined && typeof (response.score) !== 'number') | ||
throw new Error('The score for Match must be a number'); | ||
return { | ||
reason: Router.defaultReason | ||
value: response.value, | ||
score: response.score || 1 | ||
}; | ||
if (typeof (response) === 'object') { | ||
if (response.reason) { | ||
if (typeof (response.reason) !== 'string') | ||
throw new Error('The reason for NoMatch must be a string'); | ||
return { | ||
reason: response.reason | ||
}; | ||
} | ||
if (response.value !== undefined) { | ||
if (response.score !== undefined && typeof (response.score) !== 'number') | ||
throw new Error('The score for Match must be a number'); | ||
return { | ||
value: response.value, | ||
score: response.score || 1 | ||
}; | ||
} | ||
} | ||
return { | ||
value: response, | ||
score: 1 | ||
}; | ||
} | ||
return { | ||
value: response, | ||
score: 1 | ||
}; | ||
Router.toRouter = function (router) { | ||
return router || new Router(Router.getRouteNo$()); | ||
}; | ||
Router.getRouteIfMatches$ = function (matcher, getThenRouter, getElseRouter) { | ||
if (!getElseRouter) | ||
getElseRouter = function (routable, reason) { return new Router(Router.getRouteNo$(reason)); }; | ||
return function (routable) { return toObservable(matcher(routable)) | ||
.map(function (response) { return Router.normalizeMatchResult(response); }) | ||
.flatMap(function (matchResult) { return Router.isMatch(matchResult) | ||
? toObservable(getThenRouter(routable, matchResult.value)) | ||
.map(Router.toRouter) | ||
.flatMap(function (router) { return router._getRoute$(routable); }) | ||
.map(function (route) { return route.type === 'action' | ||
? Router.routeWithCombinedScore(route, matchResult.score) | ||
: route; }) | ||
: toObservable(getElseRouter(routable, matchResult.reason)) | ||
.map(Router.toRouter) | ||
.flatMap(function (router) { return router._getRoute$(routable); }); }); }; | ||
}; | ||
Router.predicateToMatcher = function (predicate) { | ||
return function (routable) { return toObservable(predicate(routable)) | ||
.map(function (response) { | ||
if (response === true || response === false) | ||
} | ||
function getNormalizedMatchResult$(matcher, routable) { | ||
return toObservable(matcher(routable)) | ||
.map(function (response) { return normalizeMatchResult(response); }); | ||
} | ||
exports.getNormalizedMatchResult$ = getNormalizedMatchResult$; | ||
function getRouteIfMatches(matcher, getThenGetRoute, elseMapRoute) { | ||
if (elseMapRoute === void 0) { elseMapRoute = function (route) { return function (routable) { return route; }; }; } | ||
return function (routable) { return getNormalizedMatchResult$(matcher, routable) | ||
.flatMap(function (matchResult) { return isMatch(matchResult) | ||
? toObservable(getThenGetRoute(matchResult.value)) | ||
.flatMap(exports.getNormalizedRoute(routable)) | ||
.map(function (route) { return isDoRoute(route) | ||
? routeWithCombinedScore(route, matchResult.score) | ||
: route; }) | ||
: toObservable(elseMapRoute(noRoute(matchResult.reason))) | ||
.flatMap(exports.getNormalizedRoute(routable)); }); }; | ||
} | ||
exports.ifGet = getRouteIfMatches; | ||
function predicateToMatcher(predicate) { | ||
return function (routable) { return toObservable(predicate(routable)) | ||
.map(function (response) { | ||
if (response === true || response === false) | ||
return response; | ||
if (typeof (response) === 'object') { | ||
if (response.reason) | ||
return response; | ||
if (typeof (response) === 'object') { | ||
if (response.reason) | ||
if (response.value !== undefined) { | ||
if (response.value === false) | ||
return false; | ||
if (response.value === true) | ||
return response; | ||
if (response.value !== undefined) { | ||
if (response.value === false) | ||
return false; | ||
if (response.value === true) | ||
return response; | ||
throw new Error('When returning a Match from a predicate, the value must be true or false'); | ||
} | ||
throw new Error('When returning a Match from a predicate, the value must be true or false'); | ||
} | ||
throw new Error('A predicate may only return true, false, a Match of true or false, or a NoMatch'); | ||
}); }; | ||
}; | ||
Router.getRouteIfTrue$ = function (predicate, getThenRouter, getElseRouter) { | ||
return Router.getRouteIfMatches$(Router.predicateToMatcher(predicate), getThenRouter, getElseRouter); | ||
}; | ||
Router.getRouteBefore$ = function (beforeHandler, router) { | ||
return function (routable) { return router | ||
._getRoute$(routable) | ||
.map(function (route) { return route.type === 'action' | ||
? __assign({}, route, { action: function () { return toObservable(beforeHandler(routable)) | ||
.flatMap(function (_) { return toObservable(route.action()); }); } }) : route; }); }; | ||
}; | ||
Router.getRouteAfter$ = function (afterHandler, router) { | ||
return function (routable) { return router | ||
._getRoute$(routable) | ||
.map(function (route) { return route.type === 'action' | ||
? __assign({}, route, { action: function () { return toObservable(route.action()) | ||
.flatMap(function (_) { return toObservable(afterHandler(routable)); }); } }) : route; }); }; | ||
}; | ||
Router.getRouteDefault$ = function (mainRouter, getDefaultRouter) { | ||
return function (routable) { return mainRouter._getRoute$(routable) | ||
.flatMap(function (route) { return route.type === 'action' | ||
? rxjs_1.Observable.of(route) | ||
: toObservable(getDefaultRouter(routable, route.reason)) | ||
.map(Router.toRouter) | ||
.flatMap(function (router) { return router._getRoute$(routable); }); }); }; | ||
}; | ||
Router.getRouteSwitch$ = function (getKey, getMapKeyToRouter) { | ||
return function (routable) { return toObservable(getKey(routable)) | ||
.flatMap(function (key) { return toObservable(getMapKeyToRouter(routable)) | ||
.map(function (mapKeyToRouter) { return mapKeyToRouter[key]; }); }) | ||
.map(Router.toRouter) | ||
.flatMap(function (router) { return router._getRoute$(routable); }); }; | ||
}; | ||
Router.minRoute = Router.actionRoute(function () { | ||
console.warn("BestRouter.minRoute.action should never be called"); | ||
}, 0); | ||
Router.defaultReason = "none"; | ||
return Router; | ||
}()); | ||
exports.Router = Router; | ||
} | ||
throw new Error('A predicate may only return true, false, a Match of true or false, or a NoMatch'); | ||
}); }; | ||
} | ||
exports.predicateToMatcher = predicateToMatcher; | ||
function getRouteIfTrue(predicate, thenGetRoute, elseMapRoute) { | ||
return getRouteIfMatches(predicateToMatcher(predicate), function (value) { return thenGetRoute; }, elseMapRoute); | ||
} | ||
exports.if = getRouteIfTrue; | ||
function map(getRoute, mapper) { | ||
return function (routable) { return rxjs_1.Observable.of(getRoute) | ||
.flatMap(exports.getNormalizedRoute(routable)) | ||
.flatMap(function (route) { return toObservable(mapper(route)); }) | ||
.flatMap(exports.getNormalizedRoute(routable)); }; | ||
} | ||
exports.map = map; | ||
function before(beforeHandler, getRoute) { | ||
return map(getRoute, function (route) { return function (routable) { return isDoRoute(route) | ||
? doRoute(function () { return toObservable(beforeHandler(routable)) | ||
.flatMap(function (_) { return toObservable(route.action()); }); }, route.score) | ||
: route; }; }); | ||
} | ||
exports.before = before; | ||
function after(afterHandler, getRoute) { | ||
return map(getRoute, function (route) { return function (routable) { return isDoRoute(route) | ||
? doRoute(function () { return toObservable(route.action()) | ||
.flatMap(function (_) { return toObservable(afterHandler(routable)); }); }, route.score) | ||
: route; }; }); | ||
} | ||
exports.after = after; | ||
function getRouteDefault(getRoute, defaultMapRoute) { | ||
return map(getRoute, function (route) { return isNoRoute(route) | ||
? defaultMapRoute(route) | ||
: function (routable) { return route; }; }); | ||
} | ||
exports.default = getRouteDefault; | ||
function getRouteSwitch(getKey, mapKeyToGetRoute) { | ||
return getRouteIfMatches(getKey, function (key) { return mapKeyToGetRoute[key]; }); | ||
} | ||
exports.switch = getRouteSwitch; | ||
//# sourceMappingURL=Router.js.map |
@@ -7,3 +7,3 @@ { | ||
}, | ||
"version": "0.16.3", | ||
"version": "0.17.0", | ||
"description": "rules-based app engine", | ||
@@ -10,0 +10,0 @@ "main": "dist/prague.js", |
1366
test/router.js
@@ -6,3 +6,3 @@ "use strict"; | ||
const expect = chai.expect; | ||
const { toObservable, Router } = require('../dist/prague.js'); | ||
const p = require('../dist/prague.js'); | ||
const { Observable } = require('rxjs'); | ||
@@ -37,10 +37,7 @@ | ||
const routerNo = (reason) => new Router(Router.getRouteNo$(reason)); | ||
const routerDo = (handler, score) => new Router(Router.getRouteDo$(handler, score)); | ||
const noop = () => {} | ||
describe('toObservable', () => { | ||
describe('p.toObservable', () => { | ||
it("should convert a number to an observable", (done) => { | ||
toObservable(5) | ||
p.toObservable(5) | ||
.subscribe(n => { | ||
@@ -52,3 +49,3 @@ expect(n).to.eql(5); | ||
it("should convert a string to an observable", (done) => { | ||
toObservable("Prague") | ||
p.toObservable("Prague") | ||
.subscribe(n => { | ||
@@ -60,3 +57,3 @@ expect(n).to.eql("Prague"); | ||
it("should convert an array to an observable", (done) => { | ||
toObservable([1, 2, 3]) | ||
p.toObservable([1, 2, 3]) | ||
.subscribe(n => { | ||
@@ -68,3 +65,3 @@ expect(n).to.eql([1, 2, 3]); | ||
it("should convert a Promise<number> to an observable", (done) => { | ||
toObservable(Promise.resolve(5)) | ||
p.toObservable(Promise.resolve(5)) | ||
.subscribe(n => { | ||
@@ -76,3 +73,3 @@ expect(n).to.eql(5); | ||
it("should convert a Promise<string> to an observable", (done) => { | ||
toObservable(Promise.resolve("Prague")) | ||
p.toObservable(Promise.resolve("Prague")) | ||
.subscribe(n => { | ||
@@ -84,3 +81,3 @@ expect(n).to.eql("Prague"); | ||
it("should convert a Promise<array> to an observable", (done) => { | ||
toObservable(Promise.resolve([1, 2, 3])) | ||
p.toObservable(Promise.resolve([1, 2, 3])) | ||
.subscribe(n => { | ||
@@ -92,3 +89,3 @@ expect(n).to.eql([1, 2, 3]); | ||
it("should convert an Observable<number> to an observable", (done) => { | ||
toObservable(Observable.of(5)) | ||
p.toObservable(Observable.of(5)) | ||
.subscribe(n => { | ||
@@ -100,3 +97,3 @@ expect(n).to.eql(5); | ||
it("should convert an Observable<string> to an observable", (done) => { | ||
toObservable(Observable.of("Prague")) | ||
p.toObservable(Observable.of("Prague")) | ||
.subscribe(n => { | ||
@@ -108,3 +105,3 @@ expect(n).to.eql("Prague"); | ||
it("should convert an Observable<array> to an observable", (done) => { | ||
toObservable(Observable.of([1, 2, 3])) | ||
p.toObservable(Observable.of([1, 2, 3])) | ||
.subscribe(n => { | ||
@@ -116,3 +113,3 @@ expect(n).to.eql([1, 2, 3]); | ||
it("should convert null to an observable", (done) => { | ||
toObservable(null) | ||
p.toObservable(null) | ||
.subscribe(n => { | ||
@@ -124,3 +121,3 @@ expect(n).to.eql(null); | ||
it("should convert undefined to an observable", (done) => { | ||
toObservable(undefined) | ||
p.toObservable(undefined) | ||
.subscribe(n => { | ||
@@ -132,3 +129,3 @@ expect(n).to.eql(undefined); | ||
it("should convert Promise<null> to an observable", (done) => { | ||
toObservable(Promise.resolve(null)) | ||
p.toObservable(Promise.resolve(null)) | ||
.subscribe(n => { | ||
@@ -140,3 +137,3 @@ expect(n).to.eql(null); | ||
it("should convert Promise<undefined> to an observable", (done) => { | ||
toObservable(Promise.resolve(undefined)) | ||
p.toObservable(Promise.resolve(undefined)) | ||
.subscribe(n => { | ||
@@ -148,3 +145,3 @@ expect(n).to.eql(undefined); | ||
it("should convert Observable<null> to an observable", (done) => { | ||
toObservable(Observable.of(null)) | ||
p.toObservable(Observable.of(null)) | ||
.subscribe(n => { | ||
@@ -156,3 +153,3 @@ expect(n).to.eql(null); | ||
it("should convert Observable<undefined> to an observable", (done) => { | ||
toObservable(Observable.of(undefined)) | ||
p.toObservable(Observable.of(undefined)) | ||
.subscribe(n => { | ||
@@ -164,13 +161,12 @@ expect(n).to.eql(undefined); | ||
it("should complete and never emit on Observable.empty()", (done) => { | ||
toObservable(Observable.empty()) | ||
p.toObservable(Observable.empty()) | ||
.subscribe(throwErr, passErr, done); | ||
}); | ||
}); | ||
describe('Router.actionRoute', () => { | ||
it('should create an ActionRoute with supplied action and no score', () => { | ||
describe('p.doRoute', () => { | ||
it('should create an doRoute with supplied action and no score', () => { | ||
let action = () => {}; | ||
let route = Router.actionRoute(action); | ||
expect(route.type).to.eql('action'); | ||
let route = p.doRoute(action); | ||
expect(route.type).to.eql('do'); | ||
expect(route.action).to.eql(action); | ||
@@ -180,6 +176,6 @@ expect(route.score).to.eql(1); | ||
it('should create an ActionRoute with supplied action and score', () => { | ||
it('should create an doRoute with supplied action and score', () => { | ||
let action = () => {}; | ||
let route = Router.actionRoute(action, 0.5); | ||
expect(route.type).to.eql('action'); | ||
let route = p.doRoute(action, 0.5); | ||
expect(route.type).to.eql('do'); | ||
expect(route.action).to.eql(action); | ||
@@ -191,57 +187,44 @@ expect(route.score).to.eql(.5); | ||
describe('router._getRoute$', () => { | ||
it('should return action route', done => { | ||
let theRoute = { | ||
type: 'action', | ||
action: noop | ||
} | ||
new Router(routable => Observable.of(theRoute)) | ||
._getRoute$(foo) | ||
.subscribe(route => { | ||
expect(route).to.eql(theRoute); | ||
}, passErr, done); | ||
describe('p.noRoute', () => { | ||
it('should create a NoRoute with default reason', () => { | ||
let route = p.noRoute(); | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('none'); | ||
expect(route.action).to.be.undefined; | ||
expect(route.score).to.be.undefined; | ||
}); | ||
it('should return no route', done => { | ||
let theRoute = { | ||
type: 'no', | ||
reason: 'reason' | ||
} | ||
new Router(routable => Observable.of(theRoute)) | ||
._getRoute$(foo) | ||
.subscribe(route => { | ||
expect(route).to.eql(theRoute); | ||
}, passErr, done); | ||
it('should create a NoRoute with supplied reason', () => { | ||
let route = p.noRoute('reason'); | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('reason'); | ||
expect(route.action).to.be.undefined; | ||
expect(route.score).to.be.undefined; | ||
}); | ||
}) | ||
}); | ||
describe('Router.getRouteDo$', () => { | ||
it('should return an ActionRoute using supplied handler and no score', (done) => { | ||
let handled; | ||
routerDo(m => { handled = m; }) | ||
._getRoute$(foo) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('action'); | ||
expect(route.score).to.eql(1); | ||
route.action(); | ||
expect(handled).to.eql(foo); | ||
}, passErr, done); | ||
describe('p.normalizeRoute', () => { | ||
it('should normalize undefined', () => { | ||
let route = p.normalizeRoute(undefined); | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('none'); | ||
expect(route.action).to.be.undefined; | ||
expect(route.score).to.be.undefined; | ||
}); | ||
it('should return an ActionRoute using supplied handler and score', (done) => { | ||
let handled; | ||
routerDo(m => { handled = m; }, .5) | ||
._getRoute$(foo) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('action'); | ||
expect(route.score).to.eql(.5); | ||
route.action(); | ||
expect(handled).to.eql(foo); | ||
}, passErr, done); | ||
it('should normalize { reason }', () => { | ||
let route = p.normalizeRoute({ reason: 'reason' }); | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('reason'); | ||
expect(route.action).to.be.undefined; | ||
expect(route.score).to.be.undefined; | ||
}); | ||
}); | ||
describe('Router.noRoute', () => { | ||
it('should create a NoRoute with default reason', () => { | ||
let route = Router.noRoute(); | ||
it('should normalize a noRoute without a reason', () => { | ||
let route = p.normalizeRoute(p.noRoute()); | ||
expect(route.type).to.eql('no'); | ||
@@ -253,4 +236,5 @@ expect(route.reason).to.eql('none'); | ||
it('should create a NoRoute with supplied reason', () => { | ||
let route = Router.noRoute('reason'); | ||
it('should normalize a noRoute with a reason', () => { | ||
let route = p.normalizeRoute(p.noRoute('reason')); | ||
expect(route.type).to.eql('no'); | ||
@@ -261,74 +245,121 @@ expect(route.reason).to.eql('reason'); | ||
}); | ||
it('should normalize an action', () => { | ||
let action = () => {} | ||
let route = p.normalizeRoute(action); | ||
expect(route.type).to.eql('do'); | ||
expect(route.action).to.eql(action); | ||
expect(route.score).to.eql(1); | ||
expect(route.reason).to.be.undefined; | ||
}); | ||
it('should normalize { action }', () => { | ||
let action = () => {} | ||
let route = p.normalizeRoute({ action }); | ||
expect(route.type).to.eql('do'); | ||
expect(route.action).to.eql(action); | ||
expect(route.score).to.eql(1); | ||
expect(route.reason).to.be.undefined; | ||
}); | ||
it('should normalize { action, score }', () => { | ||
let action = () => {} | ||
let route = p.normalizeRoute({ action, score: .5 }); | ||
expect(route.type).to.eql('do'); | ||
expect(route.action).to.eql(action); | ||
expect(route.score).to.eql(.5); | ||
expect(route.reason).to.be.undefined; | ||
}); | ||
it('should normalize a doRoute without a score', () => { | ||
let action = () => {} | ||
let route = p.normalizeRoute(p.doRoute(action)); | ||
expect(route.type).to.eql('do'); | ||
expect(route.action).to.eql(action); | ||
expect(route.score).to.eql(1); | ||
expect(route.reason).to.be.undefined; | ||
}); | ||
it('should normalize a doRoute with a score', () => { | ||
let action = () => {} | ||
let route = p.normalizeRoute(p.doRoute(action, .5)); | ||
expect(route.type).to.eql('do'); | ||
expect(route.action).to.eql(action); | ||
expect(route.score).to.eql(.5); | ||
expect(route.reason).to.be.undefined; | ||
}); | ||
}); | ||
describe('Router.getRouteNo$', () => { | ||
it('should return a NoRoute with the default reason', done => { | ||
routerNo() | ||
._getRoute$(foo) | ||
describe('p.getNormalizedRoute', () => { | ||
it("should treat undefined as NoRoute", (done) => { | ||
Observable | ||
.of(undefined) | ||
.flatMap(p.getNormalizedRoute(foo)) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('none'); | ||
}, passErr, done); | ||
}, passErr, done) | ||
}); | ||
it('should return a NoRoute with the default reason', done => { | ||
routerNo('reason') | ||
._getRoute$(foo) | ||
it("should not route to NoRoute", (done) => { | ||
Observable | ||
.of(p.no('reason')) | ||
.flatMap(p.getNormalizedRoute(foo)) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('reason'); | ||
}, passErr, done); | ||
}, passErr, done) | ||
}); | ||
}); | ||
describe('Router.route$', () => { | ||
it("should return false on when router returns NoRoute", (done) => { | ||
Router.route$(foo, routerNo()) | ||
.subscribe(t => { | ||
expect(t).to.be.false; | ||
}, passErr, done); | ||
it("should route to supplied route", (done) => { | ||
Observable | ||
.of(p.do(c => {}, .5)) | ||
.flatMap(p.getNormalizedRoute(foo)) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('do'); | ||
expect(route.score).to.eql(.5); | ||
}, passErr, done) | ||
}); | ||
it("should return true when router returns ActionRoute", (done) => { | ||
let routed; | ||
it("should route to un-normalized route", (done) => { | ||
let action = () => {}; | ||
Router.route$(foo, routerDo(() => { | ||
routed = true; | ||
})) | ||
.subscribe(t => { | ||
expect(t).to.be.true; | ||
expect(routed).to.be.true; | ||
}, passErr, done); | ||
Observable | ||
.of(c => action) | ||
.flatMap(p.getNormalizedRoute(foo)) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('do'); | ||
expect(route.score).to.eql(1); | ||
expect(route.action).to.eql(action); | ||
}, passErr, done) | ||
}); | ||
}); | ||
describe("Router.getRouteBefore$", () => { | ||
it("should return false with routerNo()", (done) => { | ||
Router.route$(foo, new Router(Router.getRouteBefore$( | ||
throwErr, | ||
routerNo() | ||
)) | ||
) | ||
.subscribe(t => expect(t).to.be.false, passErr, done); | ||
describe('p.do', () => { | ||
it('should return an doRoute using supplied handler and no score', (done) => { | ||
let handled; | ||
p.do(m => { handled = m; }) | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('do'); | ||
expect(route.score).to.eql(1); | ||
route.action(); | ||
expect(handled).to.eql(foo); | ||
}, passErr, done); | ||
}); | ||
it("should run 'before' handler and then router's action", (done) => { | ||
let handled = false; | ||
let routed = false; | ||
Router.route$(foo, new Router(Router.getRouteBefore$( | ||
m => { | ||
expect(routed).to.be.false; | ||
handled = true; | ||
}, | ||
routerDo(m => { | ||
expect(handled).to.be.true; | ||
routed = true; | ||
}) | ||
)) | ||
) | ||
.subscribe(t => { | ||
expect(t).to.be.true; | ||
expect(routed).to.be.true; | ||
it('should return an doRoute using supplied handler and score', (done) => { | ||
let handled; | ||
p.do(m => { handled = m; }, .5) | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('do'); | ||
expect(route.score).to.eql(.5); | ||
route.action(); | ||
expect(handled).to.eql(foo); | ||
}, passErr, done); | ||
@@ -338,31 +369,18 @@ }); | ||
describe("Router.getRouteBefore$", () => { | ||
it("should return false with routerNo()", (done) => { | ||
Router.route$(foo, new Router(Router.getRouteAfter$( | ||
throwErr, | ||
routerNo() | ||
)) | ||
) | ||
.subscribe(t => expect(t).to.be.false, passErr, done); | ||
describe('p.no', () => { | ||
it('should return a NoRoute with the default reason', done => { | ||
p.no() | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('none'); | ||
}, passErr, done); | ||
}); | ||
it("should run 'after' handler and then router's action", (done) => { | ||
let handled = false; | ||
let routed = false; | ||
Router.route$(foo, new Router(Router.getRouteAfter$( | ||
m => { | ||
expect(routed).to.be.true; | ||
handled = true; | ||
}, | ||
routerDo(m => { | ||
expect(handled).to.be.false; | ||
routed = true; | ||
}) | ||
)) | ||
) | ||
.subscribe(t => { | ||
expect(t).to.be.true; | ||
expect(handled).to.be.true; | ||
it('should return a NoRoute with the supplied reason', done => { | ||
p.no('reason') | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('reason'); | ||
}, passErr, done); | ||
@@ -372,48 +390,26 @@ }); | ||
describe("Router.getRouteDefault$", () => { | ||
it("should not be run when main router returns an action route", (done) => { | ||
let routed; | ||
Router.route$(foo, new Router(Router.getRouteDefault$( | ||
routerDo(m => { | ||
routed = true; | ||
}), | ||
reason => routerDo(throwErr) | ||
)) | ||
) | ||
.subscribe(n => { | ||
expect(routed).to.be.true; | ||
describe('p.route$', () => { | ||
it("should return false on NoRoute", (done) => { | ||
p.route$(foo, p.no()) | ||
.subscribe(t => { | ||
expect(t).to.be.false; | ||
}, passErr, done); | ||
}); | ||
it("should be run when router returns no route", (done) => { | ||
let handled; | ||
it("should return true on DoRoute", (done) => { | ||
let routed; | ||
Router.route$(foo, new Router(Router.getRouteDefault$( | ||
routerNo(), | ||
reason => routerDo(m => { | ||
handled = true; | ||
}) | ||
)) | ||
) | ||
.subscribe(n => { | ||
expect(handled).to.be.true; | ||
p.route$(foo, p.do(() => { | ||
routed = true; | ||
})) | ||
.subscribe(t => { | ||
expect(t).to.be.true; | ||
expect(routed).to.be.true; | ||
}, passErr, done); | ||
}); | ||
it('should allow undefined result for getDefaultRouter', (done) =>{ | ||
new Router(Router.getRouteDefault$( | ||
routerNo(), | ||
() => undefined | ||
)) | ||
._getRoute$(foo) | ||
.subscribe(route => { | ||
expect(route.type).to.eql('no') | ||
}, passErr, done); | ||
}); | ||
}); | ||
describe('Router.getRouteFirst$', () => { | ||
describe('p.first', () => { | ||
it('should return false on no routers', (done) => | ||
Router.route$(foo, new Router(Router.getRouteFirst$())) | ||
p.route$(foo, p.first()) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -423,6 +419,6 @@ ); | ||
it('should return false on only null/undefined routers', (done) => | ||
Router.route$(foo, new Router(Router.getRouteFirst$( | ||
p.route$(foo, p.first( | ||
null, | ||
undefined | ||
))) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -432,7 +428,7 @@ ); | ||
it('should return false on only unsuccessful and null/undefined routers', (done) => | ||
Router.route$(foo, new Router(Router.getRouteFirst$( | ||
() => routerNo(), | ||
p.route$(foo, p.first( | ||
p.no(), | ||
null, | ||
undefined | ||
))) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -442,5 +438,5 @@ ); | ||
it('should return false on no successful routers', (done) => { | ||
Router.route$(foo, new Router(Router.getRouteFirst$( | ||
() => routerNo() | ||
))) | ||
p.route$(foo, p.first( | ||
p.no() | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -452,7 +448,7 @@ }); | ||
Router.route$(foo, new Router(Router.getRouteFirst$( | ||
() => routerDo(m => { | ||
p.route$(foo, p.first( | ||
p.do(m => { | ||
routed = true; | ||
}) | ||
))) | ||
)) | ||
.subscribe(t => { | ||
@@ -467,9 +463,9 @@ expect(t).to.be.true; | ||
Router.route$(foo, new Router(Router.getRouteFirst$( | ||
p.route$(foo, p.first( | ||
null, | ||
undefined, | ||
() => routerDo(m => { | ||
p.do(m => { | ||
routed = true; | ||
}) | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -483,8 +479,8 @@ expect(routed).to.be.true; | ||
Router.route$(foo, new Router(Router.getRouteFirst$( | ||
() => routerNo(), | ||
() => routerDo(m => { | ||
p.route$(foo, p.first( | ||
p.no(), | ||
p.do(m => { | ||
routed = true; | ||
}) | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -496,5 +492,27 @@ expect(routed).to.be.true; | ||
describe('tryInScoreOrder', () => { | ||
describe('p.combineScore', () => { | ||
it("should return combined score", () => { | ||
expect(p.combinedScore(.4, .25)).to.eql(.1); | ||
}); | ||
}) | ||
describe('p.routeWithCombinedScore', () => { | ||
it("should return route with combined score", () => { | ||
expect(p.routeWithCombinedScore( | ||
p.doRoute(() => {}, .4), | ||
.25 | ||
).score).to.eql(.1); | ||
}); | ||
}) | ||
describe('p.minRoute', () => { | ||
it("should have a zero score", () => { | ||
let route = p.minRoute; | ||
expect(route.score).to.eql(0); | ||
}); | ||
}) | ||
describe('p.best', () => { | ||
it('should return false on no routers', (done) => | ||
Router.route$(foo, new Router(Router.getRouteBest$())) | ||
p.route$(foo, p.best()) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -504,6 +522,6 @@ ); | ||
it('should return false on only null/undefined routers', (done) => | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
p.route$(foo, p.best( | ||
null, | ||
undefined | ||
))) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -513,7 +531,7 @@ ); | ||
it('should return false on only unsuccessful and null/undefined routers', (done) => | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerNo(), | ||
p.route$(foo, p.best( | ||
p.no(), | ||
null, | ||
undefined | ||
))) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -523,5 +541,5 @@ ); | ||
it('should return false on no successful routers', (done) => { | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerNo() | ||
))) | ||
p.route$(foo, p.best( | ||
p.no() | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -533,7 +551,7 @@ }); | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerDo(m => { | ||
p.route$(foo, p.best( | ||
p.do(m => { | ||
routed = true; | ||
}) | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -547,9 +565,9 @@ expect(routed).to.be.true; | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
p.route$(foo, p.best( | ||
null, | ||
undefined, | ||
() => routerDo(m => { | ||
p.do(m => { | ||
routed = true; | ||
}) | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -563,8 +581,8 @@ expect(routed).to.be.true; | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerNo(), | ||
() => routerDo(m => { | ||
p.route$(foo, p.best( | ||
p.no(), | ||
p.do(m => { | ||
routed = true; | ||
}) | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -578,8 +596,8 @@ expect(routed).to.be.true; | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerDo(m => { | ||
p.route$(foo, p.best( | ||
p.do(m => { | ||
routed = true; | ||
}), | ||
throwErr | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -593,6 +611,6 @@ expect(routed).to.be.true; | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerDo(_ => { routed = 'first'; }, 0.75), | ||
() => routerDo(_ => { routed = 'second'; }, 0.50) | ||
))) | ||
p.route$(foo, p.best( | ||
p.do(_ => { routed = 'first'; }, 0.75), | ||
p.do(_ => { routed = 'second'; }, 0.50) | ||
)) | ||
.subscribe(n => { | ||
@@ -606,6 +624,6 @@ expect(routed).to.eql('first'); | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerDo(_ => { routed = 'first'; }, .5), | ||
() => routerDo(_ => { routed = 'second'; }, .75) | ||
))) | ||
p.route$(foo, p.best( | ||
p.do(_ => { routed = 'first'; }, .5), | ||
p.do(_ => { routed = 'second'; }, .75) | ||
)) | ||
.subscribe(n => { | ||
@@ -619,6 +637,6 @@ expect(routed).to.eql('second'); | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerDo(_ => { routed = 'first'; }), | ||
() => routerDo(_ => { routed = 'second'; }, .75) | ||
))) | ||
p.route$(foo, p.best( | ||
p.do(_ => { routed = 'first'; }), | ||
p.do(_ => { routed = 'second'; }, .75) | ||
)) | ||
.subscribe(n => { | ||
@@ -632,6 +650,6 @@ expect(routed).to.eql('first'); | ||
Router.route$(foo, new Router(Router.getRouteBest$( | ||
() => routerDo(_ => { routed = 'first'; }, 0.75), | ||
() => routerDo(_ => { routed = 'second'; }, 0.75) | ||
))) | ||
p.route$(foo, p.best( | ||
p.do(_ => { routed = 'first'; }, 0.75), | ||
p.do(_ => { routed = 'second'; }, 0.75) | ||
)) | ||
.subscribe(n => { | ||
@@ -643,11 +661,11 @@ expect(routed).to.eql('first'); | ||
describe('Router.noop', () => { | ||
describe('p.noop', () => { | ||
it("should execute the handler and return false", (done) => { | ||
let routed; | ||
Router.route$(foo, new Router(Router.getRouteNoop$( | ||
p.route$(foo, p.noop( | ||
m => { | ||
routed = true; | ||
} | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -660,17 +678,344 @@ expect(n).to.be.false; | ||
describe('Router.routeWithCombinedScore', () => { | ||
it("should return combined score", () => { | ||
expect(Router.routeWithCombinedScore( | ||
Router.actionRoute(() => {}, .4), | ||
.25 | ||
).score).to.eql(.1); | ||
describe('p.isMatch', () => { | ||
it("return true on a match", () => { | ||
expect(p.isMatch({ value: 15 })).to.be.true; | ||
}); | ||
}) | ||
describe('ifTrue', () => { | ||
it("return false on no match", () => { | ||
expect(p.isMatch({ reason: 'yo' })).to.be.false; | ||
}); | ||
}); | ||
describe('p.getNormalizedMatchResult$', (done) => { | ||
it("normalizes undefined", () => { | ||
p | ||
.getNormalizedMatchResult$(m => undefined) | ||
.subscribe(match => { | ||
expect(match.value).to.be.undefined; | ||
expect(match.reason).to.eql('none'); | ||
}, passErr, done); | ||
}); | ||
it("normalizes false", () => { | ||
p | ||
.getNormalizedMatchResult$(m => undefined) | ||
.subscribe(match => { | ||
expect(match.value).to.be.undefined; | ||
expect(match.reason).to.eql('none'); | ||
}, passErr, done); | ||
}); | ||
it("normalizes null", () => { | ||
p | ||
.getNormalizedMatchResult$(m => undefined) | ||
.subscribe(match => { | ||
expect(match.value).to.be.undefined; | ||
expect(match.reason).to.eql('none'); | ||
}, passErr, done); | ||
}); | ||
it("normalizes { reason }", () => { | ||
p | ||
.getNormalizedMatchResult$(m => ({ reason: 'reason' })) | ||
.subscribe(match => { | ||
expect(match.reason).to.eql('reason'); | ||
expect(match.value).to.be.undefined; | ||
}, passErr, done); | ||
}); | ||
it("normalizes number", () => { | ||
p | ||
.getNormalizedMatchResult$(m => 15) | ||
.subscribe(match => { | ||
expect(match.value).to.eql(15); | ||
expect(match.score).to.eql(1); | ||
expect(match.reason).to.be.undefined; | ||
}, passErr, done); | ||
}); | ||
it("normalizes object", () => { | ||
p | ||
.getNormalizedMatchResult$(m => ({ dog: 15 })) | ||
.subscribe(match => { | ||
expect(match.value.dog).to.eql(15); | ||
expect(match.reason).to.be.undefined; | ||
}, passErr, done); | ||
}); | ||
it("normalizes { value }", () => { | ||
p | ||
.getNormalizedMatchResult$(m => ({ | ||
value: 15 | ||
})) | ||
.subscribe(match => { | ||
expect(match.value).to.eql(15); | ||
expect(match.score).to.eql(1); | ||
expect(match.reason).to.be.undefined; | ||
}, passErr, done); | ||
}); | ||
it("normalizes { value, score }", () => { | ||
p | ||
.getNormalizedMatchResult$(m => ({ | ||
value: 15, | ||
score: .5 | ||
})) | ||
.subscribe(match => { | ||
expect(match.value).to.eql(15); | ||
expect(match.score).to.eql(.5); | ||
expect(match.reason).to.be.undefined; | ||
}, passErr, done); | ||
}); | ||
}); | ||
describe('p.ifGet', () => { | ||
it("should return false on no match when 'else' router doesn't exist", (done) => | ||
p.route$(notFoo, p.ifGet( | ||
barIfFoo, | ||
value => p.do(throwErr) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
); | ||
it("should return false on no match when 'else' router doesn't exist", (done) => | ||
p.route$(notFoo, p.ifGet( | ||
barIfFoo, | ||
value => p.do(throwErr) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
); | ||
it("should return false on no match when 'else' router doesn't route", (done) => | ||
p.route$(notFoo, p.ifGet( | ||
barIfFoo, | ||
value => p.do(throwErr), | ||
route => p.no() | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
); | ||
it("should return false on match when 'if' router doesn't route and 'else' router exists", (done) => | ||
p.route$(foo, p.ifGet( | ||
barIfFoo, | ||
value => p.no(), | ||
route => p.do(throwErr) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
); | ||
it("should route message to 'if' handler on match when 'else' router doesn't exist", (done) => { | ||
let routed; | ||
p.route$(foo, p.ifGet( | ||
barIfFoo, | ||
value => p.do(m => { | ||
routed = true; | ||
}) | ||
)) | ||
.subscribe(n => { | ||
expect(routed).to.be.true; | ||
}, passErr, done); | ||
}); | ||
it("should route message to 'if' handler on match when 'else' router exists", (done) => { | ||
let routed; | ||
p.route$(foo, p.ifGet( | ||
barIfFoo, | ||
value => p.do(m => { | ||
routed = true; | ||
}), | ||
route => p.do(throwErr) | ||
)) | ||
.subscribe(n => { | ||
expect(routed).to.be.true; | ||
}, passErr, done); | ||
}); | ||
it("should route message to 'else' handler on no match", (done) => { | ||
let routed; | ||
p.route$(notFoo, p.ifGet( | ||
barIfFoo, | ||
value => p.do(throwErr), | ||
route => p.do(m => { | ||
routed = true; | ||
}) | ||
)) | ||
.subscribe(n => { | ||
expect(routed).to.be.true; | ||
}, passErr, done); | ||
}); | ||
it("should route message to 'else' router on no match", (done) => { | ||
let routed; | ||
p.route$(notFoo, p.ifGet( | ||
c => ({ reason: 'reason' }), | ||
value => p.do(throwErr), | ||
route => p.do(m => { | ||
routed = route.reason; | ||
}) | ||
)) | ||
.subscribe(n => { | ||
expect(routed).to.eql('reason'); | ||
}, passErr, done); | ||
}); | ||
it("should pass value to 'then' router on match", (done) => { | ||
let routed; | ||
p.route$(foo, p.ifGet( | ||
c => ({ value: 'value' }), | ||
value => p.do(c => { | ||
routed = value; | ||
}), | ||
route => p.do(throwErr) | ||
)) | ||
.subscribe(n => { | ||
expect(routed).to.eql('value'); | ||
}, passErr, done); | ||
}); | ||
it("should pass value to 'then' handler on match", (done) => { | ||
let routed; | ||
p.route$(foo, p.ifGet( | ||
c => ({ value: 'value' }), | ||
value => p.do(() => { | ||
routed = value; | ||
}), | ||
route => p.do(throwErr) | ||
)) | ||
.subscribe(n => { | ||
expect(routed).to.eql('value'); | ||
}, passErr, done); | ||
}); | ||
it("should return score=1 when score not supplied", (done) => { | ||
p.ifGet( | ||
barIfFoo, | ||
value => p.do(m => {}) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(1); | ||
done(); | ||
}) | ||
}); | ||
it("should return supplied score", (done) => { | ||
p.ifGet( | ||
m => ({ value: 'dog', score: 0.4 }), | ||
value => p.do(m => {}) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(.4); | ||
}, passErr, done); | ||
}); | ||
it("should pass supplied value to handler", (done) => { | ||
let handled; | ||
p.route$(foo, p.ifGet( | ||
m => ({ value: 'dog' }), | ||
value => p.do(() => { | ||
handled = value; | ||
}) | ||
)) | ||
.subscribe(_ => { | ||
expect(handled).to.eql('dog'); | ||
}, passErr, done); | ||
}); | ||
it("should return combined score when route score supplied", (done) => { | ||
p.ifGet( | ||
barIfFoo, | ||
value => p.do(() => {}, .25) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(.25); | ||
}, passErr, done); | ||
}); | ||
it("should return combined score when both scores supplied", (done) => { | ||
p.ifGet( | ||
m => ({ value: 'cat', score: 0.4 }), | ||
value => p.do(() => {}, .25) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(.1); | ||
}, passErr, done); | ||
}); | ||
it("should return 'else' route score on no match", (done) => { | ||
p.ifGet( | ||
barIfFoo, | ||
value => p.do(throwErr), | ||
route => p.do(() => {}, .5) | ||
) | ||
(notFoo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(.5); | ||
}, passErr, done); | ||
}); | ||
}); | ||
describe("p.predicateToMatcher", () => { | ||
it("should pass through true", (done) => { | ||
p.predicateToMatcher(m => true) | ||
(foo) | ||
.subscribe(response => { | ||
expect(response).to.be.true; | ||
}, passErr, done); | ||
}); | ||
it("should pass through true", (done) => { | ||
p.predicateToMatcher(m => false) | ||
(foo) | ||
.subscribe(response => { | ||
expect(response).to.be.false; | ||
}, passErr, done); | ||
}); | ||
it("should throw on object", (done) => { | ||
p.predicateToMatcher(m => ({ dog: "reason"})) | ||
(foo) | ||
.subscribe(throwErr, error => done(), throwErr); | ||
}); | ||
it("should throw on number", (done) => { | ||
p.predicateToMatcher(m => 15) | ||
(foo) | ||
.subscribe(throwErr, error => done(), throwErr); | ||
}); | ||
it("should pass through { value: true }", (done) => { | ||
p.predicateToMatcher(m => ({ value: true })) | ||
(foo) | ||
.subscribe(response => { | ||
expect(response.value).to.be.true; | ||
}, passErr, done); | ||
}); | ||
it("should treat { value: false } as false", (done) => { | ||
p.predicateToMatcher(m => ({ value: false })) | ||
(foo) | ||
.subscribe(response => { | ||
expect(response).to.be.false; | ||
}, passErr, done); | ||
}); | ||
}); | ||
describe('p.if', () => { | ||
it("should return false on false when 'else' router doesn't exist", (done) => | ||
Router.route$(foo, new Router(Router.getRouteIfTrue$( | ||
p.route$(foo, p.if( | ||
m => false, | ||
() => routerDo(throwErr) | ||
))) | ||
p.do(throwErr) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -680,7 +1025,7 @@ ); | ||
it("should return false on false when 'else' router doesn't route", (done) => | ||
Router.route$(foo, new Router(Router.getRouteIfTrue$( | ||
p.route$(foo, p.if( | ||
m => false, | ||
() => routerDo(throwErr), | ||
() => routerNo() | ||
))) | ||
p.do(throwErr), | ||
route => p.no() | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -690,6 +1035,6 @@ ); | ||
it("should return false on true when 'if' router doesn't route and 'else' router doesn't exist", (done) => | ||
Router.route$(foo, new Router(Router.getRouteIfTrue$( | ||
p.route$(foo, p.if( | ||
m => true, | ||
() => routerNo() | ||
))) | ||
p.no() | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -699,7 +1044,7 @@ ); | ||
it("should return false on true when 'if' router doesn't route and 'else' router exists", (done) => | ||
Router.route$(foo, new Router(Router.getRouteIfTrue$( | ||
p.route$(foo, p.if( | ||
m => true, | ||
() => routerNo(), | ||
() => routerDo(throwErr) | ||
))) | ||
p.no(), | ||
route => p.do(throwErr) | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
@@ -711,8 +1056,8 @@ ); | ||
Router.route$(foo, new Router(Router.getRouteIfTrue$( | ||
p.route$(foo, p.if( | ||
m => true, | ||
() => routerDo(m => { | ||
p.do(m => { | ||
routed = true; | ||
}) | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -726,9 +1071,9 @@ expect(routed).to.be.true; | ||
Router.route$(foo, new Router(Router.getRouteIfTrue$( | ||
p.route$(foo, p.if( | ||
m => true, | ||
() => routerDo(m => { | ||
p.do(m => { | ||
routed = true; | ||
}), | ||
() => routerDo(throwErr) | ||
))) | ||
route => p.do(throwErr) | ||
)) | ||
.subscribe(n => { | ||
@@ -742,9 +1087,9 @@ expect(routed).to.be.true; | ||
Router.route$(foo, new Router(Router.getRouteIfTrue$( | ||
p.route$(foo, p.if( | ||
m => false, | ||
() => routerDo(throwErr), | ||
() => routerDo(m => { | ||
p.do(throwErr), | ||
route => p.do(m => { | ||
routed = true; | ||
}) | ||
))) | ||
)) | ||
.subscribe(n => { | ||
@@ -756,7 +1101,7 @@ expect(routed).to.be.true; | ||
it("should return score=1 on true predicate when 'if' score undefined", (done) => { | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => true, | ||
() => routerDo(m => {}) | ||
)) | ||
._getRoute$(foo) | ||
p.do(m => {}) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -768,7 +1113,7 @@ expect(route.score).to.eql(1); | ||
it("should return route score on true predicate", (done) => { | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => true, | ||
() => routerDo(() => {}, 0.25) | ||
)) | ||
._getRoute$(foo) | ||
p.do(() => {}, 0.25) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -780,8 +1125,8 @@ expect(route.score).to.eql(.25); | ||
it("should return score=1 on false predicate when 'else' score undefined", (done) => { | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => false, | ||
() => routernDo(throwErr), | ||
() => routerDo(m => {}) | ||
)) | ||
._getRoute$(foo) | ||
p.do(throwErr), | ||
route => p.do(m => {}) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -793,8 +1138,8 @@ expect(route.score).to.eql(1); | ||
it("should return 'else' route score on false predicate", (done) => { | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => false, | ||
() => routerDo(throwErr), | ||
() => routerDo(_ => {}, .5) | ||
)) | ||
._getRoute$(foo) | ||
p.do(throwErr), | ||
route => p.do(_ => {}, .5) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -806,7 +1151,7 @@ expect(route.score).to.eql(.5); | ||
it("should throw on string", (done) => { | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => 'foo', | ||
() => routerDo(throwErr) | ||
)) | ||
._getRoute$(foo) | ||
p.do(throwErr) | ||
) | ||
(foo) | ||
.subscribe(throwErr, error => { | ||
@@ -818,7 +1163,7 @@ done(); | ||
it("should throw on object", (done) => { | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => ({ foo: "foo" }), | ||
() => routerDo(throwErr) | ||
)) | ||
._getRoute$(foo) | ||
p.do(throwErr) | ||
) | ||
(foo) | ||
.subscribe(throwErr, error => { | ||
@@ -830,7 +1175,7 @@ done(); | ||
it("should return a default reason on false", (done) => { | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => false, | ||
() => routerDo(throwErr) | ||
)) | ||
._getRoute$(foo) | ||
p.do(throwErr) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -843,12 +1188,12 @@ expect(route.reason).to.eql("none"); | ||
let routed; | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => ({ reason: 'whatevs' }), | ||
() => routerDo(throwErr), | ||
(_, reason) => routerDo(m => { | ||
routed = reason; | ||
p.do(throwErr), | ||
route => p.do(m => { | ||
routed = route.reason; | ||
}) | ||
)) | ||
._getRoute$(foo) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.type === 'action'); | ||
expect(route.type === 'do'); | ||
route.action(); | ||
@@ -860,7 +1205,7 @@ expect(routed).to.eql("whatevs"); | ||
it("should return supplied reason when 'else' router not supplied", (done) => { | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => ({ reason: 'whatevs' }), | ||
() => routerDo(throwErr) | ||
)) | ||
._getRoute$(foo) | ||
p.do(throwErr) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -875,7 +1220,7 @@ expect(route.type).to.eql('no'); | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => ({ value: true, score: .5 }), | ||
() => routerDo(m => { handled = true; }) | ||
)) | ||
._getRoute$(foo) | ||
p.do(m => { handled = true; }) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -891,7 +1236,7 @@ route.action(); | ||
new Router(Router.getRouteIfTrue$( | ||
p.if( | ||
m => ({ value: false }), | ||
() => routerDo(throwErr) | ||
)) | ||
._getRoute$(foo) | ||
p.do(throwErr) | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -903,7 +1248,7 @@ expect(route.type).to.eql('no') | ||
it('should allow undefined result for getThenRouter', (done) =>{ | ||
new Router(Router.getRouteIfMatches$( | ||
p.if( | ||
c => true, | ||
() => undefined | ||
)) | ||
._getRoute$(foo) | ||
undefined | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -915,8 +1260,8 @@ expect(route.type).to.eql('no') | ||
it('should allow undefined result for getElseRouter', (done) =>{ | ||
new Router(Router.getRouteIfMatches$( | ||
p.if( | ||
c => false, | ||
throwErr, | ||
() => undefined | ||
)) | ||
._getRoute$(foo) | ||
route => undefined | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
@@ -929,195 +1274,104 @@ expect(route.type).to.eql('no') | ||
describe('ifMatches', () => { | ||
it("should return false on no match when 'else' router doesn't exist", (done) => | ||
Router.route$(notFoo, new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerDo(throwErr) | ||
))) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
); | ||
describe("p.before", () => { | ||
it("should return false with NoRoute", (done) => { | ||
p.route$(foo, p.before( | ||
throwErr, | ||
p.no() | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done); | ||
}); | ||
it("should return false on no match when 'else' router doesn't exist", (done) => | ||
Router.route$(notFoo, new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerDo(throwErr) | ||
))) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
); | ||
it("should return false on no match when 'else' router doesn't route", (done) => | ||
Router.route$(notFoo, new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerDo(throwErr), | ||
() => routerNo() | ||
))) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
); | ||
it("should return false on match when 'if' router doesn't route and 'else' router exists", (done) => | ||
Router.route$(foo, new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerNo(), | ||
() => routerDo(throwErr) | ||
))) | ||
.subscribe(t => expect(t).to.be.false, passErr, done) | ||
); | ||
it("should route message to 'if' handler on match when 'else' router doesn't exist", (done) => { | ||
let routed; | ||
Router.route$(foo, new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerDo(m => { | ||
it("should run 'before' handler and then router's action", (done) => { | ||
let handled = false; | ||
let routed = false; | ||
p.route$(foo, p.before( | ||
m => { | ||
expect(routed).to.be.false; | ||
handled = true; | ||
}, | ||
p.do(m => { | ||
expect(handled).to.be.true; | ||
routed = true; | ||
}) | ||
))) | ||
.subscribe(n => { | ||
)) | ||
.subscribe(t => { | ||
expect(t).to.be.true; | ||
expect(routed).to.be.true; | ||
}, passErr, done); | ||
}); | ||
}); | ||
it("should route message to 'if' handler on match when 'else' router exists", (done) => { | ||
let routed; | ||
Router.route$(foo, new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
()=> routerDo(m => { | ||
routed = true; | ||
}), | ||
() => routerDo(throwErr) | ||
))) | ||
.subscribe(n => { | ||
expect(routed).to.be.true; | ||
}, passErr, done); | ||
describe("p.before", () => { | ||
it("should return false with NoRoute", (done) => { | ||
p.route$(foo, p.after( | ||
throwErr, | ||
p.no() | ||
)) | ||
.subscribe(t => expect(t).to.be.false, passErr, done); | ||
}); | ||
it("should route message to 'else' handler on no match", (done) => { | ||
let routed; | ||
Router.route$(notFoo, new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerDo(throwErr), | ||
() => routerDo(m => { | ||
it("should run 'after' handler and then router's action", (done) => { | ||
let handled = false; | ||
let routed = false; | ||
p.route$(foo, p.after( | ||
m => { | ||
expect(routed).to.be.true; | ||
handled = true; | ||
}, | ||
p.do(m => { | ||
expect(handled).to.be.false; | ||
routed = true; | ||
}) | ||
))) | ||
.subscribe(n => { | ||
expect(routed).to.be.true; | ||
)) | ||
.subscribe(t => { | ||
expect(t).to.be.true; | ||
expect(handled).to.be.true; | ||
}, passErr, done); | ||
}); | ||
}); | ||
it("should route message to 'else' router on no match", (done) => { | ||
describe("p.default", () => { | ||
it("should not be run when main router returns an action route", (done) => { | ||
let routed; | ||
Router.route$(notFoo, new Router(Router.getRouteIfMatches$( | ||
c => ({ reason: 'reason' }), | ||
() => routerDo(throwErr), | ||
(c, reason) => routerDo(m => { | ||
routed = reason; | ||
}) | ||
))) | ||
.subscribe(n => { | ||
expect(routed).to.eql('reason'); | ||
}, passErr, done); | ||
}); | ||
it("should pass value to 'then' router on match", (done) => { | ||
let routed; | ||
Router.route$(foo, new Router(Router.getRouteIfMatches$( | ||
c => ({ value: 'value' }), | ||
(_, value) => routerDo(c => { | ||
routed = value; | ||
p.route$(foo, p.default( | ||
p.do(m => { | ||
routed = true; | ||
}), | ||
() => routerDo(throwErr) | ||
))) | ||
reason => p.do(throwErr) | ||
)) | ||
.subscribe(n => { | ||
expect(routed).to.eql('value'); | ||
expect(routed).to.be.true; | ||
}, passErr, done); | ||
}); | ||
it("should pass value to 'then' handler on match", (done) => { | ||
let routed; | ||
it("should be run when router returns no route", (done) => { | ||
let handled; | ||
Router.route$(foo, new Router(Router.getRouteIfMatches$( | ||
c => ({ value: 'value' }), | ||
(c, value) => routerDo(() => { | ||
routed = value; | ||
}), | ||
() => routerDo(throwErr) | ||
))) | ||
.subscribe(n => { | ||
expect(routed).to.eql('value'); | ||
}, passErr, done); | ||
}); | ||
it("should return score=1 when score not supplied", (done) => { | ||
new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerDo(m => {}) | ||
)) | ||
._getRoute$(foo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(1); | ||
done(); | ||
p.route$(foo, p.default( | ||
p.no('reason'), | ||
route => p.do(m => { | ||
handled = route.reason; | ||
}) | ||
}); | ||
it("should return supplied score", (done) => { | ||
new Router(Router.getRouteIfMatches$( | ||
m => ({ value: 'dog', score: 0.4 }), | ||
() => routerDo(m => {}) | ||
)) | ||
._getRoute$(foo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(.4); | ||
.subscribe(n => { | ||
expect(handled).to.eql('reason'); | ||
}, passErr, done); | ||
}); | ||
it("should pass supplied value to handler", (done) => { | ||
let handled; | ||
Router.route$(foo, new Router(Router.getRouteIfMatches$( | ||
m => ({ value: 'dog' }), | ||
(m, value) => routerDo(() => { | ||
handled = value; | ||
}) | ||
))) | ||
.subscribe(_ => { | ||
expect(handled).to.eql('dog'); | ||
}, passErr, done); | ||
}); | ||
it("should return combined score when route score supplied", (done) => { | ||
new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerDo(() => {}, .25) | ||
)) | ||
._getRoute$(foo) | ||
it('should allow undefined result for getDefaultRouter', (done) =>{ | ||
p.default( | ||
p.no('reason'), | ||
route => undefined | ||
) | ||
(foo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(.25); | ||
expect(route.type).to.eql('no'); | ||
expect(route.reason).to.eql('none'); | ||
}, passErr, done); | ||
}); | ||
it("should return combined score when both scores supplied", (done) => { | ||
new Router(Router.getRouteIfMatches$( | ||
m => ({ value: 'cat', score: 0.4 }), | ||
() => routerDo(() => {}, .25) | ||
)) | ||
._getRoute$(foo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(.1); | ||
}, passErr, done); | ||
}); | ||
it("should return 'else' route score on no match", (done) => { | ||
new Router(Router.getRouteIfMatches$( | ||
barIfFoo, | ||
() => routerDo(throwErr), | ||
() => routerDo(() => {}, .5) | ||
)) | ||
._getRoute$(notFoo) | ||
.subscribe(route => { | ||
expect(route.score).to.eql(.5); | ||
}, passErr, done); | ||
}); | ||
}); | ||
@@ -1127,4 +1381,4 @@ | ||
it("should pass through no route", (done) => | ||
Router.route$(foo, routerDo(c => | ||
Router.route$(c, routerNo()) | ||
p.route$(foo, p.do(c => | ||
p.route$(c, p.no()) | ||
)) | ||
@@ -1137,4 +1391,4 @@ .subscribe(t => expect(t).to.be.true, passErr, done) | ||
Router.route$(foo, routerDo(c => | ||
Router.route$(c, routerDo(c => { | ||
p.route$(foo, p.do(c => | ||
p.route$(c, p.do(c => { | ||
handled = true; | ||
@@ -1150,7 +1404,9 @@ })) | ||
describe('trySwitch', () => { | ||
describe('p.switch', () => { | ||
it("doesn't route on undefined key", done => { | ||
Router.route$(foo, new Router(Router.getRouteSwitch$(c => undefined, () => ({ | ||
foo: routerDo(throwErr) | ||
})))) | ||
p.route$(foo, p.switch( | ||
c => undefined, { | ||
foo: p.do(throwErr) | ||
} | ||
)) | ||
.subscribe(t => { | ||
@@ -1162,5 +1418,7 @@ expect(t).to.be.false; | ||
it("doesn't route on null key", done => { | ||
Router.route$(foo, new Router(Router.getRouteSwitch$(c => undefined, () => ({ | ||
foo: routerDo(throwErr) | ||
})))) | ||
p.route$(foo, p.switch( | ||
c => undefined, { | ||
foo: p.do(throwErr) | ||
} | ||
)) | ||
.subscribe(t => { | ||
@@ -1172,5 +1430,7 @@ expect(t).to.be.false; | ||
it("doesn't route on non-matching key", done => { | ||
Router.route$(foo, new Router(Router.getRouteSwitch$(c => 'bar', () => ({ | ||
foo: routerDo(throwErr) | ||
})))) | ||
p.route$(foo, p.switch( | ||
c => 'bar', { | ||
foo: p.do(throwErr) | ||
} | ||
)) | ||
.subscribe(t => { | ||
@@ -1183,7 +1443,9 @@ expect(t).to.be.false; | ||
let routed = false; | ||
Router.route$(foo, new Router(Router.getRouteSwitch$(c => 'foo', () => ({ | ||
foo: routerDo(c => { | ||
routed = true; | ||
}), | ||
})))) | ||
p.route$(foo, p.switch( | ||
c => 'foo', { | ||
foo: p.do(c => { | ||
routed = true; | ||
}), | ||
} | ||
)) | ||
.subscribe(t => { | ||
@@ -1197,8 +1459,10 @@ expect(t).to.be.true; | ||
let routed = false; | ||
Router.route$(foo, new Router(Router.getRouteSwitch$(c => 'foo', () => ({ | ||
foo: routerDo(c => { | ||
routed = true; | ||
}), | ||
bar: routerDo(throwErr) | ||
})))) | ||
p.route$(foo, p.switch( | ||
c => 'foo', { | ||
foo: p.do(c => { | ||
routed = true; | ||
}), | ||
bar: p.do(throwErr) | ||
} | ||
)) | ||
.subscribe(t => { | ||
@@ -1212,8 +1476,10 @@ expect(t).to.be.true; | ||
let routed = false; | ||
Router.route$(foo, new Router(Router.getRouteSwitch$(c => 'foo', () => ({ | ||
bar: routerDo(throwErr), | ||
foo: routerDo(c => { | ||
routed = true; | ||
}) | ||
})))) | ||
p.route$(foo, p.switch( | ||
c => 'foo', { | ||
bar: p.do(throwErr), | ||
foo: p.do(c => { | ||
routed = true; | ||
}) | ||
} | ||
)) | ||
.subscribe(t => { | ||
@@ -1226,5 +1492,7 @@ expect(t).to.be.true; | ||
it("doesn't route when router for key doesn't route", done => { | ||
Router.route$(foo, new Router(Router.getRouteSwitch$(c => 'foo', () => ({ | ||
foo: routerNo() | ||
})))) | ||
p.route$(foo, p.switch( | ||
c => 'foo', { | ||
foo: p.no() | ||
} | ||
)) | ||
.subscribe(t => { | ||
@@ -1237,7 +1505,13 @@ expect(t).to.be.false; | ||
let routed; | ||
Router.route$(foo, new Router(Router.getRouteSwitch$(c => 'foo', (c) => ({ | ||
foo: c.foo === 'foo' | ||
? routerDo(c => { routed = true; }) | ||
: routerDo(throwErr) | ||
})))) | ||
p.route$(foo, p.switch( | ||
c => 'foo', { | ||
foo: p.if( | ||
c => c.foo === 'foo', | ||
p.do(c => { | ||
routed = true; | ||
}), | ||
reason => p.do(throwErr) | ||
) | ||
} | ||
)) | ||
.subscribe(t => { | ||
@@ -1244,0 +1518,0 @@ expect(t).to.be.true; |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
109609
21
1941
1