refactor(router): cleanup & simplification (#15436)
This commit is contained in:
parent
910c0d9ee7
commit
d58a242fe7
|
@ -162,43 +162,43 @@ export function checkAndUpdateDirectiveInline(
|
|||
if (bindLen > 0 && checkBinding(view, def, 0, v0)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 0, v0, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 1 && checkBinding(view, def, 1, v1)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 1, v1, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 2 && checkBinding(view, def, 2, v2)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 2, v2, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 3 && checkBinding(view, def, 3, v3)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 3, v3, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 4 && checkBinding(view, def, 4, v4)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 4, v4, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 5 && checkBinding(view, def, 5, v5)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 5, v5, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 6 && checkBinding(view, def, 6, v6)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 6, v6, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 7 && checkBinding(view, def, 7, v7)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 7, v7, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 8 && checkBinding(view, def, 8, v8)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 8, v8, changes);
|
||||
};
|
||||
}
|
||||
if (bindLen > 9 && checkBinding(view, def, 9, v9)) {
|
||||
changed = true;
|
||||
changes = updateProp(view, providerData, def, 9, v9, changes);
|
||||
};
|
||||
}
|
||||
if (changes) {
|
||||
directive.ngOnChanges(changes);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import {map} from 'rxjs/operator/map';
|
|||
import {mergeMap} from 'rxjs/operator/mergeMap';
|
||||
import {EmptyError} from 'rxjs/util/EmptyError';
|
||||
|
||||
import {Route, Routes} from './config';
|
||||
import {InternalRoute, Route, Routes} from './config';
|
||||
import {LoadedRouterConfig, RouterConfigLoader} from './router_config_loader';
|
||||
import {PRIMARY_OUTLET, Params, defaultUrlMatcher, navigationCancelingError} from './shared';
|
||||
import {UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree} from './url_tree';
|
||||
|
@ -241,13 +241,13 @@ class ApplyRedirects {
|
|||
}
|
||||
|
||||
private matchSegmentAgainstRoute(
|
||||
ngModule: NgModuleRef<any>, rawSegmentGroup: UrlSegmentGroup, route: Route,
|
||||
ngModule: NgModuleRef<any>, rawSegmentGroup: UrlSegmentGroup, route: InternalRoute,
|
||||
segments: UrlSegment[]): Observable<UrlSegmentGroup> {
|
||||
if (route.path === '**') {
|
||||
if (route.loadChildren) {
|
||||
return map.call(
|
||||
this.configLoader.load(ngModule.injector, route), (cfg: LoadedRouterConfig) => {
|
||||
(<any>route)._loadedConfig = cfg;
|
||||
route._loadedConfig = cfg;
|
||||
return new UrlSegmentGroup(segments, {});
|
||||
});
|
||||
}
|
||||
|
@ -286,7 +286,8 @@ class ApplyRedirects {
|
|||
});
|
||||
}
|
||||
|
||||
private getChildConfig(ngModule: NgModuleRef<any>, route: Route): Observable<LoadedRouterConfig> {
|
||||
private getChildConfig(ngModule: NgModuleRef<any>, route: InternalRoute):
|
||||
Observable<LoadedRouterConfig> {
|
||||
if (route.children) {
|
||||
// The children belong to the same module
|
||||
return of (new LoadedRouterConfig(route.children, ngModule));
|
||||
|
@ -302,7 +303,7 @@ class ApplyRedirects {
|
|||
if (shouldLoad) {
|
||||
return map.call(
|
||||
this.configLoader.load(ngModule.injector, route), (cfg: LoadedRouterConfig) => {
|
||||
(<any>route)._loadedConfig = cfg;
|
||||
route._loadedConfig = cfg;
|
||||
return cfg;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
import {NgModuleFactory, Type} from '@angular/core';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
|
||||
import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
|
||||
import {PRIMARY_OUTLET} from './shared';
|
||||
import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
||||
|
||||
|
@ -362,6 +361,11 @@ export interface Route {
|
|||
runGuardsAndResolvers?: RunGuardsAndResolvers;
|
||||
}
|
||||
|
||||
export interface InternalRoute extends Route {
|
||||
// `LoadedRouterConfig` loaded via a Route `loadChildren`
|
||||
_loadedConfig?: any;
|
||||
}
|
||||
|
||||
export function validateConfig(config: Routes, parentPath: string = ''): void {
|
||||
// forEach doesn't iterate undefined values
|
||||
for (let i = 0; i < config.length; i++) {
|
||||
|
|
|
@ -7,6 +7,5 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
export {ROUTER_PROVIDERS as ɵROUTER_PROVIDERS} from './router_module';
|
||||
export {flatten as ɵflatten} from './utils/collection';
|
||||
|
|
|
@ -11,7 +11,7 @@ import {Observable} from 'rxjs/Observable';
|
|||
import {Observer} from 'rxjs/Observer';
|
||||
import {of } from 'rxjs/observable/of';
|
||||
|
||||
import {Data, ResolveData, Route, Routes} from './config';
|
||||
import {Data, InternalRoute, ResolveData, Route, Routes} from './config';
|
||||
import {ActivatedRouteSnapshot, RouterStateSnapshot, inheritedParamsDataResolve} from './router_state';
|
||||
import {PRIMARY_OUTLET, defaultUrlMatcher} from './shared';
|
||||
import {UrlSegment, UrlSegmentGroup, UrlTree, mapChildrenIntoArray} from './url_tree';
|
||||
|
@ -66,9 +66,9 @@ class Recognizer {
|
|||
TreeNode<ActivatedRouteSnapshot>[] {
|
||||
if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
|
||||
return this.processChildren(config, segmentGroup);
|
||||
} else {
|
||||
return this.processSegment(config, segmentGroup, segmentGroup.segments, outlet);
|
||||
}
|
||||
|
||||
return this.processSegment(config, segmentGroup, segmentGroup.segments, outlet);
|
||||
}
|
||||
|
||||
processChildren(config: Route[], segmentGroup: UrlSegmentGroup):
|
||||
|
@ -92,9 +92,9 @@ class Recognizer {
|
|||
}
|
||||
if (this.noLeftoversInUrl(segmentGroup, segments, outlet)) {
|
||||
return [];
|
||||
} else {
|
||||
throw new NoMatch();
|
||||
}
|
||||
|
||||
throw new NoMatch();
|
||||
}
|
||||
|
||||
private noLeftoversInUrl(segmentGroup: UrlSegmentGroup, segments: UrlSegment[], outlet: string):
|
||||
|
@ -107,7 +107,7 @@ class Recognizer {
|
|||
outlet: string): TreeNode<ActivatedRouteSnapshot>[] {
|
||||
if (route.redirectTo) throw new NoMatch();
|
||||
|
||||
if ((route.outlet ? route.outlet : PRIMARY_OUTLET) !== outlet) throw new NoMatch();
|
||||
if ((route.outlet || PRIMARY_OUTLET) !== outlet) throw new NoMatch();
|
||||
|
||||
if (route.path === '**') {
|
||||
const params = segments.length > 0 ? last(segments).parameters : {};
|
||||
|
@ -135,15 +135,14 @@ class Recognizer {
|
|||
if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
|
||||
const children = this.processChildren(childConfig, segmentGroup);
|
||||
return [new TreeNode<ActivatedRouteSnapshot>(snapshot, children)];
|
||||
|
||||
} else if (childConfig.length === 0 && slicedSegments.length === 0) {
|
||||
return [new TreeNode<ActivatedRouteSnapshot>(snapshot, [])];
|
||||
|
||||
} else {
|
||||
const children =
|
||||
this.processSegment(childConfig, segmentGroup, slicedSegments, PRIMARY_OUTLET);
|
||||
return [new TreeNode<ActivatedRouteSnapshot>(snapshot, children)];
|
||||
}
|
||||
|
||||
if (childConfig.length === 0 && slicedSegments.length === 0) {
|
||||
return [new TreeNode<ActivatedRouteSnapshot>(snapshot, [])];
|
||||
}
|
||||
|
||||
const children = this.processSegment(childConfig, segmentGroup, slicedSegments, PRIMARY_OUTLET);
|
||||
return [new TreeNode<ActivatedRouteSnapshot>(snapshot, children)];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,23 +154,25 @@ function sortActivatedRouteSnapshots(nodes: TreeNode<ActivatedRouteSnapshot>[]):
|
|||
});
|
||||
}
|
||||
|
||||
function getChildConfig(route: Route): Route[] {
|
||||
function getChildConfig(route: InternalRoute): Route[] {
|
||||
if (route.children) {
|
||||
return route.children;
|
||||
} else if (route.loadChildren) {
|
||||
return (<any>route)._loadedConfig.routes;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (route.loadChildren) {
|
||||
return route._loadedConfig.routes;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function match(segmentGroup: UrlSegmentGroup, route: Route, segments: UrlSegment[]) {
|
||||
if (route.path === '') {
|
||||
if (route.pathMatch === 'full' && (segmentGroup.hasChildren() || segments.length > 0)) {
|
||||
throw new NoMatch();
|
||||
} else {
|
||||
return {consumedSegments: [], lastChild: 0, parameters: {}};
|
||||
}
|
||||
|
||||
return {consumedSegments: [], lastChild: 0, parameters: {}};
|
||||
}
|
||||
|
||||
const matcher = route.matcher || defaultUrlMatcher;
|
||||
|
@ -228,9 +229,9 @@ function split(
|
|||
s._sourceSegment = segmentGroup;
|
||||
s._segmentIndexShift = consumedSegments.length;
|
||||
return {segmentGroup: s, slicedSegments: []};
|
||||
}
|
||||
|
||||
} else if (
|
||||
slicedSegments.length === 0 &&
|
||||
if (slicedSegments.length === 0 &&
|
||||
containsEmptyPathMatches(segmentGroup, slicedSegments, config)) {
|
||||
const s = new UrlSegmentGroup(
|
||||
segmentGroup.segments, addEmptyPathsToChildrenIfNeeded(
|
||||
|
@ -238,14 +239,13 @@ function split(
|
|||
s._sourceSegment = segmentGroup;
|
||||
s._segmentIndexShift = consumedSegments.length;
|
||||
return {segmentGroup: s, slicedSegments};
|
||||
}
|
||||
|
||||
} else {
|
||||
const s = new UrlSegmentGroup(segmentGroup.segments, segmentGroup.children);
|
||||
s._sourceSegment = segmentGroup;
|
||||
s._segmentIndexShift = consumedSegments.length;
|
||||
return {segmentGroup: s, slicedSegments};
|
||||
}
|
||||
}
|
||||
|
||||
function addEmptyPathsToChildrenIfNeeded(
|
||||
segmentGroup: UrlSegmentGroup, slicedSegments: UrlSegment[], routes: Route[],
|
||||
|
@ -283,33 +283,32 @@ function createChildrenForEmptyPaths(
|
|||
|
||||
function containsEmptyPathMatchesWithNamedOutlets(
|
||||
segmentGroup: UrlSegmentGroup, slicedSegments: UrlSegment[], routes: Route[]): boolean {
|
||||
return routes
|
||||
.filter(
|
||||
r => emptyPathMatch(segmentGroup, slicedSegments, r) &&
|
||||
getOutlet(r) !== PRIMARY_OUTLET)
|
||||
.length > 0;
|
||||
return routes.some(
|
||||
r => emptyPathMatch(segmentGroup, slicedSegments, r) && getOutlet(r) !== PRIMARY_OUTLET);
|
||||
}
|
||||
|
||||
function containsEmptyPathMatches(
|
||||
segmentGroup: UrlSegmentGroup, slicedSegments: UrlSegment[], routes: Route[]): boolean {
|
||||
return routes.filter(r => emptyPathMatch(segmentGroup, slicedSegments, r)).length > 0;
|
||||
return routes.some(r => emptyPathMatch(segmentGroup, slicedSegments, r));
|
||||
}
|
||||
|
||||
function emptyPathMatch(
|
||||
segmentGroup: UrlSegmentGroup, slicedSegments: UrlSegment[], r: Route): boolean {
|
||||
if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === 'full')
|
||||
if ((segmentGroup.hasChildren() || slicedSegments.length > 0) && r.pathMatch === 'full') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return r.path === '' && r.redirectTo === undefined;
|
||||
}
|
||||
|
||||
function getOutlet(route: Route): string {
|
||||
return route.outlet ? route.outlet : PRIMARY_OUTLET;
|
||||
return route.outlet || PRIMARY_OUTLET;
|
||||
}
|
||||
|
||||
function getData(route: Route): Data {
|
||||
return route.data ? route.data : {};
|
||||
return route.data || {};
|
||||
}
|
||||
|
||||
function getResolve(route: Route): ResolveData {
|
||||
return route.resolve ? route.resolve : {};
|
||||
return route.resolve || {};
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import {mergeMap} from 'rxjs/operator/mergeMap';
|
|||
import {reduce} from 'rxjs/operator/reduce';
|
||||
|
||||
import {applyRedirects} from './apply_redirects';
|
||||
import {QueryParamsHandling, ResolveData, Route, Routes, RunGuardsAndResolvers, validateConfig} from './config';
|
||||
import {InternalRoute, QueryParamsHandling, ResolveData, Route, Routes, RunGuardsAndResolvers, validateConfig} from './config';
|
||||
import {createRouterState} from './create_router_state';
|
||||
import {createUrlTree} from './create_url_tree';
|
||||
import {RouterOutlet} from './directives/router_outlet';
|
||||
|
@ -806,15 +806,15 @@ export class PreActivation {
|
|||
private traverseChildRoutes(
|
||||
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>,
|
||||
outletMap: RouterOutletMap, futurePath: ActivatedRouteSnapshot[]): void {
|
||||
const prevChildren: {[key: string]: any} = nodeChildrenAsMap(currNode);
|
||||
const prevChildren = nodeChildrenAsMap(currNode);
|
||||
|
||||
futureNode.children.forEach(c => {
|
||||
this.traverseRoutes(c, prevChildren[c.value.outlet], outletMap, futurePath.concat([c.value]));
|
||||
delete prevChildren[c.value.outlet];
|
||||
});
|
||||
forEach(
|
||||
prevChildren,
|
||||
(v: any, k: string) => this.deactiveRouteAndItsChildren(v, outletMap._outlets[k]));
|
||||
prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) =>
|
||||
this.deactiveRouteAndItsChildren(v, outletMap._outlets[k]));
|
||||
}
|
||||
|
||||
private traverseRoutes(
|
||||
|
@ -881,10 +881,10 @@ export class PreActivation {
|
|||
|
||||
private deactiveRouteAndItsChildren(
|
||||
route: TreeNode<ActivatedRouteSnapshot>, outlet: RouterOutlet): void {
|
||||
const prevChildren: {[key: string]: any} = nodeChildrenAsMap(route);
|
||||
const prevChildren = nodeChildrenAsMap(route);
|
||||
const r = route.value;
|
||||
|
||||
forEach(prevChildren, (v: any, k: string) => {
|
||||
forEach(prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) => {
|
||||
if (!r.component) {
|
||||
this.deactiveRouteAndItsChildren(v, outlet);
|
||||
} else if (!!outlet) {
|
||||
|
@ -1167,33 +1167,34 @@ function advanceActivatedRouteNodeAndItsChildren(node: TreeNode<ActivatedRoute>)
|
|||
}
|
||||
|
||||
function parentLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConfig {
|
||||
let s = snapshot.parent;
|
||||
while (s) {
|
||||
const c: any = s._routeConfig;
|
||||
if (c && c._loadedConfig) return c._loadedConfig;
|
||||
if (c && c.component) return null;
|
||||
s = s.parent;
|
||||
for (let s = snapshot.parent; s; s = s.parent) {
|
||||
const route: InternalRoute = s._routeConfig;
|
||||
if (route && route._loadedConfig) return route._loadedConfig;
|
||||
if (route && route.component) return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function closestLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConfig {
|
||||
if (!snapshot) return null;
|
||||
|
||||
let s = snapshot.parent;
|
||||
while (s) {
|
||||
const c: any = s._routeConfig;
|
||||
if (c && c._loadedConfig) return c._loadedConfig;
|
||||
s = s.parent;
|
||||
for (let s = snapshot.parent; s; s = s.parent) {
|
||||
const route: InternalRoute = s._routeConfig;
|
||||
if (route && route._loadedConfig) return route._loadedConfig;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function nodeChildrenAsMap(node: TreeNode<any>) {
|
||||
return node ? node.children.reduce((m: any, c: TreeNode<any>) => {
|
||||
m[c.value.outlet] = c;
|
||||
return m;
|
||||
}, {}) : {};
|
||||
function nodeChildrenAsMap<T extends{outlet: string}>(node: TreeNode<T>) {
|
||||
const map: {[key: string]: TreeNode<T>} = {};
|
||||
|
||||
if (node) {
|
||||
node.children.forEach(child => map[child.value.outlet] = child);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
function getOutlet(outletMap: RouterOutletMap, route: ActivatedRoute): RouterOutlet {
|
||||
|
|
|
@ -16,7 +16,7 @@ import {concatMap} from 'rxjs/operator/concatMap';
|
|||
import {filter} from 'rxjs/operator/filter';
|
||||
import {mergeAll} from 'rxjs/operator/mergeAll';
|
||||
import {mergeMap} from 'rxjs/operator/mergeMap';
|
||||
import {Route, Routes} from './config';
|
||||
import {InternalRoute, Route, Routes} from './config';
|
||||
import {NavigationEnd, RouteConfigLoadEnd, RouteConfigLoadStart} from './events';
|
||||
import {Router} from './router';
|
||||
import {RouterConfigLoader} from './router_config_loader';
|
||||
|
@ -100,30 +100,30 @@ export class RouterPreloader {
|
|||
|
||||
private processRoutes(ngModule: NgModuleRef<any>, routes: Routes): Observable<void> {
|
||||
const res: Observable<any>[] = [];
|
||||
for (const c of routes) {
|
||||
for (const r of routes) {
|
||||
const route: InternalRoute = r;
|
||||
// we already have the config loaded, just recurse
|
||||
if (c.loadChildren && !c.canLoad && (<any>c)._loadedConfig) {
|
||||
const childConfig = (<any>c)._loadedConfig;
|
||||
res.push(this.processRoutes(childConfig.module, childConfig.routes));
|
||||
if (route.loadChildren && !route.canLoad && route._loadedConfig) {
|
||||
const childConfig = route._loadedConfig;
|
||||
res.push(this.processRoutes(ngModule, childConfig.routes));
|
||||
|
||||
// no config loaded, fetch the config
|
||||
} else if (c.loadChildren && !c.canLoad) {
|
||||
res.push(this.preloadConfig(ngModule, c));
|
||||
} else if (route.loadChildren && !route.canLoad) {
|
||||
res.push(this.preloadConfig(ngModule, route));
|
||||
|
||||
// recurse into children
|
||||
} else if (c.children) {
|
||||
res.push(this.processRoutes(ngModule, c.children));
|
||||
} else if (route.children) {
|
||||
res.push(this.processRoutes(ngModule, route.children));
|
||||
}
|
||||
}
|
||||
return mergeAll.call(from(res));
|
||||
}
|
||||
|
||||
private preloadConfig(ngModule: NgModuleRef<any>, route: Route): Observable<void> {
|
||||
private preloadConfig(ngModule: NgModuleRef<any>, route: InternalRoute): Observable<void> {
|
||||
return this.preloadingStrategy.preload(route, () => {
|
||||
const loaded = this.loader.load(ngModule.injector, route);
|
||||
return mergeMap.call(loaded, (config: any): any => {
|
||||
const c: any = route;
|
||||
c._loadedConfig = config;
|
||||
route._loadedConfig = config;
|
||||
return this.processRoutes(config.module, config.routes);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -345,7 +345,7 @@ export function serializePath(path: UrlSegment): string {
|
|||
}
|
||||
|
||||
function serializeParams(params: {[key: string]: string}): string {
|
||||
return pairs(params).map(p => `;${encode(p.first)}=${encode(p.second)}`).join('');
|
||||
return Object.keys(params).map(key => `;${encode(key)}=${encode(params[key])}`).join('');
|
||||
}
|
||||
|
||||
function serializeQueryParams(params: {[key: string]: any}): string {
|
||||
|
@ -358,20 +358,6 @@ function serializeQueryParams(params: {[key: string]: any}): string {
|
|||
return strParams.length ? `?${strParams.join("&")}` : '';
|
||||
}
|
||||
|
||||
class Pair<A, B> {
|
||||
constructor(public first: A, public second: B) {}
|
||||
}
|
||||
|
||||
function pairs<T>(obj: {[key: string]: T}): Pair<string, T>[] {
|
||||
const res: Pair<string, T>[] = [];
|
||||
for (const prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
res.push(new Pair<string, T>(prop, obj[prop]));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const SEGMENT_RE = /^[^\/()?;=&#]+/;
|
||||
function matchSegments(str: string): string {
|
||||
SEGMENT_RE.lastIndex = 0;
|
||||
|
|
Loading…
Reference in New Issue