Skip to content

Commit 79830f1

Browse files
committed
feat(router): add RouterUrlSerializer
1 parent 6e1fed4 commit 79830f1

File tree

3 files changed

+182
-129
lines changed

3 files changed

+182
-129
lines changed

modules/angular2/src/alt_router/router_url_parser.ts renamed to modules/angular2/src/alt_router/router_url_serializer.ts

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,44 @@
1-
import {UrlSegment, Tree, TreeNode} from './segments';
1+
import {UrlSegment, Tree, TreeNode, rootNode} from './segments';
22
import {BaseException} from 'angular2/src/facade/exceptions';
33
import {isBlank, isPresent, RegExpWrapper} from 'angular2/src/facade/lang';
4-
import {DEFAULT_OUTLET_NAME} from './constants';
4+
import {ListWrapper} from 'angular2/src/facade/collection';
55

6-
export abstract class RouterUrlParser { abstract parse(url: string): Tree<UrlSegment>; }
6+
export abstract class RouterUrlSerializer {
7+
abstract parse(url: string): Tree<UrlSegment>;
8+
abstract serialize(tree: Tree<UrlSegment>): string;
9+
}
710

8-
export class DefaultRouterUrlParser extends RouterUrlParser {
11+
export class DefaultRouterUrlSerializer extends RouterUrlSerializer {
912
parse(url: string): Tree<UrlSegment> {
1013
if (url.length === 0) {
1114
throw new BaseException(`Invalid url '${url}'`);
1215
}
1316
let root = new _UrlParser().parse(url);
1417
return new Tree<UrlSegment>(root);
1518
}
19+
20+
serialize(tree: Tree<UrlSegment>): string { return _serializeUrlTreeNode(rootNode(tree)); }
21+
}
22+
23+
function _serializeUrlTreeNode(node: TreeNode<UrlSegment>): string {
24+
return `${node.value}${_serializeChildren(node)}`;
25+
}
26+
27+
function _serializeUrlTreeNodes(nodes: TreeNode<UrlSegment>[]): string {
28+
let main = nodes[0].value.toString();
29+
let auxNodes = nodes.slice(1);
30+
let aux = auxNodes.length > 0 ? `(${auxNodes.map(_serializeUrlTreeNode).join("//")})` : "";
31+
let children = _serializeChildren(nodes[0]);
32+
return `${main}${aux}${children}`;
33+
}
34+
35+
function _serializeChildren(node: TreeNode<UrlSegment>): string {
36+
if (node.children.length > 0) {
37+
let slash = isBlank(node.children[0].value.segment) ? "" : "/";
38+
return `${slash}${_serializeUrlTreeNodes(node.children)}`;
39+
} else {
40+
return "";
41+
}
1642
}
1743

1844
var SEGMENT_RE = RegExpWrapper.create('^[^\\/\\(\\)\\?;=&#]+');
@@ -41,19 +67,19 @@ class _UrlParser {
4167
parse(url: string): TreeNode<UrlSegment> {
4268
this._remaining = url;
4369
if (url == '' || url == '/') {
44-
return new TreeNode<UrlSegment>(new UrlSegment('', {}, DEFAULT_OUTLET_NAME), []);
70+
return new TreeNode<UrlSegment>(new UrlSegment('', {}, null), []);
4571
} else {
4672
return this.parseRoot();
4773
}
4874
}
4975

5076
parseRoot(): TreeNode<UrlSegment> {
51-
let segments = this.parseSegments(DEFAULT_OUTLET_NAME);
77+
let segments = this.parseSegments();
5278
let queryParams = this.peekStartsWith('?') ? this.parseQueryParams() : {};
53-
return new TreeNode<UrlSegment>(new UrlSegment('', queryParams, DEFAULT_OUTLET_NAME), segments);
79+
return new TreeNode<UrlSegment>(new UrlSegment('', queryParams, null), segments);
5480
}
5581

56-
parseSegments(outletName: string): TreeNode<UrlSegment>[] {
82+
parseSegments(outletName: string = null): TreeNode<UrlSegment>[] {
5783
if (this._remaining.length == 0) {
5884
return [];
5985
}
@@ -70,7 +96,7 @@ class _UrlParser {
7096
path = parts[1];
7197
}
7298

73-
var matrixParams: {[key: string]: any} = {};
99+
var matrixParams: {[key: string]: any} = null;
74100
if (this.peekStartsWith(';')) {
75101
matrixParams = this.parseMatrixParams();
76102
}
@@ -83,12 +109,19 @@ class _UrlParser {
83109
var children: TreeNode<UrlSegment>[] = [];
84110
if (this.peekStartsWith('/') && !this.peekStartsWith('//')) {
85111
this.capture('/');
86-
children = this.parseSegments(DEFAULT_OUTLET_NAME);
112+
children = this.parseSegments();
87113
}
88114

89-
let segment = new UrlSegment(path, matrixParams, outletName);
90-
let node = new TreeNode<UrlSegment>(segment, children);
91-
return [node].concat(aux);
115+
if (isPresent(matrixParams)) {
116+
let matrixParamsSegment = new UrlSegment(null, matrixParams, null);
117+
let matrixParamsNode = new TreeNode<UrlSegment>(matrixParamsSegment, children);
118+
let segment = new UrlSegment(path, null, outletName);
119+
return [new TreeNode<UrlSegment>(segment, [matrixParamsNode].concat(aux))];
120+
} else {
121+
let segment = new UrlSegment(path, null, outletName);
122+
let node = new TreeNode<UrlSegment>(segment, children);
123+
return [node].concat(aux);
124+
}
92125
}
93126

94127
parseQueryParams(): {[key: string]: any} {

modules/angular2/test/alt_router/router_url_parser_spec.ts

Lines changed: 0 additions & 116 deletions
This file was deleted.
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import {
2+
ComponentFixture,
3+
AsyncTestCompleter,
4+
TestComponentBuilder,
5+
beforeEach,
6+
ddescribe,
7+
xdescribe,
8+
describe,
9+
el,
10+
expect,
11+
iit,
12+
inject,
13+
beforeEachProviders,
14+
it,
15+
xit
16+
} from 'angular2/testing_internal';
17+
18+
import {DefaultRouterUrlSerializer} from 'angular2/src/alt_router/router_url_serializer';
19+
import {UrlSegment} from 'angular2/src/alt_router/segments';
20+
21+
export function main() {
22+
describe('url parsing', () => {
23+
let url = new DefaultRouterUrlSerializer();
24+
25+
it('should throw on an empty urls', () => { expect(() => url.parse("")).toThrow(); });
26+
27+
it('should parse the root url', () => {
28+
let tree = url.parse("/");
29+
expectSegment(tree.root, "");
30+
expect(url.serialize(tree)).toEqual("");
31+
});
32+
33+
it('should parse non-empty urls', () => {
34+
let tree = url.parse("one/two");
35+
expectSegment(tree.firstChild(tree.root), "one");
36+
expectSegment(tree.firstChild(tree.firstChild(tree.root)), "two");
37+
expect(url.serialize(tree)).toEqual("/one/two");
38+
});
39+
40+
it("should parse multiple aux routes", () => {
41+
let tree = url.parse("/one/two(/three//right:four)/five");
42+
let c = tree.children(tree.firstChild(tree.root));
43+
44+
expectSegment(c[0], "two");
45+
expectSegment(c[1], "aux:three");
46+
expectSegment(c[2], "right:four");
47+
48+
expectSegment(tree.firstChild(c[0]), "five");
49+
50+
expect(url.serialize(tree)).toEqual("/one/two(aux:three//right:four)/five");
51+
});
52+
53+
it("should parse aux routes that have aux routes", () => {
54+
let tree = url.parse("/one(/two(/three))");
55+
let c = tree.children(tree.root);
56+
57+
expectSegment(c[0], "one");
58+
expectSegment(c[1], "aux:two");
59+
expectSegment(c[2], "aux:three");
60+
61+
expect(url.serialize(tree)).toEqual("/one(aux:two//aux:three)");
62+
});
63+
64+
it("should parse aux routes that have children", () => {
65+
let tree = url.parse("/one(/two/three)");
66+
let c = tree.children(tree.root);
67+
68+
expectSegment(c[0], "one");
69+
expectSegment(c[1], "aux:two");
70+
expectSegment(tree.firstChild(c[1]), "three");
71+
72+
expect(url.serialize(tree)).toEqual("/one(aux:two/three)");
73+
});
74+
75+
it("should parse an empty aux route definition", () => {
76+
let tree = url.parse("/one()");
77+
let c = tree.children(tree.root);
78+
79+
expectSegment(c[0], "one");
80+
expect(tree.children(c[0]).length).toEqual(0);
81+
82+
expect(url.serialize(tree)).toEqual("/one");
83+
});
84+
85+
it("should parse key-value matrix params", () => {
86+
let tree = url.parse("/one;a=11a;b=11b(/two;c=22//right:three;d=33)");
87+
88+
let c = tree.firstChild(tree.root);
89+
expectSegment(c, "one");
90+
91+
let c2 = tree.children(c);
92+
expectSegment(c2[0], ";a=11a;b=11b");
93+
expectSegment(c2[1], "aux:two");
94+
expectSegment(c2[2], "right:three");
95+
96+
expectSegment(tree.firstChild(c2[1]), ";c=22");
97+
expectSegment(tree.firstChild(c2[2]), ";d=33");
98+
99+
expect(url.serialize(tree)).toEqual("/one;a=11a;b=11b(aux:two;c=22//right:three;d=33)");
100+
});
101+
102+
it("should parse key only matrix params", () => {
103+
let tree = url.parse("/one;a");
104+
105+
let c = tree.firstChild(tree.root);
106+
expectSegment(c, "one");
107+
expectSegment(tree.firstChild(c), ";a=true");
108+
109+
expect(url.serialize(tree)).toEqual("/one;a=true");
110+
});
111+
112+
// it("should parse key-value query params", () => {
113+
// let tree = url.parse("/one?a=1&b=2");
114+
// expect(tree.root).toEqual(new UrlSegment("", {'a': '1', 'b': '2'}, DEFAULT_OUTLET_NAME));
115+
// });
116+
//
117+
// it("should parse key only query params", () => {
118+
// let tree = url.parse("/one?a");
119+
// expect(tree.root).toEqual(new UrlSegment("", {'a': "true"}, DEFAULT_OUTLET_NAME));
120+
// });
121+
//
122+
// it("should parse a url with only query params", () => {
123+
// let tree = url.parse("?a");
124+
// expect(tree.root).toEqual(new UrlSegment("", {'a': "true"}, DEFAULT_OUTLET_NAME));
125+
// });
126+
//
127+
// it("should allow slashes within query params", () => {
128+
// let tree = url.parse("?a=http://boo");
129+
// expect(tree.root).toEqual(new UrlSegment("", {'a': "http://boo"}, DEFAULT_OUTLET_NAME));
130+
// });
131+
});
132+
}
133+
134+
function expectSegment(segment: UrlSegment, expected: string): void {
135+
expect(segment.toString()).toEqual(expected);
136+
}

0 commit comments

Comments
 (0)