build: reformat repo to new clang@1.4.0 (#36613)

PR Close #36613
This commit is contained in:
Joey Perrott
2020-04-13 16:40:21 -07:00
committed by atscott
parent 5e80e7e216
commit 698b0288be
1160 changed files with 31667 additions and 24000 deletions

View File

@ -76,12 +76,14 @@ Promise
testing.TestBed.initTestEnvironment(
testingBrowser.BrowserDynamicTestingModule,
testingBrowser.platformBrowserDynamicTesting());
})
.then(function() {
// Finally, load all spec files.
// This will run the tests directly.
return Promise.all(
allSpecFiles.map(function(moduleName) { return System.import(moduleName); }));
return Promise.all(allSpecFiles.map(function(moduleName) {
return System.import(moduleName);
}));
})
.then(__karma__.start, function(v) { console.error(v); });
.then(__karma__.start, function(v) {
console.error(v);
});

View File

@ -7,13 +7,13 @@
*/
import {Injector, NgModuleRef} from '@angular/core';
import {EmptyError, Observable, Observer, from, of } from 'rxjs';
import {EmptyError, from, Observable, Observer, of} from 'rxjs';
import {catchError, concatAll, every, first, map, mergeMap} from 'rxjs/operators';
import {LoadedRouterConfig, Route, Routes} from './config';
import {CanLoadFn} from './interfaces';
import {RouterConfigLoader} from './router_config_loader';
import {PRIMARY_OUTLET, Params, defaultUrlMatcher, navigationCancelingError} from './shared';
import {defaultUrlMatcher, navigationCancelingError, Params, PRIMARY_OUTLET} from './shared';
import {UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree} from './url_tree';
import {forEach, waitForMap, wrapIntoObservable} from './utils/collection';
import {isCanLoad, isFunction} from './utils/type_guards';
@ -21,7 +21,9 @@ import {isCanLoad, isFunction} from './utils/type_guards';
class NoMatch {
public segmentGroup: UrlSegmentGroup|null;
constructor(segmentGroup?: UrlSegmentGroup) { this.segmentGroup = segmentGroup || null; }
constructor(segmentGroup?: UrlSegmentGroup) {
this.segmentGroup = segmentGroup || null;
}
}
class AbsoluteRedirect {
@ -46,8 +48,9 @@ function namedOutletsRedirect(redirectTo: string): Observable<any> {
function canLoadFails(route: Route): Observable<LoadedRouterConfig> {
return new Observable<LoadedRouterConfig>(
(obs: Observer<LoadedRouterConfig>) => obs.error(navigationCancelingError(
`Cannot load children because the guard of the route "path: '${route.path}'" returned false`)));
(obs: Observer<LoadedRouterConfig>) => obs.error(
navigationCancelingError(`Cannot load children because the guard of the route "path: '${
route.path}'" returned false`)));
}
/**
@ -76,7 +79,7 @@ class ApplyRedirects {
this.expandSegmentGroup(this.ngModule, this.config, this.urlTree.root, PRIMARY_OUTLET);
const urlTrees$ = expanded$.pipe(
map((rootSegmentGroup: UrlSegmentGroup) => this.createUrlTree(
rootSegmentGroup, this.urlTree.queryParams, this.urlTree.fragment !)));
rootSegmentGroup, this.urlTree.queryParams, this.urlTree.fragment!)));
return urlTrees$.pipe(catchError((e: any) => {
if (e instanceof AbsoluteRedirect) {
// after an absolute redirect we do not apply any more redirects!
@ -98,7 +101,7 @@ class ApplyRedirects {
this.expandSegmentGroup(this.ngModule, this.config, tree.root, PRIMARY_OUTLET);
const mapped$ = expanded$.pipe(
map((rootSegmentGroup: UrlSegmentGroup) =>
this.createUrlTree(rootSegmentGroup, tree.queryParams, tree.fragment !)));
this.createUrlTree(rootSegmentGroup, tree.queryParams, tree.fragment!)));
return mapped$.pipe(catchError((e: any): Observable<UrlTree> => {
if (e instanceof NoMatch) {
throw this.noMatchError(e);
@ -144,7 +147,7 @@ class ApplyRedirects {
ngModule: NgModuleRef<any>, segmentGroup: UrlSegmentGroup, routes: Route[],
segments: UrlSegment[], outlet: string,
allowRedirects: boolean): Observable<UrlSegmentGroup> {
return of (...routes).pipe(
return of(...routes).pipe(
map((r: any) => {
const expanded$ = this.expandSegmentAgainstRoute(
ngModule, segmentGroup, routes, r, segments, outlet, allowRedirects);
@ -152,7 +155,7 @@ class ApplyRedirects {
if (e instanceof NoMatch) {
// TODO(i): this return type doesn't match the declared Observable<UrlSegmentGroup> -
// talk to Jason
return of (null) as any;
return of(null) as any;
}
throw e;
}));
@ -160,7 +163,7 @@ class ApplyRedirects {
concatAll(), first((s: any) => !!s), catchError((e: any, _: any) => {
if (e instanceof EmptyError || e.name === 'EmptyError') {
if (this.noLeftoversInUrl(segmentGroup, segments, outlet)) {
return of (new UrlSegmentGroup([], {}));
return of(new UrlSegmentGroup([], {}));
}
throw new NoMatch(segmentGroup);
}
@ -207,8 +210,8 @@ class ApplyRedirects {
private expandWildCardWithParamsAgainstRouteUsingRedirect(
ngModule: NgModuleRef<any>, routes: Route[], route: Route,
outlet: string): Observable<UrlSegmentGroup> {
const newTree = this.applyRedirectCommands([], route.redirectTo !, {});
if (route.redirectTo !.startsWith('/')) {
const newTree = this.applyRedirectCommands([], route.redirectTo!, {});
if (route.redirectTo!.startsWith('/')) {
return absoluteRedirect(newTree);
}
@ -226,8 +229,8 @@ class ApplyRedirects {
if (!matched) return noMatch(segmentGroup);
const newTree = this.applyRedirectCommands(
consumedSegments, route.redirectTo !, <any>positionalParamSegments);
if (route.redirectTo !.startsWith('/')) {
consumedSegments, route.redirectTo!, <any>positionalParamSegments);
if (route.redirectTo!.startsWith('/')) {
return absoluteRedirect(newTree);
}
@ -250,7 +253,7 @@ class ApplyRedirects {
}));
}
return of (new UrlSegmentGroup(segments, {}));
return of(new UrlSegmentGroup(segments, {}));
}
const {matched, consumedSegments, lastChild} = match(rawSegmentGroup, route, segments);
@ -273,7 +276,7 @@ class ApplyRedirects {
}
if (childConfig.length === 0 && slicedSegments.length === 0) {
return of (new UrlSegmentGroup(consumedSegments, {}));
return of(new UrlSegmentGroup(consumedSegments, {}));
}
const expanded$ = this.expandSegment(
@ -288,13 +291,13 @@ class ApplyRedirects {
Observable<LoadedRouterConfig> {
if (route.children) {
// The children belong to the same module
return of (new LoadedRouterConfig(route.children, ngModule));
return of(new LoadedRouterConfig(route.children, ngModule));
}
if (route.loadChildren) {
// lazy children belong to the loaded module
if (route._loadedConfig !== undefined) {
return of (route._loadedConfig);
return of(route._loadedConfig);
}
return runCanLoadGuard(ngModule.injector, route, segments)
@ -310,7 +313,7 @@ class ApplyRedirects {
}));
}
return of (new LoadedRouterConfig([], ngModule));
return of(new LoadedRouterConfig([], ngModule));
}
private lineralizeSegments(route: Route, urlTree: UrlTree): Observable<UrlSegment[]> {
@ -319,11 +322,11 @@ class ApplyRedirects {
while (true) {
res = res.concat(c.segments);
if (c.numberOfChildren === 0) {
return of (res);
return of(res);
}
if (c.numberOfChildren > 1 || !c.children[PRIMARY_OUTLET]) {
return namedOutletsRedirect(route.redirectTo !);
return namedOutletsRedirect(route.redirectTo!);
}
c = c.children[PRIMARY_OUTLET];
@ -406,7 +409,7 @@ class ApplyRedirects {
function runCanLoadGuard(
moduleInjector: Injector, route: Route, segments: UrlSegment[]): Observable<boolean> {
const canLoad = route.canLoad;
if (!canLoad || canLoad.length === 0) return of (true);
if (!canLoad || canLoad.length === 0) return of(true);
const obs = from(canLoad).pipe(map((injectionToken: any) => {
const guard = moduleInjector.get(injectionToken);
@ -452,9 +455,9 @@ function match(segmentGroup: UrlSegmentGroup, route: Route, segments: UrlSegment
return {
matched: true,
consumedSegments: res.consumed !,
lastChild: res.consumed.length !,
positionalParamSegments: res.posParams !,
consumedSegments: res.consumed!,
lastChild: res.consumed.length!,
positionalParamSegments: res.posParams!,
};
}
@ -464,16 +467,18 @@ function split(
if (slicedSegments.length > 0 &&
containsEmptyPathRedirectsWithNamedOutlets(segmentGroup, slicedSegments, config)) {
const s = new UrlSegmentGroup(
consumedSegments, createChildrenForEmptySegments(
config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
consumedSegments,
createChildrenForEmptySegments(
config, new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
return {segmentGroup: mergeTrivialChildren(s), slicedSegments: []};
}
if (slicedSegments.length === 0 &&
containsEmptyPathRedirects(segmentGroup, slicedSegments, config)) {
const s = new UrlSegmentGroup(
segmentGroup.segments, addEmptySegmentsToChildrenIfNeeded(
segmentGroup, slicedSegments, config, segmentGroup.children));
segmentGroup.segments,
addEmptySegmentsToChildrenIfNeeded(
segmentGroup, slicedSegments, config, segmentGroup.children));
return {segmentGroup: mergeTrivialChildren(s), slicedSegments};
}

View File

@ -7,7 +7,7 @@
*/
import {ActivatedRoute} from './router_state';
import {PRIMARY_OUTLET, Params} from './shared';
import {Params, PRIMARY_OUTLET} from './shared';
import {UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree';
import {forEach, last, shallowEqual} from './utils/collection';
@ -164,7 +164,7 @@ function createPositionApplyingDoubleDots(
let dd = numberOfDoubleDots;
while (dd > ci) {
dd -= ci;
g = g.parent !;
g = g.parent!;
if (!g) {
throw new Error('Invalid number of \'../\'');
}

View File

@ -76,14 +76,12 @@ import {RouterLink, RouterLinkWithHref} from './router_link';
selector: '[routerLinkActive]',
exportAs: 'routerLinkActive',
})
export class RouterLinkActive implements OnChanges,
OnDestroy, AfterContentInit {
export class RouterLinkActive implements OnChanges, OnDestroy, AfterContentInit {
// TODO(issue/24571): remove '!'.
@ContentChildren(RouterLink, {descendants: true})
links !: QueryList<RouterLink>;
@ContentChildren(RouterLink, {descendants: true}) links!: QueryList<RouterLink>;
// TODO(issue/24571): remove '!'.
@ContentChildren(RouterLinkWithHref, {descendants: true})
linksWithHrefs !: QueryList<RouterLinkWithHref>;
linksWithHrefs!: QueryList<RouterLinkWithHref>;
private classes: string[] = [];
private subscription: Subscription;
@ -115,8 +113,12 @@ export class RouterLinkActive implements OnChanges,
this.classes = classes.filter(c => !!c);
}
ngOnChanges(changes: SimpleChanges): void { this.update(); }
ngOnDestroy(): void { this.subscription.unsubscribe(); }
ngOnChanges(changes: SimpleChanges): void {
this.update();
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
private update(): void {
if (!this.links || !this.linksWithHrefs || !this.router.navigated) return;
@ -136,7 +138,7 @@ export class RouterLinkActive implements OnChanges,
}
private isLinkActive(router: Router): (link: (RouterLink|RouterLinkWithHref)) => boolean {
return (link: RouterLink | RouterLinkWithHref) =>
return (link: RouterLink|RouterLinkWithHref) =>
router.isActive(link.urlTree, this.routerLinkActiveOptions.exact);
}

View File

@ -56,7 +56,9 @@ export class RouterOutlet implements OnDestroy, OnInit {
parentContexts.onChildOutletCreated(this.name, this);
}
ngOnDestroy(): void { this.parentContexts.onChildOutletDestroyed(this.name); }
ngOnDestroy(): void {
this.parentContexts.onChildOutletDestroyed(this.name);
}
ngOnInit(): void {
if (!this.activated) {
@ -75,7 +77,9 @@ export class RouterOutlet implements OnDestroy, OnInit {
}
}
get isActivated(): boolean { return !!this.activated; }
get isActivated(): boolean {
return !!this.activated;
}
get component(): Object {
if (!this.activated) throw new Error('Outlet is not activated');
@ -131,7 +135,7 @@ export class RouterOutlet implements OnDestroy, OnInit {
}
this._activatedRoute = activatedRoute;
const snapshot = activatedRoute._futureSnapshot;
const component = <any>snapshot.routeConfig !.component;
const component = <any>snapshot.routeConfig!.component;
resolver = resolver || this.resolver;
const factory = resolver.resolveComponentFactory(component);
const childContexts = this.parentContexts.getOrCreateContext(this.name).children;

View File

@ -18,7 +18,7 @@ import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
*
* @publicApi
*/
export type NavigationTrigger = 'imperative' | 'popstate' | 'hashchange';
export type NavigationTrigger = 'imperative'|'popstate'|'hashchange';
/**
* Base for events the router goes through, as opposed to events tied to a specific
@ -96,7 +96,9 @@ export class NavigationStart extends RouterEvent {
}
/** @docsNotRequired */
toString(): string { return `NavigationStart(id: ${this.id}, url: '${this.url}')`; }
toString(): string {
return `NavigationStart(id: ${this.id}, url: '${this.url}')`;
}
}
/**
@ -117,7 +119,8 @@ export class NavigationEnd extends RouterEvent {
/** @docsNotRequired */
toString(): string {
return `NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`;
return `NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${
this.urlAfterRedirects}')`;
}
}
@ -141,7 +144,9 @@ export class NavigationCancel extends RouterEvent {
}
/** @docsNotRequired */
toString(): string { return `NavigationCancel(id: ${this.id}, url: '${this.url}')`; }
toString(): string {
return `NavigationCancel(id: ${this.id}, url: '${this.url}')`;
}
}
/**
@ -186,7 +191,8 @@ export class RoutesRecognized extends RouterEvent {
/** @docsNotRequired */
toString(): string {
return `RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
return `RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${
this.urlAfterRedirects}', state: ${this.state})`;
}
}
@ -209,7 +215,8 @@ export class GuardsCheckStart extends RouterEvent {
}
toString(): string {
return `GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
return `GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${
this.urlAfterRedirects}', state: ${this.state})`;
}
}
@ -234,7 +241,8 @@ export class GuardsCheckEnd extends RouterEvent {
}
toString(): string {
return `GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`;
return `GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${
this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`;
}
}
@ -260,7 +268,8 @@ export class ResolveStart extends RouterEvent {
}
toString(): string {
return `ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
return `ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${
this.urlAfterRedirects}', state: ${this.state})`;
}
}
@ -284,7 +293,8 @@ export class ResolveEnd extends RouterEvent {
}
toString(): string {
return `ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
return `ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${
this.urlAfterRedirects}', state: ${this.state})`;
}
}
@ -297,7 +307,9 @@ export class RouteConfigLoadStart {
constructor(
/** @docsNotRequired */
public route: Route) {}
toString(): string { return `RouteConfigLoadStart(path: ${this.route.path})`; }
toString(): string {
return `RouteConfigLoadStart(path: ${this.route.path})`;
}
}
/**
@ -309,7 +321,9 @@ export class RouteConfigLoadEnd {
constructor(
/** @docsNotRequired */
public route: Route) {}
toString(): string { return `RouteConfigLoadEnd(path: ${this.route.path})`; }
toString(): string {
return `RouteConfigLoadEnd(path: ${this.route.path})`;
}
}
/**
@ -429,5 +443,5 @@ export class Scroll {
*
* @publicApi
*/
export type Event = RouterEvent | RouteConfigLoadStart | RouteConfigLoadEnd | ChildActivationStart |
ChildActivationEnd | ActivationStart | ActivationEnd | Scroll;
export type Event = RouterEvent|RouteConfigLoadStart|RouteConfigLoadEnd|ChildActivationStart|
ChildActivationEnd|ActivationStart|ActivationEnd|Scroll;

View File

@ -7,7 +7,7 @@
*/
export {Data, DeprecatedLoadChildren, LoadChildren, LoadChildrenCallback, QueryParamsHandling, ResolveData, Route, Routes, RunGuardsAndResolvers, UrlMatchResult, UrlMatcher} from './config';
export {Data, DeprecatedLoadChildren, LoadChildren, LoadChildrenCallback, QueryParamsHandling, ResolveData, Route, Routes, RunGuardsAndResolvers, UrlMatcher, UrlMatchResult} from './config';
export {RouterLink, RouterLinkWithHref} from './directives/router_link';
export {RouterLinkActive} from './directives/router_link_active';
export {RouterOutlet} from './directives/router_outlet';
@ -16,11 +16,11 @@ export {CanActivate, CanActivateChild, CanDeactivate, CanLoad, Resolve} from './
export {DetachedRouteHandle, RouteReuseStrategy} from './route_reuse_strategy';
export {Navigation, NavigationExtras, Router} from './router';
export {ROUTES} from './router_config_loader';
export {ExtraOptions, InitialNavigation, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, RouterModule, provideRoutes} from './router_module';
export {ExtraOptions, InitialNavigation, provideRoutes, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, RouterModule} from './router_module';
export {ChildrenOutletContexts, OutletContext} from './router_outlet_context';
export {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} from './router_preloader';
export {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from './router_state';
export {PRIMARY_OUTLET, ParamMap, Params, convertToParamMap} from './shared';
export {convertToParamMap, ParamMap, Params, PRIMARY_OUTLET} from './shared';
export {UrlHandlingStrategy} from './url_handling_strategy';
export {DefaultUrlSerializer, UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree} from './url_tree';
export {VERSION} from './version';

View File

@ -88,7 +88,7 @@ export interface CanActivate {
}
export type CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) =>
Observable<boolean|UrlTree>| Promise<boolean|UrlTree>| boolean | UrlTree;
Observable<boolean|UrlTree>|Promise<boolean|UrlTree>|boolean|UrlTree;
/**
* @description
@ -175,7 +175,7 @@ export interface CanActivateChild {
}
export type CanActivateChildFn = (childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) =>
Observable<boolean|UrlTree>| Promise<boolean|UrlTree>| boolean | UrlTree;
Observable<boolean|UrlTree>|Promise<boolean|UrlTree>|boolean|UrlTree;
/**
* @description
@ -259,7 +259,7 @@ export interface CanDeactivate<T> {
export type CanDeactivateFn<T> =
(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot) =>
Observable<boolean|UrlTree>| Promise<boolean|UrlTree>| boolean | UrlTree;
Observable<boolean|UrlTree>|Promise<boolean|UrlTree>|boolean|UrlTree;
/**
* @description
@ -404,4 +404,4 @@ export interface CanLoad {
}
export type CanLoadFn = (route: Route, segments: UrlSegment[]) =>
Observable<boolean>| Promise<boolean>| boolean;
Observable<boolean>|Promise<boolean>|boolean;

View File

@ -14,16 +14,16 @@ import {ActivationEnd, ChildActivationEnd, Event} from '../events';
import {DetachedRouteHandleInternal, RouteReuseStrategy} from '../route_reuse_strategy';
import {NavigationTransition} from '../router';
import {ChildrenOutletContexts} from '../router_outlet_context';
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, advanceActivatedRoute} from '../router_state';
import {ActivatedRoute, ActivatedRouteSnapshot, advanceActivatedRoute, RouterState} from '../router_state';
import {forEach} from '../utils/collection';
import {TreeNode, nodeChildrenAsMap} from '../utils/tree';
import {nodeChildrenAsMap, TreeNode} from '../utils/tree';
export const activateRoutes =
(rootContexts: ChildrenOutletContexts, routeReuseStrategy: RouteReuseStrategy,
forwardEvent: (evt: Event) => void): MonoTypeOperatorFunction<NavigationTransition> =>
map(t => {
new ActivateRoutes(
routeReuseStrategy, t.targetRouterState !, t.currentRouterState, forwardEvent)
routeReuseStrategy, t.targetRouterState!, t.currentRouterState, forwardEvent)
.activate(rootContexts);
return t;
});

View File

@ -7,7 +7,7 @@
*/
import {Injector} from '@angular/core';
import {MonoTypeOperatorFunction, Observable, defer, from, of } from 'rxjs';
import {defer, from, MonoTypeOperatorFunction, Observable, of} from 'rxjs';
import {concatAll, concatMap, first, map, mergeMap} from 'rxjs/operators';
import {ActivationStart, ChildActivationStart, Event} from '../events';
@ -24,21 +24,20 @@ import {prioritizedGuardValue} from './prioritized_guard_value';
export function checkGuards(moduleInjector: Injector, forwardEvent?: (evt: Event) => void):
MonoTypeOperatorFunction<NavigationTransition> {
return function(source: Observable<NavigationTransition>) {
return source.pipe(mergeMap(t => {
const {targetSnapshot, currentSnapshot, guards: {canActivateChecks, canDeactivateChecks}} = t;
if (canDeactivateChecks.length === 0 && canActivateChecks.length === 0) {
return of ({...t, guardsResult: true});
return of({...t, guardsResult: true});
}
return runCanDeactivateChecks(
canDeactivateChecks, targetSnapshot !, currentSnapshot, moduleInjector)
canDeactivateChecks, targetSnapshot!, currentSnapshot, moduleInjector)
.pipe(
mergeMap(canDeactivate => {
return canDeactivate && isBoolean(canDeactivate) ?
runCanActivateChecks(
targetSnapshot !, canActivateChecks, moduleInjector, forwardEvent) :
of (canDeactivate);
targetSnapshot!, canActivateChecks, moduleInjector, forwardEvent) :
of(canDeactivate);
}),
map(guardsResult => ({...t, guardsResult})));
}));
@ -52,7 +51,9 @@ function runCanDeactivateChecks(
mergeMap(
check =>
runCanDeactivate(check.component, check.route, currRSS, futureRSS, moduleInjector)),
first(result => { return result !== true; }, true as boolean | UrlTree));
first(result => {
return result !== true;
}, true as boolean | UrlTree));
}
function runCanActivateChecks(
@ -70,48 +71,50 @@ function runCanActivateChecks(
return result !== true;
}, true as boolean | UrlTree));
}),
first(result => { return result !== true; }, true as boolean | UrlTree));
first(result => {
return result !== true;
}, true as boolean | UrlTree));
}
/**
* This should fire off `ActivationStart` events for each route being activated at this
* level.
* In other words, if you're activating `a` and `b` below, `path` will contain the
* `ActivatedRouteSnapshot`s for both and we will fire `ActivationStart` for both. Always
* return
* `true` so checks continue to run.
*/
* This should fire off `ActivationStart` events for each route being activated at this
* level.
* In other words, if you're activating `a` and `b` below, `path` will contain the
* `ActivatedRouteSnapshot`s for both and we will fire `ActivationStart` for both. Always
* return
* `true` so checks continue to run.
*/
function fireActivationStart(
snapshot: ActivatedRouteSnapshot | null,
snapshot: ActivatedRouteSnapshot|null,
forwardEvent?: (evt: Event) => void): Observable<boolean> {
if (snapshot !== null && forwardEvent) {
forwardEvent(new ActivationStart(snapshot));
}
return of (true);
return of(true);
}
/**
* This should fire off `ChildActivationStart` events for each route being activated at this
* level.
* In other words, if you're activating `a` and `b` below, `path` will contain the
* `ActivatedRouteSnapshot`s for both and we will fire `ChildActivationStart` for both. Always
* return
* `true` so checks continue to run.
*/
* This should fire off `ChildActivationStart` events for each route being activated at this
* level.
* In other words, if you're activating `a` and `b` below, `path` will contain the
* `ActivatedRouteSnapshot`s for both and we will fire `ChildActivationStart` for both. Always
* return
* `true` so checks continue to run.
*/
function fireChildActivationStart(
snapshot: ActivatedRouteSnapshot | null,
snapshot: ActivatedRouteSnapshot|null,
forwardEvent?: (evt: Event) => void): Observable<boolean> {
if (snapshot !== null && forwardEvent) {
forwardEvent(new ChildActivationStart(snapshot));
}
return of (true);
return of(true);
}
function runCanActivate(
futureRSS: RouterStateSnapshot, futureARS: ActivatedRouteSnapshot,
moduleInjector: Injector): Observable<boolean|UrlTree> {
const canActivate = futureARS.routeConfig ? futureARS.routeConfig.canActivate : null;
if (!canActivate || canActivate.length === 0) return of (true);
if (!canActivate || canActivate.length === 0) return of(true);
const canActivateObservables = canActivate.map((c: any) => {
return defer(() => {
@ -127,7 +130,7 @@ function runCanActivate(
return observable.pipe(first());
});
});
return of (canActivateObservables).pipe(prioritizedGuardValue());
return of(canActivateObservables).pipe(prioritizedGuardValue());
}
function runCanActivateChild(
@ -154,23 +157,22 @@ function runCanActivateChild(
}
return observable.pipe(first());
});
return of (guardsMapped).pipe(prioritizedGuardValue());
return of(guardsMapped).pipe(prioritizedGuardValue());
});
});
return of (canActivateChildGuardsMapped).pipe(prioritizedGuardValue());
return of(canActivateChildGuardsMapped).pipe(prioritizedGuardValue());
}
function runCanDeactivate(
component: Object | null, currARS: ActivatedRouteSnapshot, currRSS: RouterStateSnapshot,
component: Object|null, currARS: ActivatedRouteSnapshot, currRSS: RouterStateSnapshot,
futureRSS: RouterStateSnapshot, moduleInjector: Injector): Observable<boolean|UrlTree> {
const canDeactivate = currARS && currARS.routeConfig ? currARS.routeConfig.canDeactivate : null;
if (!canDeactivate || canDeactivate.length === 0) return of (true);
if (!canDeactivate || canDeactivate.length === 0) return of(true);
const canDeactivateObservables = canDeactivate.map((c: any) => {
const guard = getToken(c, currARS, moduleInjector);
let observable;
if (isCanDeactivate(guard)) {
observable =
wrapIntoObservable(guard.canDeactivate(component !, currARS, currRSS, futureRSS));
observable = wrapIntoObservable(guard.canDeactivate(component!, currARS, currRSS, futureRSS));
} else if (isFunction<CanDeactivateFn<any>>(guard)) {
observable = wrapIntoObservable(guard(component, currARS, currRSS, futureRSS));
} else {
@ -178,5 +180,5 @@ function runCanDeactivate(
}
return observable.pipe(first());
});
return of (canDeactivateObservables).pipe(prioritizedGuardValue());
return of(canDeactivateObservables).pipe(prioritizedGuardValue());
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Observable, OperatorFunction, combineLatest} from 'rxjs';
import {combineLatest, Observable, OperatorFunction} from 'rxjs';
import {filter, map, scan, startWith, switchMap, take} from 'rxjs/operators';
import {UrlTree} from '../url_tree';
@ -20,36 +20,36 @@ export function prioritizedGuardValue():
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;
.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;
// 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;
// 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;
}
}
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>;
return innerAcc;
}, acc);
},
INITIAL_VALUE),
filter(item => item !== INITIAL_VALUE),
map(item => isUrlTree(item) ? item : item === true), //
take(1)) as Observable<boolean|UrlTree>;
});
}

