UNPKG

6.99 kBJavaScriptView Raw
1import { StringMapWrapper } from '../src/facade/collection';
2import { BaseException } from '../src/facade/exceptions';
3import { RegExpWrapper, isBlank, isPresent } from '../src/facade/lang';
4export function convertUrlParamsToArray(urlParams) {
5 var paramsArray = [];
6 if (isBlank(urlParams)) {
7 return [];
8 }
9 StringMapWrapper.forEach(urlParams, (value /** TODO #9100 */, key /** TODO #9100 */) => {
10 paramsArray.push((value === true) ? key : key + '=' + value);
11 });
12 return paramsArray;
13}
14// Convert an object of url parameters into a string that can be used in an URL
15export function serializeParams(urlParams, joiner = '&') {
16 return convertUrlParamsToArray(urlParams).join(joiner);
17}
18/**
19 * This class represents a parsed URL
20 */
21export class Url {
22 constructor(path, child = null, auxiliary = [], params = {}) {
23 this.path = path;
24 this.child = child;
25 this.auxiliary = auxiliary;
26 this.params = params;
27 }
28 toString() {
29 return this.path + this._matrixParamsToString() + this._auxToString() + this._childString();
30 }
31 segmentToString() { return this.path + this._matrixParamsToString(); }
32 /** @internal */
33 _auxToString() {
34 return this.auxiliary.length > 0 ?
35 ('(' + this.auxiliary.map(sibling => sibling.toString()).join('//') + ')') :
36 '';
37 }
38 _matrixParamsToString() {
39 var paramString = serializeParams(this.params, ';');
40 if (paramString.length > 0) {
41 return ';' + paramString;
42 }
43 return '';
44 }
45 /** @internal */
46 _childString() { return isPresent(this.child) ? ('/' + this.child.toString()) : ''; }
47}
48export class RootUrl extends Url {
49 constructor(path, child = null, auxiliary = [], params = null) {
50 super(path, child, auxiliary, params);
51 }
52 toString() {
53 return this.path + this._auxToString() + this._childString() + this._queryParamsToString();
54 }
55 segmentToString() { return this.path + this._queryParamsToString(); }
56 _queryParamsToString() {
57 if (isBlank(this.params)) {
58 return '';
59 }
60 return '?' + serializeParams(this.params);
61 }
62}
63export function pathSegmentsToUrl(pathSegments) {
64 var url = new Url(pathSegments[pathSegments.length - 1]);
65 for (var i = pathSegments.length - 2; i >= 0; i -= 1) {
66 url = new Url(pathSegments[i], url);
67 }
68 return url;
69}
70var SEGMENT_RE = RegExpWrapper.create('^[^\\/\\(\\)\\?;=&#]+');
71function matchUrlSegment(str) {
72 var match = RegExpWrapper.firstMatch(SEGMENT_RE, str);
73 return isPresent(match) ? match[0] : '';
74}
75var QUERY_PARAM_VALUE_RE = RegExpWrapper.create('^[^\\(\\)\\?;&#]+');
76function matchUrlQueryParamValue(str) {
77 var match = RegExpWrapper.firstMatch(QUERY_PARAM_VALUE_RE, str);
78 return isPresent(match) ? match[0] : '';
79}
80export class UrlParser {
81 peekStartsWith(str) { return this._remaining.startsWith(str); }
82 capture(str) {
83 if (!this._remaining.startsWith(str)) {
84 throw new BaseException(`Expected "${str}".`);
85 }
86 this._remaining = this._remaining.substring(str.length);
87 }
88 parse(url) {
89 this._remaining = url;
90 if (url == '' || url == '/') {
91 return new Url('');
92 }
93 return this.parseRoot();
94 }
95 // segment + (aux segments) + (query params)
96 parseRoot() {
97 if (this.peekStartsWith('/')) {
98 this.capture('/');
99 }
100 var path = matchUrlSegment(this._remaining);
101 this.capture(path);
102 var aux = [];
103 if (this.peekStartsWith('(')) {
104 aux = this.parseAuxiliaryRoutes();
105 }
106 if (this.peekStartsWith(';')) {
107 // TODO: should these params just be dropped?
108 this.parseMatrixParams();
109 }
110 var child = null;
111 if (this.peekStartsWith('/') && !this.peekStartsWith('//')) {
112 this.capture('/');
113 child = this.parseSegment();
114 }
115 var queryParams = null;
116 if (this.peekStartsWith('?')) {
117 queryParams = this.parseQueryParams();
118 }
119 return new RootUrl(path, child, aux, queryParams);
120 }
121 // segment + (matrix params) + (aux segments)
122 parseSegment() {
123 if (this._remaining.length == 0) {
124 return null;
125 }
126 if (this.peekStartsWith('/')) {
127 this.capture('/');
128 }
129 var path = matchUrlSegment(this._remaining);
130 this.capture(path);
131 var matrixParams = null;
132 if (this.peekStartsWith(';')) {
133 matrixParams = this.parseMatrixParams();
134 }
135 var aux = [];
136 if (this.peekStartsWith('(')) {
137 aux = this.parseAuxiliaryRoutes();
138 }
139 var child = null;
140 if (this.peekStartsWith('/') && !this.peekStartsWith('//')) {
141 this.capture('/');
142 child = this.parseSegment();
143 }
144 return new Url(path, child, aux, matrixParams);
145 }
146 parseQueryParams() {
147 var params = {};
148 this.capture('?');
149 this.parseQueryParam(params);
150 while (this._remaining.length > 0 && this.peekStartsWith('&')) {
151 this.capture('&');
152 this.parseQueryParam(params);
153 }
154 return params;
155 }
156 parseMatrixParams() {
157 var params = {};
158 while (this._remaining.length > 0 && this.peekStartsWith(';')) {
159 this.capture(';');
160 this.parseParam(params);
161 }
162 return params;
163 }
164 parseParam(params) {
165 var key = matchUrlSegment(this._remaining);
166 if (isBlank(key)) {
167 return;
168 }
169 this.capture(key);
170 var value = true;
171 if (this.peekStartsWith('=')) {
172 this.capture('=');
173 var valueMatch = matchUrlSegment(this._remaining);
174 if (isPresent(valueMatch)) {
175 value = valueMatch;
176 this.capture(value);
177 }
178 }
179 params[key] = value;
180 }
181 parseQueryParam(params) {
182 var key = matchUrlSegment(this._remaining);
183 if (isBlank(key)) {
184 return;
185 }
186 this.capture(key);
187 var value = true;
188 if (this.peekStartsWith('=')) {
189 this.capture('=');
190 var valueMatch = matchUrlQueryParamValue(this._remaining);
191 if (isPresent(valueMatch)) {
192 value = valueMatch;
193 this.capture(value);
194 }
195 }
196 params[key] = value;
197 }
198 parseAuxiliaryRoutes() {
199 var routes = [];
200 this.capture('(');
201 while (!this.peekStartsWith(')') && this._remaining.length > 0) {
202 routes.push(this.parseSegment());
203 if (this.peekStartsWith('//')) {
204 this.capture('//');
205 }
206 }
207 this.capture(')');
208 return routes;
209 }
210}
211export var parser = new UrlParser();
212//# sourceMappingURL=url_parser.js.map
\No newline at end of file