refactor(router): cleanup config

This commit is contained in:
Victor Berchet 2016-12-02 14:09:09 -08:00 committed by Alex Rickabaugh
parent 51b06924bd
commit d7d8fab211
2 changed files with 60 additions and 72 deletions

View File

@ -8,7 +8,7 @@
import {Type} from '@angular/core'; import {Type} from '@angular/core';
import {Observable} from 'rxjs/Observable'; import {Observable} from 'rxjs/Observable';
import {PRIMARY_OUTLET, Params} from './shared'; import {PRIMARY_OUTLET} from './shared';
import {UrlSegment, UrlSegmentGroup} from './url_tree'; import {UrlSegment, UrlSegmentGroup} from './url_tree';
/** /**
@ -19,20 +19,25 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* *
* - `path` is a string that uses the route matcher DSL. * - `path` is a string that uses the route matcher DSL.
* - `pathMatch` is a string that specifies the matching strategy. * - `pathMatch` is a string that specifies the matching strategy.
* - `matcher` defines a custom strategy for path matching and supersedes `path` and `pathMatch`.
* See {@link UrlMatcher} for more info.
* - `component` is a component type. * - `component` is a component type.
* - `redirectTo` is the url fragment which will replace the current matched segment. * - `redirectTo` is the url fragment which will replace the current matched segment.
* - `outlet` is the name of the outlet the component should be placed into. * - `outlet` is the name of the outlet the component should be placed into.
* - `canActivate` is an array of DI tokens used to look up CanActivate handlers. See {@link * - `canActivate` is an array of DI tokens used to look up CanActivate handlers. See
* CanActivate} for more info. * {@link CanActivate} for more info.
* - `canActivateChild` is an array of DI tokens used to look up CanActivateChild handlers. See * - `canActivateChild` is an array of DI tokens used to look up CanActivateChild handlers. See
* {@link * {@link CanActivateChild} for more info.
* CanActivateChild} for more info. * - `canDeactivate` is an array of DI tokens used to look up CanDeactivate handlers. See
* - `canDeactivate` is an array of DI tokens used to look up CanDeactivate handlers. See {@link * {@link CanDeactivate} for more info.
* CanDeactivate} for more info. * - `canLoad` is an array of DI tokens used to look up CanDeactivate handlers. See
* {@link CanLoad} for more info.
* - `data` is additional data provided to the component via `ActivatedRoute`. * - `data` is additional data provided to the component via `ActivatedRoute`.
* - `resolve` is a map of DI tokens used to look up data resolvers. See {@link Resolve} for more * - `resolve` is a map of DI tokens used to look up data resolvers. See {@link Resolve} for more
* info. * info.
* - `children` is an array of child route definitions. * - `children` is an array of child route definitions.
* - `loadChildren` is a reference to lazy loaded child routes. See {@link LoadChildren} for more
* info.
* *
* ### Simple Configuration * ### Simple Configuration
* *
@ -40,12 +45,10 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* [{ * [{
* path: 'team/:id', * path: 'team/:id',
* component: Team, * component: Team,
* children: [ * children: [{
* {
* path: 'user/:name', * path: 'user/:name',
* component: User * component: User
* } * }]
* ]
* }] * }]
* ``` * ```
* *
@ -58,8 +61,7 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* [{ * [{
* path: 'team/:id', * path: 'team/:id',
* component: Team * component: Team
* }, * }, {
* {
* path: 'chat/:user', * path: 'chat/:user',
* component: Chat * component: Chat
* outlet: 'aux' * outlet: 'aux'
@ -86,16 +88,13 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* [{ * [{
* path: 'team/:id', * path: 'team/:id',
* component: Team, * component: Team,
* children: [ * children: [{
* {
* path: 'legacy/user/:name', * path: 'legacy/user/:name',
* redirectTo: 'user/:name' * redirectTo: 'user/:name'
* }, * }, {
* {
* path: 'user/:name', * path: 'user/:name',
* component: User * component: User
* } * }]
* ]
* }] * }]
* ``` * ```
* *
@ -115,16 +114,13 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* [{ * [{
* path: 'team/:id', * path: 'team/:id',
* component: Team, * component: Team,
* children: [ * children: [{
* {
* path: '', * path: '',
* component: AllUsers * component: AllUsers
* }, * }, {
* {
* path: 'user/:name', * path: 'user/:name',
* component: User * component: User
* } * }]
* ]
* }] * }]
* ``` * ```
* *
@ -136,18 +132,14 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* [{ * [{
* path: 'team/:id', * path: 'team/:id',
* component: Team, * component: Team,
* children: [ * children: [{
* {
* path: '', * path: '',
* component: WrapperCmp, * component: WrapperCmp,
* children: [ * children: [{
* {
* path: 'user/:name', * path: 'user/:name',
* component: User * component: User
* } * }]
* ] * }]
* }
* ]
* }] * }]
* ``` * ```
* *
@ -172,8 +164,7 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* path: '', * path: '',
* pathMatch: 'prefix', //default * pathMatch: 'prefix', //default
* redirectTo: 'main' * redirectTo: 'main'
* }, * }, {
* {
* path: 'main', * path: 'main',
* component: Main * component: Main
* }] * }]
@ -190,8 +181,7 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* path: '', * path: '',
* pathMatch: 'full', * pathMatch: 'full',
* redirectTo: 'main' * redirectTo: 'main'
* }, * }, {
* {
* path: 'main', * path: 'main',
* component: Main * component: Main
* }] * }]
@ -244,8 +234,7 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* *
* Lazy loading speeds up our application load time by splitting it into multiple bundles, and * Lazy loading speeds up our application load time by splitting it into multiple bundles, and
* loading them on demand. The router is designed to make lazy loading simple and easy. Instead of * loading them on demand. The router is designed to make lazy loading simple and easy. Instead of
* providing the children property, you can provide * providing the children property, you can provide the `loadChildren` property, as follows:
* the loadChildren property, as follows:
* *
* ``` * ```
* [{ * [{
@ -256,9 +245,8 @@ import {UrlSegment, UrlSegmentGroup} from './url_tree';
* ``` * ```
* *
* The router will use registered NgModuleFactoryLoader to fetch an NgModule associated with 'team'. * The router will use registered NgModuleFactoryLoader to fetch an NgModule associated with 'team'.
* Then it will * Then it will extract the set of routes defined in that NgModule, and will transparently add
* extract the set of routes defined in that NgModule, and will transparently add those routes to * those routes to the main configuration.
* the main configuration.
* *
* @stable use Routes * @stable use Routes
*/ */
@ -326,7 +314,6 @@ export type LoadChildrenCallback = () => Type<any>| Promise<Type<any>>| Observab
/** /**
* @whatItDoes The type of `loadChildren`. * @whatItDoes The type of `loadChildren`.
*
* See {@link Routes} for more details. * See {@link Routes} for more details.
* @stable * @stable
*/ */
@ -377,32 +364,31 @@ function validateNode(route: Route): void {
if (Array.isArray(route)) { if (Array.isArray(route)) {
throw new Error(`Invalid route configuration: Array cannot be specified`); throw new Error(`Invalid route configuration: Array cannot be specified`);
} }
if (route.component === undefined && (route.outlet && route.outlet !== PRIMARY_OUTLET)) { if (!route.component && (route.outlet && route.outlet !== PRIMARY_OUTLET)) {
throw new Error( throw new Error(
`Invalid route configuration of route '${route.path}': a componentless route cannot have a named outlet set`); `Invalid route configuration of route '${route.path}': a componentless route cannot have a named outlet set`);
} }
if (!!route.redirectTo && !!route.children) { if (route.redirectTo && route.children) {
throw new Error( throw new Error(
`Invalid configuration of route '${route.path}': redirectTo and children cannot be used together`); `Invalid configuration of route '${route.path}': redirectTo and children cannot be used together`);
} }
if (!!route.redirectTo && !!route.loadChildren) { if (route.redirectTo && route.loadChildren) {
throw new Error( throw new Error(
`Invalid configuration of route '${route.path}': redirectTo and loadChildren cannot be used together`); `Invalid configuration of route '${route.path}': redirectTo and loadChildren cannot be used together`);
} }
if (!!route.children && !!route.loadChildren) { if (route.children && route.loadChildren) {
throw new Error( throw new Error(
`Invalid configuration of route '${route.path}': children and loadChildren cannot be used together`); `Invalid configuration of route '${route.path}': children and loadChildren cannot be used together`);
} }
if (!!route.redirectTo && !!route.component) { if (route.redirectTo && route.component) {
throw new Error( throw new Error(
`Invalid configuration of route '${route.path}': redirectTo and component cannot be used together`); `Invalid configuration of route '${route.path}': redirectTo and component cannot be used together`);
} }
if (!!route.path && !!route.matcher) { if (route.path && route.matcher) {
throw new Error( throw new Error(
`Invalid configuration of route '${route.path}': path and matcher cannot be used together`); `Invalid configuration of route '${route.path}': path and matcher cannot be used together`);
} }
if (route.redirectTo === undefined && !route.component && !route.children && if (route.redirectTo === void 0 && !route.component && !route.children && !route.loadChildren) {
!route.loadChildren) {
throw new Error( throw new Error(
`Invalid configuration of route '${route.path}': one of the following must be provided (component or redirectTo or children or loadChildren)`); `Invalid configuration of route '${route.path}': one of the following must be provided (component or redirectTo or children or loadChildren)`);
} }
@ -413,13 +399,13 @@ function validateNode(route: Route): void {
throw new Error( throw new Error(
`Invalid route configuration of route '${route.path}': path cannot start with a slash`); `Invalid route configuration of route '${route.path}': path cannot start with a slash`);
} }
if (route.path === '' && route.redirectTo !== undefined && route.pathMatch === undefined) { if (route.path === '' && route.redirectTo !== void 0 && route.pathMatch === void 0) {
const exp = const exp =
`The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`; `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;
throw new Error( throw new Error(
`Invalid route configuration of route '{path: "${route.path}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`); `Invalid route configuration of route '{path: "${route.path}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`);
} }
if (route.pathMatch !== undefined && route.pathMatch !== 'full' && route.pathMatch !== 'prefix') { if (route.pathMatch !== void 0 && route.pathMatch !== 'full' && route.pathMatch !== 'prefix') {
throw new Error( throw new Error(
`Invalid configuration of route '${route.path}': pathMatch can only be set to 'prefix' or 'full'`); `Invalid configuration of route '${route.path}': pathMatch can only be set to 'prefix' or 'full'`);
} }

View File

@ -12,7 +12,10 @@ import {PRIMARY_OUTLET} from '../src/shared';
describe('config', () => { describe('config', () => {
describe('validateConfig', () => { describe('validateConfig', () => {
it('should not throw when no errors', () => { it('should not throw when no errors', () => {
validateConfig([{path: 'a', redirectTo: 'b'}, {path: 'b', component: ComponentA}]); expect(
() => validateConfig([{path: 'a', redirectTo: 'b'}, {path: 'b', component: ComponentA}]))
.not.toThrow();
});
}); });
it('should throw for undefined route', () => { it('should throw for undefined route', () => {
@ -57,8 +60,7 @@ describe('config', () => {
`Invalid configuration of route 'a': redirectTo and component cannot be used together`); `Invalid configuration of route 'a': redirectTo and component cannot be used together`);
}); });
it('should throw when path and matcher are used together', () => {
it('should throw when path and mathcer are used together', () => {
expect(() => { validateConfig([{path: 'a', matcher: <any>'someFunc', children: []}]); }) expect(() => { validateConfig([{path: 'a', matcher: <any>'someFunc', children: []}]); })
.toThrowError( .toThrowError(
`Invalid configuration of route 'a': path and matcher cannot be used together`); `Invalid configuration of route 'a': path and matcher cannot be used together`);