All files createOutputStream.ts

85.29% Statements 29/34
80% Branches 20/25
100% Functions 10/10
85.29% Lines 29/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102                                20x 20x   23x 13x   10x   10x           5x 5x         5x     5x 5x               10x 10x       20x 20x 15x   5x   5x 5x 5x     5x         5x 1x   4x 3x   1x     6x             6x               6x                
import {
  Subject,
  queueScheduler,
  merge,
  empty,
  defer,
  from,
  of,
  Observable,
} from 'rxjs';
import { mergeMap, observeOn, subscribeOn } from 'rxjs/operators';
import { Deps, Action } from './types';
import { Store } from './Store';
import { logAction, isAction } from './utils';
 
function getHandlers(stores: Store[], action: Action) {
  const [symbol, type] = action.type;
  return stores
    .filter(store => {
      if (!store.isEnabled || !store.epic) {
        return false;
      }
      const { handlers, moduleHandlers } = store.epic;
 
      return (
        moduleHandlers.has(symbol) ||
        (handlers.has(symbol) && handlers.get(symbol)!.has(type))
      );
    })
    .map(store => {
      const { handlers, moduleHandlers } = store.epic!;
      return [
        ...(handlers.has(symbol) && handlers.get(symbol)!.has(type)
          ? handlers.get(symbol)!.get(type)
          : []),
        ...(moduleHandlers.has(symbol) ? moduleHandlers.get(symbol) : []),
      ].map(handler => ({ store, handler }));
    })
    .reduce((ret, arr) => {
      ret.push(...arr);
      return ret;
    }, []);
}
 
export function createOutputStream(
  action$: Subject<Action>,
  stores: Store[]
): Observable<Action> {
  const deps = { action$: action$ as Deps['action$'] };
  return action$.pipe(
    subscribeOn(queueScheduler),
    observeOn(queueScheduler),
    mergeMap(sourceAction => {
      const handlers = getHandlers(stores, sourceAction);
      if (!handlers.length) {
        return empty();
      }
      return merge(
        ...handlers.map(({ store, handler }) => {
          return defer(() => {
            const name = store.displayName;
            Iif (process.env.NODE_ENV === 'development') {
              logAction(name, sourceAction);
            }
            const result = handler(
              sourceAction.payload,
              deps,
              sourceAction
            ) as (Observable<Action> | Action | Action[]);
            if (Array.isArray(result)) {
              return from(result);
            }
            if (isAction(result)) {
              return of(result);
            }
            return result;
          }).pipe(
            mergeMap((action: Action) => {
              Iif (action == null) {
                console.error('Undefined action returned in epic.', {
                  action,
                  store: name,
                });
                return empty();
              }
              Iif (!isAction(action)) {
                console.error('Invalid action returned in epic.', {
                  sourceAction,
                  action,
                  store: name,
                });
                return empty();
              }
              return of(action);
            })
          );
        })
      );
    })
  );
}