Refactor and simplifiy RxJS usage in the router package in order to reduce its size and increase performance. PR Close #40290
55 lines
2.4 KiB
TypeScript
55 lines
2.4 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {combineLatest, Observable, OperatorFunction} from 'rxjs';
|
|
import {filter, map, scan, startWith, switchMap, take} from 'rxjs/operators';
|
|
|
|
import {UrlTree} from '../url_tree';
|
|
import {isUrlTree} from '../utils/type_guards';
|
|
|
|
const INITIAL_VALUE = Symbol('INITIAL_VALUE');
|
|
declare type INTERIM_VALUES = typeof INITIAL_VALUE | boolean | UrlTree;
|
|
|
|
export function prioritizedGuardValue():
|
|
OperatorFunction<Observable<boolean|UrlTree>[], boolean|UrlTree> {
|
|
return switchMap(obs => {
|
|
return combineLatest(obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE as INTERIM_VALUES))))
|
|
.pipe(
|
|
scan(
|
|
(acc: INTERIM_VALUES, list: INTERIM_VALUES[]) => {
|
|
let isPending = false;
|
|
return list.reduce((innerAcc, val, i: number) => {
|
|
if (innerAcc !== INITIAL_VALUE) return innerAcc;
|
|
|
|
// Toggle pending flag if any values haven't been set yet
|
|
if (val === INITIAL_VALUE) isPending = true;
|
|
|
|
// Any other return values are only valid if we haven't yet hit a pending
|
|
// call. This guarantees that in the case of a guard at the bottom of the
|
|
// tree that returns a redirect, we will wait for the higher priority
|
|
// guard at the top to finish before performing the redirect.
|
|
if (!isPending) {
|
|
// Early return when we hit a `false` value as that should always
|
|
// cancel navigation
|
|
if (val === false) return val;
|
|
|
|
if (i === list.length - 1 || isUrlTree(val)) {
|
|
return val;
|
|
}
|
|
}
|
|
|
|
return innerAcc;
|
|
}, acc);
|
|
},
|
|
INITIAL_VALUE),
|
|
filter(item => item !== INITIAL_VALUE),
|
|
map(item => isUrlTree(item) ? item : item === true), //
|
|
take(1)) as Observable<boolean|UrlTree>;
|
|
});
|
|
}
|