refactor(router): removes a circualr dep
This commit is contained in:
parent
8dd3f59c81
commit
15911367a2
|
@ -10,7 +10,6 @@ export {RouterOutletMap} from './src/router_outlet_map';
|
||||||
export {provideRouter} from './src/router_providers';
|
export {provideRouter} from './src/router_providers';
|
||||||
export {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from './src/router_state';
|
export {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from './src/router_state';
|
||||||
export {PRIMARY_OUTLET, Params} from './src/shared';
|
export {PRIMARY_OUTLET, Params} from './src/shared';
|
||||||
export {DefaultUrlSerializer, UrlSerializer} from './src/url_serializer';
|
export {DefaultUrlSerializer, UrlPathWithParams, UrlSerializer, UrlTree} from './src/url_tree';
|
||||||
export {UrlPathWithParams, UrlTree} from './src/url_tree';
|
|
||||||
|
|
||||||
export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkActive];
|
export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkActive];
|
|
@ -5,7 +5,7 @@ import {RouterConfig} from './config';
|
||||||
import {Router} from './router';
|
import {Router} from './router';
|
||||||
import {RouterOutletMap} from './router_outlet_map';
|
import {RouterOutletMap} from './router_outlet_map';
|
||||||
import {ActivatedRoute} from './router_state';
|
import {ActivatedRoute} from './router_state';
|
||||||
import {DefaultUrlSerializer, UrlSerializer} from './url_serializer';
|
import {DefaultUrlSerializer, UrlSerializer} from './url_tree';
|
||||||
|
|
||||||
export const ROUTER_CONFIG = new OpaqueToken('ROUTER_CONFIG');
|
export const ROUTER_CONFIG = new OpaqueToken('ROUTER_CONFIG');
|
||||||
export const ROUTER_OPTIONS = new OpaqueToken('ROUTER_OPTIONS');
|
export const ROUTER_OPTIONS = new OpaqueToken('ROUTER_OPTIONS');
|
||||||
|
|
|
@ -21,8 +21,7 @@ import {resolve} from './resolve';
|
||||||
import {RouterOutletMap} from './router_outlet_map';
|
import {RouterOutletMap} from './router_outlet_map';
|
||||||
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from './router_state';
|
import {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from './router_state';
|
||||||
import {PRIMARY_OUTLET, Params} from './shared';
|
import {PRIMARY_OUTLET, Params} from './shared';
|
||||||
import {UrlSerializer} from './url_serializer';
|
import {UrlSerializer, UrlTree, createEmptyUrlTree} from './url_tree';
|
||||||
import {UrlTree, createEmptyUrlTree} from './url_tree';
|
|
||||||
import {forEach, shallowEqual} from './utils/collection';
|
import {forEach, shallowEqual} from './utils/collection';
|
||||||
import {TreeNode} from './utils/tree';
|
import {TreeNode} from './utils/tree';
|
||||||
|
|
||||||
|
|
|
@ -1,275 +0,0 @@
|
||||||
import {PRIMARY_OUTLET} from './shared';
|
|
||||||
import {UrlPathWithParams, UrlSegment, UrlTree, mapChildrenIntoArray} from './url_tree';
|
|
||||||
import {forEach} from './utils/collection';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines a way to serialize/deserialize a url tree.
|
|
||||||
*/
|
|
||||||
export abstract class UrlSerializer {
|
|
||||||
/**
|
|
||||||
* Parse a url into a {@Link UrlTree}
|
|
||||||
*/
|
|
||||||
abstract parse(url: string): UrlTree;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a {@Link UrlTree} into a url
|
|
||||||
*/
|
|
||||||
abstract serialize(tree: UrlTree): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A default implementation of the serialization.
|
|
||||||
*/
|
|
||||||
export class DefaultUrlSerializer implements UrlSerializer {
|
|
||||||
parse(url: string): UrlTree {
|
|
||||||
const p = new UrlParser(url);
|
|
||||||
return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());
|
|
||||||
}
|
|
||||||
|
|
||||||
serialize(tree: UrlTree): string {
|
|
||||||
const segment = `/${serializeSegment(tree.root, true)}`;
|
|
||||||
const query = serializeQueryParams(tree.queryParams);
|
|
||||||
const fragment = tree.fragment !== null ? `#${tree.fragment}` : '';
|
|
||||||
return `${segment}${query}${fragment}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function serializePaths(segment: UrlSegment): string {
|
|
||||||
return segment.pathsWithParams.map(p => serializePath(p)).join('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeSegment(segment: UrlSegment, root: boolean): string {
|
|
||||||
if (segment.children[PRIMARY_OUTLET] && root) {
|
|
||||||
const primary = serializeSegment(segment.children[PRIMARY_OUTLET], false);
|
|
||||||
const children: string[] = [];
|
|
||||||
forEach(segment.children, (v: UrlSegment, k: string) => {
|
|
||||||
if (k !== PRIMARY_OUTLET) {
|
|
||||||
children.push(`${k}:${serializeSegment(v, false)}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (children.length > 0) {
|
|
||||||
return `${primary}(${children.join('//')})`;
|
|
||||||
} else {
|
|
||||||
return `${primary}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (segment.hasChildren() && !root) {
|
|
||||||
const children = mapChildrenIntoArray(segment, (v: UrlSegment, k: string) => {
|
|
||||||
if (k === PRIMARY_OUTLET) {
|
|
||||||
return [serializeSegment(segment.children[PRIMARY_OUTLET], false)];
|
|
||||||
} else {
|
|
||||||
return [`${k}:${serializeSegment(v, false)}`];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return `${serializePaths(segment)}/(${children.join('//')})`;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return serializePaths(segment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function serializePath(path: UrlPathWithParams): string {
|
|
||||||
return `${path.path}${serializeParams(path.parameters)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeParams(params: {[key: string]: string}): string {
|
|
||||||
return pairs(params).map(p => `;${p.first}=${p.second}`).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeQueryParams(params: {[key: string]: string}): string {
|
|
||||||
const strs = pairs(params).map(p => `${p.first}=${p.second}`);
|
|
||||||
return strs.length > 0 ? `?${strs.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 (let prop in obj) {
|
|
||||||
if (obj.hasOwnProperty(prop)) {
|
|
||||||
res.push(new Pair<string, T>(prop, obj[prop]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SEGMENT_RE = /^[^\/\(\)\?;=&#]+/;
|
|
||||||
function matchPathWithParams(str: string): string {
|
|
||||||
SEGMENT_RE.lastIndex = 0;
|
|
||||||
const match = SEGMENT_RE.exec(str);
|
|
||||||
return match ? match[0] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const QUERY_PARAM_RE = /^[^=\?&#]+/;
|
|
||||||
function matchQueryParams(str: string): string {
|
|
||||||
QUERY_PARAM_RE.lastIndex = 0;
|
|
||||||
const match = SEGMENT_RE.exec(str);
|
|
||||||
return match ? match[0] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const QUERY_PARAM_VALUE_RE = /^[^\?&#]+/;
|
|
||||||
function matchUrlQueryParamValue(str: string): string {
|
|
||||||
QUERY_PARAM_VALUE_RE.lastIndex = 0;
|
|
||||||
const match = QUERY_PARAM_VALUE_RE.exec(str);
|
|
||||||
return match ? match[0] : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
class UrlParser {
|
|
||||||
constructor(private remaining: string) {}
|
|
||||||
|
|
||||||
peekStartsWith(str: string): boolean { return this.remaining.startsWith(str); }
|
|
||||||
|
|
||||||
capture(str: string): void {
|
|
||||||
if (!this.remaining.startsWith(str)) {
|
|
||||||
throw new Error(`Expected "${str}".`);
|
|
||||||
}
|
|
||||||
this.remaining = this.remaining.substring(str.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
parseRootSegment(): UrlSegment {
|
|
||||||
if (this.remaining === '' || this.remaining === '/') {
|
|
||||||
return new UrlSegment([], {});
|
|
||||||
} else {
|
|
||||||
return new UrlSegment([], this.parseSegmentChildren());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parseSegmentChildren(): {[key: string]: UrlSegment} {
|
|
||||||
if (this.remaining.length == 0) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.peekStartsWith('/')) {
|
|
||||||
this.capture('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
const paths = [this.parsePathWithParams()];
|
|
||||||
|
|
||||||
while (this.peekStartsWith('/') && !this.peekStartsWith('//') && !this.peekStartsWith('/(')) {
|
|
||||||
this.capture('/');
|
|
||||||
paths.push(this.parsePathWithParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
let children: {[key: string]: UrlSegment} = {};
|
|
||||||
if (this.peekStartsWith('/(')) {
|
|
||||||
this.capture('/');
|
|
||||||
children = this.parseParens(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let res: {[key: string]: UrlSegment} = {};
|
|
||||||
if (this.peekStartsWith('(')) {
|
|
||||||
res = this.parseParens(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
res[PRIMARY_OUTLET] = new UrlSegment(paths, children);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
parsePathWithParams(): UrlPathWithParams {
|
|
||||||
let path = matchPathWithParams(this.remaining);
|
|
||||||
this.capture(path);
|
|
||||||
let matrixParams: {[key: string]: any} = {};
|
|
||||||
if (this.peekStartsWith(';')) {
|
|
||||||
matrixParams = this.parseMatrixParams();
|
|
||||||
}
|
|
||||||
return new UrlPathWithParams(path, matrixParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
parseQueryParams(): {[key: string]: any} {
|
|
||||||
const params: {[key: string]: any} = {};
|
|
||||||
if (this.peekStartsWith('?')) {
|
|
||||||
this.capture('?');
|
|
||||||
this.parseQueryParam(params);
|
|
||||||
while (this.remaining.length > 0 && this.peekStartsWith('&')) {
|
|
||||||
this.capture('&');
|
|
||||||
this.parseQueryParam(params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
parseFragment(): string {
|
|
||||||
if (this.peekStartsWith('#')) {
|
|
||||||
return this.remaining.substring(1);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parseMatrixParams(): {[key: string]: any} {
|
|
||||||
const params: {[key: string]: any} = {};
|
|
||||||
while (this.remaining.length > 0 && this.peekStartsWith(';')) {
|
|
||||||
this.capture(';');
|
|
||||||
this.parseParam(params);
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
parseParam(params: {[key: string]: any}): void {
|
|
||||||
const key = matchPathWithParams(this.remaining);
|
|
||||||
if (!key) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.capture(key);
|
|
||||||
let value: any = 'true';
|
|
||||||
if (this.peekStartsWith('=')) {
|
|
||||||
this.capture('=');
|
|
||||||
const valueMatch = matchPathWithParams(this.remaining);
|
|
||||||
if (valueMatch) {
|
|
||||||
value = valueMatch;
|
|
||||||
this.capture(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
parseQueryParam(params: {[key: string]: any}): void {
|
|
||||||
const key = matchQueryParams(this.remaining);
|
|
||||||
if (!key) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.capture(key);
|
|
||||||
let value: any = 'true';
|
|
||||||
if (this.peekStartsWith('=')) {
|
|
||||||
this.capture('=');
|
|
||||||
var valueMatch = matchUrlQueryParamValue(this.remaining);
|
|
||||||
if (valueMatch) {
|
|
||||||
value = valueMatch;
|
|
||||||
this.capture(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
parseParens(allowPrimary: boolean): {[key: string]: UrlSegment} {
|
|
||||||
const segments: {[key: string]: UrlSegment} = {};
|
|
||||||
this.capture('(');
|
|
||||||
|
|
||||||
while (!this.peekStartsWith(')') && this.remaining.length > 0) {
|
|
||||||
let path = matchPathWithParams(this.remaining);
|
|
||||||
let outletName: string;
|
|
||||||
if (path.indexOf(':') > -1) {
|
|
||||||
outletName = path.substr(0, path.indexOf(':'));
|
|
||||||
this.capture(outletName);
|
|
||||||
this.capture(':');
|
|
||||||
} else if (allowPrimary) {
|
|
||||||
outletName = PRIMARY_OUTLET;
|
|
||||||
}
|
|
||||||
|
|
||||||
const children = this.parseSegmentChildren();
|
|
||||||
segments[outletName] = Object.keys(children).length === 1 ? children[PRIMARY_OUTLET] :
|
|
||||||
new UrlSegment([], children);
|
|
||||||
|
|
||||||
if (this.peekStartsWith('//')) {
|
|
||||||
this.capture('//');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.capture(')');
|
|
||||||
|
|
||||||
return segments;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {PRIMARY_OUTLET} from './shared';
|
import {PRIMARY_OUTLET} from './shared';
|
||||||
import {DefaultUrlSerializer, serializePath, serializePaths} from './url_serializer';
|
|
||||||
import {forEach, shallowEqual} from './utils/collection';
|
import {forEach, shallowEqual} from './utils/collection';
|
||||||
|
|
||||||
export function createEmptyUrlTree() {
|
export function createEmptyUrlTree() {
|
||||||
|
@ -132,3 +131,274 @@ export function mapChildrenIntoArray<T>(
|
||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a way to serialize/deserialize a url tree.
|
||||||
|
*/
|
||||||
|
export abstract class UrlSerializer {
|
||||||
|
/**
|
||||||
|
* Parse a url into a {@Link UrlTree}
|
||||||
|
*/
|
||||||
|
abstract parse(url: string): UrlTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a {@Link UrlTree} into a url
|
||||||
|
*/
|
||||||
|
abstract serialize(tree: UrlTree): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A default implementation of the serialization.
|
||||||
|
*/
|
||||||
|
export class DefaultUrlSerializer implements UrlSerializer {
|
||||||
|
parse(url: string): UrlTree {
|
||||||
|
const p = new UrlParser(url);
|
||||||
|
return new UrlTree(p.parseRootSegment(), p.parseQueryParams(), p.parseFragment());
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(tree: UrlTree): string {
|
||||||
|
const segment = `/${serializeSegment(tree.root, true)}`;
|
||||||
|
const query = serializeQueryParams(tree.queryParams);
|
||||||
|
const fragment = tree.fragment !== null ? `#${tree.fragment}` : '';
|
||||||
|
return `${segment}${query}${fragment}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serializePaths(segment: UrlSegment): string {
|
||||||
|
return segment.pathsWithParams.map(p => serializePath(p)).join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeSegment(segment: UrlSegment, root: boolean): string {
|
||||||
|
if (segment.children[PRIMARY_OUTLET] && root) {
|
||||||
|
const primary = serializeSegment(segment.children[PRIMARY_OUTLET], false);
|
||||||
|
const children: string[] = [];
|
||||||
|
forEach(segment.children, (v: UrlSegment, k: string) => {
|
||||||
|
if (k !== PRIMARY_OUTLET) {
|
||||||
|
children.push(`${k}:${serializeSegment(v, false)}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (children.length > 0) {
|
||||||
|
return `${primary}(${children.join('//')})`;
|
||||||
|
} else {
|
||||||
|
return `${primary}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (segment.hasChildren() && !root) {
|
||||||
|
const children = mapChildrenIntoArray(segment, (v: UrlSegment, k: string) => {
|
||||||
|
if (k === PRIMARY_OUTLET) {
|
||||||
|
return [serializeSegment(segment.children[PRIMARY_OUTLET], false)];
|
||||||
|
} else {
|
||||||
|
return [`${k}:${serializeSegment(v, false)}`];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return `${serializePaths(segment)}/(${children.join('//')})`;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return serializePaths(segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serializePath(path: UrlPathWithParams): string {
|
||||||
|
return `${path.path}${serializeParams(path.parameters)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeParams(params: {[key: string]: string}): string {
|
||||||
|
return pairs(params).map(p => `;${p.first}=${p.second}`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeQueryParams(params: {[key: string]: string}): string {
|
||||||
|
const strs = pairs(params).map(p => `${p.first}=${p.second}`);
|
||||||
|
return strs.length > 0 ? `?${strs.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 (let prop in obj) {
|
||||||
|
if (obj.hasOwnProperty(prop)) {
|
||||||
|
res.push(new Pair<string, T>(prop, obj[prop]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SEGMENT_RE = /^[^\/\(\)\?;=&#]+/;
|
||||||
|
function matchPathWithParams(str: string): string {
|
||||||
|
SEGMENT_RE.lastIndex = 0;
|
||||||
|
const match = SEGMENT_RE.exec(str);
|
||||||
|
return match ? match[0] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUERY_PARAM_RE = /^[^=\?&#]+/;
|
||||||
|
function matchQueryParams(str: string): string {
|
||||||
|
QUERY_PARAM_RE.lastIndex = 0;
|
||||||
|
const match = SEGMENT_RE.exec(str);
|
||||||
|
return match ? match[0] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUERY_PARAM_VALUE_RE = /^[^\?&#]+/;
|
||||||
|
function matchUrlQueryParamValue(str: string): string {
|
||||||
|
QUERY_PARAM_VALUE_RE.lastIndex = 0;
|
||||||
|
const match = QUERY_PARAM_VALUE_RE.exec(str);
|
||||||
|
return match ? match[0] : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
class UrlParser {
|
||||||
|
constructor(private remaining: string) {}
|
||||||
|
|
||||||
|
peekStartsWith(str: string): boolean { return this.remaining.startsWith(str); }
|
||||||
|
|
||||||
|
capture(str: string): void {
|
||||||
|
if (!this.remaining.startsWith(str)) {
|
||||||
|
throw new Error(`Expected "${str}".`);
|
||||||
|
}
|
||||||
|
this.remaining = this.remaining.substring(str.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseRootSegment(): UrlSegment {
|
||||||
|
if (this.remaining === '' || this.remaining === '/') {
|
||||||
|
return new UrlSegment([], {});
|
||||||
|
} else {
|
||||||
|
return new UrlSegment([], this.parseSegmentChildren());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseSegmentChildren(): {[key: string]: UrlSegment} {
|
||||||
|
if (this.remaining.length == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.peekStartsWith('/')) {
|
||||||
|
this.capture('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
const paths = [this.parsePathWithParams()];
|
||||||
|
|
||||||
|
while (this.peekStartsWith('/') && !this.peekStartsWith('//') && !this.peekStartsWith('/(')) {
|
||||||
|
this.capture('/');
|
||||||
|
paths.push(this.parsePathWithParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
let children: {[key: string]: UrlSegment} = {};
|
||||||
|
if (this.peekStartsWith('/(')) {
|
||||||
|
this.capture('/');
|
||||||
|
children = this.parseParens(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
let res: {[key: string]: UrlSegment} = {};
|
||||||
|
if (this.peekStartsWith('(')) {
|
||||||
|
res = this.parseParens(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
res[PRIMARY_OUTLET] = new UrlSegment(paths, children);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
parsePathWithParams(): UrlPathWithParams {
|
||||||
|
let path = matchPathWithParams(this.remaining);
|
||||||
|
this.capture(path);
|
||||||
|
let matrixParams: {[key: string]: any} = {};
|
||||||
|
if (this.peekStartsWith(';')) {
|
||||||
|
matrixParams = this.parseMatrixParams();
|
||||||
|
}
|
||||||
|
return new UrlPathWithParams(path, matrixParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseQueryParams(): {[key: string]: any} {
|
||||||
|
const params: {[key: string]: any} = {};
|
||||||
|
if (this.peekStartsWith('?')) {
|
||||||
|
this.capture('?');
|
||||||
|
this.parseQueryParam(params);
|
||||||
|
while (this.remaining.length > 0 && this.peekStartsWith('&')) {
|
||||||
|
this.capture('&');
|
||||||
|
this.parseQueryParam(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseFragment(): string {
|
||||||
|
if (this.peekStartsWith('#')) {
|
||||||
|
return this.remaining.substring(1);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMatrixParams(): {[key: string]: any} {
|
||||||
|
const params: {[key: string]: any} = {};
|
||||||
|
while (this.remaining.length > 0 && this.peekStartsWith(';')) {
|
||||||
|
this.capture(';');
|
||||||
|
this.parseParam(params);
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseParam(params: {[key: string]: any}): void {
|
||||||
|
const key = matchPathWithParams(this.remaining);
|
||||||
|
if (!key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.capture(key);
|
||||||
|
let value: any = 'true';
|
||||||
|
if (this.peekStartsWith('=')) {
|
||||||
|
this.capture('=');
|
||||||
|
const valueMatch = matchPathWithParams(this.remaining);
|
||||||
|
if (valueMatch) {
|
||||||
|
value = valueMatch;
|
||||||
|
this.capture(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseQueryParam(params: {[key: string]: any}): void {
|
||||||
|
const key = matchQueryParams(this.remaining);
|
||||||
|
if (!key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.capture(key);
|
||||||
|
let value: any = 'true';
|
||||||
|
if (this.peekStartsWith('=')) {
|
||||||
|
this.capture('=');
|
||||||
|
var valueMatch = matchUrlQueryParamValue(this.remaining);
|
||||||
|
if (valueMatch) {
|
||||||
|
value = valueMatch;
|
||||||
|
this.capture(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseParens(allowPrimary: boolean): {[key: string]: UrlSegment} {
|
||||||
|
const segments: {[key: string]: UrlSegment} = {};
|
||||||
|
this.capture('(');
|
||||||
|
|
||||||
|
while (!this.peekStartsWith(')') && this.remaining.length > 0) {
|
||||||
|
let path = matchPathWithParams(this.remaining);
|
||||||
|
let outletName: string;
|
||||||
|
if (path.indexOf(':') > -1) {
|
||||||
|
outletName = path.substr(0, path.indexOf(':'));
|
||||||
|
this.capture(outletName);
|
||||||
|
this.capture(':');
|
||||||
|
} else if (allowPrimary) {
|
||||||
|
outletName = PRIMARY_OUTLET;
|
||||||
|
}
|
||||||
|
|
||||||
|
const children = this.parseSegmentChildren();
|
||||||
|
segments[outletName] = Object.keys(children).length === 1 ? children[PRIMARY_OUTLET] :
|
||||||
|
new UrlSegment([], children);
|
||||||
|
|
||||||
|
if (this.peekStartsWith('//')) {
|
||||||
|
this.capture('//');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.capture(')');
|
||||||
|
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import {applyRedirects} from '../src/apply_redirects';
|
import {applyRedirects} from '../src/apply_redirects';
|
||||||
import {RouterConfig} from '../src/config';
|
import {RouterConfig} from '../src/config';
|
||||||
import {DefaultUrlSerializer} from '../src/url_serializer';
|
import {DefaultUrlSerializer, UrlSegment, UrlTree, equalPathsWithParams} from '../src/url_tree';
|
||||||
import {UrlSegment, UrlTree, equalPathsWithParams} from '../src/url_tree';
|
|
||||||
import {TreeNode} from '../src/utils/tree';
|
import {TreeNode} from '../src/utils/tree';
|
||||||
|
|
||||||
describe('applyRedirects', () => {
|
describe('applyRedirects', () => {
|
||||||
|
|
|
@ -3,8 +3,7 @@ import {createRouterState} from '../src/create_router_state';
|
||||||
import {recognize} from '../src/recognize';
|
import {recognize} from '../src/recognize';
|
||||||
import {ActivatedRoute, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from '../src/router_state';
|
import {ActivatedRoute, RouterState, RouterStateSnapshot, advanceActivatedRoute, createEmptyState} from '../src/router_state';
|
||||||
import {PRIMARY_OUTLET, Params} from '../src/shared';
|
import {PRIMARY_OUTLET, Params} from '../src/shared';
|
||||||
import {DefaultUrlSerializer} from '../src/url_serializer';
|
import {DefaultUrlSerializer, UrlSegment, UrlTree} from '../src/url_tree';
|
||||||
import {UrlSegment, UrlTree} from '../src/url_tree';
|
|
||||||
import {TreeNode} from '../src/utils/tree';
|
import {TreeNode} from '../src/utils/tree';
|
||||||
|
|
||||||
describe('create router state', () => {
|
describe('create router state', () => {
|
||||||
|
|
|
@ -3,8 +3,7 @@ import {BehaviorSubject} from 'rxjs/BehaviorSubject';
|
||||||
import {createUrlTree} from '../src/create_url_tree';
|
import {createUrlTree} from '../src/create_url_tree';
|
||||||
import {ActivatedRoute, ActivatedRouteSnapshot, advanceActivatedRoute} from '../src/router_state';
|
import {ActivatedRoute, ActivatedRouteSnapshot, advanceActivatedRoute} from '../src/router_state';
|
||||||
import {PRIMARY_OUTLET, Params} from '../src/shared';
|
import {PRIMARY_OUTLET, Params} from '../src/shared';
|
||||||
import {DefaultUrlSerializer} from '../src/url_serializer';
|
import {DefaultUrlSerializer, UrlPathWithParams, UrlSegment, UrlTree} from '../src/url_tree';
|
||||||
import {UrlPathWithParams, UrlSegment, UrlTree} from '../src/url_tree';
|
|
||||||
|
|
||||||
describe('createUrlTree', () => {
|
describe('createUrlTree', () => {
|
||||||
const serializer = new DefaultUrlSerializer();
|
const serializer = new DefaultUrlSerializer();
|
||||||
|
|
|
@ -2,8 +2,7 @@ import {RouterConfig} from '../src/config';
|
||||||
import {recognize} from '../src/recognize';
|
import {recognize} from '../src/recognize';
|
||||||
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '../src/router_state';
|
import {ActivatedRouteSnapshot, RouterStateSnapshot} from '../src/router_state';
|
||||||
import {PRIMARY_OUTLET, Params} from '../src/shared';
|
import {PRIMARY_OUTLET, Params} from '../src/shared';
|
||||||
import {DefaultUrlSerializer} from '../src/url_serializer';
|
import {DefaultUrlSerializer, UrlTree} from '../src/url_tree';
|
||||||
import {UrlTree} from '../src/url_tree';
|
|
||||||
|
|
||||||
describe('recognize', () => {
|
describe('recognize', () => {
|
||||||
it('should work', () => {
|
it('should work', () => {
|
||||||
|
|
|
@ -2,8 +2,7 @@ import {RouterConfig} from '../src/config';
|
||||||
import {recognize} from '../src/recognize';
|
import {recognize} from '../src/recognize';
|
||||||
import {resolve} from '../src/resolve';
|
import {resolve} from '../src/resolve';
|
||||||
import {RouterStateSnapshot} from '../src/router_state';
|
import {RouterStateSnapshot} from '../src/router_state';
|
||||||
import {DefaultUrlSerializer} from '../src/url_serializer';
|
import {DefaultUrlSerializer, UrlSegment, UrlTree} from '../src/url_tree';
|
||||||
import {UrlSegment, UrlTree} from '../src/url_tree';
|
|
||||||
|
|
||||||
describe('resolve', () => {
|
describe('resolve', () => {
|
||||||
it('should resolve components', () => {
|
it('should resolve components', () => {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import {PRIMARY_OUTLET} from '../src/shared';
|
import {PRIMARY_OUTLET} from '../src/shared';
|
||||||
import {DefaultUrlSerializer, serializePath} from '../src/url_serializer';
|
import {DefaultUrlSerializer, UrlSegment, serializePath} from '../src/url_tree';
|
||||||
import {UrlSegment} from '../src/url_tree';
|
|
||||||
|
|
||||||
describe('url serializer', () => {
|
describe('url serializer', () => {
|
||||||
const url = new DefaultUrlSerializer();
|
const url = new DefaultUrlSerializer();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {DefaultUrlSerializer} from '../src/url_serializer';
|
import {DefaultUrlSerializer, UrlTree, containsTree} from '../src/url_tree';
|
||||||
import {UrlTree, containsTree} from '../src/url_tree';
|
|
||||||
|
|
||||||
describe('UrlTree', () => {
|
describe('UrlTree', () => {
|
||||||
const serializer = new DefaultUrlSerializer();
|
const serializer = new DefaultUrlSerializer();
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
"src/config.ts",
|
"src/config.ts",
|
||||||
"src/router_outlet_map.ts",
|
"src/router_outlet_map.ts",
|
||||||
"src/router_state.ts",
|
"src/router_state.ts",
|
||||||
"src/url_serializer.ts",
|
|
||||||
"src/url_tree.ts",
|
|
||||||
"src/shared.ts",
|
"src/shared.ts",
|
||||||
"src/common_router_providers.ts",
|
"src/common_router_providers.ts",
|
||||||
"src/router_providers.ts",
|
"src/router_providers.ts",
|
||||||
|
|
Loading…
Reference in New Issue