View File

@ -16,9 +16,9 @@ import {NavigationTransition} from '../router';
import {UrlTree} from '../url_tree';
export function recognize(
rootComponentType: Type<any>| null, config: Route[], serializer: (url: UrlTree) => string,
paramsInheritanceStrategy: 'emptyOnly' | 'always', relativeLinkResolution: 'legacy' |
'corrected'): MonoTypeOperatorFunction<NavigationTransition> {
rootComponentType: Type<any>|null, config: Route[], serializer: (url: UrlTree) => string,
paramsInheritanceStrategy: 'emptyOnly'|'always',
relativeLinkResolution: 'legacy'|'corrected'): MonoTypeOperatorFunction<NavigationTransition> {
return function(source: Observable<NavigationTransition>) {
return source.pipe(mergeMap(
t => recognizeFn(

View File

@ -7,32 +7,31 @@
*/
import {Injector} from '@angular/core';
import {MonoTypeOperatorFunction, Observable, from, of } from 'rxjs';
import {from, MonoTypeOperatorFunction, Observable, of} from 'rxjs';
import {concatMap, last, map, mergeMap, reduce} from 'rxjs/operators';
import {ResolveData} from '../config';
import {NavigationTransition} from '../router';
import {ActivatedRouteSnapshot, RouterStateSnapshot, inheritedParamsDataResolve} from '../router_state';
import {ActivatedRouteSnapshot, inheritedParamsDataResolve, RouterStateSnapshot} from '../router_state';
import {wrapIntoObservable} from '../utils/collection';
import {getToken} from '../utils/preactivation';
export function resolveData(
paramsInheritanceStrategy: 'emptyOnly' | 'always',
paramsInheritanceStrategy: 'emptyOnly'|'always',
moduleInjector: Injector): MonoTypeOperatorFunction<NavigationTransition> {
return function(source: Observable<NavigationTransition>) {
return source.pipe(mergeMap(t => {
const {targetSnapshot, guards: {canActivateChecks}} = t;
if (!canActivateChecks.length) {
return of (t);
return of(t);
}
return from(canActivateChecks)
.pipe(
concatMap(
check => runResolve(
check.route, targetSnapshot !, paramsInheritanceStrategy, moduleInjector)),
check.route, targetSnapshot!, paramsInheritanceStrategy, moduleInjector)),
reduce((_: any, __: any) => _), map(_ => t));
}));
};
@ -40,14 +39,15 @@ export function resolveData(
function runResolve(
futureARS: ActivatedRouteSnapshot, futureRSS: RouterStateSnapshot,
paramsInheritanceStrategy: 'emptyOnly' | 'always', moduleInjector: Injector) {
paramsInheritanceStrategy: 'emptyOnly'|'always', moduleInjector: Injector) {
const resolve = futureARS._resolve;
return resolveNode(resolve, futureARS, futureRSS, moduleInjector)
.pipe(map((resolvedData: any) => {
futureARS._resolvedData = resolvedData;
futureARS.data = {
...futureARS.data,
...inheritedParamsDataResolve(futureARS, paramsInheritanceStrategy).resolve};
...futureARS.data,
...inheritedParamsDataResolve(futureARS, paramsInheritanceStrategy).resolve
};
return null;
}));
}
@ -57,12 +57,14 @@ function resolveNode(
moduleInjector: Injector): Observable<any> {
const keys = Object.keys(resolve);
if (keys.length === 0) {
return of ({});
return of({});
}
if (keys.length === 1) {
const key = keys[0];
return getResolver(resolve[key], futureARS, futureRSS, moduleInjector)
.pipe(map((value: any) => { return {[key]: value}; }));
.pipe(map((value: any) => {
return {[key]: value};
}));
}
const data: {[k: string]: any} = {};
const runningResolvers$ = from(keys).pipe(mergeMap((key: string) => {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {MonoTypeOperatorFunction, ObservableInput, from} from 'rxjs';
import {from, MonoTypeOperatorFunction, ObservableInput} from 'rxjs';
import {map, switchMap} from 'rxjs/operators';
/**

View File

@ -7,21 +7,21 @@
*/
import {Type} from '@angular/core';
import {Observable, Observer, of } from 'rxjs';
import {Observable, Observer, of} from 'rxjs';
import {Data, ResolveData, Route, Routes} from './config';
import {ActivatedRouteSnapshot, ParamsInheritanceStrategy, RouterStateSnapshot, inheritedParamsDataResolve} from './router_state';
import {PRIMARY_OUTLET, defaultUrlMatcher} from './shared';
import {UrlSegment, UrlSegmentGroup, UrlTree, mapChildrenIntoArray} from './url_tree';
import {ActivatedRouteSnapshot, inheritedParamsDataResolve, ParamsInheritanceStrategy, RouterStateSnapshot} from './router_state';
import {defaultUrlMatcher, PRIMARY_OUTLET} from './shared';
import {mapChildrenIntoArray, UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree';
import {forEach, last} from './utils/collection';
import {TreeNode} from './utils/tree';
class NoMatch {}
export function recognize(
rootComponentType: Type<any>| null, config: Routes, urlTree: UrlTree, url: string,
rootComponentType: Type<any>|null, config: Routes, urlTree: UrlTree, url: string,
paramsInheritanceStrategy: ParamsInheritanceStrategy = 'emptyOnly',
relativeLinkResolution: 'legacy' | 'corrected' = 'legacy'): Observable<RouterStateSnapshot> {
relativeLinkResolution: 'legacy'|'corrected' = 'legacy'): Observable<RouterStateSnapshot> {
return new Recognizer(
rootComponentType, config, urlTree, url, paramsInheritanceStrategy,
relativeLinkResolution)
@ -43,13 +43,13 @@ class Recognizer {
const root = new ActivatedRouteSnapshot(
[], Object.freeze({}), Object.freeze({...this.urlTree.queryParams}),
this.urlTree.fragment !, {}, PRIMARY_OUTLET, this.rootComponentType, null,
this.urlTree.fragment!, {}, PRIMARY_OUTLET, this.rootComponentType, null,
this.urlTree.root, -1, {});
const rootNode = new TreeNode<ActivatedRouteSnapshot>(root, children);
const routeState = new RouterStateSnapshot(this.url, rootNode);
this.inheritParamsAndData(routeState._root);
return of (routeState);
return of(routeState);
} catch (e) {
return new Observable<RouterStateSnapshot>(
@ -119,10 +119,10 @@ class Recognizer {
let rawSlicedSegments: UrlSegment[] = [];
if (route.path === '**') {
const params = segments.length > 0 ? last(segments) !.parameters : {};
const params = segments.length > 0 ? last(segments)!.parameters : {};
snapshot = new ActivatedRouteSnapshot(
segments, params, Object.freeze({...this.urlTree.queryParams}), this.urlTree.fragment !,
getData(route), outlet, route.component !, route, getSourceSegmentGroup(rawSegment),
segments, params, Object.freeze({...this.urlTree.queryParams}), this.urlTree.fragment!,
getData(route), outlet, route.component!, route, getSourceSegmentGroup(rawSegment),
getPathIndexShift(rawSegment) + segments.length, getResolve(route));
} else {
const result: MatchResult = match(rawSegment, route, segments);
@ -131,7 +131,7 @@ class Recognizer {
snapshot = new ActivatedRouteSnapshot(
consumedSegments, result.parameters, Object.freeze({...this.urlTree.queryParams}),
this.urlTree.fragment !, getData(route), outlet, route.component !, route,
this.urlTree.fragment!, getData(route), outlet, route.component!, route,
getSourceSegmentGroup(rawSegment),
getPathIndexShift(rawSegment) + consumedSegments.length, getResolve(route));
}
@ -169,7 +169,7 @@ function getChildConfig(route: Route): Route[] {
}
if (route.loadChildren) {
return route._loadedConfig !.routes;
return route._loadedConfig!.routes;
}
return [];
@ -195,7 +195,9 @@ function match(segmentGroup: UrlSegmentGroup, route: Route, segments: UrlSegment
if (!res) throw new NoMatch();
const posParams: {[n: string]: string} = {};
forEach(res.posParams !, (v: UrlSegment, k: string) => { posParams[k] = v.path; });
forEach(res.posParams!, (v: UrlSegment, k: string) => {
posParams[k] = v.path;
});
const parameters = res.consumed.length > 0 ?
{...posParams, ...res.consumed[res.consumed.length - 1].parameters} :
posParams;
@ -236,13 +238,14 @@ function getPathIndexShift(segmentGroup: UrlSegmentGroup): number {
function split(
segmentGroup: UrlSegmentGroup, consumedSegments: UrlSegment[], slicedSegments: UrlSegment[],
config: Route[], relativeLinkResolution: 'legacy' | 'corrected') {
config: Route[], relativeLinkResolution: 'legacy'|'corrected') {
if (slicedSegments.length > 0 &&
containsEmptyPathMatchesWithNamedOutlets(segmentGroup, slicedSegments, config)) {
const s = new UrlSegmentGroup(
consumedSegments, createChildrenForEmptyPaths(
segmentGroup, consumedSegments, config,
new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
consumedSegments,
createChildrenForEmptyPaths(
segmentGroup, consumedSegments, config,
new UrlSegmentGroup(slicedSegments, segmentGroup.children)));
s._sourceSegment = segmentGroup;
s._segmentIndexShift = consumedSegments.length;
return {segmentGroup: s, slicedSegments: []};
@ -251,9 +254,10 @@ function split(
if (slicedSegments.length === 0 &&
containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {
const s = new UrlSegmentGroup(
segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(
segmentGroup, consumedSegments, slicedSegments, config,
segmentGroup.children, relativeLinkResolution));
segmentGroup.segments,
addEmptyPathsToChildrenIfNeeded(
segmentGroup, consumedSegments, slicedSegments, config, segmentGroup.children,
relativeLinkResolution));
s._sourceSegment = segmentGroup;
s._segmentIndexShift = consumedSegments.length;
return {segmentGroup: s, slicedSegments};
@ -268,7 +272,7 @@ function split(
function addEmptyPathsToChildrenIfNeeded(
segmentGroup: UrlSegmentGroup, consumedSegments: UrlSegment[], slicedSegments: UrlSegment[],
routes: Route[], children: {[name: string]: UrlSegmentGroup},
relativeLinkResolution: 'legacy' | 'corrected'): {[name: string]: UrlSegmentGroup} {
relativeLinkResolution: 'legacy'|'corrected'): {[name: string]: UrlSegmentGroup} {
const res: {[name: string]: UrlSegmentGroup} = {};
for (const r of routes) {
if (emptyPathMatch(segmentGroup, slicedSegments, r) && !children[getOutlet(r)]) {

View File

@ -63,10 +63,16 @@ export abstract class RouteReuseStrategy {
* Does not detach any subtrees. Reuses routes as long as their route config is the same.
*/
export class DefaultRouteReuseStrategy implements RouteReuseStrategy {
shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; }
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return false;
}
store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {}
shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; }
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { return null; }
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return false;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null {
return null;
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}

View File

@ -7,8 +7,8 @@
*/
import {Location} from '@angular/common';
import {Compiler, Injector, NgModuleFactoryLoader, NgModuleRef, NgZone, Type, isDevMode, ɵConsole as Console} from '@angular/core';
import {BehaviorSubject, EMPTY, Observable, Subject, Subscription, defer, of } from 'rxjs';
import {Compiler, Injector, isDevMode, NgModuleFactoryLoader, NgModuleRef, NgZone, Type, ɵConsole as Console} from '@angular/core';
import {BehaviorSubject, defer, EMPTY, Observable, of, Subject, Subscription} from 'rxjs';
import {catchError, filter, finalize, map, switchMap, tap} from 'rxjs/operators';
import {QueryParamsHandling, Route, Routes, standardizeConfig, validateConfig} from './config';
@ -24,10 +24,10 @@ import {switchTap} from './operators/switch_tap';
import {DefaultRouteReuseStrategy, RouteReuseStrategy} from './route_reuse_strategy';
import {RouterConfigLoader} from './router_config_loader';
import {ChildrenOutletContexts} from './router_outlet_context';
import {ActivatedRoute, RouterState, RouterStateSnapshot, createEmptyState} from './router_state';
import {Params, isNavigationCancelingError, navigationCancelingError} from './shared';
import {ActivatedRoute, createEmptyState, RouterState, RouterStateSnapshot} from './router_state';
import {isNavigationCancelingError, navigationCancelingError, Params} from './shared';
import {DefaultUrlHandlingStrategy, UrlHandlingStrategy} from './url_handling_strategy';
import {UrlSerializer, UrlTree, containsTree, createEmptyUrlTree} from './url_tree';
import {containsTree, createEmptyUrlTree, UrlSerializer, UrlTree} from './url_tree';
import {Checks, getAllRouteGuards} from './utils/preactivation';
import {isUrlTree} from './utils/type_guards';
@ -49,16 +49,16 @@ export interface NavigationExtras {
*
* ```
* [{
* path: 'parent',
* component: ParentComponent,
* children: [{
* path: 'list',
* component: ListComponent
* },{
* path: 'child',
* component: ChildComponent
* }]
* }]
* path: 'parent',
* component: ParentComponent,
* children: [{
* path: 'list',
* component: ListComponent
* },{
* path: 'child',
* component: ChildComponent
* }]
* }]
* ```
*
* The following `go()` function navigates to the `list` route by
@ -67,12 +67,12 @@ export interface NavigationExtras {
* ```
* @Component({...})
* class ChildComponent {
* constructor(private router: Router, private route: ActivatedRoute) {}
*
* go() {
* this.router.navigate(['../list'], { relativeTo: this.route });
* }
* }
* constructor(private router: Router, private route: ActivatedRoute) {}
*
* go() {
* this.router.navigate(['../list'], { relativeTo: this.route });
* }
* }
* ```
*/
relativeTo?: ActivatedRoute|null;
@ -243,13 +243,13 @@ export type NavigationTransition = {
reject: any,
promise: Promise<boolean>,
source: NavigationTrigger,
restoredState: RestoredState | null,
restoredState: RestoredState|null,
currentSnapshot: RouterStateSnapshot,
targetSnapshot: RouterStateSnapshot | null,
targetSnapshot: RouterStateSnapshot|null,
currentRouterState: RouterState,
targetRouterState: RouterState | null,
targetRouterState: RouterState|null,
guards: Checks,
guardsResult: boolean | UrlTree | null,
guardsResult: boolean|UrlTree|null,
};
/**
@ -273,7 +273,7 @@ function defaultRouterHook(snapshot: RouterStateSnapshot, runExtras: {
replaceUrl: boolean,
navigationId: number
}): Observable<void> {
return of (null) as any;
return of(null) as any;
}
/**
@ -298,7 +298,7 @@ export class Router {
private currentNavigation: Navigation|null = null;
// TODO(issue/24571): remove '!'.
private locationSubscription !: Subscription;
private locationSubscription!: Subscription;
private navigationId: number = 0;
private configLoader: RouterConfigLoader;
private ngModule: NgModuleRef<any>;
@ -343,10 +343,10 @@ export class Router {
*
* @internal
*/
hooks: {beforePreactivation: RouterHook, afterPreactivation: RouterHook} = {
beforePreactivation: defaultRouterHook,
afterPreactivation: defaultRouterHook
};
hooks: {
beforePreactivation: RouterHook,
afterPreactivation: RouterHook
} = {beforePreactivation: defaultRouterHook, afterPreactivation: defaultRouterHook};
/**
* A strategy for extracting and merging URLs.
@ -445,339 +445,358 @@ export class Router {
Observable<NavigationTransition> {
const eventsSubject = (this.events as Subject<Event>);
return transitions.pipe(
filter(t => t.id !== 0),
filter(t => t.id !== 0),
// Extract URL
map(t => ({
...t, extractedUrl: this.urlHandlingStrategy.extract(t.rawUrl)
} as NavigationTransition)),
// Extract URL
map(t =>
({...t, extractedUrl: this.urlHandlingStrategy.extract(t.rawUrl)} as
NavigationTransition)),
// Using switchMap so we cancel executing navigations when a new one comes in
switchMap(t => {
let completed = false;
let errored = false;
return of (t).pipe(
// Store the Navigation object
tap(t => {
this.currentNavigation = {
id: t.id,
initialUrl: t.currentRawUrl,
extractedUrl: t.extractedUrl,
trigger: t.source,
extras: t.extras,
previousNavigation: this.lastSuccessfulNavigation ?
{...this.lastSuccessfulNavigation, previousNavigation: null} :
null
};
}),
switchMap(t => {
const urlTransition =
!this.navigated || t.extractedUrl.toString() !== this.browserUrlTree.toString();
const processCurrentUrl =
(this.onSameUrlNavigation === 'reload' ? true : urlTransition) &&
this.urlHandlingStrategy.shouldProcessUrl(t.rawUrl);
// Using switchMap so we cancel executing navigations when a new one comes in
switchMap(t => {
let completed = false;
let errored = false;
return of(t).pipe(
// Store the Navigation object
tap(t => {
this.currentNavigation = {
id: t.id,
initialUrl: t.currentRawUrl,
extractedUrl: t.extractedUrl,
trigger: t.source,
extras: t.extras,
previousNavigation: this.lastSuccessfulNavigation ?
{...this.lastSuccessfulNavigation, previousNavigation: null} :
null
};
}),
switchMap(t => {
const urlTransition = !this.navigated ||
t.extractedUrl.toString() !== this.browserUrlTree.toString();
const processCurrentUrl =
(this.onSameUrlNavigation === 'reload' ? true : urlTransition) &&
this.urlHandlingStrategy.shouldProcessUrl(t.rawUrl);
if (processCurrentUrl) {
return of (t).pipe(
// Fire NavigationStart event
switchMap(t => {
const transition = this.transitions.getValue();
eventsSubject.next(new NavigationStart(
t.id, this.serializeUrl(t.extractedUrl), t.source, t.restoredState));
if (transition !== this.transitions.getValue()) {
return EMPTY;
}
return [t];
}),
if (processCurrentUrl) {
return of(t).pipe(
// Fire NavigationStart event
switchMap(t => {
const transition = this.transitions.getValue();
eventsSubject.next(new NavigationStart(
t.id, this.serializeUrl(t.extractedUrl), t.source,
t.restoredState));
if (transition !== this.transitions.getValue()) {
return EMPTY;
}
return [t];
}),
// This delay is required to match old behavior that forced navigation to
// always be async
switchMap(t => Promise.resolve(t)),
// This delay is required to match old behavior that forced navigation
// to always be async
switchMap(t => Promise.resolve(t)),
// ApplyRedirects
applyRedirects(
this.ngModule.injector, this.configLoader, this.urlSerializer,
this.config),
// ApplyRedirects
applyRedirects(
this.ngModule.injector, this.configLoader, this.urlSerializer,
this.config),
// Update the currentNavigation
tap(t => {
this.currentNavigation = {
...this.currentNavigation !,
finalUrl: t.urlAfterRedirects
};
}),
// Update the currentNavigation
tap(t => {
this.currentNavigation = {
...this.currentNavigation!,
finalUrl: t.urlAfterRedirects
};
}),
// Recognize
recognize(
this.rootComponentType, this.config, (url) => this.serializeUrl(url),
this.paramsInheritanceStrategy, this.relativeLinkResolution),
// Recognize
recognize(
this.rootComponentType, this.config,
(url) => this.serializeUrl(url), this.paramsInheritanceStrategy,
this.relativeLinkResolution),
// Update URL if in `eager` update mode
tap(t => {
if (this.urlUpdateStrategy === 'eager') {
if (!t.extras.skipLocationChange) {
this.setBrowserUrl(
t.urlAfterRedirects, !!t.extras.replaceUrl, t.id, t.extras.state);
}
this.browserUrlTree = t.urlAfterRedirects;
}
}),
// Update URL if in `eager` update mode
tap(t => {
if (this.urlUpdateStrategy === 'eager') {
if (!t.extras.skipLocationChange) {
this.setBrowserUrl(
t.urlAfterRedirects, !!t.extras.replaceUrl, t.id,
t.extras.state);
}
this.browserUrlTree = t.urlAfterRedirects;
}
}),
// Fire RoutesRecognized
tap(t => {
const routesRecognized = new RoutesRecognized(
t.id, this.serializeUrl(t.extractedUrl),
this.serializeUrl(t.urlAfterRedirects), t.targetSnapshot !);
eventsSubject.next(routesRecognized);
}));
} else {
const processPreviousUrl = urlTransition && this.rawUrlTree &&
this.urlHandlingStrategy.shouldProcessUrl(this.rawUrlTree);
/* When the current URL shouldn't be processed, but the previous one was, we
* handle this "error condition" by navigating to the previously successful URL,
* but leaving the URL intact.*/
if (processPreviousUrl) {
const {id, extractedUrl, source, restoredState, extras} = t;
const navStart = new NavigationStart(
id, this.serializeUrl(extractedUrl), source, restoredState);
eventsSubject.next(navStart);
const targetSnapshot =
createEmptyState(extractedUrl, this.rootComponentType).snapshot;
// Fire RoutesRecognized
tap(t => {
const routesRecognized = new RoutesRecognized(
t.id, this.serializeUrl(t.extractedUrl),
this.serializeUrl(t.urlAfterRedirects), t.targetSnapshot!);
eventsSubject.next(routesRecognized);
}));
} else {
const processPreviousUrl = urlTransition && this.rawUrlTree &&
this.urlHandlingStrategy.shouldProcessUrl(this.rawUrlTree);
/* When the current URL shouldn't be processed, but the previous one was,
* we handle this "error condition" by navigating to the previously
* successful URL, but leaving the URL intact.*/
if (processPreviousUrl) {
const {id, extractedUrl, source, restoredState, extras} = t;
const navStart = new NavigationStart(
id, this.serializeUrl(extractedUrl), source, restoredState);
eventsSubject.next(navStart);
const targetSnapshot =
createEmptyState(extractedUrl, this.rootComponentType).snapshot;
return of ({
...t,
targetSnapshot,
urlAfterRedirects: extractedUrl,
extras: {...extras, skipLocationChange: false, replaceUrl: false},
});
} else {
/* When neither the current or previous URL can be processed, do nothing other
* than update router's internal reference to the current "settled" URL. This
* way the next navigation will be coming from the current URL in the browser.
*/
this.rawUrlTree = t.rawUrl;
this.browserUrlTree = t.urlAfterRedirects;
t.resolve(null);
return EMPTY;
}
}
}),
return of({
...t,
targetSnapshot,
urlAfterRedirects: extractedUrl,
extras: {...extras, skipLocationChange: false, replaceUrl: false},
});
} else {
/* When neither the current or previous URL can be processed, do nothing
* other than update router's internal reference to the current "settled"
* URL. This way the next navigation will be coming from the current URL
* in the browser.
*/
this.rawUrlTree = t.rawUrl;
this.browserUrlTree = t.urlAfterRedirects;
t.resolve(null);
return EMPTY;
}
}
}),
// Before Preactivation
switchTap(t => {
const {
targetSnapshot,
id: navigationId,
extractedUrl: appliedUrlTree,
rawUrl: rawUrlTree,
extras: {skipLocationChange, replaceUrl}
} = t;
return this.hooks.beforePreactivation(targetSnapshot !, {
navigationId,
appliedUrlTree,
rawUrlTree,
skipLocationChange: !!skipLocationChange,
replaceUrl: !!replaceUrl,
});
}),
// Before Preactivation
switchTap(t => {
const {
targetSnapshot,
id: navigationId,
extractedUrl: appliedUrlTree,
rawUrl: rawUrlTree,
extras: {skipLocationChange, replaceUrl}
} = t;
return this.hooks.beforePreactivation(targetSnapshot!, {
navigationId,
appliedUrlTree,
rawUrlTree,
skipLocationChange: !!skipLocationChange,
replaceUrl: !!replaceUrl,
});
}),
// --- GUARDS ---
tap(t => {
const guardsStart = new GuardsCheckStart(
t.id, this.serializeUrl(t.extractedUrl), this.serializeUrl(t.urlAfterRedirects),
t.targetSnapshot !);
this.triggerEvent(guardsStart);
}),
// --- GUARDS ---
tap(t => {
const guardsStart = new GuardsCheckStart(
t.id, this.serializeUrl(t.extractedUrl),
this.serializeUrl(t.urlAfterRedirects), t.targetSnapshot!);
this.triggerEvent(guardsStart);
}),
map(t => ({
...t,
guards:
getAllRouteGuards(t.targetSnapshot !, t.currentSnapshot, this.rootContexts)
})),
map(t => ({
...t,
guards: getAllRouteGuards(
t.targetSnapshot!, t.currentSnapshot, this.rootContexts)
})),
checkGuards(this.ngModule.injector, (evt: Event) => this.triggerEvent(evt)),
tap(t => {
if (isUrlTree(t.guardsResult)) {
const error: Error&{url?: UrlTree} = navigationCancelingError(
`Redirecting to "${this.serializeUrl(t.guardsResult)}"`);
error.url = t.guardsResult;
throw error;
}
}),
checkGuards(this.ngModule.injector, (evt: Event) => this.triggerEvent(evt)),
tap(t => {
if (isUrlTree(t.guardsResult)) {
const error: Error&{url?: UrlTree} = navigationCancelingError(
`Redirecting to "${this.serializeUrl(t.guardsResult)}"`);
error.url = t.guardsResult;
throw error;
}
}),
tap(t => {
const guardsEnd = new GuardsCheckEnd(
t.id, this.serializeUrl(t.extractedUrl), this.serializeUrl(t.urlAfterRedirects),
t.targetSnapshot !, !!t.guardsResult);
this.triggerEvent(guardsEnd);
}),
tap(t => {
const guardsEnd = new GuardsCheckEnd(
t.id, this.serializeUrl(t.extractedUrl),
this.serializeUrl(t.urlAfterRedirects), t.targetSnapshot!,
!!t.guardsResult);
this.triggerEvent(guardsEnd);
}),
filter(t => {
if (!t.guardsResult) {
this.resetUrlToCurrentUrlTree();
const navCancel =
new NavigationCancel(t.id, this.serializeUrl(t.extractedUrl), '');
eventsSubject.next(navCancel);
t.resolve(false);
return false;
}
return true;
}),
filter(t => {
if (!t.guardsResult) {
this.resetUrlToCurrentUrlTree();
const navCancel =
new NavigationCancel(t.id, this.serializeUrl(t.extractedUrl), '');
eventsSubject.next(navCancel);
t.resolve(false);
return false;
}
return true;
}),
// --- RESOLVE ---
switchTap(t => {
if (t.guards.canActivateChecks.length) {
return of (t).pipe(
tap(t => {
const resolveStart = new ResolveStart(
t.id, this.serializeUrl(t.extractedUrl),
this.serializeUrl(t.urlAfterRedirects), t.targetSnapshot !);
this.triggerEvent(resolveStart);
}),
resolveData(
this.paramsInheritanceStrategy,
this.ngModule.injector), //
tap(t => {
const resolveEnd = new ResolveEnd(
t.id, this.serializeUrl(t.extractedUrl),
this.serializeUrl(t.urlAfterRedirects), t.targetSnapshot !);
this.triggerEvent(resolveEnd);
}));
}
return undefined;
}),
// --- RESOLVE ---
switchTap(t => {
if (t.guards.canActivateChecks.length) {
return of(t).pipe(
tap(t => {
const resolveStart = new ResolveStart(
t.id, this.serializeUrl(t.extractedUrl),
this.serializeUrl(t.urlAfterRedirects), t.targetSnapshot!);
this.triggerEvent(resolveStart);
}),
resolveData(
this.paramsInheritanceStrategy,
this.ngModule.injector), //
tap(t => {
const resolveEnd = new ResolveEnd(
t.id, this.serializeUrl(t.extractedUrl),
this.serializeUrl(t.urlAfterRedirects), t.targetSnapshot!);
this.triggerEvent(resolveEnd);
}));
}
return undefined;
}),
// --- AFTER PREACTIVATION ---
switchTap((t: NavigationTransition) => {
const {
targetSnapshot,
id: navigationId,
extractedUrl: appliedUrlTree,
rawUrl: rawUrlTree,
extras: {skipLocationChange, replaceUrl}
} = t;
return this.hooks.afterPreactivation(targetSnapshot !, {
navigationId,
appliedUrlTree,
rawUrlTree,
skipLocationChange: !!skipLocationChange,
replaceUrl: !!replaceUrl,
});
}),
// --- AFTER PREACTIVATION ---
switchTap((t: NavigationTransition) => {
const {
targetSnapshot,
id: navigationId,
extractedUrl: appliedUrlTree,
rawUrl: rawUrlTree,
extras: {skipLocationChange, replaceUrl}
} = t;
return this.hooks.afterPreactivation(targetSnapshot!, {
navigationId,
appliedUrlTree,
rawUrlTree,
skipLocationChange: !!skipLocationChange,
replaceUrl: !!replaceUrl,
});
}),
map((t: NavigationTransition) => {
const targetRouterState = createRouterState(
this.routeReuseStrategy, t.targetSnapshot !, t.currentRouterState);
return ({...t, targetRouterState});
}),
map((t: NavigationTransition) => {
const targetRouterState = createRouterState(
this.routeReuseStrategy, t.targetSnapshot!, t.currentRouterState);
return ({...t, targetRouterState});
}),
/* Once here, we are about to activate syncronously. The assumption is this will
succeed, and user code may read from the Router service. Therefore before
activation, we need to update router properties storing the current URL and the
RouterState, as well as updated the browser URL. All this should happen *before*
activating. */
tap((t: NavigationTransition) => {
this.currentUrlTree = t.urlAfterRedirects;
this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, t.rawUrl);
/* Once here, we are about to activate syncronously. The assumption is this
will succeed, and user code may read from the Router service. Therefore
before activation, we need to update router properties storing the current
URL and the RouterState, as well as updated the browser URL. All this should
happen *before* activating. */
tap((t: NavigationTransition) => {
this.currentUrlTree = t.urlAfterRedirects;
this.rawUrlTree =
this.urlHandlingStrategy.merge(this.currentUrlTree, t.rawUrl);
(this as{routerState: RouterState}).routerState = t.targetRouterState !;
(this as {routerState: RouterState}).routerState = t.targetRouterState!;
if (this.urlUpdateStrategy === 'deferred') {
if (!t.extras.skipLocationChange) {
this.setBrowserUrl(
this.rawUrlTree, !!t.extras.replaceUrl, t.id, t.extras.state);
}
this.browserUrlTree = t.urlAfterRedirects;
}
}),
if (this.urlUpdateStrategy === 'deferred') {
if (!t.extras.skipLocationChange) {
this.setBrowserUrl(
this.rawUrlTree, !!t.extras.replaceUrl, t.id, t.extras.state);
}
this.browserUrlTree = t.urlAfterRedirects;
}
}),
activateRoutes(
this.rootContexts, this.routeReuseStrategy,
(evt: Event) => this.triggerEvent(evt)),
activateRoutes(
this.rootContexts, this.routeReuseStrategy,
(evt: Event) => this.triggerEvent(evt)),
tap({next() { completed = true; }, complete() { completed = true; }}),
finalize(() => {
/* When the navigation stream finishes either through error or success, we set the
* `completed` or `errored` flag. However, there are some situations where we could
* get here without either of those being set. For instance, a redirect during
* NavigationStart. Therefore, this is a catch-all to make sure the NavigationCancel
* event is fired when a navigation gets cancelled but not caught by other means. */
if (!completed && !errored) {
// Must reset to current URL tree here to ensure history.state is set. On a fresh
// page load, if a new navigation comes in before a successful navigation
// completes, there will be nothing in history.state.navigationId. This can cause
// sync problems with AngularJS sync code which looks for a value here in order
// to determine whether or not to handle a given popstate event or to leave it
// to the Angualr router.
this.resetUrlToCurrentUrlTree();
const navCancel = new NavigationCancel(
t.id, this.serializeUrl(t.extractedUrl),
`Navigation ID ${t.id} is not equal to the current navigation id ${this.navigationId}`);
eventsSubject.next(navCancel);
t.resolve(false);
}
// currentNavigation should always be reset to null here. If navigation was
// successful, lastSuccessfulTransition will have already been set. Therefore we
// can safely set currentNavigation to null here.
this.currentNavigation = null;
}),
catchError((e) => {
errored = true;
/* This error type is issued during Redirect, and is handled as a cancellation
* rather than an error. */
if (isNavigationCancelingError(e)) {
const redirecting = isUrlTree(e.url);
if (!redirecting) {
// Set property only if we're not redirecting. If we landed on a page and
// redirect to `/` route, the new navigation is going to see the `/` isn't
// a change from the default currentUrlTree and won't navigate. This is
// only applicable with initial navigation, so setting `navigated` only when
// not redirecting resolves this scenario.
this.navigated = true;
this.resetStateAndUrl(t.currentRouterState, t.currentUrlTree, t.rawUrl);
}
const navCancel =
new NavigationCancel(t.id, this.serializeUrl(t.extractedUrl), e.message);
eventsSubject.next(navCancel);
tap({
next() {
completed = true;
},
complete() {
completed = true;
}
}),
finalize(() => {
/* When the navigation stream finishes either through error or success, we
* set the `completed` or `errored` flag. However, there are some situations
* where we could get here without either of those being set. For instance, a
* redirect during NavigationStart. Therefore, this is a catch-all to make
* sure the NavigationCancel
* event is fired when a navigation gets cancelled but not caught by other
* means. */
if (!completed && !errored) {
// Must reset to current URL tree here to ensure history.state is set. On a
// fresh page load, if a new navigation comes in before a successful
// navigation completes, there will be nothing in
// history.state.navigationId. This can cause sync problems with AngularJS
// sync code which looks for a value here in order to determine whether or
// not to handle a given popstate event or to leave it to the Angualr
// router.
this.resetUrlToCurrentUrlTree();
const navCancel = new NavigationCancel(
t.id, this.serializeUrl(t.extractedUrl),
`Navigation ID ${t.id} is not equal to the current navigation id ${
this.navigationId}`);
eventsSubject.next(navCancel);
t.resolve(false);
}
// currentNavigation should always be reset to null here. If navigation was
// successful, lastSuccessfulTransition will have already been set. Therefore
// we can safely set currentNavigation to null here.
this.currentNavigation = null;
}),
catchError((e) => {
errored = true;
/* This error type is issued during Redirect, and is handled as a
* cancellation rather than an error. */
if (isNavigationCancelingError(e)) {
const redirecting = isUrlTree(e.url);
if (!redirecting) {
// Set property only if we're not redirecting. If we landed on a page and
// redirect to `/` route, the new navigation is going to see the `/`
// isn't a change from the default currentUrlTree and won't navigate.
// This is only applicable with initial navigation, so setting
// `navigated` only when not redirecting resolves this scenario.
this.navigated = true;
this.resetStateAndUrl(t.currentRouterState, t.currentUrlTree, t.rawUrl);
}
const navCancel = new NavigationCancel(
t.id, this.serializeUrl(t.extractedUrl), e.message);
eventsSubject.next(navCancel);
// When redirecting, we need to delay resolving the navigation
// promise and push it to the redirect navigation
if (!redirecting) {
t.resolve(false);
} else {
// setTimeout is required so this navigation finishes with
// the return EMPTY below. If it isn't allowed to finish
// processing, there can be multiple navigations to the same
// URL.
setTimeout(() => {
const mergedTree = this.urlHandlingStrategy.merge(e.url, this.rawUrlTree);
const extras = {
skipLocationChange: t.extras.skipLocationChange,
replaceUrl: this.urlUpdateStrategy === 'eager'
};
// When redirecting, we need to delay resolving the navigation
// promise and push it to the redirect navigation
if (!redirecting) {
t.resolve(false);
} else {
// setTimeout is required so this navigation finishes with
// the return EMPTY below. If it isn't allowed to finish
// processing, there can be multiple navigations to the same
// URL.
setTimeout(() => {
const mergedTree =
this.urlHandlingStrategy.merge(e.url, this.rawUrlTree);
const extras = {
skipLocationChange: t.extras.skipLocationChange,
replaceUrl: this.urlUpdateStrategy === 'eager'
};
return this.scheduleNavigation(
mergedTree, 'imperative', null, extras,
{resolve: t.resolve, reject: t.reject, promise: t.promise});
}, 0);
}
return this.scheduleNavigation(
mergedTree, 'imperative', null, extras,
{resolve: t.resolve, reject: t.reject, promise: t.promise});
}, 0);
}
/* All other errors should reset to the router's internal URL reference to the
* pre-error state. */
} else {
this.resetStateAndUrl(t.currentRouterState, t.currentUrlTree, t.rawUrl);
const navError = new NavigationError(t.id, this.serializeUrl(t.extractedUrl), e);
eventsSubject.next(navError);
try {
t.resolve(this.errorHandler(e));
} catch (ee) {
t.reject(ee);
}
}
return EMPTY;
}));
// TODO(jasonaden): remove cast once g3 is on updated TypeScript
})) as any as Observable<NavigationTransition>;
/* All other errors should reset to the router's internal URL reference to
* the pre-error state. */
} else {
this.resetStateAndUrl(t.currentRouterState, t.currentUrlTree, t.rawUrl);
const navError =
new NavigationError(t.id, this.serializeUrl(t.extractedUrl), e);
eventsSubject.next(navError);
try {
t.resolve(this.errorHandler(e));
} catch (ee) {
t.reject(ee);
}
}
return EMPTY;
}));
// TODO(jasonaden): remove cast once g3 is on updated TypeScript
})) as any as Observable<NavigationTransition>;
}
/**
@ -828,20 +847,27 @@ export class Router {
// Navigations coming from Angular router have a navigationId state property. When this
// exists, restore the state.
const state = change.state && change.state.navigationId ? change.state : null;
setTimeout(
() => { this.scheduleNavigation(rawUrlTree, source, state, {replaceUrl: true}); }, 0);
setTimeout(() => {
this.scheduleNavigation(rawUrlTree, source, state, {replaceUrl: true});
}, 0);
});
}
}
/** The current URL. */
get url(): string { return this.serializeUrl(this.currentUrlTree); }
get url(): string {
return this.serializeUrl(this.currentUrlTree);
}
/** The current Navigation object if one exists */
getCurrentNavigation(): Navigation|null { return this.currentNavigation; }
getCurrentNavigation(): Navigation|null {
return this.currentNavigation;
}
/** @internal */
triggerEvent(event: Event): void { (this.events as Subject<Event>).next(event); }
triggerEvent(event: Event): void {
(this.events as Subject<Event>).next(event);
}
/**
* Resets the configuration used for navigation and generating links.
@ -867,13 +893,15 @@ export class Router {
}
/** @docsNotRequired */
ngOnDestroy(): void { this.dispose(); }
ngOnDestroy(): void {
this.dispose();
}
/** Disposes of the router. */
dispose(): void {
if (this.locationSubscription) {
this.locationSubscription.unsubscribe();
this.locationSubscription = null !;
this.locationSubscription = null!;
}
}
@ -923,8 +951,14 @@ export class Router {
* ```
*/
createUrlTree(commands: any[], navigationExtras: NavigationExtras = {}): UrlTree {
const {relativeTo, queryParams, fragment,
preserveQueryParams, queryParamsHandling, preserveFragment} = navigationExtras;
const {
relativeTo,
queryParams,
fragment,
preserveQueryParams,
queryParamsHandling,
preserveFragment
} = navigationExtras;
if (isDevMode() && preserveQueryParams && <any>console && <any>console.warn) {
console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.');
}
@ -948,7 +982,7 @@ export class Router {
if (q !== null) {
q = this.removeEmptyProps(q);
}
return createUrlTree(a, this.currentUrlTree, commands, q !, f !);
return createUrlTree(a, this.currentUrlTree, commands, q!, f!);
}
/**
@ -1019,7 +1053,9 @@ export class Router {
}
/** Serializes a `UrlTree` into a string */
serializeUrl(url: UrlTree): string { return this.urlSerializer.serialize(url); }
serializeUrl(url: UrlTree): string {
return this.urlSerializer.serialize(url);
}
/** Parses a string into a `UrlTree` */
parseUrl(url: string): UrlTree {
@ -1064,7 +1100,9 @@ export class Router {
this.currentNavigation = null;
t.resolve(true);
},
e => { this.console.warn(`Unhandled Navigation Error: `); });
e => {
this.console.warn(`Unhandled Navigation Error: `);
});
}
private scheduleNavigation(
@ -1116,14 +1154,21 @@ export class Router {
source,
restoredState,
currentUrlTree: this.currentUrlTree,
currentRawUrl: this.rawUrlTree, rawUrl, extras, resolve, reject, promise,
currentRawUrl: this.rawUrlTree,
rawUrl,
extras,
resolve,
reject,
promise,
currentSnapshot: this.routerState.snapshot,
currentRouterState: this.routerState
});
// Make sure that the error is propagated even though `processNavigations` catch
// handler does not rethrow
return promise.catch((e: any) => { return Promise.reject(e); });
return promise.catch((e: any) => {
return Promise.reject(e);
});
}
private setBrowserUrl(
@ -1139,7 +1184,7 @@ export class Router {
}
private resetStateAndUrl(storedState: RouterState, storedUrl: UrlTree, rawUrl: UrlTree): void {
(this as{routerState: RouterState}).routerState = storedState;
(this as {routerState: RouterState}).routerState = storedState;
this.currentUrlTree = storedUrl;
this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, rawUrl);
this.resetUrlToCurrentUrlTree();

View File

@ -7,8 +7,9 @@
*/
import {Compiler, InjectionToken, Injector, NgModuleFactory, NgModuleFactoryLoader} from '@angular/core';
import {Observable, from, of } from 'rxjs';
import {from, Observable, of} from 'rxjs';
import {map, mergeMap} from 'rxjs/operators';
import {LoadChildren, LoadedRouterConfig, Route, standardizeConfig} from './config';
import {flatten, wrapIntoObservable} from './utils/collection';
@ -30,7 +31,7 @@ export class RouterConfigLoader {
this.onLoadStartListener(route);
}
const moduleFactory$ = this.loadModuleFactory(route.loadChildren !);
const moduleFactory$ = this.loadModuleFactory(route.loadChildren!);
return moduleFactory$.pipe(map((factory: NgModuleFactory<any>) => {
if (this.onLoadEndListener) {
@ -50,7 +51,7 @@ export class RouterConfigLoader {
} else {
return wrapIntoObservable(loadChildren()).pipe(mergeMap((t: any) => {
if (t instanceof NgModuleFactory) {
return of (t);
return of(t);
} else {
return from(this.compiler.compileModuleAsync(t));
}

View File

@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {APP_BASE_HREF, HashLocationStrategy, LOCATION_INITIALIZED, Location, LocationStrategy, PathLocationStrategy, PlatformLocation, ViewportScroller, ɵgetDOM as getDOM} from '@angular/common';
import {APP_BASE_HREF, HashLocationStrategy, Location, LOCATION_INITIALIZED, LocationStrategy, PathLocationStrategy, PlatformLocation, ViewportScroller, ɵgetDOM as getDOM} from '@angular/common';
import {ANALYZE_FOR_ENTRY_COMPONENTS, APP_BOOTSTRAP_LISTENER, APP_INITIALIZER, ApplicationRef, Compiler, ComponentRef, Inject, Injectable, InjectionToken, Injector, ModuleWithProviders, NgModule, NgModuleFactoryLoader, NgProbeToken, Optional, Provider, SkipSelf, SystemJsNgModuleLoader} from '@angular/core';
import {Subject, of } from 'rxjs';
import {of, Subject} from 'rxjs';
import {EmptyOutletComponent} from './components/empty_outlet';
import {Route, Routes} from './config';
import {RouterLink, RouterLinkWithHref} from './directives/router_link';
@ -136,7 +137,7 @@ export class RouterModule {
* @param routes An array of `Route` objects that define the navigation paths for the application.
* @param config An `ExtraOptions` configuration object that controls how navigation is performed.
* @return The new router module.
*/
*/
static forRoot(routes: Routes, config?: ExtraOptions): ModuleWithProviders<RouterModule> {
return {
ngModule: RouterModule,
@ -152,9 +153,8 @@ export class RouterModule {
{
provide: LocationStrategy,
useFactory: provideLocationStrategy,
deps: [
PlatformLocation, [new Inject(APP_BASE_HREF), new Optional()], ROUTER_CONFIGURATION
]
deps:
[PlatformLocation, [new Inject(APP_BASE_HREF), new Optional()], ROUTER_CONFIGURATION]
},
{
provide: RouterScroller,
@ -236,8 +236,9 @@ export function provideRoutes(routes: Routes): any {
* the root component gets created. Use if there is a reason to have
* more control over when the router starts its initial navigation due to some complex
* initialization logic.
* * 'legacy_enabled'- (Default, for compatibility.) The initial navigation starts after the root component has been created.
* The bootstrap is not blocked until the initial navigation is complete. @deprecated
* * 'legacy_enabled'- (Default, for compatibility.) The initial navigation starts after the root
* component has been created. The bootstrap is not blocked until the initial navigation is
* complete. @deprecated
* * 'legacy_disabled'- The initial navigation is not performed. The location listener is set up
* after the root component gets created. @deprecated since v4
* * `true` - same as 'legacy_enabled'. @deprecated since v4
@ -249,8 +250,7 @@ export function provideRoutes(routes: Routes): any {
*
* @publicApi
*/
export type InitialNavigation =
true | false | 'enabled' | 'disabled' | 'legacy_enabled' | 'legacy_disabled';
export type InitialNavigation = true|false|'enabled'|'disabled'|'legacy_enabled'|'legacy_disabled';
/**
* A set of configuration options for a router module, provided in the
@ -506,7 +506,7 @@ export class RouterInitializer {
appInitializer(): Promise<any> {
const p: Promise<any> = this.injector.get(LOCATION_INITIALIZED, Promise.resolve(null));
return p.then(() => {
let resolve: Function = null !;
let resolve: Function = null!;
const res = new Promise(r => resolve = r);
const router = this.injector.get(Router);
const opts = this.injector.get(ROUTER_CONFIGURATION);
@ -528,7 +528,7 @@ export class RouterInitializer {
// subsequent navigations should not be delayed
} else {
return of (null) as any;
return of(null) as any;
}
};
router.initialNavigation();
@ -561,7 +561,7 @@ export class RouterInitializer {
preloader.setUpPreloading();
routerScroller.init();
router.resetRootComponentType(ref.componentTypes[0]);
this.resultOfPreactivationDone.next(null !);
this.resultOfPreactivationDone.next(null!);
this.resultOfPreactivationDone.complete();
}

View File

@ -63,7 +63,9 @@ export class ChildrenOutletContexts {
return contexts;
}
onOutletReAttached(contexts: Map<string, OutletContext>) { this.contexts = contexts; }
onOutletReAttached(contexts: Map<string, OutletContext>) {
this.contexts = contexts;
}
getOrCreateContext(childName: string): OutletContext {
let context = this.getContext(childName);
@ -76,5 +78,7 @@ export class ChildrenOutletContexts {
return context;
}
getContext(childName: string): OutletContext|null { return this.contexts.get(childName) || null; }
getContext(childName: string): OutletContext|null {
return this.contexts.get(childName) || null;
}
}

View File

@ -1,13 +1,13 @@
/**
*@license
*Copyright Google Inc. 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
*/
*@license
*Copyright Google Inc. 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 {Compiler, Injectable, Injector, NgModuleFactoryLoader, NgModuleRef, OnDestroy} from '@angular/core';
import {Observable, Subscription, from, of } from 'rxjs';
import {from, Observable, of, Subscription} from 'rxjs';
import {catchError, concatMap, filter, map, mergeAll, mergeMap} from 'rxjs/operators';
import {LoadedRouterConfig, Route, Routes} from './config';
@ -40,7 +40,7 @@ export abstract class PreloadingStrategy {
*/
export class PreloadAllModules implements PreloadingStrategy {
preload(route: Route, fn: () => Observable<any>): Observable<any> {
return fn().pipe(catchError(() => of (null)));
return fn().pipe(catchError(() => of(null)));
}
}
@ -54,7 +54,9 @@ export class PreloadAllModules implements PreloadingStrategy {
* @publicApi
*/
export class NoPreloading implements PreloadingStrategy {
preload(route: Route, fn: () => Observable<any>): Observable<any> { return of (null); }
preload(route: Route, fn: () => Observable<any>): Observable<any> {
return of(null);
}
}
/**
@ -73,7 +75,7 @@ export class NoPreloading implements PreloadingStrategy {
export class RouterPreloader implements OnDestroy {
private loader: RouterConfigLoader;
// TODO(issue/24571): remove '!'.
private subscription !: Subscription;
private subscription!: Subscription;
constructor(
private router: Router, moduleLoader: NgModuleFactoryLoader, compiler: Compiler,
@ -99,7 +101,9 @@ export class RouterPreloader implements OnDestroy {
// TODO(jasonaden): This class relies on code external to the class to call setUpPreloading. If
// this hasn't been done, ngOnDestroy will fail as this.subscription will be undefined. This
// should be refactored.
ngOnDestroy(): void { this.subscription.unsubscribe(); }
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
private processRoutes(ngModule: NgModuleRef<any>, routes: Routes): Observable<void> {
const res: Observable<any>[] = [];

View File

@ -15,9 +15,9 @@ import {Router} from './router';
export class RouterScroller implements OnDestroy {
// TODO(issue/24571): remove '!'.
private routerEventsSubscription !: Unsubscribable;
private routerEventsSubscription!: Unsubscribable;
// TODO(issue/24571): remove '!'.
private scrollEventsSubscription !: Unsubscribable;
private scrollEventsSubscription!: Unsubscribable;
private lastId = 0;
private lastSource: 'imperative'|'popstate'|'hashchange'|undefined = 'imperative';
@ -27,7 +27,7 @@ export class RouterScroller implements OnDestroy {
constructor(
private router: Router,
/** @docsNotRequired */ public readonly viewportScroller: ViewportScroller, private options: {
scrollPositionRestoration?: 'disabled' | 'enabled' | 'top',
scrollPositionRestoration?: 'disabled'|'enabled'|'top',
anchorScrolling?: 'disabled'|'enabled'
} = {}) {
// Default both options to 'disabled'

View File

@ -11,8 +11,8 @@ import {BehaviorSubject, Observable} from 'rxjs';
import {map} from 'rxjs/operators';
import {Data, ResolveData, Route} from './config';
import {PRIMARY_OUTLET, ParamMap, Params, convertToParamMap} from './shared';
import {UrlSegment, UrlSegmentGroup, UrlTree, equalSegments} from './url_tree';
import {convertToParamMap, ParamMap, Params, PRIMARY_OUTLET} from './shared';
import {equalSegments, UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree';
import {shallowEqual, shallowEqualArrays} from './utils/collection';
import {Tree, TreeNode} from './utils/tree';
@ -57,10 +57,12 @@ export class RouterState extends Tree<ActivatedRoute> {
setRouterState(<RouterState>this, root);
}
toString(): string { return this.snapshot.toString(); }
toString(): string {
return this.snapshot.toString();
}
}
export function createEmptyState(urlTree: UrlTree, rootComponent: Type<any>| null): RouterState {
export function createEmptyState(urlTree: UrlTree, rootComponent: Type<any>|null): RouterState {
const snapshot = createEmptyStateSnapshot(urlTree, rootComponent);
const emptyUrl = new BehaviorSubject([new UrlSegment('', {})]);
const emptyParams = new BehaviorSubject({});
@ -75,7 +77,7 @@ export function createEmptyState(urlTree: UrlTree, rootComponent: Type<any>| nul
}
export function createEmptyStateSnapshot(
urlTree: UrlTree, rootComponent: Type<any>| null): RouterStateSnapshot {
urlTree: UrlTree, rootComponent: Type<any>|null): RouterStateSnapshot {
const emptyParams = {};
const emptyData = {};
const emptyQueryParams = {};
@ -98,15 +100,15 @@ export function createEmptyStateSnapshot(
*/
export class ActivatedRoute {
/** The current snapshot of this route */
snapshot !: ActivatedRouteSnapshot;
snapshot!: ActivatedRouteSnapshot;
/** @internal */
_futureSnapshot: ActivatedRouteSnapshot;
/** @internal */
_routerState !: RouterState;
_routerState!: RouterState;
/** @internal */
_paramMap !: Observable<ParamMap>;
_paramMap!: Observable<ParamMap>;
/** @internal */
_queryParamMap !: Observable<ParamMap>;
_queryParamMap!: Observable<ParamMap>;
/** @internal */
constructor(
@ -129,26 +131,40 @@ export class ActivatedRoute {
}
/** The configuration used to match this route. */
get routeConfig(): Route|null { return this._futureSnapshot.routeConfig; }
get routeConfig(): Route|null {
return this._futureSnapshot.routeConfig;
}
/** The root of the router state. */
get root(): ActivatedRoute { return this._routerState.root; }
get root(): ActivatedRoute {
return this._routerState.root;
}
/** The parent of this route in the router state tree. */
get parent(): ActivatedRoute|null { return this._routerState.parent(this); }
get parent(): ActivatedRoute|null {
return this._routerState.parent(this);
}
/** The first child of this route in the router state tree. */
get firstChild(): ActivatedRoute|null { return this._routerState.firstChild(this); }
get firstChild(): ActivatedRoute|null {
return this._routerState.firstChild(this);
}
/** The children of this route in the router state tree. */
get children(): ActivatedRoute[] { return this._routerState.children(this); }
get children(): ActivatedRoute[] {
return this._routerState.children(this);
}
/** The path from the root of the router state tree to this route. */
get pathFromRoot(): ActivatedRoute[] { return this._routerState.pathFromRoot(this); }
get pathFromRoot(): ActivatedRoute[] {
return this._routerState.pathFromRoot(this);
}
/** An Observable that contains a map of the required and optional parameters
/**
* An Observable that contains a map of the required and optional parameters
* specific to the route.
* The map supports retrieving single and multiple values from the same parameter. */
* The map supports retrieving single and multiple values from the same parameter.
*/
get paramMap(): Observable<ParamMap> {
if (!this._paramMap) {
this._paramMap = this.params.pipe(map((p: Params): ParamMap => convertToParamMap(p)));
@ -173,7 +189,7 @@ export class ActivatedRoute {
}
}
export type ParamsInheritanceStrategy = 'emptyOnly' | 'always';
export type ParamsInheritanceStrategy = 'emptyOnly'|'always';
/** @internal */
export type Inherited = {
@ -257,16 +273,16 @@ export class ActivatedRouteSnapshot {
_resolve: ResolveData;
/** @internal */
// TODO(issue/24571): remove '!'.
_resolvedData !: Data;
_resolvedData!: Data;
/** @internal */
// TODO(issue/24571): remove '!'.
_routerState !: RouterStateSnapshot;
_routerState!: RouterStateSnapshot;
/** @internal */
// TODO(issue/24571): remove '!'.
_paramMap !: ParamMap;
_paramMap!: ParamMap;
/** @internal */
// TODO(issue/24571): remove '!'.
_queryParamMap !: ParamMap;
_queryParamMap!: ParamMap;
/** @internal */
constructor(
@ -292,19 +308,29 @@ export class ActivatedRouteSnapshot {
}
/** The root of the router state */
get root(): ActivatedRouteSnapshot { return this._routerState.root; }
get root(): ActivatedRouteSnapshot {
return this._routerState.root;
}
/** The parent of this route in the router state tree */
get parent(): ActivatedRouteSnapshot|null { return this._routerState.parent(this); }
get parent(): ActivatedRouteSnapshot|null {
return this._routerState.parent(this);
}
/** The first child of this route in the router state tree */
get firstChild(): ActivatedRouteSnapshot|null { return this._routerState.firstChild(this); }
get firstChild(): ActivatedRouteSnapshot|null {
return this._routerState.firstChild(this);
}
/** The children of this route in the router state tree */
get children(): ActivatedRouteSnapshot[] { return this._routerState.children(this); }
get children(): ActivatedRouteSnapshot[] {
return this._routerState.children(this);
}
/** The path from the root of the router state tree to this route */
get pathFromRoot(): ActivatedRouteSnapshot[] { return this._routerState.pathFromRoot(this); }
get pathFromRoot(): ActivatedRouteSnapshot[] {
return this._routerState.pathFromRoot(this);
}
get paramMap(): ParamMap {
if (!this._paramMap) {
@ -363,10 +389,12 @@ export class RouterStateSnapshot extends Tree<ActivatedRouteSnapshot> {
setRouterState(<RouterStateSnapshot>this, root);
}
toString(): string { return serializeNode(this._root); }
toString(): string {
return serializeNode(this._root);
}
}
function setRouterState<U, T extends{_routerState: U}>(state: U, node: TreeNode<T>): void {
function setRouterState<U, T extends {_routerState: U}>(state: U, node: TreeNode<T>): void {
node.value._routerState = state;
node.children.forEach(c => setRouterState(state, c));
}
@ -416,5 +444,5 @@ export function equalParamsAndUrlSegments(
const parentsMismatch = !a.parent !== !b.parent;
return equalUrlParams && !parentsMismatch &&
(!a.parent || equalParamsAndUrlSegments(a.parent, b.parent !));
(!a.parent || equalParamsAndUrlSegments(a.parent, b.parent!));
}

View File

@ -69,9 +69,13 @@ export interface ParamMap {
class ParamsAsMap implements ParamMap {
private params: Params;
constructor(params: Params) { this.params = params || {}; }
constructor(params: Params) {
this.params = params || {};
}
has(name: string): boolean { return this.params.hasOwnProperty(name); }
has(name: string): boolean {
return this.params.hasOwnProperty(name);
}
get(name: string): string|null {
if (this.has(name)) {
@ -91,7 +95,9 @@ class ParamsAsMap implements ParamMap {
return [];
}
get keys(): string[] { return Object.keys(this.params); }
get keys(): string[] {
return Object.keys(this.params);
}
}
/**
@ -120,7 +126,7 @@ export function isNavigationCancelingError(error: Error) {
// Matches the route configuration (`route`) against the actual URL (`segments`).
export function defaultUrlMatcher(
segments: UrlSegment[], segmentGroup: UrlSegmentGroup, route: Route): UrlMatchResult|null {
const parts = route.path !.split('/');
const parts = route.path!.split('/');
if (parts.length > segments.length) {
// The actual URL is shorter than the config, no match

View File

@ -42,7 +42,13 @@ export abstract class UrlHandlingStrategy {
* @publicApi
*/
export class DefaultUrlHandlingStrategy implements UrlHandlingStrategy {
shouldProcessUrl(url: UrlTree): boolean { return true; }
extract(url: UrlTree): UrlTree { return url; }
merge(newUrlPart: UrlTree, wholeUrl: UrlTree): UrlTree { return newUrlPart; }
shouldProcessUrl(url: UrlTree): boolean {
return true;
}
extract(url: UrlTree): UrlTree {
return url;
}
merge(newUrlPart: UrlTree, wholeUrl: UrlTree): UrlTree {
return newUrlPart;
}
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {PRIMARY_OUTLET, ParamMap, Params, convertToParamMap} from './shared';
import {convertToParamMap, ParamMap, Params, PRIMARY_OUTLET} from './shared';
import {equalArraysOrString, forEach, shallowEqual} from './utils/collection';
export function createEmptyUrlTree() {
@ -106,7 +106,7 @@ function containsSegmentGroupHelper(
export class UrlTree {
/** @internal */
// TODO(issue/24571): remove '!'.
_queryParamMap !: ParamMap;
_queryParamMap!: ParamMap;
/** @internal */
constructor(
@ -125,7 +125,9 @@ export class UrlTree {
}
/** @docsNotRequired */
toString(): string { return DEFAULT_SERIALIZER.serialize(this); }
toString(): string {
return DEFAULT_SERIALIZER.serialize(this);
}
}
/**
@ -140,10 +142,10 @@ export class UrlTree {
export class UrlSegmentGroup {
/** @internal */
// TODO(issue/24571): remove '!'.
_sourceSegment !: UrlSegmentGroup;
_sourceSegment!: UrlSegmentGroup;
/** @internal */
// TODO(issue/24571): remove '!'.
_segmentIndexShift !: number;
_segmentIndexShift!: number;
/** The parent node in the url tree */
parent: UrlSegmentGroup|null = null;
@ -156,13 +158,19 @@ export class UrlSegmentGroup {
}
/** Whether the segment has child segments */
hasChildren(): boolean { return this.numberOfChildren > 0; }
hasChildren(): boolean {
return this.numberOfChildren > 0;
}
/** Number of child segments */
get numberOfChildren(): number { return Object.keys(this.children).length; }
get numberOfChildren(): number {
return Object.keys(this.children).length;
}
/** @docsNotRequired */
toString(): string { return serializePaths(this); }
toString(): string {
return serializePaths(this);
}
}
@ -195,7 +203,7 @@ export class UrlSegmentGroup {
export class UrlSegment {
/** @internal */
// TODO(issue/24571): remove '!'.
_parameterMap !: ParamMap;
_parameterMap!: ParamMap;
constructor(
/** The path part of a URL segment */
@ -212,7 +220,9 @@ export class UrlSegment {
}
/** @docsNotRequired */
toString(): string { return serializePath(this); }
toString(): string {
return serializePath(this);
}
}
export function equalSegments(as: UrlSegment[], bs: UrlSegment[]): boolean {
@ -291,7 +301,7 @@ export class DefaultUrlSerializer implements UrlSerializer {
const segment = `/${serializeSegment(tree.root, true)}`;
const query = serializeQueryParams(tree.queryParams);
const fragment =
typeof tree.fragment === `string` ? `#${encodeUriFragment(tree.fragment !)}` : '';
typeof tree.fragment === `string` ? `#${encodeUriFragment(tree.fragment!)}` : '';
return `${segment}${query}${fragment}`;
}
@ -329,7 +339,6 @@ function serializeSegment(segment: UrlSegmentGroup, root: boolean): string {
}
return [`${k}:${serializeSegment(v, false)}`];
});
return `${serializePaths(segment)}/(${children.join('//')})`;
@ -409,7 +418,7 @@ function serializeQueryParams(params: {[key: string]: any}): string {
`${encodeUriQuery(name)}=${encodeUriQuery(value)}`;
});
return strParams.length ? `?${strParams.join("&")}` : '';
return strParams.length ? `?${strParams.join('&')}` : '';
}
const SEGMENT_RE = /^[^\/()?;=#]+/;
@ -435,7 +444,9 @@ function matchUrlQueryParamValue(str: string): string {
class UrlParser {
private remaining: string;
constructor(private url: string) { this.remaining = url; }
constructor(private url: string) {
this.remaining = url;
}
parseRootSegment(): UrlSegmentGroup {
this.consumeOptional('/');
@ -584,7 +595,7 @@ class UrlParser {
throw new Error(`Cannot parse url '${this.url}'`);
}
let outletName: string = undefined !;
let outletName: string = undefined!;
if (path.indexOf(':') > -1) {
outletName = path.substr(0, path.indexOf(':'));
this.capture(outletName);
@ -602,7 +613,9 @@ class UrlParser {
return segments;
}
private peekStartsWith(str: string): boolean { return this.remaining.startsWith(str); }
private peekStartsWith(str: string): boolean {
return this.remaining.startsWith(str);
}
// Consumes the prefix when it is present and returns whether it has been consumed
private consumeOptional(str: string): boolean {

View File

@ -7,10 +7,10 @@
*/
import {NgModuleFactory, ɵisObservable as isObservable, ɵisPromise as isPromise} from '@angular/core';
import {Observable, from, of } from 'rxjs';
import {from, Observable, of} from 'rxjs';
import {concatAll, last as lastValue, map} from 'rxjs/operators';
import {PRIMARY_OUTLET, Params} from '../shared';
import {Params, PRIMARY_OUTLET} from '../shared';
export function shallowEqualArrays(a: any[], b: any[]): boolean {
if (a.length !== b.length) return false;
@ -43,7 +43,7 @@ export function shallowEqual(a: Params, b: Params): boolean {
/**
* Test equality for arrays of strings or a string.
*/
export function equalArraysOrString(a: string | string[], b: string | string[]) {
export function equalArraysOrString(a: string|string[], b: string|string[]) {
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length != b.length) return false;
return a.every(aItem => b.indexOf(aItem) > -1);
@ -84,7 +84,7 @@ export function forEach<K, V>(map: {[key: string]: V}, callback: (v: V, k: strin
export function waitForMap<A, B>(
obj: {[k: string]: A}, fn: (k: string, a: A) => Observable<B>): Observable<{[k: string]: B}> {
if (Object.keys(obj).length === 0) {
return of ({});
return of({});
}
const waitHead: Observable<B>[] = [];
@ -103,11 +103,11 @@ export function waitForMap<A, B>(
// Closure compiler has problem with using spread operator here. So we use "Array.concat".
// Note that we also need to cast the new promise because TypeScript cannot infer the type
// when calling the "of" function through "Function.apply"
return (of .apply(null, waitHead.concat(waitTail)) as Observable<Observable<B>>)
return (of.apply(null, waitHead.concat(waitTail)) as Observable<Observable<B>>)
.pipe(concatAll(), lastValue(), map(() => res));
}
export function wrapIntoObservable<T>(value: T | Promise<T>| Observable<T>): Observable<T> {
export function wrapIntoObservable<T>(value: T|Promise<T>|Observable<T>): Observable<T> {
if (isObservable(value)) {
return value;
}
@ -119,5 +119,5 @@ export function wrapIntoObservable<T>(value: T | Promise<T>| Observable<T>): Obs
return from(Promise.resolve(value));
}
return of (value);
return of(value);
}

View File

@ -10,9 +10,13 @@ export class Tree<T> {
/** @internal */
_root: TreeNode<T>;
constructor(root: TreeNode<T>) { this._root = root; }
constructor(root: TreeNode<T>) {
this._root = root;
}
get root(): T { return this._root.value; }
get root(): T {
return this._root.value;
}
/**
* @internal
@ -52,7 +56,9 @@ export class Tree<T> {
/**
* @internal
*/
pathFromRoot(t: T): T[] { return findPath(t, this._root).map(s => s.value); }
pathFromRoot(t: T): T[] {
return findPath(t, this._root).map(s => s.value);
}
}
@ -86,11 +92,13 @@ function findPath<T>(value: T, node: TreeNode<T>): TreeNode<T>[] {
export class TreeNode<T> {
constructor(public value: T, public children: TreeNode<T>[]) {}
toString(): string { return `TreeNode(${this.value})`; }
toString(): string {
return `TreeNode(${this.value})`;
}
}
// Return the list of T indexed by outlet name
export function nodeChildrenAsMap<T extends{outlet: string}>(node: TreeNode<T>| null) {
export function nodeChildrenAsMap<T extends {outlet: string}>(node: TreeNode<T>|null) {
const map: {[outlet: string]: TreeNode<T>} = {};
if (node) {

View File

@ -8,17 +8,19 @@
import {NgModuleRef} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {Observable, of } from 'rxjs';
import {Observable, of} from 'rxjs';
import {applyRedirects} from '../src/apply_redirects';
import {LoadedRouterConfig, Route, Routes} from '../src/config';
import {DefaultUrlSerializer, UrlSegment, UrlSegmentGroup, UrlTree, equalSegments} from '../src/url_tree';
import {DefaultUrlSerializer, equalSegments, UrlSegment, UrlSegmentGroup, UrlTree} from '../src/url_tree';
describe('applyRedirects', () => {
const serializer = new DefaultUrlSerializer();
let testModule: NgModuleRef<any>;
beforeEach(() => { testModule = TestBed.inject(NgModuleRef); });
beforeEach(() => {
testModule = TestBed.inject(NgModuleRef);
});
it('should return the same url tree when no redirects', () => {
checkRedirect(
@ -31,13 +33,17 @@ describe('applyRedirects', () => {
],
},
],
'/a/b', (t: UrlTree) => { expectTreeToBe(t, '/a/b'); });
'/a/b', (t: UrlTree) => {
expectTreeToBe(t, '/a/b');
});
});
it('should add new segments when needed', () => {
checkRedirect(
[{path: 'a/b', redirectTo: 'a/b/c'}, {path: '**', component: ComponentC}], '/a/b',
(t: UrlTree) => { expectTreeToBe(t, '/a/b/c'); });
(t: UrlTree) => {
expectTreeToBe(t, '/a/b/c');
});
});
it('should support redirecting with to an URL with query parameters', () => {
@ -57,11 +63,13 @@ describe('applyRedirects', () => {
{path: 'a/:aid/b/:bid', redirectTo: 'newa/:aid/newb/:bid'},
{path: '**', component: ComponentC}
],
'/a/1/b/2', (t: UrlTree) => { expectTreeToBe(t, '/newa/1/newb/2'); });
'/a/1/b/2', (t: UrlTree) => {
expectTreeToBe(t, '/newa/1/newb/2');
});
});
it('should throw when cannot handle a positional parameter', () => {
applyRedirects(testModule.injector, null !, serializer, tree('/a/1'), [
applyRedirects(testModule.injector, null!, serializer, tree('/a/1'), [
{path: 'a/:id', redirectTo: 'a/:other'}
]).subscribe(() => {}, (e) => {
expect(e.message).toEqual('Cannot redirect to \'a/:other\'. Cannot find \':other\'.');
@ -71,7 +79,9 @@ describe('applyRedirects', () => {
it('should pass matrix parameters', () => {
checkRedirect(
[{path: 'a/:id', redirectTo: 'd/a/:id/e'}, {path: '**', component: ComponentC}],
'/a;p1=1/1;p2=2', (t: UrlTree) => { expectTreeToBe(t, '/d/a;p1=1/1;p2=2/e'); });
'/a;p1=1/1;p2=2', (t: UrlTree) => {
expectTreeToBe(t, '/d/a;p1=1/1;p2=2/e');
});
});
it('should handle preserve secondary routes', () => {
@ -80,7 +90,9 @@ describe('applyRedirects', () => {
{path: 'a/:id', redirectTo: 'd/a/:id/e'},
{path: 'c/d', component: ComponentA, outlet: 'aux'}, {path: '**', component: ComponentC}
],
'/a/1(aux:c/d)', (t: UrlTree) => { expectTreeToBe(t, '/d/a/1/e(aux:c/d)'); });
'/a/1(aux:c/d)', (t: UrlTree) => {
expectTreeToBe(t, '/d/a/1/e(aux:c/d)');
});
});
it('should redirect secondary routes', () => {
@ -90,7 +102,9 @@ describe('applyRedirects', () => {
{path: 'c/d', redirectTo: 'f/c/d/e', outlet: 'aux'},
{path: '**', component: ComponentC, outlet: 'aux'}
],
'/a/1(aux:c/d)', (t: UrlTree) => { expectTreeToBe(t, '/a/1(aux:f/c/d/e)'); });
'/a/1(aux:c/d)', (t: UrlTree) => {
expectTreeToBe(t, '/a/1(aux:f/c/d/e)');
});
});
it('should use the configuration of the route redirected to', () => {
@ -105,7 +119,9 @@ describe('applyRedirects', () => {
},
{path: 'c', redirectTo: 'a'}
],
'c/b', (t: UrlTree) => { expectTreeToBe(t, 'a/b'); });
'c/b', (t: UrlTree) => {
expectTreeToBe(t, 'a/b');
});
});
it('should support redirects with both main and aux', () => {
@ -119,7 +135,9 @@ describe('applyRedirects', () => {
{path: 'b', redirectTo: 'cc', outlet: 'aux'}
]
}],
'a/(b//aux:b)', (t: UrlTree) => { expectTreeToBe(t, 'a/(bb//aux:cc)'); });
'a/(b//aux:b)', (t: UrlTree) => {
expectTreeToBe(t, 'a/(bb//aux:cc)');
});
});
it('should support redirects with both main and aux (with a nested redirect)', () => {
@ -138,7 +156,9 @@ describe('applyRedirects', () => {
{path: 'b', redirectTo: 'cc/d', outlet: 'aux'}
]
}],
'a/(b//aux:b)', (t: UrlTree) => { expectTreeToBe(t, 'a/(bb//aux:cc/dd)'); });
'a/(b//aux:b)', (t: UrlTree) => {
expectTreeToBe(t, 'a/(bb//aux:cc/dd)');
});
});
it('should redirect wild cards', () => {
@ -147,7 +167,9 @@ describe('applyRedirects', () => {
{path: '404', component: ComponentA},
{path: '**', redirectTo: '/404'},
],
'/a/1(aux:c/d)', (t: UrlTree) => { expectTreeToBe(t, '/404'); });
'/a/1(aux:c/d)', (t: UrlTree) => {
expectTreeToBe(t, '/404');
});
});
it('should support absolute redirects', () => {
@ -160,7 +182,9 @@ describe('applyRedirects', () => {
},
{path: '**', component: ComponentC}
],
'/a/b/1?b=2', (t: UrlTree) => { expectTreeToBe(t, '/absolute/1?a=1&b=2#f1'); });
'/a/b/1?b=2', (t: UrlTree) => {
expectTreeToBe(t, '/absolute/1?a=1&b=2#f1');
});
});
describe('lazy loading', () => {
@ -169,7 +193,7 @@ describe('applyRedirects', () => {
const loader = {
load: (injector: any, p: any) => {
if (injector !== testModule.injector) throw 'Invalid Injector';
return of (loadedConfig);
return of(loadedConfig);
}
};
const config: Routes = [{path: 'a', component: ComponentA, loadChildren: 'children'}];
@ -188,24 +212,23 @@ describe('applyRedirects', () => {
const config = [{path: 'a', component: ComponentA, loadChildren: 'children'}];
applyRedirects(testModule.injector, <any>loader, serializer, tree('a/b'), config)
.subscribe(() => {}, (e) => { expect(e.message).toEqual('Loading Error'); });
.subscribe(() => {}, (e) => {
expect(e.message).toEqual('Loading Error');
});
});
it('should load when all canLoad guards return true', () => {
const loadedConfig = new LoadedRouterConfig([{path: 'b', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
const guard = () => true;
const injector = {
get: (token: any) => token === 'guard1' || token === 'guard2' ? guard : {injector}
};
const config = [{
path: 'a',
component: ComponentA,
canLoad: ['guard1', 'guard2'],
loadChildren: 'children'
}];
const config = [
{path: 'a', component: ComponentA, canLoad: ['guard1', 'guard2'], loadChildren: 'children'}
];
applyRedirects(<any>injector, <any>loader, serializer, tree('a/b'), config).forEach(r => {
expectTreeToBe(r, '/a/b');
@ -214,7 +237,7 @@ describe('applyRedirects', () => {
it('should not load when any canLoad guards return false', () => {
const loadedConfig = new LoadedRouterConfig([{path: 'b', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
const trueGuard = () => true;
const falseGuard = () => false;
@ -231,16 +254,15 @@ describe('applyRedirects', () => {
}
};
const config = [{
path: 'a',
component: ComponentA,
canLoad: ['guard1', 'guard2'],
loadChildren: 'children'
}];
const config = [
{path: 'a', component: ComponentA, canLoad: ['guard1', 'guard2'], loadChildren: 'children'}
];
applyRedirects(<any>injector, <any>loader, serializer, tree('a/b'), config)
.subscribe(
() => { throw 'Should not reach'; },
() => {
throw 'Should not reach';
},
(e) => {
expect(e.message).toEqual(
`NavigationCancelingError: Cannot load children because the guard of the route "path: 'a'" returned false`);
@ -249,7 +271,7 @@ describe('applyRedirects', () => {
it('should not load when any canLoad guards is rejected (promises)', () => {
const loadedConfig = new LoadedRouterConfig([{path: 'b', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
const trueGuard = () => Promise.resolve(true);
const falseGuard = () => Promise.reject('someError');
@ -266,21 +288,23 @@ describe('applyRedirects', () => {
}
};
const config = [{
path: 'a',
component: ComponentA,
canLoad: ['guard1', 'guard2'],
loadChildren: 'children'
}];
const config = [
{path: 'a', component: ComponentA, canLoad: ['guard1', 'guard2'], loadChildren: 'children'}
];
applyRedirects(<any>injector, <any>loader, serializer, tree('a/b'), config)
.subscribe(
() => { throw 'Should not reach'; }, (e) => { expect(e).toEqual('someError'); });
() => {
throw 'Should not reach';
},
(e) => {
expect(e).toEqual('someError');
});
});
it('should work with objects implementing the CanLoad interface', () => {
const loadedConfig = new LoadedRouterConfig([{path: 'b', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
const guard = {canLoad: () => Promise.resolve(true)};
const injector = {get: (token: any) => token === 'guard' ? guard : {injector}};
@ -289,13 +313,18 @@ describe('applyRedirects', () => {
[{path: 'a', component: ComponentA, canLoad: ['guard'], loadChildren: 'children'}];
applyRedirects(<any>injector, <any>loader, serializer, tree('a/b'), config)
.subscribe((r) => { expectTreeToBe(r, '/a/b'); }, (e) => { throw 'Should not reach'; });
.subscribe(
(r) => {
expectTreeToBe(r, '/a/b');
},
(e) => {
throw 'Should not reach';
});
});
it('should pass UrlSegments to functions implementing the canLoad guard interface', () => {
const loadedConfig = new LoadedRouterConfig([{path: 'b', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
let passedUrlSegments: UrlSegment[];
@ -316,13 +345,14 @@ describe('applyRedirects', () => {
expect(passedUrlSegments[0].path).toBe('a');
expect(passedUrlSegments[1].path).toBe('b');
},
(e) => { throw 'Should not reach'; });
(e) => {
throw 'Should not reach';
});
});
it('should pass UrlSegments to objects implementing the canLoad guard interface', () => {
const loadedConfig = new LoadedRouterConfig([{path: 'b', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
let passedUrlSegments: UrlSegment[];
@ -345,14 +375,15 @@ describe('applyRedirects', () => {
expect(passedUrlSegments[0].path).toBe('a');
expect(passedUrlSegments[1].path).toBe('b');
},
(e) => { throw 'Should not reach'; });
(e) => {
throw 'Should not reach';
});
});
it('should work with absolute redirects', () => {
const loadedConfig = new LoadedRouterConfig([{path: '', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
const config: Routes =
[{path: '', pathMatch: 'full', redirectTo: '/a'}, {path: 'a', loadChildren: 'children'}];
@ -371,7 +402,7 @@ describe('applyRedirects', () => {
load: (injector: any, p: any) => {
if (called) throw new Error('Should not be called twice');
called = true;
return of (loadedConfig);
return of(loadedConfig);
}
};
@ -386,42 +417,50 @@ describe('applyRedirects', () => {
expectTreeToBe(r, 'a?k2');
expect((config[0] as any)._loadedConfig).toBe(loadedConfig);
},
(e) => { throw 'Should not reach'; });
(e) => {
throw 'Should not reach';
});
});
it('should load the configuration of a wildcard route', () => {
const loadedConfig = new LoadedRouterConfig([{path: '', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
const config: Routes = [{path: '**', loadChildren: 'children'}];
applyRedirects(testModule.injector, <any>loader, serializer, tree('xyz'), config)
.forEach(r => { expect((config[0] as any)._loadedConfig).toBe(loadedConfig); });
.forEach(r => {
expect((config[0] as any)._loadedConfig).toBe(loadedConfig);
});
});
it('should load the configuration after a local redirect from a wildcard route', () => {
const loadedConfig = new LoadedRouterConfig([{path: '', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
const config: Routes =
[{path: 'not-found', loadChildren: 'children'}, {path: '**', redirectTo: 'not-found'}];
applyRedirects(testModule.injector, <any>loader, serializer, tree('xyz'), config)
.forEach(r => { expect((config[0] as any)._loadedConfig).toBe(loadedConfig); });
.forEach(r => {
expect((config[0] as any)._loadedConfig).toBe(loadedConfig);
});
});
it('should load the configuration after an absolute redirect from a wildcard route', () => {
const loadedConfig = new LoadedRouterConfig([{path: '', component: ComponentB}], testModule);
const loader = {load: (injector: any, p: any) => of (loadedConfig)};
const loader = {load: (injector: any, p: any) => of(loadedConfig)};
const config: Routes =
[{path: 'not-found', loadChildren: 'children'}, {path: '**', redirectTo: '/not-found'}];
applyRedirects(testModule.injector, <any>loader, serializer, tree('xyz'), config)
.forEach(r => { expect((config[0] as any)._loadedConfig).toBe(loadedConfig); });
.forEach(r => {
expect((config[0] as any)._loadedConfig).toBe(loadedConfig);
});
});
});
@ -438,7 +477,9 @@ describe('applyRedirects', () => {
},
{path: '', redirectTo: 'a'}
],
'b', (t: UrlTree) => { expectTreeToBe(t, 'a/b'); });
'b', (t: UrlTree) => {
expectTreeToBe(t, 'a/b');
});
});
it('redirect from an empty path should work (absolute redirect)', () => {
@ -453,7 +494,9 @@ describe('applyRedirects', () => {
},
{path: '', redirectTo: '/a/b'}
],
'', (t: UrlTree) => { expectTreeToBe(t, 'a/b'); });
'', (t: UrlTree) => {
expectTreeToBe(t, 'a/b');
});
});
it('should redirect empty path route only when terminal', () => {
@ -468,10 +511,14 @@ describe('applyRedirects', () => {
{path: '', redirectTo: 'a', pathMatch: 'full'}
];
applyRedirects(testModule.injector, null !, serializer, tree('b'), config)
applyRedirects(testModule.injector, null!, serializer, tree('b'), config)
.subscribe(
(_) => { throw 'Should not be reached'; },
e => { expect(e.message).toEqual('Cannot match any routes. URL Segment: \'b\''); });
(_) => {
throw 'Should not be reached';
},
e => {
expect(e.message).toEqual('Cannot match any routes. URL Segment: \'b\'');
});
});
it('redirect from an empty path should work (nested case)', () => {
@ -484,7 +531,9 @@ describe('applyRedirects', () => {
},
{path: '', redirectTo: 'a'}
],
'', (t: UrlTree) => { expectTreeToBe(t, 'a/b'); });
'', (t: UrlTree) => {
expectTreeToBe(t, 'a/b');
});
});
it('redirect to an empty path should work', () => {
@ -493,7 +542,9 @@ describe('applyRedirects', () => {
{path: '', component: ComponentA, children: [{path: 'b', component: ComponentB}]},
{path: 'a', redirectTo: ''}
],
'a/b', (t: UrlTree) => { expectTreeToBe(t, 'b'); });
'a/b', (t: UrlTree) => {
expectTreeToBe(t, 'b');
});
});
describe('aux split is in the middle', () => {
@ -507,7 +558,9 @@ describe('applyRedirects', () => {
{path: '', redirectTo: 'c', outlet: 'aux'}
]
}],
'a/b', (t: UrlTree) => { expectTreeToBe(t, 'a/(b//aux:c)'); });
'a/b', (t: UrlTree) => {
expectTreeToBe(t, 'a/(b//aux:c)');
});
});
it('should create a new url segment (terminal)', () => {
@ -520,7 +573,9 @@ describe('applyRedirects', () => {
{path: '', pathMatch: 'full', redirectTo: 'c', outlet: 'aux'}
]
}],
'a/b', (t: UrlTree) => { expectTreeToBe(t, 'a/b'); });
'a/b', (t: UrlTree) => {
expectTreeToBe(t, 'a/b');
});
});
});
@ -535,7 +590,9 @@ describe('applyRedirects', () => {
{path: '', redirectTo: 'c', outlet: 'aux'}
]
}],
'a', (t: UrlTree) => { expectTreeToBe(t, 'a/(b//aux:c)'); });
'a', (t: UrlTree) => {
expectTreeToBe(t, 'a/(b//aux:c)');
});
});
it('should create a new child (terminal)', () => {
@ -548,7 +605,9 @@ describe('applyRedirects', () => {
{path: '', pathMatch: 'full', redirectTo: 'c', outlet: 'aux'}
]
}],
'a', (t: UrlTree) => { expectTreeToBe(t, 'a/(b//aux:c)'); });
'a', (t: UrlTree) => {
expectTreeToBe(t, 'a/(b//aux:c)');
});
});
it('should work only only primary outlet', () => {
@ -560,7 +619,9 @@ describe('applyRedirects', () => {
{path: 'c', component: ComponentC, outlet: 'aux'}
]
}],
'a/(aux:c)', (t: UrlTree) => { expectTreeToBe(t, 'a/(b//aux:c)'); });
'a/(aux:c)', (t: UrlTree) => {
expectTreeToBe(t, 'a/(b//aux:c)');
});
});
});
@ -580,7 +641,9 @@ describe('applyRedirects', () => {
{path: '', redirectTo: 'c', outlet: 'aux'}
]
}],
'a/(d//aux:e)', (t: UrlTree) => { expectTreeToBe(t, 'a/(b/d//aux:c/e)'); });
'a/(d//aux:e)', (t: UrlTree) => {
expectTreeToBe(t, 'a/(b/d//aux:c/e)');
});
});
it('should not create a new child (terminal)', () => {
@ -598,10 +661,14 @@ describe('applyRedirects', () => {
]
}];
applyRedirects(testModule.injector, null !, serializer, tree('a/(d//aux:e)'), config)
applyRedirects(testModule.injector, null!, serializer, tree('a/(d//aux:e)'), config)
.subscribe(
(_) => { throw 'Should not be reached'; },
e => { expect(e.message).toEqual('Cannot match any routes. URL Segment: \'a\''); });
(_) => {
throw 'Should not be reached';
},
e => {
expect(e.message).toEqual('Cannot match any routes. URL Segment: \'a\'');
});
});
});
});
@ -610,7 +677,9 @@ describe('applyRedirects', () => {
it('should not error when no children matching and no url is left', () => {
checkRedirect(
[{path: 'a', component: ComponentA, children: [{path: 'b', component: ComponentB}]}],
'/a', (t: UrlTree) => { expectTreeToBe(t, 'a'); });
'/a', (t: UrlTree) => {
expectTreeToBe(t, 'a');
});
});
it('should not error when no children matching and no url is left (aux routes)', () => {
@ -624,16 +693,22 @@ describe('applyRedirects', () => {
{path: 'c', component: ComponentC, outlet: 'aux'},
]
}],
'/a', (t: UrlTree) => { expectTreeToBe(t, 'a/(aux:c)'); });
'/a', (t: UrlTree) => {
expectTreeToBe(t, 'a/(aux:c)');
});
});
it('should error when no children matching and some url is left', () => {
applyRedirects(
testModule.injector, null !, serializer, tree('/a/c'),
testModule.injector, null!, serializer, tree('/a/c'),
[{path: 'a', component: ComponentA, children: [{path: 'b', component: ComponentB}]}])
.subscribe(
(_) => { throw 'Should not be reached'; },
e => { expect(e.message).toEqual('Cannot match any routes. URL Segment: \'a/c\''); });
(_) => {
throw 'Should not be reached';
},
e => {
expect(e.message).toEqual('Cannot match any routes. URL Segment: \'a/c\'');
});
});
});
@ -653,7 +728,9 @@ describe('applyRedirects', () => {
component: ComponentA,
children: [{path: 'b', component: ComponentB}]
}] as any,
'/a/1/b', (t: UrlTree) => { expectTreeToBe(t, 'a/1/b'); });
'/a/1/b', (t: UrlTree) => {
expectTreeToBe(t, 'a/1/b');
});
});
});
@ -665,7 +742,9 @@ describe('applyRedirects', () => {
{path: 'b/:id', component: ComponentB},
{path: 'c/:id', component: ComponentC, outlet: 'aux'}
],
'a/1;p=99', (t: UrlTree) => { expectTreeToBe(t, '/b/1;p=99(aux:c/1;p=99)'); });
'a/1;p=99', (t: UrlTree) => {
expectTreeToBe(t, '/b/1;p=99(aux:c/1;p=99)');
});
});
it('should work when using absolute redirects (wildcard)', () => {
@ -674,17 +753,21 @@ describe('applyRedirects', () => {
{path: '**', redirectTo: '/b(aux:c)'}, {path: 'b', component: ComponentB},
{path: 'c', component: ComponentC, outlet: 'aux'}
],
'a/1', (t: UrlTree) => { expectTreeToBe(t, '/b(aux:c)'); });
'a/1', (t: UrlTree) => {
expectTreeToBe(t, '/b(aux:c)');
});
});
it('should throw when using non-absolute redirects', () => {
applyRedirects(
testModule.injector, null !, serializer, tree('a'),
testModule.injector, null!, serializer, tree('a'),
[
{path: 'a', redirectTo: 'b(aux:c)'},
])
.subscribe(
() => { throw new Error('should not be reached'); },
() => {
throw new Error('should not be reached');
},
(e) => {
expect(e.message).toEqual(
'Only absolute redirects can have named outlets. redirectTo: \'b(aux:c)\'');
@ -694,8 +777,10 @@ describe('applyRedirects', () => {
});
function checkRedirect(config: Routes, url: string, callback: any): void {
applyRedirects(TestBed, null !, new DefaultUrlSerializer(), tree(url), config)
.subscribe(callback, e => { throw e; });
applyRedirects(TestBed, null!, new DefaultUrlSerializer(), tree(url), config)
.subscribe(callback, e => {
throw e;
});
}
function tree(url: string): UrlTree {

View File

@ -7,7 +7,7 @@
*/
import {APP_BASE_HREF, DOCUMENT, Location, ɵgetDOM as getDOM} from '@angular/common';
import {ApplicationRef, CUSTOM_ELEMENTS_SCHEMA, Component, NgModule, destroyPlatform} from '@angular/core';
import {ApplicationRef, Component, CUSTOM_ELEMENTS_SCHEMA, destroyPlatform, NgModule} from '@angular/core';
import {inject} from '@angular/core/testing';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
@ -17,11 +17,13 @@ import {filter, first} from 'rxjs/operators';
describe('bootstrap', () => {
if (isNode) return;
let log: any[] = [];
let testProviders: any[] = null !;
let testProviders: any[] = null!;
@Component({selector: 'test-app', template: 'root <router-outlet></router-outlet>'})
class RootCmp {
constructor() { log.push('RootCmp'); }
constructor() {
log.push('RootCmp');
}
}
@Component({selector: 'test-app2', template: 'root <router-outlet></router-outlet>'})
@ -63,9 +65,10 @@ describe('bootstrap', () => {
@NgModule({
imports: [
BrowserModule, RouterModule.forRoot(
[{path: '**', component: TestCmpEnabled, resolve: {test: TestResolver}}],
{useHash: true, initialNavigation: 'enabled'})
BrowserModule,
RouterModule.forRoot(
[{path: '**', component: TestCmpEnabled, resolve: {test: TestResolver}}],
{useHash: true, initialNavigation: 'enabled'})
],
declarations: [RootCmp, TestCmpEnabled],
bootstrap: [RootCmp],
@ -81,7 +84,7 @@ describe('bootstrap', () => {
platformBrowserDynamic([]).bootstrapModule(TestModule).then(res => {
const router = res.injector.get(Router);
const data = router.routerState.snapshot.root.firstChild !.data;
const data = router.routerState.snapshot.root.firstChild!.data;
expect(data['test']).toEqual('test-data');
expect(log).toEqual([
'TestModule', 'NavigationStart', 'RoutesRecognized', 'GuardsCheckStart',
@ -141,9 +144,10 @@ describe('bootstrap', () => {
@NgModule({
imports: [
BrowserModule, RouterModule.forRoot(
[{path: '**', component: TestCmpDiabled, resolve: {test: TestResolver}}],
{useHash: true, initialNavigation: 'disabled'})
BrowserModule,
RouterModule.forRoot(
[{path: '**', component: TestCmpDiabled, resolve: {test: TestResolver}}],
{useHash: true, initialNavigation: 'disabled'})
],
declarations: [RootCmp, TestCmpDiabled],
bootstrap: [RootCmp],
@ -250,7 +254,7 @@ describe('bootstrap', () => {
});
it('should restore the scrolling position', async(done) => {
it('should restore the scrolling position', async (done) => {
@Component({
selector: 'component-a',
template: `

View File

@ -32,12 +32,12 @@ describe('config', () => {
it('should throw for undefined route in children', () => {
expect(() => {
validateConfig([{
path: 'a',
children: [
{path: 'b', component: ComponentB},
,
]
}] as any);
path: 'a',
children: [
{path: 'b', component: ComponentB},
,
]
}] as any);
}).toThrowError(/Invalid configuration of route 'a'/);
});
@ -66,46 +66,58 @@ describe('config', () => {
});
it('should properly report deeply nested path', () => {
expect(() => validateConfig([{
path: 'a',
children: [{path: 'b', children: [{path: 'c', children: [{path: 'd'}]}]}]
}]))
expect(
() => validateConfig([
{path: 'a', children: [{path: 'b', children: [{path: 'c', children: [{path: 'd'}]}]}]}
]))
.toThrowError(
`Invalid configuration of route 'a/b/c/d'. One of the following must be provided: component, redirectTo, children or loadChildren`);
});
it('should throw when redirectTo and loadChildren are used together', () => {
expect(() => { validateConfig([{path: 'a', redirectTo: 'b', loadChildren: 'value'}]); })
expect(() => {
validateConfig([{path: 'a', redirectTo: 'b', loadChildren: 'value'}]);
})
.toThrowError(
`Invalid configuration of route 'a': redirectTo and loadChildren cannot be used together`);
});
it('should throw when children and loadChildren are used together', () => {
expect(() => { validateConfig([{path: 'a', children: [], loadChildren: 'value'}]); })
expect(() => {
validateConfig([{path: 'a', children: [], loadChildren: 'value'}]);
})
.toThrowError(
`Invalid configuration of route 'a': children and loadChildren cannot be used together`);
});
it('should throw when component and redirectTo are used together', () => {
expect(() => { validateConfig([{path: 'a', component: ComponentA, redirectTo: 'b'}]); })
expect(() => {
validateConfig([{path: 'a', component: ComponentA, redirectTo: 'b'}]);
})
.toThrowError(
`Invalid configuration of route 'a': redirectTo and component cannot be used together`);
});
it('should throw when path and matcher are used together', () => {
expect(() => { validateConfig([{path: 'a', matcher: <any>'someFunc', children: []}]); })
expect(() => {
validateConfig([{path: 'a', matcher: <any>'someFunc', children: []}]);
})
.toThrowError(
`Invalid configuration of route 'a': path and matcher cannot be used together`);
});
it('should throw when path and matcher are missing', () => {
expect(() => { validateConfig([{component: null, redirectTo: 'b'}] as any); })
expect(() => {
validateConfig([{component: null, redirectTo: 'b'}] as any);
})
.toThrowError(
`Invalid configuration of route '': routes must have either a path or a matcher specified`);
});
it('should throw when none of component and children or direct are missing', () => {
expect(() => { validateConfig([{path: 'a'}]); })
expect(() => {
validateConfig([{path: 'a'}]);
})
.toThrowError(
`Invalid configuration of route 'a'. One of the following must be provided: component, redirectTo, children or loadChildren`);
});
@ -124,13 +136,17 @@ describe('config', () => {
});
it('should throw when pathMatch is invalid', () => {
expect(() => { validateConfig([{path: 'a', pathMatch: 'invalid', component: ComponentB}]); })
expect(() => {
validateConfig([{path: 'a', pathMatch: 'invalid', component: ComponentB}]);
})
.toThrowError(
/Invalid configuration of route 'a': pathMatch can only be set to 'prefix' or 'full'/);
});
it('should throw when path/outlet combination is invalid', () => {
expect(() => { validateConfig([{path: 'a', outlet: 'aux'}]); })
expect(() => {
validateConfig([{path: 'a', outlet: 'aux'}]);
})
.toThrowError(
/Invalid configuration of route 'a': a componentless route without children or loadChildren cannot have a named outlet set/);
expect(() => validateConfig([{path: 'a', outlet: '', children: []}])).not.toThrow();
@ -139,7 +155,9 @@ describe('config', () => {
});
it('should not throw when path/outlet combination is valid', () => {
expect(() => { validateConfig([{path: 'a', outlet: 'aux', children: []}]); }).not.toThrow();
expect(() => {
validateConfig([{path: 'a', outlet: 'aux', children: []}]);
}).not.toThrow();
expect(() => {
validateConfig([{path: 'a', outlet: 'aux', loadChildren: 'child'}]);
}).not.toThrow();

View File

@ -10,7 +10,7 @@ import {Routes} from '../src/config';
import {createRouterState} from '../src/create_router_state';
import {recognize} from '../src/recognize';
import {DefaultRouteReuseStrategy} from '../src/route_reuse_strategy';
import {ActivatedRoute, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from '../src/router_state';
import {ActivatedRoute, advanceActivatedRoute, createEmptyState, RouterState, RouterStateSnapshot} from '../src/router_state';
import {PRIMARY_OUTLET} from '../src/shared';
import {DefaultUrlSerializer, UrlSegmentGroup, UrlTree} from '../src/url_tree';
import {TreeNode} from '../src/utils/tree';
@ -18,18 +18,19 @@ import {TreeNode} from '../src/utils/tree';
describe('create router state', () => {
const reuseStrategy = new DefaultRouteReuseStrategy();
const emptyState = () => createEmptyState(
new (UrlTree as any)(new UrlSegmentGroup([], {}), {}, null !), RootComponent);
const emptyState = () =>
createEmptyState(new (UrlTree as any)(new UrlSegmentGroup([], {}), {}, null!), RootComponent);
it('should create new state', () => {
const state = createRouterState(
reuseStrategy, createState(
[
{path: 'a', component: ComponentA},
{path: 'b', component: ComponentB, outlet: 'left'},
{path: 'c', component: ComponentC, outlet: 'right'}
],
'a(left:b//right:c)'),
reuseStrategy,
createState(
[
{path: 'a', component: ComponentA},
{path: 'b', component: ComponentB, outlet: 'left'},
{path: 'c', component: ComponentC, outlet: 'right'}
],
'a(left:b//right:c)'),
emptyState());
checkActivatedRoute(state.root, RootComponent);
@ -63,9 +64,8 @@ describe('create router state', () => {
it('should handle componentless routes', () => {
const config = [{
path: 'a/:id',
children: [
{path: 'b', component: ComponentA}, {path: 'c', component: ComponentB, outlet: 'right'}
]
children:
[{path: 'b', component: ComponentA}, {path: 'c', component: ComponentB, outlet: 'right'}]
}];
@ -76,8 +76,8 @@ describe('create router state', () => {
createRouterState(reuseStrategy, createState(config, 'a/2;p=22/(b//right:c)'), prevState);
expect(prevState.root).toBe(state.root);
const prevP = (prevState as any).firstChild(prevState.root) !;
const currP = (state as any).firstChild(state.root) !;
const prevP = (prevState as any).firstChild(prevState.root)!;
const currP = (state as any).firstChild(state.root)!;
expect(prevP).toBe(currP);
const currC = (state as any).children(currP);
@ -121,7 +121,7 @@ function advanceNode(node: TreeNode<ActivatedRoute>): void {
}
function createState(config: Routes, url: string): RouterStateSnapshot {
let res: RouterStateSnapshot = undefined !;
let res: RouterStateSnapshot = undefined!;
recognize(RootComponent, config, tree(url), url).forEach(s => res = s);
return res;
}

View File

@ -10,7 +10,7 @@ import {BehaviorSubject} from 'rxjs';
import {createUrlTree} from '../src/create_url_tree';
import {ActivatedRoute, ActivatedRouteSnapshot, advanceActivatedRoute} from '../src/router_state';
import {PRIMARY_OUTLET, Params} from '../src/shared';
import {Params, PRIMARY_OUTLET} from '../src/shared';
import {DefaultUrlSerializer, UrlSegmentGroup, UrlTree} from '../src/url_tree';
describe('createUrlTree', () => {
@ -247,10 +247,10 @@ function createRoot(tree: UrlTree, commands: any[], queryParams?: Params, fragme
[], <any>{}, <any>{}, '', <any>{}, PRIMARY_OUTLET, 'someComponent', null, tree.root, -1,
<any>null);
const a = new (ActivatedRoute as any)(
new BehaviorSubject(null !), new BehaviorSubject(null !), new BehaviorSubject(null !),
new BehaviorSubject(null !), new BehaviorSubject(null !), PRIMARY_OUTLET, 'someComponent', s);
new BehaviorSubject(null!), new BehaviorSubject(null!), new BehaviorSubject(null!),
new BehaviorSubject(null!), new BehaviorSubject(null!), PRIMARY_OUTLET, 'someComponent', s);
advanceActivatedRoute(a);
return createUrlTree(a, tree, commands, queryParams !, fragment !);
return createUrlTree(a, tree, commands, queryParams!, fragment!);
}
function create(
@ -263,8 +263,8 @@ function create(
[], <any>{}, <any>{}, '', <any>{}, PRIMARY_OUTLET, 'someComponent', null, <any>segment,
startIndex, <any>null);
const a = new (ActivatedRoute as any)(
new BehaviorSubject(null !), new BehaviorSubject(null !), new BehaviorSubject(null !),
new BehaviorSubject(null !), new BehaviorSubject(null !), PRIMARY_OUTLET, 'someComponent', s);
new BehaviorSubject(null!), new BehaviorSubject(null!), new BehaviorSubject(null!),
new BehaviorSubject(null!), new BehaviorSubject(null!), PRIMARY_OUTLET, 'someComponent', s);
advanceActivatedRoute(a);
return createUrlTree(a, tree, commands, queryParams !, fragment !);
return createUrlTree(a, tree, commands, queryParams!, fragment!);
}

View File

@ -10,13 +10,17 @@ import {Type} from '@angular/core';
import {Data, ResolveData, Route} from '../src/config';
import {ActivatedRouteSnapshot} from '../src/router_state';
import {PRIMARY_OUTLET, ParamMap, Params, convertToParamMap} from '../src/shared';
import {UrlSegment, UrlSegmentGroup, UrlTree, equalSegments} from '../src/url_tree';
import {convertToParamMap, ParamMap, Params, PRIMARY_OUTLET} from '../src/shared';
import {equalSegments, UrlSegment, UrlSegmentGroup, UrlTree} from '../src/url_tree';
export class Logger {
logs: string[] = [];
add(thing: string) { this.logs.push(thing); }
empty() { this.logs.length = 0; }
add(thing: string) {
this.logs.push(thing);
}
empty() {
this.logs.length = 0;
}
}
export function provideTokenLogger(token: string, returnValue = true as boolean | UrlTree) {
@ -33,8 +37,7 @@ export declare type ARSArgs = {
queryParams?: Params,
fragment?: string,
data?: Data,
outlet?: string,
component: Type<any>| string | null,
outlet?: string, component: Type<any>| string | null,
routeConfig?: Route | null,
urlSegment?: UrlSegmentGroup,
lastPathIndex?: number,

View File

@ -9,7 +9,7 @@
import {TestBed} from '@angular/core/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {Observable, Observer, of } from 'rxjs';
import {Observable, Observer, of} from 'rxjs';
import {every, mergeMap} from 'rxjs/operators';
import {TestScheduler} from 'rxjs/testing';
@ -23,13 +23,18 @@ describe('prioritizedGuardValue operator', () => {
let router: Router;
const TF = {T: true, F: false};
beforeEach(() => { TestBed.configureTestingModule({imports: [RouterTestingModule]}); });
beforeEach(() => { testScheduler = new TestScheduler(assertDeepEquals); });
beforeEach(() => { router = TestBed.inject(Router); });
beforeEach(() => {
TestBed.configureTestingModule({imports: [RouterTestingModule]});
});
beforeEach(() => {
testScheduler = new TestScheduler(assertDeepEquals);
});
beforeEach(() => {
router = TestBed.inject(Router);
});
it('should return true if all values are true', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const a = cold(' --(T|)', TF);
const b = cold(' ----------(T|)', TF);
const c = cold(' ------(T|)', TF);
@ -38,13 +43,15 @@ describe('prioritizedGuardValue operator', () => {
const expected = ' -------------T--';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
.toBe(
expected,
TF,
/* an error here maybe */);
});
});
it('should return false if observables to the left of false have produced a value', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const a = cold(' --(T|)', TF);
const b = cold(' ----------(T|)', TF);
const c = cold(' ------(F|)', TF);
@ -53,13 +60,15 @@ describe('prioritizedGuardValue operator', () => {
const expected = ' -------------F--';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
.toBe(
expected,
TF,
/* an error here maybe */);
});
});
it('should ignore results for unresolved sets of Observables', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const a = cold(' --(T|)', TF);
const b = cold(' -------------(T|)', TF);
const c = cold(' ------(F|)', TF);
@ -71,13 +80,15 @@ describe('prioritizedGuardValue operator', () => {
const expected = ' ------------T---';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
.toBe(
expected,
TF,
/* an error here maybe */);
});
});
it('should return UrlTree if higher priority guards have resolved', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const urlTree = router.parseUrl('/');
const urlLookup = {U: urlTree};
@ -91,13 +102,15 @@ describe('prioritizedGuardValue operator', () => {
const expected = ' -------------U---';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, urlLookup, /* an error here maybe */);
.toBe(
expected,
urlLookup,
/* an error here maybe */);
});
});
it('should return false even with UrlTree if UrlTree is lower priority', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const urlTree = router.parseUrl('/');
const urlLookup = {U: urlTree};
@ -111,13 +124,15 @@ describe('prioritizedGuardValue operator', () => {
const expected = ' -------------F---';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
.toBe(
expected,
TF,
/* an error here maybe */);
});
});
it('should return UrlTree even after a false if the false is lower priority', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const urlTree = router.parseUrl('/');
const urlLookup = {U: urlTree};
@ -131,13 +146,15 @@ describe('prioritizedGuardValue operator', () => {
const expected = ' -------------U----';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, urlLookup, /* an error here maybe */);
.toBe(
expected,
urlLookup,
/* an error here maybe */);
});
});
it('should return the highest priority UrlTree', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const urlTreeU = router.parseUrl('/u');
const urlTreeR = router.parseUrl('/r');
const urlTreeL = router.parseUrl('/l');
@ -153,13 +170,15 @@ describe('prioritizedGuardValue operator', () => {
const expected = ' -------------U---';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, urlLookup, /* an error here maybe */);
.toBe(
expected,
urlLookup,
/* an error here maybe */);
});
});
it('should propagate errors', () => {
testScheduler.run(({hot, cold, expectObservable}) => {
const a = cold(' --(T|)', TF);
const b = cold(' ------#', TF);
const c = cold(' ----------(F|)', TF);
@ -168,11 +187,12 @@ describe('prioritizedGuardValue operator', () => {
const expected = ' ---------#';
expectObservable(source.pipe(prioritizedGuardValue()))
.toBe(expected, TF, /* an error here maybe */);
.toBe(
expected,
TF,
/* an error here maybe */);
});
});
});

View File

@ -9,21 +9,21 @@
import {Routes} from '../src/config';
import {recognize} from '../src/recognize';
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '../src/router_state';
import {PRIMARY_OUTLET, Params} from '../src/shared';
import {Params, PRIMARY_OUTLET} from '../src/shared';
import {DefaultUrlSerializer, UrlTree} from '../src/url_tree';
describe('recognize', () => {
it('should work', () => {
checkRecognize([{path: 'a', component: ComponentA}], 'a', (s: any) => {
checkActivatedRoute(s.root, '', {}, RootComponent);
checkActivatedRoute(s.firstChild(s.root) !, 'a', {}, ComponentA);
checkActivatedRoute(s.firstChild(s.root)!, 'a', {}, ComponentA);
});
});
it('should freeze params object', () => {
checkRecognize([{path: 'a/:id', component: ComponentA}], 'a/10', (s: RouterStateSnapshot) => {
checkActivatedRoute(s.root, '', {}, RootComponent);
const child = (s as any).firstChild(s.root) !;
const child = (s as any).firstChild(s.root)!;
expect(Object.isFrozen(child.params)).toBeTruthy();
});
});
@ -79,11 +79,11 @@ describe('recognize', () => {
expect((s.root as any)._urlSegment).toBe(url.root);
expect((s.root as any)._lastPathIndex).toBe(-1);
const compA = (s as any).firstChild(s.root) !;
const compA = (s as any).firstChild(s.root)!;
expect(compA._urlSegment).toBe((url.root as any).children[PRIMARY_OUTLET]);
expect(compA._lastPathIndex).toBe(1);
const compC = (s as any).firstChild(<any>compA) !;
const compC = (s as any).firstChild(<any>compA)!;
expect(compC._urlSegment).toBe((url.root as any).children[PRIMARY_OUTLET]);
expect(compC._lastPathIndex).toBe(2);
});
@ -101,11 +101,11 @@ describe('recognize', () => {
expect(s.root._urlSegment).toBe(url.root);
expect(s.root._lastPathIndex).toBe(-1);
const compA = (s as any).firstChild(s.root) !;
const compA = (s as any).firstChild(s.root)!;
expect(compA._urlSegment).toBe((url as any).root.children[PRIMARY_OUTLET]);
expect(compA._lastPathIndex).toBe(0);
const compC = (s as any).firstChild(<any>compA) !;
const compC = (s as any).firstChild(<any>compA)!;
expect(compC._urlSegment).toBe((url as any).root.children[PRIMARY_OUTLET]);
expect(compC._lastPathIndex).toBe(2);
});
@ -119,9 +119,9 @@ describe('recognize', () => {
],
'a/paramA', (s: RouterStateSnapshot) => {
checkActivatedRoute(s.root, '', {}, RootComponent);
checkActivatedRoute((s as any).firstChild(s.root) !, 'a', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a', {}, ComponentA);
checkActivatedRoute(
(s as any).firstChild(<any>(s as any).firstChild(s.root)) !, 'paramA', {id: 'paramA'},
(s as any).firstChild(<any>(s as any).firstChild(s.root))!, 'paramA', {id: 'paramA'},
ComponentB);
});
@ -130,7 +130,7 @@ describe('recognize', () => {
(s: RouterStateSnapshot) => {
checkActivatedRoute(s.root, '', {}, RootComponent);
checkActivatedRoute(
(s as any).firstChild(s.root) !, 'a/paramA', {id: 'paramA'}, ComponentC);
(s as any).firstChild(s.root)!, 'a/paramA', {id: 'paramA'}, ComponentC);
});
});
@ -154,8 +154,7 @@ describe('recognize', () => {
path: 'a',
component: ComponentA,
children: [
{path: 'b', component: ComponentB},
{path: 'c', component: ComponentC, outlet: 'left'}
{path: 'b', component: ComponentB}, {path: 'c', component: ComponentC, outlet: 'left'}
]
},
],
@ -190,7 +189,7 @@ describe('recognize', () => {
const c = (s as any).children(s.root);
checkActivatedRoute(c[0], 'a', {a1: '11', a2: '22'}, ComponentA);
checkActivatedRoute(
(s as any).firstChild(<any>c[0]) !, 'b', {b1: '111', b2: '222'}, ComponentB);
(s as any).firstChild(<any>c[0])!, 'b', {b1: '111', b2: '222'}, ComponentB);
checkActivatedRoute(c[1], 'c', {c1: '1111', c2: '2222'}, ComponentC, 'left');
});
});
@ -199,7 +198,7 @@ describe('recognize', () => {
it('should set static data', () => {
checkRecognize(
[{path: 'a', data: {one: 1}, component: ComponentA}], 'a', (s: RouterStateSnapshot) => {
const r: ActivatedRouteSnapshot = (s as any).firstChild(s.root) !;
const r: ActivatedRouteSnapshot = (s as any).firstChild(s.root)!;
expect(r.data).toEqual({one: 1});
});
});
@ -213,7 +212,7 @@ describe('recognize', () => {
}],
'a/b', (s: RouterStateSnapshot) => {
const r: ActivatedRouteSnapshot =
(s as any).firstChild(<any>(s as any).firstChild(s.root)) !;
(s as any).firstChild(<any>(s as any).firstChild(s.root))!;
expect(r.data).toEqual({one: 1, two: 2});
});
});
@ -227,7 +226,7 @@ describe('recognize', () => {
children: [{path: 'b', data: {two: 2}, component: ComponentB}]
}],
'a/b', (s: any /* RouterStateSnapshot */) => {
const r: ActivatedRouteSnapshot = s.firstChild(<any>s.firstChild(s.root)) !;
const r: ActivatedRouteSnapshot = s.firstChild(<any>s.firstChild(s.root))!;
expect(r.data).toEqual({two: 2});
});
});
@ -241,7 +240,7 @@ describe('recognize', () => {
children: [{path: 'b', data: {two: 2}, component: ComponentB}]
}],
'a/b', (s: any /* RouterStateSnapshot */) => {
const r: ActivatedRouteSnapshot = s.firstChild(<any>s.firstChild(s.root)) !;
const r: ActivatedRouteSnapshot = s.firstChild(<any>s.firstChild(s.root))!;
expect(r.data).toEqual({one: 1, two: 2});
}, 'always');
});
@ -249,7 +248,7 @@ describe('recognize', () => {
it('should set resolved data', () => {
checkRecognize(
[{path: 'a', resolve: {one: 'some-token'}, component: ComponentA}], 'a', (s: any) => {
const r: any = s.firstChild(s.root) !;
const r: any = s.firstChild(s.root)!;
expect(r._resolve).toEqual({one: 'some-token'});
});
});
@ -259,7 +258,7 @@ describe('recognize', () => {
describe('root', () => {
it('should work', () => {
checkRecognize([{path: '', component: ComponentA}], '', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, '', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, '', {}, ComponentA);
});
});
@ -267,7 +266,7 @@ describe('recognize', () => {
checkRecognize(
[{path: '', pathMatch: 'full', component: ComponentA}], '',
(s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, '', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, '', {}, ComponentA);
});
});
@ -275,9 +274,9 @@ describe('recognize', () => {
checkRecognize(
[{path: '', component: ComponentA, children: [{path: '', component: ComponentB}]}], '',
(s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, '', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, '', {}, ComponentA);
checkActivatedRoute(
(s as any).firstChild(<any>(s as any).firstChild(s.root)) !, '', {}, ComponentB);
(s as any).firstChild(<any>(s as any).firstChild(s.root))!, '', {}, ComponentB);
});
});
@ -291,11 +290,11 @@ describe('recognize', () => {
expect(s.root._urlSegment).toBe(url.root);
expect(s.root._lastPathIndex).toBe(-1);
const c = s.firstChild(s.root) !;
const c = s.firstChild(s.root)!;
expect(c._urlSegment).toBe(url.root);
expect(c._lastPathIndex).toBe(-1);
const c2 = s.firstChild(<any>s.firstChild(s.root)) !;
const c2 = s.firstChild(<any>s.firstChild(s.root))!;
expect(c2._urlSegment).toBe(url.root);
expect(c2._lastPathIndex).toBe(-1);
});
@ -306,17 +305,15 @@ describe('recognize', () => {
[{
path: 'a',
component: ComponentA,
children: [
{path: '', component: ComponentB, children: [{path: '', component: ComponentC}]}
]
children:
[{path: '', component: ComponentB, children: [{path: '', component: ComponentC}]}]
}],
'/a;p=1', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, 'a', {p: '1'}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a', {p: '1'}, ComponentA);
checkActivatedRoute(
(s as any).firstChild((s as any).firstChild(s.root) !) !, '', {p: '1'},
ComponentB);
(s as any).firstChild((s as any).firstChild(s.root)!)!, '', {p: '1'}, ComponentB);
checkActivatedRoute(
(s as any).firstChild((s as any).firstChild((s as any).firstChild(s.root) !) !) !,
(s as any).firstChild((s as any).firstChild((s as any).firstChild(s.root)!)!)!,
'', {p: '1'}, ComponentC);
});
});
@ -329,14 +326,13 @@ describe('recognize', () => {
path: 'a',
component: ComponentA,
children: [
{path: 'b', component: ComponentB},
{path: '', component: ComponentC, outlet: 'aux'}
{path: 'b', component: ComponentB}, {path: '', component: ComponentC, outlet: 'aux'}
]
}],
'a/b', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, 'a', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a', {}, ComponentA);
const c = (s as any).children((s as any).firstChild(s.root) !);
const c = (s as any).children((s as any).firstChild(s.root)!);
checkActivatedRoute(c[0], 'b', {}, ComponentB);
checkActivatedRoute(c[1], '', {}, ComponentC, 'aux');
});
@ -365,13 +361,13 @@ describe('recognize', () => {
checkRecognize(config, 'parent/b', (s: RouterStateSnapshot) => {
checkActivatedRoute(s.root, '', {}, RootComponent);
checkActivatedRoute((s as any).firstChild(s.root) !, 'parent', {}, undefined !);
checkActivatedRoute((s as any).firstChild(s.root)!, 'parent', {}, undefined!);
const cc = (s as any).children((s as any).firstChild(s.root) !);
const cc = (s as any).children((s as any).firstChild(s.root)!);
checkActivatedRoute(cc[0], '', {}, ComponentA);
checkActivatedRoute(cc[1], '', {}, ComponentD, 'secondary');
checkActivatedRoute((s as any).firstChild(cc[0]) !, 'b', {}, ComponentB);
checkActivatedRoute((s as any).firstChild(cc[0])!, 'b', {}, ComponentB);
});
});
@ -386,9 +382,9 @@ describe('recognize', () => {
]
}],
'a/b', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, 'a', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a', {}, ComponentA);
const c = (s as any).children((s as any).firstChild(s.root) !);
const c = (s as any).children((s as any).firstChild(s.root)!);
expect(c.length).toEqual(1);
checkActivatedRoute(c[0], 'b', {}, ComponentB);
});
@ -401,8 +397,7 @@ describe('recognize', () => {
path: 'a',
component: ComponentA,
children: [
{path: 'b', component: ComponentB},
{path: '', component: ComponentC, outlet: 'aux'}
{path: 'b', component: ComponentB}, {path: '', component: ComponentC, outlet: 'aux'}
]
}],
url, 'a/b')
@ -410,11 +405,11 @@ describe('recognize', () => {
expect(s.root._urlSegment).toBe(url.root);
expect(s.root._lastPathIndex).toBe(-1);
const a = s.firstChild(s.root) !;
const a = s.firstChild(s.root)!;
expect(a._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(a._lastPathIndex).toBe(0);
const b = s.firstChild(a) !;
const b = s.firstChild(a)!;
expect(b._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(b._lastPathIndex).toBe(1);
@ -429,24 +424,23 @@ describe('recognize', () => {
recognize(
RootComponent, [{
path: 'a',
children: [
{path: '', component: ComponentB, children: [{path: '', component: ComponentC}]}
]
children:
[{path: '', component: ComponentB, children: [{path: '', component: ComponentC}]}]
}],
url, 'a')
.forEach((s: any) => {
expect(s.root._urlSegment).toBe(url.root);
expect(s.root._lastPathIndex).toBe(-1);
const a = s.firstChild(s.root) !;
const a = s.firstChild(s.root)!;
expect(a._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(a._lastPathIndex).toBe(0);
const b = s.firstChild(a) !;
const b = s.firstChild(a)!;
expect(b._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(b._lastPathIndex).toBe(0);
const c = s.firstChild(b) !;
const c = s.firstChild(b)!;
expect(c._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(c._lastPathIndex).toBe(0);
});
@ -473,19 +467,19 @@ describe('recognize', () => {
expect(s.root._urlSegment).toBe(url.root);
expect(s.root._lastPathIndex).toBe(-1);
const a = s.firstChild(s.root) !;
const a = s.firstChild(s.root)!;
expect(a._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(a._lastPathIndex).toBe(0);
const b = s.firstChild(a) !;
const b = s.firstChild(a)!;
expect(b._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(b._lastPathIndex).toBe(1);
const c = s.firstChild(b) !;
const c = s.firstChild(b)!;
expect(c._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(c._lastPathIndex).toBe(1);
const d = s.firstChild(c) !;
const d = s.firstChild(c)!;
expect(d._urlSegment).toBe(url.root.children[PRIMARY_OUTLET]);
expect(d._lastPathIndex).toBe(1);
});
@ -496,24 +490,23 @@ describe('recognize', () => {
recognize(
RootComponent, [{
path: '',
children: [
{path: '', component: ComponentB, children: [{path: '', component: ComponentC}]}
]
children:
[{path: '', component: ComponentB, children: [{path: '', component: ComponentC}]}]
}],
url, '')
.forEach((s: any) => {
expect(s.root._urlSegment).toBe(url.root);
expect(s.root._lastPathIndex).toBe(-1);
const a = (s as any).firstChild(s.root) !;
const a = (s as any).firstChild(s.root)!;
expect(a._urlSegment).toBe(url.root);
expect(a._lastPathIndex).toBe(-1);
const b = (s as any).firstChild(a) !;
const b = (s as any).firstChild(a)!;
expect(b._urlSegment).toBe(url.root);
expect(b._lastPathIndex).toBe(-1);
const c = (s as any).firstChild(b) !;
const c = (s as any).firstChild(b)!;
expect(c._urlSegment).toBe(url.root);
expect(c._lastPathIndex).toBe(-1);
});
@ -532,9 +525,9 @@ describe('recognize', () => {
]
}],
'a', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, 'a', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a', {}, ComponentA);
const c = (s as any).children((s as any).firstChild(s.root) !);
const c = (s as any).children((s as any).firstChild(s.root)!);
checkActivatedRoute(c[0], '', {}, ComponentB);
checkActivatedRoute(c[1], '', {}, ComponentC, 'aux');
});
@ -551,9 +544,9 @@ describe('recognize', () => {
]
}],
'a', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, 'a', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a', {}, ComponentA);
const c = (s as any).children((s as any).firstChild(s.root) !);
const c = (s as any).children((s as any).firstChild(s.root)!);
checkActivatedRoute(c[0], '', {}, ComponentB);
checkActivatedRoute(c[1], '', {}, ComponentC, 'aux');
});
@ -570,9 +563,9 @@ describe('recognize', () => {
]
}],
'a/(aux:c)', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, 'a', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a', {}, ComponentA);
const c = (s as any).children((s as any).firstChild(s.root) !);
const c = (s as any).children((s as any).firstChild(s.root)!);
checkActivatedRoute(c[0], '', {}, ComponentB);
checkActivatedRoute(c[1], 'c', {}, ComponentC, 'aux');
});
@ -612,13 +605,13 @@ describe('recognize', () => {
]
}],
'a/(d//aux:e)', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, 'a', {}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a', {}, ComponentA);
const c = (s as any).children((s as any).firstChild(s.root) !);
const c = (s as any).children((s as any).firstChild(s.root)!);
checkActivatedRoute(c[0], '', {}, ComponentB);
checkActivatedRoute((s as any).firstChild(c[0]) !, 'd', {}, ComponentD);
checkActivatedRoute((s as any).firstChild(c[0])!, 'd', {}, ComponentD);
checkActivatedRoute(c[1], '', {}, ComponentC, 'aux');
checkActivatedRoute((s as any).firstChild(c[1]) !, 'e', {}, ComponentE);
checkActivatedRoute((s as any).firstChild(c[1])!, 'e', {}, ComponentE);
});
});
});
@ -628,7 +621,7 @@ describe('recognize', () => {
it('should support simple wildcards', () => {
checkRecognize(
[{path: '**', component: ComponentA}], 'a/b/c/d;a1=11', (s: RouterStateSnapshot) => {
checkActivatedRoute((s as any).firstChild(s.root) !, 'a/b/c/d', {a1: '11'}, ComponentA);
checkActivatedRoute((s as any).firstChild(s.root)!, 'a/b/c/d', {a1: '11'}, ComponentA);
});
});
});
@ -639,13 +632,12 @@ describe('recognize', () => {
[{
path: 'p/:id',
children: [
{path: 'a', component: ComponentA},
{path: 'b', component: ComponentB, outlet: 'aux'}
{path: 'a', component: ComponentA}, {path: 'b', component: ComponentB, outlet: 'aux'}
]
}],
'p/11;pp=22/(a;pa=33//aux:b;pb=44)', (s: RouterStateSnapshot) => {
const p = (s as any).firstChild(s.root) !;
checkActivatedRoute(p, 'p/11', {id: '11', pp: '22'}, undefined !);
const p = (s as any).firstChild(s.root)!;
checkActivatedRoute(p, 'p/11', {id: '11', pp: '22'}, undefined!);
const c = (s as any).children(p);
checkActivatedRoute(c[0], 'a', {id: '11', pp: '22', pa: '33'}, ComponentA);
@ -659,24 +651,22 @@ describe('recognize', () => {
path: 'p/:id',
children: [{
path: 'a/:name',
children: [{
path: 'b',
component: ComponentB,
children: [{path: 'c', component: ComponentC}]
}]
children: [
{path: 'b', component: ComponentB, children: [{path: 'c', component: ComponentC}]}
]
}]
}],
'p/11/a/victor/b/c', (s: RouterStateSnapshot) => {
const p = (s as any).firstChild(s.root) !;
checkActivatedRoute(p, 'p/11', {id: '11'}, undefined !);
const p = (s as any).firstChild(s.root)!;
checkActivatedRoute(p, 'p/11', {id: '11'}, undefined!);
const a = (s as any).firstChild(p) !;
checkActivatedRoute(a, 'a/victor', {id: '11', name: 'victor'}, undefined !);
const a = (s as any).firstChild(p)!;
checkActivatedRoute(a, 'a/victor', {id: '11', name: 'victor'}, undefined!);
const b = (s as any).firstChild(a) !;
const b = (s as any).firstChild(a)!;
checkActivatedRoute(b, 'b', {id: '11', name: 'victor'}, ComponentB);
const c = (s as any).firstChild(b) !;
const c = (s as any).firstChild(b)!;
checkActivatedRoute(c, 'c', {}, ComponentC);
});
});
@ -687,15 +677,13 @@ describe('recognize', () => {
path: 'p/:id',
children: [{
path: 'a/:name',
children: [{
path: 'b',
component: ComponentB,
children: [{path: 'c', component: ComponentC}]
}]
children: [
{path: 'b', component: ComponentB, children: [{path: 'c', component: ComponentC}]}
]
}]
}],
'p/11/a/victor/b/c', (s: any /* RouterStateSnapshot */) => {
const c = s.firstChild(s.firstChild(s.firstChild(s.firstChild(s.root) !) !) !) !;
const c = s.firstChild(s.firstChild(s.firstChild(s.firstChild(s.root)!)!)!)!;
checkActivatedRoute(c, 'c', {id: '11', name: 'victor'}, ComponentC);
}, 'always');
});
@ -707,7 +695,7 @@ describe('recognize', () => {
[{path: 'a', component: ComponentA, children: [{path: 'b', component: ComponentB}]}],
'/a', (s: RouterStateSnapshot) => {
const a = (s as any).firstChild(s.root);
checkActivatedRoute(a !, 'a', {}, ComponentA);
checkActivatedRoute(a!, 'a', {}, ComponentA);
});
});
@ -722,7 +710,7 @@ describe('recognize', () => {
]
}],
'/a', (s: RouterStateSnapshot) => {
const a = (s as any).firstChild(s.root) !;
const a = (s as any).firstChild(s.root)!;
checkActivatedRoute(a, 'a', {}, ComponentA);
checkActivatedRoute((a as any).children[0], '', {}, ComponentC, 'aux');
});
@ -746,9 +734,9 @@ describe('recognize', () => {
children: [{path: 'b', component: ComponentB}]
}] as any,
'/a/1;p=99/b', (s: RouterStateSnapshot) => {
const a = (s as any).root.firstChild !;
const a = (s as any).root.firstChild!;
checkActivatedRoute(a, 'a/1', {id: '1', p: '99'}, ComponentA);
checkActivatedRoute((a as any).firstChild !, 'b', {}, ComponentB);
checkActivatedRoute((a as any).firstChild!, 'b', {}, ComponentB);
});
});
@ -756,7 +744,7 @@ describe('recognize', () => {
const matcher = (s: any, g: any, r: any) => s.length === 0 ? ({consumed: s}) : null;
checkRecognize([{matcher, component: ComponentA}] as any, '', (s: RouterStateSnapshot) => {
const a = (s as any).root.firstChild !;
const a = (s as any).root.firstChild!;
checkActivatedRoute(a, '', {}, ComponentA);
});
});
@ -767,7 +755,7 @@ describe('recognize', () => {
checkRecognize(
[{path: 'a', component: ComponentA, children: [{matcher, component: ComponentB}]}] as any,
'a', (s: RouterStateSnapshot) => {
const a = (s as any).root.firstChild !;
const a = (s as any).root.firstChild!;
checkActivatedRoute(a, 'a', {}, ComponentA);
});
});
@ -800,8 +788,9 @@ describe('recognize', () => {
describe('fragment', () => {
it('should support fragment', () => {
const config = [{path: 'a', component: ComponentA}];
checkRecognize(
config, 'a#f1', (s: RouterStateSnapshot) => { expect(s.root.fragment).toEqual('f1'); });
checkRecognize(config, 'a#f1', (s: RouterStateSnapshot) => {
expect(s.root.fragment).toEqual('f1');
});
});
});
@ -825,9 +814,11 @@ describe('recognize', () => {
function checkRecognize(
config: Routes, url: string, callback: any,
paramsInheritanceStrategy?: 'emptyOnly' | 'always'): void {
paramsInheritanceStrategy?: 'emptyOnly'|'always'): void {
recognize(RootComponent, config, tree(url), url, paramsInheritanceStrategy)
.subscribe(callback, e => { throw e; });
.subscribe(callback, e => {
throw e;
});
}
function checkActivatedRoute(

View File

@ -8,12 +8,11 @@
import {CommonModule} from '@angular/common';
import {Component, ContentChild, NgModule, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core';
import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing';
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {Router} from '@angular/router';
import {RouterTestingModule} from '@angular/router/testing';
describe('Integration', () => {
describe('routerLinkActive', () => {
it('should not cause infinite loops in the change detection - #15825', fakeAsync(() => {
@Component({selector: 'simple', template: 'simple'})
@ -73,16 +72,18 @@ describe('Integration', () => {
})
class ComponentWithRouterLink {
// TODO(issue/24571): remove '!'.
@ViewChild(TemplateRef, {static: true}) templateRef !: TemplateRef<any>;
@ViewChild(TemplateRef, {static: true}) templateRef!: TemplateRef<any>;
// TODO(issue/24571): remove '!'.
@ViewChild('container', {read: ViewContainerRef, static: true})
container !: ViewContainerRef;
container!: ViewContainerRef;
addLink() {
this.container.createEmbeddedView(this.templateRef, {$implicit: '/simple'});
}
removeLink() { this.container.clear(); }
removeLink() {
this.container.clear();
}
}
@Component({template: 'simple'})
@ -108,9 +109,7 @@ describe('Integration', () => {
expect(fixture.nativeElement.innerHTML).toContain('isActive: false');
}));
});
});
function advance<T>(fixture: ComponentFixture<T>): void {

View File

@ -7,9 +7,9 @@
*/
import {Location} from '@angular/common';
import {TestBed, inject} from '@angular/core/testing';
import {inject, TestBed} from '@angular/core/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {of } from 'rxjs';
import {of} from 'rxjs';
import {Routes} from '../src/config';
import {ChildActivationStart} from '../src/events';
@ -17,19 +17,20 @@ import {checkGuards as checkGuardsOperator} from '../src/operators/check_guards'
import {resolveData as resolveDataOperator} from '../src/operators/resolve_data';
import {NavigationTransition, Router} from '../src/router';
import {ChildrenOutletContexts} from '../src/router_outlet_context';
import {RouterStateSnapshot, createEmptyStateSnapshot} from '../src/router_state';
import {createEmptyStateSnapshot, RouterStateSnapshot} from '../src/router_state';
import {DefaultUrlSerializer, UrlTree} from '../src/url_tree';
import {getAllRouteGuards} from '../src/utils/preactivation';
import {TreeNode} from '../src/utils/tree';
import {Logger, createActivatedRouteSnapshot, provideTokenLogger} from './helpers';
import {createActivatedRouteSnapshot, Logger, provideTokenLogger} from './helpers';
describe('Router', () => {
describe('resetConfig', () => {
class TestComponent {}
beforeEach(() => { TestBed.configureTestingModule({imports: [RouterTestingModule]}); });
beforeEach(() => {
TestBed.configureTestingModule({imports: [RouterTestingModule]});
});
it('should copy config to avoid mutations of user-provided objects', () => {
const r: Router = TestBed.inject(Router);
@ -38,12 +39,12 @@ describe('Router', () => {
component: TestComponent,
children: [{path: 'b', component: TestComponent}, {path: 'c', component: TestComponent}]
}];
const children = configs[0].children !;
const children = configs[0].children!;
r.resetConfig(configs);
const rConfigs = r.config;
const rChildren = rConfigs[0].children !;
const rChildren = rConfigs[0].children!;
// routes array and shallow copy
expect(configs).not.toBe(rConfigs);
@ -63,7 +64,9 @@ describe('Router', () => {
describe('resetRootComponentType', () => {
class NewRootComponent {}
beforeEach(() => { TestBed.configureTestingModule({imports: [RouterTestingModule]}); });
beforeEach(() => {
TestBed.configureTestingModule({imports: [RouterTestingModule]});
});
it('should not change root route when updating the root component', () => {
const r: Router = TestBed.inject(Router);
@ -76,7 +79,9 @@ describe('Router', () => {
});
describe('setUpLocationChangeListener', () => {
beforeEach(() => { TestBed.configureTestingModule({imports: [RouterTestingModule]}); });
beforeEach(() => {
TestBed.configureTestingModule({imports: [RouterTestingModule]});
});
it('should be idempotent', inject([Router, Location], (r: Router, location: Location) => {
r.setUpLocationChangeListener();
@ -118,7 +123,6 @@ describe('Router', () => {
const CDA_GRANDCHILD_REDIRECT = 'canDeactivate_grandchild_redirect';
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
providers: [
@ -137,11 +141,10 @@ describe('Router', () => {
CDA_GRANDCHILD_REDIRECT, serializer.parse('/canDeactivate_grandchild_redirect'))
]
});
});
beforeEach(inject([Logger], (_logger: Logger) => {
empty = createEmptyStateSnapshot(serializer.parse('/'), null !);
empty = createEmptyStateSnapshot(serializer.parse('/'), null!);
logger = _logger;
events = [];
}));
@ -164,9 +167,15 @@ describe('Router', () => {
guards: getAllRouteGuards(futureState, empty, new ChildrenOutletContexts())
} as NavigationTransition;
of (testTransition).pipe(checkGuardsOperator(TestBed, (evt) => {
events.push(evt);
})).subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
of(testTransition)
.pipe(checkGuardsOperator(
TestBed,
(evt) => {
events.push(evt);
}))
.subscribe((x) => result = !!x.guardsResult, (e) => {
throw e;
});
expect(result).toBe(true);
expect(events.length).toEqual(2);
@ -203,9 +212,15 @@ describe('Router', () => {
guards: getAllRouteGuards(futureState, empty, new ChildrenOutletContexts())
} as NavigationTransition;
of (testTransition).pipe(checkGuardsOperator(TestBed, (evt) => {
events.push(evt);
})).subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
of(testTransition)
.pipe(checkGuardsOperator(
TestBed,
(evt) => {
events.push(evt);
}))
.subscribe((x) => result = !!x.guardsResult, (e) => {
throw e;
});
expect(result).toBe(true);
expect(events.length).toEqual(6);
@ -240,9 +255,15 @@ describe('Router', () => {
guards: getAllRouteGuards(futureState, currentState, new ChildrenOutletContexts())
} as NavigationTransition;
of (testTransition).pipe(checkGuardsOperator(TestBed, (evt) => {
events.push(evt);
})).subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
of(testTransition)
.pipe(checkGuardsOperator(
TestBed,
(evt) => {
events.push(evt);
}))
.subscribe((x) => result = !!x.guardsResult, (e) => {
throw e;
});
expect(result).toBe(true);
expect(events.length).toEqual(2);
@ -290,9 +311,15 @@ describe('Router', () => {
guards: getAllRouteGuards(futureState, currentState, new ChildrenOutletContexts())
} as NavigationTransition;
of (testTransition).pipe(checkGuardsOperator(TestBed, (evt) => {
events.push(evt);
})).subscribe((x) => result = !!x.guardsResult, (e) => { throw e; });
of(testTransition)
.pipe(checkGuardsOperator(
TestBed,
(evt) => {
events.push(evt);
}))
.subscribe((x) => result = !!x.guardsResult, (e) => {
throw e;
});
expect(result).toBe(true);
expect(events.length).toEqual(4);
@ -536,9 +563,9 @@ describe('Router', () => {
{component: 'grandchild', routeConfig: {canActivate: [CA_GRANDCHILD]}});
const futureState = new (RouterStateSnapshot as any)(
'url', new TreeNode(
empty.root,
[new TreeNode(childSnapshot, [new TreeNode(grandchildSnapshot, [])])]));
'url', new TreeNode(empty.root, [
new TreeNode(childSnapshot, [new TreeNode(grandchildSnapshot, [])])
]));
checkGuards(futureState, empty, TestBed, (result) => {
expect(serializer.serialize(result as UrlTree)).toBe('/' + CAC_CHILD_REDIRECT);
@ -561,9 +588,9 @@ describe('Router', () => {
{component: 'grandchild', routeConfig: {canActivate: [CA_GRANDCHILD_REDIRECT]}});
const futureState = new (RouterStateSnapshot as any)(
'url', new TreeNode(
empty.root,
[new TreeNode(childSnapshot, [new TreeNode(grandchildSnapshot, [])])]));
'url', new TreeNode(empty.root, [
new TreeNode(childSnapshot, [new TreeNode(grandchildSnapshot, [])])
]));
checkGuards(futureState, empty, TestBed, (result) => {
expect(serializer.serialize(result as UrlTree)).toBe('/' + CA_GRANDCHILD_REDIRECT);
@ -592,21 +619,19 @@ describe('Router', () => {
const currentState = new (RouterStateSnapshot as any)(
'prev', new TreeNode(empty.root, [new TreeNode(prevSnapshot, [])]));
const futureState = new (RouterStateSnapshot as any)(
'url', new TreeNode(
empty.root,
[new TreeNode(childSnapshot, [new TreeNode(grandchildSnapshot, [])])]));
'url', new TreeNode(empty.root, [
new TreeNode(childSnapshot, [new TreeNode(grandchildSnapshot, [])])
]));
checkGuards(futureState, currentState, TestBed, (result) => {
expect(serializer.serialize(result as UrlTree)).toBe('/' + CDA_CHILD_REDIRECT);
expect(logger.logs).toEqual([CDA_CHILD_REDIRECT]);
});
});
});
});
describe('resolve', () => {
it('should resolve data', () => {
/**
* R --> R
@ -619,7 +644,7 @@ describe('Router', () => {
'url', new TreeNode(empty.root, [new TreeNode(n, [])]));
checkResolveData(s, empty, inj, () => {
expect(s.root.firstChild !.data).toEqual({data: 'resolver_value'});
expect(s.root.firstChild!.data).toEqual({data: 'resolver_value'});
});
});
@ -634,7 +659,7 @@ describe('Router', () => {
const parentResolve = {data: 'resolver'};
const childResolve = {};
const parent = createActivatedRouteSnapshot({component: null !, resolve: parentResolve});
const parent = createActivatedRouteSnapshot({component: null!, resolve: parentResolve});
const child = createActivatedRouteSnapshot({component: 'b', resolve: childResolve});
const s = new (RouterStateSnapshot as any)(
@ -643,7 +668,7 @@ describe('Router', () => {
const inj = {get: (token: any) => () => Promise.resolve(`${token}_value`)};
checkResolveData(s, empty, inj, () => {
expect(s.root.firstChild !.firstChild !.data).toEqual({data: 'resolver_value'});
expect(s.root.firstChild!.firstChild!.data).toEqual({data: 'resolver_value'});
});
});
@ -668,8 +693,8 @@ describe('Router', () => {
const s2 = new (RouterStateSnapshot as any)(
'url', new TreeNode(empty.root, [new TreeNode(n21, [new TreeNode(n22, [])])]));
checkResolveData(s2, s1, inj, () => {
expect(s2.root.firstChild !.data).toEqual({data: 'resolver1_value'});
expect(s2.root.firstChild !.firstChild !.data).toEqual({data: 'resolver2_value'});
expect(s2.root.firstChild!.data).toEqual({data: 'resolver1_value'});
expect(s2.root.firstChild!.firstChild!.data).toEqual({data: 'resolver2_value'});
});
});
});
@ -680,27 +705,29 @@ function checkResolveData(
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any, check: any): void {
// Since we only test the guards and their resolve data function, we don't need to provide
// a full navigation transition object with all properties set.
of ({
guards: getAllRouteGuards(future, curr, new ChildrenOutletContexts())
} as NavigationTransition)
of({guards: getAllRouteGuards(future, curr, new ChildrenOutletContexts())} as
NavigationTransition)
.pipe(resolveDataOperator('emptyOnly', injector))
.subscribe(check, (e) => { throw e; });
.subscribe(check, (e) => {
throw e;
});
}
function checkGuards(
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any,
check: (result: boolean | UrlTree) => void): void {
check: (result: boolean|UrlTree) => void): void {
// Since we only test the guards, we don't need to provide a full navigation
// transition object with all properties set.
of ({
guards: getAllRouteGuards(future, curr, new ChildrenOutletContexts())
} as NavigationTransition)
of({guards: getAllRouteGuards(future, curr, new ChildrenOutletContexts())} as
NavigationTransition)
.pipe(checkGuardsOperator(injector))
.subscribe({
next(t) {
if (t.guardsResult === null) throw new Error('Guard result expected');
return check(t.guardsResult);
},
error(e) { throw e; }
error(e) {
throw e;
}
});
}

View File

@ -7,7 +7,7 @@
*/
import {Compiler, Component, NgModule, NgModuleFactoryLoader, NgModuleRef} from '@angular/core';
import {TestBed, fakeAsync, inject, tick} from '@angular/core/testing';
import {fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
import {PreloadAllModules, PreloadingStrategy, RouterPreloader} from '@angular/router';
import {Route, RouteConfigLoadEnd, RouteConfigLoadStart, Router, RouterModule} from '../index';
@ -67,8 +67,7 @@ describe('RouterPreloader', () => {
const events: Array<RouteConfigLoadStart|RouteConfigLoadEnd> = [];
@NgModule({
declarations: [LazyLoadedCmp],
imports:
[RouterModule.forChild([{path: 'LoadedModule2', component: LazyLoadedCmp}])]
imports: [RouterModule.forChild([{path: 'LoadedModule2', component: LazyLoadedCmp}])]
})
class LoadedModule2 {
}
@ -98,13 +97,13 @@ describe('RouterPreloader', () => {
const c = router.config;
expect(c[0].loadChildren).toEqual('expected');
const loadedConfig: LoadedRouterConfig = (c[0] as any)._loadedConfig !;
const loadedConfig: LoadedRouterConfig = (c[0] as any)._loadedConfig!;
const module: any = loadedConfig.module;
expect(loadedConfig.routes[0].path).toEqual('LoadedModule1');
expect(module._parent).toBe(testModule);
const loadedConfig2: LoadedRouterConfig =
(loadedConfig.routes[0] as any)._loadedConfig !;
(loadedConfig.routes[0] as any)._loadedConfig!;
const module2: any = loadedConfig2.module;
expect(loadedConfig2.routes[0].path).toEqual('LoadedModule2');
expect(module2._parent).toBe(module);
@ -126,57 +125,58 @@ describe('RouterPreloader', () => {
});
});
it('should work', fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef, Compiler],
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader,
router: Router, testModule: NgModuleRef<any>, compiler: Compiler) => {
@NgModule()
class LoadedModule2 {
}
it('should work',
fakeAsync(inject(
[NgModuleFactoryLoader, RouterPreloader, Router, NgModuleRef, Compiler],
(loader: SpyNgModuleFactoryLoader, preloader: RouterPreloader, router: Router,
testModule: NgModuleRef<any>, compiler: Compiler) => {
@NgModule()
class LoadedModule2 {
}
const module2 = compiler.compileModuleSync(LoadedModule2).create(null);
const module2 = compiler.compileModuleSync(LoadedModule2).create(null);
@NgModule({
imports: [RouterModule.forChild([
<Route>{
path: 'LoadedModule2',
loadChildren: 'no',
_loadedConfig: {
routes: [{path: 'LoadedModule3', loadChildren: 'expected3'}],
module: module2,
}
},
])]
})
class LoadedModule1 {
}
@NgModule({
imports: [RouterModule.forChild([
<Route>{
path: 'LoadedModule2',
loadChildren: 'no',
_loadedConfig: {
routes: [{path: 'LoadedModule3', loadChildren: 'expected3'}],
module: module2,
}
},
])]
})
class LoadedModule1 {
}
@NgModule({imports: [RouterModule.forChild([])]})
class LoadedModule3 {
}
@NgModule({imports: [RouterModule.forChild([])]})
class LoadedModule3 {
}
loader.stubbedModules = {
expected: LoadedModule1,
expected3: LoadedModule3,
};
loader.stubbedModules = {
expected: LoadedModule1,
expected3: LoadedModule3,
};
preloader.preload().subscribe(() => {});
preloader.preload().subscribe(() => {});
tick();
tick();
const c = router.config;
const c = router.config;
const loadedConfig: LoadedRouterConfig = (c[0] as any)._loadedConfig !;
const module: any = loadedConfig.module;
expect(module._parent).toBe(testModule);
const loadedConfig: LoadedRouterConfig = (c[0] as any)._loadedConfig!;
const module: any = loadedConfig.module;
expect(module._parent).toBe(testModule);
const loadedConfig2: LoadedRouterConfig =
(loadedConfig.routes[0] as any)._loadedConfig !;
const loadedConfig3: LoadedRouterConfig =
(loadedConfig2.routes[0] as any)._loadedConfig !;
const module3: any = loadedConfig3.module;
expect(module3._parent).toBe(module2);
})));
const loadedConfig2: LoadedRouterConfig =
(loadedConfig.routes[0] as any)._loadedConfig!;
const loadedConfig3: LoadedRouterConfig =
(loadedConfig2.routes[0] as any)._loadedConfig!;
const module3: any = loadedConfig3.module;
expect(module3._parent).toBe(module2);
})));
});
describe('should ignore errors', () => {
@ -237,11 +237,11 @@ describe('RouterPreloader', () => {
tick();
const c = router.config as{_loadedConfig: LoadedRouterConfig}[];
const c = router.config as {_loadedConfig: LoadedRouterConfig}[];
expect(c[0]._loadedConfig).toBeDefined();
expect(c[0]._loadedConfig !.routes).not.toBe(configs);
expect(c[0]._loadedConfig !.routes[0]).not.toBe(configs[0]);
expect(c[0]._loadedConfig !.routes[0].component).toBe(configs[0].component);
expect(c[0]._loadedConfig!.routes).not.toBe(configs);
expect(c[0]._loadedConfig!.routes[0]).not.toBe(configs[0]);
expect(c[0]._loadedConfig!.routes[0].component).toBe(configs[0].component);
})));
});
});

View File

@ -128,7 +128,9 @@ describe('RouterScroller', () => {
}, 1000);
return r;
}))
.subscribe((e: Scroll) => { viewportScroller.scrollToPosition(e.position); });
.subscribe((e: Scroll) => {
viewportScroller.scrollToPosition(e.position);
});
events.next(new NavigationStart(1, '/a'));
events.next(new NavigationEnd(1, '/a', '/a'));
@ -158,8 +160,8 @@ describe('RouterScroller', () => {
function createRouterScroller({scrollPositionRestoration, anchorScrolling}: {
scrollPositionRestoration: 'disabled' | 'enabled' | 'top',
anchorScrolling: 'disabled' | 'enabled'
scrollPositionRestoration: 'disabled'|'enabled'|'top',
anchorScrolling: 'disabled'|'enabled'
}) {
const events = new Subject<RouterEvent>();
const router = <any>{

View File

@ -8,7 +8,7 @@
import {BehaviorSubject} from 'rxjs';
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, equalParamsAndUrlSegments} from '../src/router_state';
import {ActivatedRoute, ActivatedRouteSnapshot, advanceActivatedRoute, equalParamsAndUrlSegments, RouterState, RouterStateSnapshot} from '../src/router_state';
import {Params} from '../src/shared';
import {UrlSegment} from '../src/url_tree';
import {TreeNode} from '../src/utils/tree';
@ -30,7 +30,9 @@ describe('RouterState & Snapshot', () => {
state = new (RouterStateSnapshot as any)('url', root);
});
it('should return first child', () => { expect(state.root.firstChild).toBe(b); });
it('should return first child', () => {
expect(state.root.firstChild).toBe(b);
});
it('should return children', () => {
const cc = state.root.children;
@ -39,17 +41,17 @@ describe('RouterState & Snapshot', () => {
});
it('should return root', () => {
const b = state.root.firstChild !;
const b = state.root.firstChild!;
expect(b.root).toBe(state.root);
});
it('should return parent', () => {
const b = state.root.firstChild !;
const b = state.root.firstChild!;
expect(b.parent).toBe(state.root);
});
it('should return path from root', () => {
const b = state.root.firstChild !;
const b = state.root.firstChild!;
const p = b.pathFromRoot;
expect(p[0]).toBe(state.root);
expect(p[1]).toBe(b);
@ -72,7 +74,9 @@ describe('RouterState & Snapshot', () => {
state = new (RouterState as any)(root, <any>null);
});
it('should return first child', () => { expect(state.root.firstChild).toBe(b); });
it('should return first child', () => {
expect(state.root.firstChild).toBe(b);
});
it('should return children', () => {
const cc = state.root.children;
@ -81,17 +85,17 @@ describe('RouterState & Snapshot', () => {
});
it('should return root', () => {
const b = state.root.firstChild !;
const b = state.root.firstChild!;
expect(b.root).toBe(state.root);
});
it('should return parent', () => {
const b = state.root.firstChild !;
const b = state.root.firstChild!;
expect(b.parent).toBe(state.root);
});
it('should return path from root', () => {
const b = state.root.firstChild !;
const b = state.root.firstChild!;
const p = b.pathFromRoot;
expect(p[0]).toBe(state.root);
expect(p[1]).toBe(b);
@ -102,7 +106,7 @@ describe('RouterState & Snapshot', () => {
function createSnapshot(params: Params, url: UrlSegment[]): ActivatedRouteSnapshot {
const snapshot = new (ActivatedRouteSnapshot as any)(
url, params, <any>null, <any>null, <any>null, <any>null, <any>null, <any>null, <any>null,
-1, null !);
-1, null!);
snapshot._routerState = new (RouterStateSnapshot as any)('', new TreeNode(snapshot, []));
return snapshot;
}
@ -166,10 +170,11 @@ describe('RouterState & Snapshot', () => {
});
describe('advanceActivatedRoute', () => {
let route: ActivatedRoute;
beforeEach(() => { route = createActivatedRoute('a'); });
beforeEach(() => {
route = createActivatedRoute('a');
});
function createSnapshot(params: Params, url: UrlSegment[]): ActivatedRouteSnapshot {
const queryParams = {};
@ -177,7 +182,7 @@ describe('RouterState & Snapshot', () => {
const data = {};
const snapshot = new (ActivatedRouteSnapshot as any)(
url, params, queryParams, fragment, data, <any>null, <any>null, <any>null, <any>null, -1,
null !);
null!);
const state = new (RouterStateSnapshot as any)('', new TreeNode(snapshot, []));
snapshot._routerState = state;
return snapshot;
@ -190,7 +195,9 @@ describe('RouterState & Snapshot', () => {
(route as any)._futureSnapshot = secondPlace;
let hasSeenDataChange = false;
route.data.forEach((data) => { hasSeenDataChange = true; });
route.data.forEach((data) => {
hasSeenDataChange = true;
});
advanceActivatedRoute(route);
expect(hasSeenDataChange).toEqual(true);
});
@ -200,7 +207,7 @@ describe('RouterState & Snapshot', () => {
function createActivatedRouteSnapshot(cmp: string) {
return new (ActivatedRouteSnapshot as any)(
<any>[], <any>null, <any>null, <any>null, <any>null, <any>null, <any>cmp, <any>null,
<any>null, -1, null !);
<any>null, -1, null!);
}
function createActivatedRoute(cmp: string) {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ParamMap, convertToParamMap} from '../src/shared';
import {convertToParamMap, ParamMap} from '../src/shared';
describe('ParamsMap', () => {
it('should returns whether a parameter is present', () => {

View File

@ -7,7 +7,7 @@
*/
import {PRIMARY_OUTLET} from '../src/shared';
import {DefaultUrlSerializer, UrlSegmentGroup, encodeUriFragment, encodeUriQuery, encodeUriSegment, serializePath} from '../src/url_tree';
import {DefaultUrlSerializer, encodeUriFragment, encodeUriQuery, encodeUriSegment, serializePath, UrlSegmentGroup} from '../src/url_tree';
describe('url serializer', () => {
const url = new DefaultUrlSerializer();
@ -188,8 +188,8 @@ describe('url serializer', () => {
describe('encoding/decoding', () => {
it('should encode/decode path segments and parameters', () => {
const u =
`/${encodeUriSegment("one two")};${encodeUriSegment("p 1")}=${encodeUriSegment("v 1")};${encodeUriSegment("p 2")}=${encodeUriSegment("v 2")}`;
const u = `/${encodeUriSegment('one two')};${encodeUriSegment('p 1')}=${
encodeUriSegment('v 1')};${encodeUriSegment('p 2')}=${encodeUriSegment('v 2')}`;
const tree = url.parse(u);
expect(tree.root.children[PRIMARY_OUTLET].segments[0].path).toEqual('one two');
@ -199,8 +199,8 @@ describe('url serializer', () => {
});
it('should encode/decode "slash" in path segments and parameters', () => {
const u =
`/${encodeUriSegment("one/two")};${encodeUriSegment("p/1")}=${encodeUriSegment("v/1")}/three`;
const u = `/${encodeUriSegment('one/two')};${encodeUriSegment('p/1')}=${
encodeUriSegment('v/1')}/three`;
const tree = url.parse(u);
const segment = tree.root.children[PRIMARY_OUTLET].segments[0];
expect(segment.path).toEqual('one/two');
@ -211,8 +211,8 @@ describe('url serializer', () => {
});
it('should encode/decode query params', () => {
const u =
`/one?${encodeUriQuery("p 1")}=${encodeUriQuery("v 1")}&${encodeUriQuery("p 2")}=${encodeUriQuery("v 2")}`;
const u = `/one?${encodeUriQuery('p 1')}=${encodeUriQuery('v 1')}&${encodeUriQuery('p 2')}=${
encodeUriQuery('v 2')}`;
const tree = url.parse(u);
expect(tree.queryParams).toEqual({'p 1': 'v 1', 'p 2': 'v 2'});
@ -263,7 +263,6 @@ describe('url serializer', () => {
});
describe('special character encoding/decoding', () => {
// Tests specific to https://github.com/angular/angular/issues/10280
it('should parse encoded parens in matrix params', () => {
const auxRoutesUrl = '/abc;foo=(other:val)';

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {DefaultUrlSerializer, containsTree} from '../src/url_tree';
import {containsTree, DefaultUrlSerializer} from '../src/url_tree';
describe('UrlTree', () => {
const serializer = new DefaultUrlSerializer();
@ -14,7 +14,9 @@ describe('UrlTree', () => {
describe('DefaultUrlSerializer', () => {
let serializer: DefaultUrlSerializer;
beforeEach(() => { serializer = new DefaultUrlSerializer(); });
beforeEach(() => {
serializer = new DefaultUrlSerializer();
});
it('should parse query parameters', () => {
const tree = serializer.parse('/path/to?k=v&k/(a;b)=c');

View File

@ -21,8 +21,8 @@ describe('tree', () => {
});
it('should return the parent of a node (second child)', () => {
const t = new Tree<any>(
new TreeNode<number>(1, [new TreeNode<number>(2, []), new TreeNode<number>(3, [])])) as any;
const t = new Tree<any>(new TreeNode<number>(
1, [new TreeNode<number>(2, []), new TreeNode<number>(3, [])])) as any;
expect(t.parent(1)).toEqual(null);
expect(t.parent(3)).toEqual(1);
});
@ -40,8 +40,8 @@ describe('tree', () => {
});
it('should return the siblings of a node', () => {
const t = new Tree<any>(
new TreeNode<number>(1, [new TreeNode<number>(2, []), new TreeNode<number>(3, [])])) as any;
const t = new Tree<any>(new TreeNode<number>(
1, [new TreeNode<number>(2, []), new TreeNode<number>(3, [])])) as any;
expect(t.siblings(2)).toEqual([3]);
expect(t.siblings(1)).toEqual([]);
});

View File

@ -9,7 +9,7 @@
import {Location, LocationStrategy} from '@angular/common';
import {MockLocationStrategy, SpyLocation} from '@angular/common/testing';
import {Compiler, Injectable, Injector, ModuleWithProviders, NgModule, NgModuleFactory, NgModuleFactoryLoader, Optional} from '@angular/core';
import {ChildrenOutletContexts, ExtraOptions, NoPreloading, PreloadingStrategy, ROUTER_CONFIGURATION, ROUTES, Route, Router, RouterModule, Routes, UrlHandlingStrategy, UrlSerializer, provideRoutes, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵflatten as flatten} from '@angular/router';
import {ChildrenOutletContexts, ExtraOptions, NoPreloading, PreloadingStrategy, provideRoutes, Route, Router, ROUTER_CONFIGURATION, RouterModule, ROUTES, Routes, UrlHandlingStrategy, UrlSerializer, ɵflatten as flatten, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS} from '@angular/router';
@ -63,7 +63,9 @@ export class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader {
/**
* @docsNotRequired
*/
get stubbedModules(): {[path: string]: any} { return this._stubbedModules; }
get stubbedModules(): {[path: string]: any} {
return this._stubbedModules;
}
constructor(private compiler: Compiler) {}
@ -76,8 +78,8 @@ export class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader {
}
}
function isUrlHandlingStrategy(opts: ExtraOptions | UrlHandlingStrategy):
opts is UrlHandlingStrategy {
function isUrlHandlingStrategy(opts: ExtraOptions|
UrlHandlingStrategy): opts is UrlHandlingStrategy {
// This property check is needed because UrlHandlingStrategy is an interface and doesn't exist at
// runtime.
return 'shouldProcessUrl' in opts;
@ -113,9 +115,9 @@ export function setupTestingRouter(
export function setupTestingRouter(
urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location,
loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][],
opts?: ExtraOptions | UrlHandlingStrategy, urlHandlingStrategy?: UrlHandlingStrategy) {
opts?: ExtraOptions|UrlHandlingStrategy, urlHandlingStrategy?: UrlHandlingStrategy) {
const router = new Router(
null !, urlSerializer, contexts, location, injector, loader, compiler, flatten(routes));
null!, urlSerializer, contexts, location, injector, loader, compiler, flatten(routes));
if (opts) {
// Handle deprecated argument ordering.
if (isUrlHandlingStrategy(opts)) {

View File

@ -37,7 +37,7 @@ import {UpgradeModule} from '@angular/upgrade/static';
export const RouterUpgradeInitializer = {
provide: APP_BOOTSTRAP_LISTENER,
multi: true,
useFactory: locationSyncBootstrapListener as(ngUpgrade: UpgradeModule) => () => void,
useFactory: locationSyncBootstrapListener as (ngUpgrade: UpgradeModule) => () => void,
deps: [UpgradeModule]
};
@ -45,7 +45,9 @@ export const RouterUpgradeInitializer = {
* @internal
*/
export function locationSyncBootstrapListener(ngUpgrade: UpgradeModule) {
return () => { setUpLocationSync(ngUpgrade); };
return () => {
setUpLocationSync(ngUpgrade);
};
}
/**
@ -60,7 +62,7 @@ export function locationSyncBootstrapListener(ngUpgrade: UpgradeModule) {
*
* @publicApi
*/
export function setUpLocationSync(ngUpgrade: UpgradeModule, urlType: 'path' | 'hash' = 'path') {
export function setUpLocationSync(ngUpgrade: UpgradeModule, urlType: 'path'|'hash' = 'path') {
if (!ngUpgrade.$injector) {
throw new Error(`
RouterUpgradeInitializer can be used only after UpgradeModule.bootstrap has been called.

View File

@ -119,8 +119,7 @@ describe('setUpLocationSync', () => {
expect(LocationMock.normalize).toHaveBeenCalledWith('/foo/bar');
} finally {
Object.defineProperty(anchorProto, 'pathname', originalDescriptor !);
Object.defineProperty(anchorProto, 'pathname', originalDescriptor!);
}
});
});