refactor(router): get guards only one time and simplify guard operator signature (#26239)
PR Close #26239
This commit is contained in:
parent
f859d83298
commit
532e53678d
|
@ -12,28 +12,27 @@ import {concatMap, every, first, map, mergeMap} from 'rxjs/operators';
|
||||||
|
|
||||||
import {ActivationStart, ChildActivationStart, Event} from '../events';
|
import {ActivationStart, ChildActivationStart, Event} from '../events';
|
||||||
import {NavigationTransition} from '../router';
|
import {NavigationTransition} from '../router';
|
||||||
import {ChildrenOutletContexts} from '../router_outlet_context';
|
|
||||||
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '../router_state';
|
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '../router_state';
|
||||||
import {andObservables, wrapIntoObservable} from '../utils/collection';
|
import {andObservables, wrapIntoObservable} from '../utils/collection';
|
||||||
import {CanActivate, CanDeactivate, Checks, getAllRouteGuards, getCanActivateChild, getToken} from '../utils/preactivation';
|
import {CanActivate, CanDeactivate, getCanActivateChild, getToken} from '../utils/preactivation';
|
||||||
|
|
||||||
export function checkGuards(
|
export function checkGuards(moduleInjector: Injector, forwardEvent?: (evt: Event) => void):
|
||||||
rootContexts: ChildrenOutletContexts, moduleInjector: Injector,
|
MonoTypeOperatorFunction<NavigationTransition> {
|
||||||
forwardEvent?: (evt: Event) => void): MonoTypeOperatorFunction<NavigationTransition> {
|
|
||||||
return function(source: Observable<NavigationTransition>) {
|
return function(source: Observable<NavigationTransition>) {
|
||||||
|
|
||||||
return source.pipe(mergeMap(t => {
|
return source.pipe(mergeMap(t => {
|
||||||
const {targetSnapshot, currentSnapshot} = t;
|
const {targetSnapshot, currentSnapshot, guards: {canActivateChecks, canDeactivateChecks}} = t;
|
||||||
const checks = getAllRouteGuards(targetSnapshot !, currentSnapshot, rootContexts);
|
if (canDeactivateChecks.length === 0 && canActivateChecks.length === 0) {
|
||||||
if (checks.canDeactivateChecks.length === 0 && checks.canActivateChecks.length === 0) {
|
|
||||||
return of ({...t, guardsResult: true});
|
return of ({...t, guardsResult: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
return runCanDeactivateChecks(checks, targetSnapshot !, currentSnapshot, moduleInjector)
|
return runCanDeactivateChecks(
|
||||||
|
canDeactivateChecks, targetSnapshot !, currentSnapshot, moduleInjector)
|
||||||
.pipe(
|
.pipe(
|
||||||
mergeMap((canDeactivate: boolean) => {
|
mergeMap((canDeactivate: boolean) => {
|
||||||
return canDeactivate ?
|
return canDeactivate ?
|
||||||
runCanActivateChecks(targetSnapshot !, checks, moduleInjector, forwardEvent) :
|
runCanActivateChecks(
|
||||||
|
targetSnapshot !, canActivateChecks, moduleInjector, forwardEvent) :
|
||||||
of (false);
|
of (false);
|
||||||
}),
|
}),
|
||||||
map(guardsResult => ({...t, guardsResult})));
|
map(guardsResult => ({...t, guardsResult})));
|
||||||
|
@ -42,21 +41,19 @@ export function checkGuards(
|
||||||
}
|
}
|
||||||
|
|
||||||
function runCanDeactivateChecks(
|
function runCanDeactivateChecks(
|
||||||
checks: Checks, futureRSS: RouterStateSnapshot, currRSS: RouterStateSnapshot,
|
checks: CanDeactivate[], futureRSS: RouterStateSnapshot, currRSS: RouterStateSnapshot,
|
||||||
moduleInjector: Injector): Observable<boolean> {
|
moduleInjector: Injector): Observable<boolean> {
|
||||||
return from(checks.canDeactivateChecks)
|
return from(checks).pipe(
|
||||||
.pipe(
|
|
||||||
mergeMap(
|
mergeMap(
|
||||||
(check: CanDeactivate) => runCanDeactivate(
|
(check: CanDeactivate) =>
|
||||||
check.component, check.route, currRSS, futureRSS, moduleInjector)),
|
runCanDeactivate(check.component, check.route, currRSS, futureRSS, moduleInjector)),
|
||||||
every((result: boolean) => result === true));
|
every((result: boolean) => result === true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function runCanActivateChecks(
|
function runCanActivateChecks(
|
||||||
futureSnapshot: RouterStateSnapshot, checks: Checks, moduleInjector: Injector,
|
futureSnapshot: RouterStateSnapshot, checks: CanActivate[], moduleInjector: Injector,
|
||||||
forwardEvent?: (evt: Event) => void): Observable<boolean> {
|
forwardEvent?: (evt: Event) => void): Observable<boolean> {
|
||||||
return from(checks.canActivateChecks)
|
return from(checks).pipe(
|
||||||
.pipe(
|
|
||||||
concatMap((check: CanActivate) => andObservables(from([
|
concatMap((check: CanActivate) => andObservables(from([
|
||||||
fireChildActivationStart(check.route.parent, forwardEvent),
|
fireChildActivationStart(check.route.parent, forwardEvent),
|
||||||
fireActivationStart(check.route, forwardEvent),
|
fireActivationStart(check.route, forwardEvent),
|
||||||
|
|
|
@ -12,25 +12,23 @@ import {concatMap, last, map, mergeMap, reduce} from 'rxjs/operators';
|
||||||
|
|
||||||
import {ResolveData} from '../config';
|
import {ResolveData} from '../config';
|
||||||
import {NavigationTransition} from '../router';
|
import {NavigationTransition} from '../router';
|
||||||
import {ChildrenOutletContexts} from '../router_outlet_context';
|
|
||||||
import {ActivatedRouteSnapshot, RouterStateSnapshot, inheritedParamsDataResolve} from '../router_state';
|
import {ActivatedRouteSnapshot, RouterStateSnapshot, inheritedParamsDataResolve} from '../router_state';
|
||||||
import {wrapIntoObservable} from '../utils/collection';
|
import {wrapIntoObservable} from '../utils/collection';
|
||||||
|
|
||||||
import {getAllRouteGuards, getToken} from '../utils/preactivation';
|
import {getToken} from '../utils/preactivation';
|
||||||
|
|
||||||
export function resolveData(
|
export function resolveData(
|
||||||
rootContexts: ChildrenOutletContexts, paramsInheritanceStrategy: 'emptyOnly' | 'always',
|
paramsInheritanceStrategy: 'emptyOnly' | 'always',
|
||||||
moduleInjector: Injector): MonoTypeOperatorFunction<NavigationTransition> {
|
moduleInjector: Injector): MonoTypeOperatorFunction<NavigationTransition> {
|
||||||
return function(source: Observable<NavigationTransition>) {
|
return function(source: Observable<NavigationTransition>) {
|
||||||
return source.pipe(mergeMap(t => {
|
return source.pipe(mergeMap(t => {
|
||||||
const {targetSnapshot, currentSnapshot} = t;
|
const {targetSnapshot, guards: {canActivateChecks}} = t;
|
||||||
const checks = getAllRouteGuards(targetSnapshot !, currentSnapshot, rootContexts);
|
|
||||||
|
|
||||||
if (!checks.canActivateChecks.length) {
|
if (!canActivateChecks.length) {
|
||||||
return of (t);
|
return of (t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return from(checks.canActivateChecks)
|
return from(canActivateChecks)
|
||||||
.pipe(
|
.pipe(
|
||||||
concatMap(
|
concatMap(
|
||||||
check => runResolve(
|
check => runResolve(
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {ActivatedRoute, RouterState, RouterStateSnapshot, createEmptyState} from
|
||||||
import {Params, isNavigationCancelingError} from './shared';
|
import {Params, isNavigationCancelingError} from './shared';
|
||||||
import {DefaultUrlHandlingStrategy, UrlHandlingStrategy} from './url_handling_strategy';
|
import {DefaultUrlHandlingStrategy, UrlHandlingStrategy} from './url_handling_strategy';
|
||||||
import {UrlSerializer, UrlTree, containsTree, createEmptyUrlTree} from './url_tree';
|
import {UrlSerializer, UrlTree, containsTree, createEmptyUrlTree} from './url_tree';
|
||||||
import {getAllRouteGuards} from './utils/preactivation';
|
import {Checks, getAllRouteGuards} from './utils/preactivation';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,6 +185,7 @@ export type NavigationTransition = {
|
||||||
targetSnapshot: RouterStateSnapshot | null,
|
targetSnapshot: RouterStateSnapshot | null,
|
||||||
currentRouterState: RouterState,
|
currentRouterState: RouterState,
|
||||||
targetRouterState: RouterState | null,
|
targetRouterState: RouterState | null,
|
||||||
|
guards: Checks,
|
||||||
guardsResult: boolean | null,
|
guardsResult: boolean | null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -354,6 +355,7 @@ export class Router {
|
||||||
targetSnapshot: null,
|
targetSnapshot: null,
|
||||||
currentRouterState: this.routerState,
|
currentRouterState: this.routerState,
|
||||||
targetRouterState: null,
|
targetRouterState: null,
|
||||||
|
guards: {canActivateChecks: [], canDeactivateChecks: []},
|
||||||
guardsResult: null,
|
guardsResult: null,
|
||||||
});
|
});
|
||||||
this.navigations = this.setupNavigations(this.transitions);
|
this.navigations = this.setupNavigations(this.transitions);
|
||||||
|
@ -478,9 +480,13 @@ export class Router {
|
||||||
this.triggerEvent(guardsStart);
|
this.triggerEvent(guardsStart);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
checkGuards(
|
map(t => ({
|
||||||
this.rootContexts, this.ngModule.injector,
|
...t,
|
||||||
(evt: Event) => this.triggerEvent(evt)),
|
guards:
|
||||||
|
getAllRouteGuards(t.targetSnapshot !, t.currentSnapshot, this.rootContexts)
|
||||||
|
})),
|
||||||
|
|
||||||
|
checkGuards(this.ngModule.injector, (evt: Event) => this.triggerEvent(evt)),
|
||||||
|
|
||||||
tap(t => {
|
tap(t => {
|
||||||
const guardsEnd = new GuardsCheckEnd(
|
const guardsEnd = new GuardsCheckEnd(
|
||||||
|
@ -503,8 +509,7 @@ export class Router {
|
||||||
|
|
||||||
// --- RESOLVE ---
|
// --- RESOLVE ---
|
||||||
switchTap(t => {
|
switchTap(t => {
|
||||||
if (getAllRouteGuards(t.targetSnapshot !, t.currentSnapshot, this.rootContexts)
|
if (t.guards.canActivateChecks.length) {
|
||||||
.canActivateChecks.length) {
|
|
||||||
return of (t).pipe(
|
return of (t).pipe(
|
||||||
tap(t => {
|
tap(t => {
|
||||||
const resolveStart = new ResolveStart(
|
const resolveStart = new ResolveStart(
|
||||||
|
@ -513,7 +518,7 @@ export class Router {
|
||||||
this.triggerEvent(resolveStart);
|
this.triggerEvent(resolveStart);
|
||||||
}),
|
}),
|
||||||
resolveData(
|
resolveData(
|
||||||
this.rootContexts, this.paramsInheritanceStrategy,
|
this.paramsInheritanceStrategy,
|
||||||
this.ngModule.injector), //
|
this.ngModule.injector), //
|
||||||
tap(t => {
|
tap(t => {
|
||||||
const resolveEnd = new ResolveEnd(
|
const resolveEnd = new ResolveEnd(
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {NavigationTransition, Router} from '../src/router';
|
||||||
import {ChildrenOutletContexts} from '../src/router_outlet_context';
|
import {ChildrenOutletContexts} from '../src/router_outlet_context';
|
||||||
import {RouterStateSnapshot, createEmptyStateSnapshot} from '../src/router_state';
|
import {RouterStateSnapshot, createEmptyStateSnapshot} from '../src/router_state';
|
||||||
import {DefaultUrlSerializer} from '../src/url_tree';
|
import {DefaultUrlSerializer} from '../src/url_tree';
|
||||||
|
import {getAllRouteGuards} from '../src/utils/preactivation';
|
||||||
import {TreeNode} from '../src/utils/tree';
|
import {TreeNode} from '../src/utils/tree';
|
||||||
import {RouterTestingModule} from '../testing/src/router_testing_module';
|
import {RouterTestingModule} from '../testing/src/router_testing_module';
|
||||||
|
|
||||||
|
@ -143,9 +144,8 @@ describe('Router', () => {
|
||||||
const futureState = new (RouterStateSnapshot as any)(
|
const futureState = new (RouterStateSnapshot as any)(
|
||||||
'url', new TreeNode(empty.root, [new TreeNode(childSnapshot, [])]));
|
'url', new TreeNode(empty.root, [new TreeNode(childSnapshot, [])]));
|
||||||
|
|
||||||
of ({targetSnapshot: futureState, currentSnapshot: empty})
|
of ({guards: getAllRouteGuards(futureState, empty, new ChildrenOutletContexts())})
|
||||||
.pipe(checkGuardsOperator(
|
.pipe(checkGuardsOperator(TestBed, (evt) => { events.push(evt); }))
|
||||||
new ChildrenOutletContexts(), TestBed, (evt) => { events.push(evt); }))
|
|
||||||
.subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
|
.subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
|
@ -178,9 +178,8 @@ describe('Router', () => {
|
||||||
new TreeNode(grandchildSnapshot, [new TreeNode(greatGrandchildSnapshot, [])])
|
new TreeNode(grandchildSnapshot, [new TreeNode(greatGrandchildSnapshot, [])])
|
||||||
])]));
|
])]));
|
||||||
|
|
||||||
of ({targetSnapshot: futureState, currentSnapshot: empty})
|
of ({guards: getAllRouteGuards(futureState, empty, new ChildrenOutletContexts())})
|
||||||
.pipe(checkGuardsOperator(
|
.pipe(checkGuardsOperator(TestBed, (evt) => { events.push(evt); }))
|
||||||
new ChildrenOutletContexts(), TestBed, (evt) => { events.push(evt); }))
|
|
||||||
.subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
|
.subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
|
@ -211,9 +210,8 @@ describe('Router', () => {
|
||||||
new TreeNode(
|
new TreeNode(
|
||||||
empty.root, [new TreeNode(childSnapshot, [new TreeNode(grandchildSnapshot, [])])]));
|
empty.root, [new TreeNode(childSnapshot, [new TreeNode(grandchildSnapshot, [])])]));
|
||||||
|
|
||||||
of ({targetSnapshot: futureState, currentSnapshot: currentState})
|
of ({guards: getAllRouteGuards(futureState, currentState, new ChildrenOutletContexts())})
|
||||||
.pipe(checkGuardsOperator(
|
.pipe(checkGuardsOperator(TestBed, (evt) => { events.push(evt); }))
|
||||||
new ChildrenOutletContexts(), TestBed, (evt) => { events.push(evt); }))
|
|
||||||
.subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
|
.subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
|
@ -257,9 +255,8 @@ describe('Router', () => {
|
||||||
greatGrandchildSnapshot, [new TreeNode(greatGreatGrandchildSnapshot, [])])
|
greatGrandchildSnapshot, [new TreeNode(greatGreatGrandchildSnapshot, [])])
|
||||||
])])]));
|
])])]));
|
||||||
|
|
||||||
of ({targetSnapshot: futureState, currentSnapshot: currentState})
|
of ({guards: getAllRouteGuards(futureState, currentState, new ChildrenOutletContexts())})
|
||||||
.pipe(checkGuardsOperator(
|
.pipe(checkGuardsOperator(TestBed, (evt) => { events.push(evt); }))
|
||||||
new ChildrenOutletContexts(), TestBed, (evt) => { events.push(evt); }))
|
|
||||||
.subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
|
.subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
|
@ -538,15 +535,19 @@ describe('Router', () => {
|
||||||
|
|
||||||
function checkResolveData(
|
function checkResolveData(
|
||||||
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any, check: any): void {
|
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any, check: any): void {
|
||||||
of ({ targetSnapshot: future, currentSnapshot: curr } as Partial<NavigationTransition>)
|
of ({
|
||||||
.pipe(resolveDataOperator(new ChildrenOutletContexts(), 'emptyOnly', injector))
|
guards: getAllRouteGuards(future, curr, new ChildrenOutletContexts())
|
||||||
|
} as Partial<NavigationTransition>)
|
||||||
|
.pipe(resolveDataOperator('emptyOnly', injector))
|
||||||
.subscribe(check, (e) => { throw e; });
|
.subscribe(check, (e) => { throw e; });
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkGuards(
|
function checkGuards(
|
||||||
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any,
|
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any,
|
||||||
check: (result: boolean) => void): void {
|
check: (result: boolean) => void): void {
|
||||||
of ({ targetSnapshot: future, currentSnapshot: curr } as Partial<NavigationTransition>)
|
of ({
|
||||||
.pipe(checkGuardsOperator(new ChildrenOutletContexts(), injector))
|
guards: getAllRouteGuards(future, curr, new ChildrenOutletContexts())
|
||||||
|
} as Partial<NavigationTransition>)
|
||||||
|
.pipe(checkGuardsOperator(injector))
|
||||||
.subscribe(t => check(!!t.guardsResult), (e) => { throw e; });
|
.subscribe(t => check(!!t.guardsResult), (e) => { throw e; });
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue