1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.UrlMatcher = void 0;
|
4 | var common_1 = require("../common/common");
|
5 | var hof_1 = require("../common/hof");
|
6 | var predicates_1 = require("../common/predicates");
|
7 | var param_1 = require("../params/param");
|
8 | var strings_1 = require("../common/strings");
|
9 | var common_2 = require("../common");
|
10 | function quoteRegExp(str, param) {
|
11 | var surroundPattern = ['', ''], result = str.replace(/[\\\[\]\^$*+?.()|{}]/g, '\\$&');
|
12 | if (!param)
|
13 | return result;
|
14 | switch (param.squash) {
|
15 | case false:
|
16 | surroundPattern = ['(', ')' + (param.isOptional ? '?' : '')];
|
17 | break;
|
18 | case true:
|
19 | result = result.replace(/\/$/, '');
|
20 | surroundPattern = ['(?:/(', ')|/)?'];
|
21 | break;
|
22 | default:
|
23 | surroundPattern = ["(" + param.squash + "|", ')?'];
|
24 | break;
|
25 | }
|
26 | return result + surroundPattern[0] + param.type.pattern.source + surroundPattern[1];
|
27 | }
|
28 | var memoizeTo = function (obj, _prop, fn) { return (obj[_prop] = obj[_prop] || fn()); };
|
29 | var splitOnSlash = strings_1.splitOnDelim('/');
|
30 | var defaultConfig = {
|
31 | state: { params: {} },
|
32 | strict: true,
|
33 | caseInsensitive: true,
|
34 | decodeParams: true,
|
35 | };
|
36 | /**
|
37 | * Matches URLs against patterns.
|
38 | *
|
39 | * Matches URLs against patterns and extracts named parameters from the path or the search
|
40 | * part of the URL.
|
41 | *
|
42 | * A URL pattern consists of a path pattern, optionally followed by '?' and a list of search (query)
|
43 | * parameters. Multiple search parameter names are separated by '&'. Search parameters
|
44 | * do not influence whether or not a URL is matched, but their values are passed through into
|
45 | * the matched parameters returned by [[UrlMatcher.exec]].
|
46 | *
|
47 | * - *Path parameters* are defined using curly brace placeholders (`/somepath/{param}`)
|
48 | * or colon placeholders (`/somePath/:param`).
|
49 | *
|
50 | * - *A parameter RegExp* may be defined for a param after a colon
|
51 | * (`/somePath/{param:[a-zA-Z0-9]+}`) in a curly brace placeholder.
|
52 | * The regexp must match for the url to be matched.
|
53 | * Should the regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash.
|
54 | *
|
55 | * Note: a RegExp parameter will encode its value using either [[ParamTypes.path]] or [[ParamTypes.query]].
|
56 | *
|
57 | * - *Custom parameter types* may also be specified after a colon (`/somePath/{param:int}`) in curly brace parameters.
|
58 | * See [[UrlMatcherFactory.type]] for more information.
|
59 | *
|
60 | * - *Catch-all parameters* are defined using an asterisk placeholder (`/somepath/*catchallparam`).
|
61 | * A catch-all * parameter value will contain the remainder of the URL.
|
62 | *
|
63 | * ---
|
64 | *
|
65 | * Parameter names may contain only word characters (latin letters, digits, and underscore) and
|
66 | * must be unique within the pattern (across both path and search parameters).
|
67 | * A path parameter matches any number of characters other than '/'. For catch-all
|
68 | * placeholders the path parameter matches any number of characters.
|
69 | *
|
70 | * Examples:
|
71 | *
|
72 | * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for
|
73 | * trailing slashes, and patterns have to match the entire path, not just a prefix.
|
74 | * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
|
75 | * '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
|
76 | * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax.
|
77 | * * `'/user/{id:[^/]*}'` - Same as the previous example.
|
78 | * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id
|
79 | * parameter consists of 1 to 8 hex digits.
|
80 | * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the
|
81 | * path into the parameter 'path'.
|
82 | * * `'/files/*path'` - ditto.
|
83 | * * `'/calendar/{start:date}'` - Matches "/calendar/2014-11-12" (because the pattern defined
|
84 | * in the built-in `date` ParamType matches `2014-11-12`) and provides a Date object in $stateParams.start
|
85 | *
|
86 | */
|
87 | var UrlMatcher = /** @class */ (function () {
|
88 | /**
|
89 | * @param pattern The pattern to compile into a matcher.
|
90 | * @param paramTypes The [[ParamTypes]] registry
|
91 | * @param paramFactory A [[ParamFactory]] object
|
92 | * @param config A [[UrlMatcherCompileConfig]] configuration object
|
93 | */
|
94 | function UrlMatcher(pattern, paramTypes, paramFactory, config) {
|
95 | var _this = this;
|
96 | /** @internal */
|
97 | this._cache = { path: [this] };
|
98 | /** @internal */
|
99 | this._children = [];
|
100 | /** @internal */
|
101 | this._params = [];
|
102 | /** @internal */
|
103 | this._segments = [];
|
104 | /** @internal */
|
105 | this._compiled = [];
|
106 | this.config = config = common_2.defaults(config, defaultConfig);
|
107 | this.pattern = pattern;
|
108 | // Find all placeholders and create a compiled pattern, using either classic or curly syntax:
|
109 | // '*' name
|
110 | // ':' name
|
111 | // '{' name '}'
|
112 | // '{' name ':' regexp '}'
|
113 | // The regular expression is somewhat complicated due to the need to allow curly braces
|
114 | // inside the regular expression. The placeholder regexp breaks down as follows:
|
115 | // ([:*])([\w\[\]]+) - classic placeholder ($1 / $2) (search version has - for snake-case)
|
116 | // \{([\w\[\]]+)(?:\:\s*( ... ))?\} - curly brace placeholder ($3) with optional regexp/type ... ($4) (search version has - for snake-case
|
117 | // (?: ... | ... | ... )+ - the regexp consists of any number of atoms, an atom being either
|
118 | // [^{}\\]+ - anything other than curly braces or backslash
|
119 | // \\. - a backslash escape
|
120 | // \{(?:[^{}\\]+|\\.)*\} - a matched set of curly braces containing other atoms
|
121 | var placeholder = /([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:\s*((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g;
|
122 | var searchPlaceholder = /([:]?)([\w\[\].-]+)|\{([\w\[\].-]+)(?:\:\s*((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g;
|
123 | var patterns = [];
|
124 | var last = 0;
|
125 | var matchArray;
|
126 | var checkParamErrors = function (id) {
|
127 | if (!UrlMatcher.nameValidator.test(id))
|
128 | throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
|
129 | if (common_1.find(_this._params, hof_1.propEq('id', id)))
|
130 | throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
|
131 | };
|
132 | // Split into static segments separated by path parameter placeholders.
|
133 | // The number of segments is always 1 more than the number of parameters.
|
134 | var matchDetails = function (m, isSearch) {
|
135 | // IE[78] returns '' for unmatched groups instead of null
|
136 | var id = m[2] || m[3];
|
137 | var regexp = isSearch ? m[4] : m[4] || (m[1] === '*' ? '[\\s\\S]*' : null);
|
138 | var makeRegexpType = function (str) {
|
139 | return common_1.inherit(paramTypes.type(isSearch ? 'query' : 'path'), {
|
140 | pattern: new RegExp(str, _this.config.caseInsensitive ? 'i' : undefined),
|
141 | });
|
142 | };
|
143 | return {
|
144 | id: id,
|
145 | regexp: regexp,
|
146 | segment: pattern.substring(last, m.index),
|
147 | type: !regexp ? null : paramTypes.type(regexp) || makeRegexpType(regexp),
|
148 | };
|
149 | };
|
150 | var details;
|
151 | var segment;
|
152 | // tslint:disable-next-line:no-conditional-assignment
|
153 | while ((matchArray = placeholder.exec(pattern))) {
|
154 | details = matchDetails(matchArray, false);
|
155 | if (details.segment.indexOf('?') >= 0)
|
156 | break; // we're into the search part
|
157 | checkParamErrors(details.id);
|
158 | this._params.push(paramFactory.fromPath(details.id, details.type, config.state));
|
159 | this._segments.push(details.segment);
|
160 | patterns.push([details.segment, common_1.tail(this._params)]);
|
161 | last = placeholder.lastIndex;
|
162 | }
|
163 | segment = pattern.substring(last);
|
164 | // Find any search parameter names and remove them from the last segment
|
165 | var i = segment.indexOf('?');
|
166 | if (i >= 0) {
|
167 | var search = segment.substring(i);
|
168 | segment = segment.substring(0, i);
|
169 | if (search.length > 0) {
|
170 | last = 0;
|
171 | // tslint:disable-next-line:no-conditional-assignment
|
172 | while ((matchArray = searchPlaceholder.exec(search))) {
|
173 | details = matchDetails(matchArray, true);
|
174 | checkParamErrors(details.id);
|
175 | this._params.push(paramFactory.fromSearch(details.id, details.type, config.state));
|
176 | last = placeholder.lastIndex;
|
177 | // check if ?&
|
178 | }
|
179 | }
|
180 | }
|
181 | this._segments.push(segment);
|
182 | this._compiled = patterns.map(function (_pattern) { return quoteRegExp.apply(null, _pattern); }).concat(quoteRegExp(segment));
|
183 | }
|
184 | /** @internal */
|
185 | UrlMatcher.encodeDashes = function (str) {
|
186 | // Replace dashes with encoded "\-"
|
187 | return encodeURIComponent(str).replace(/-/g, function (c) { return "%5C%" + c.charCodeAt(0).toString(16).toUpperCase(); });
|
188 | };
|
189 | /** @internal Given a matcher, return an array with the matcher's path segments and path params, in order */
|
190 | UrlMatcher.pathSegmentsAndParams = function (matcher) {
|
191 | var staticSegments = matcher._segments;
|
192 | var pathParams = matcher._params.filter(function (p) { return p.location === param_1.DefType.PATH; });
|
193 | return common_1.arrayTuples(staticSegments, pathParams.concat(undefined))
|
194 | .reduce(common_1.unnestR, [])
|
195 | .filter(function (x) { return x !== '' && predicates_1.isDefined(x); });
|
196 | };
|
197 | /** @internal Given a matcher, return an array with the matcher's query params */
|
198 | UrlMatcher.queryParams = function (matcher) {
|
199 | return matcher._params.filter(function (p) { return p.location === param_1.DefType.SEARCH; });
|
200 | };
|
201 | /**
|
202 | * Compare two UrlMatchers
|
203 | *
|
204 | * This comparison function converts a UrlMatcher into static and dynamic path segments.
|
205 | * Each static path segment is a static string between a path separator (slash character).
|
206 | * Each dynamic segment is a path parameter.
|
207 | *
|
208 | * The comparison function sorts static segments before dynamic ones.
|
209 | */
|
210 | UrlMatcher.compare = function (a, b) {
|
211 | /**
|
212 | * Turn a UrlMatcher and all its parent matchers into an array
|
213 | * of slash literals '/', string literals, and Param objects
|
214 | *
|
215 | * This example matcher matches strings like "/foo/:param/tail":
|
216 | * var matcher = $umf.compile("/foo").append($umf.compile("/:param")).append($umf.compile("/")).append($umf.compile("tail"));
|
217 | * var result = segments(matcher); // [ '/', 'foo', '/', Param, '/', 'tail' ]
|
218 | *
|
219 | * Caches the result as `matcher._cache.segments`
|
220 | */
|
221 | var segments = function (matcher) {
|
222 | return (matcher._cache.segments =
|
223 | matcher._cache.segments ||
|
224 | matcher._cache.path
|
225 | .map(UrlMatcher.pathSegmentsAndParams)
|
226 | .reduce(common_1.unnestR, [])
|
227 | .reduce(strings_1.joinNeighborsR, [])
|
228 | .map(function (x) { return (predicates_1.isString(x) ? splitOnSlash(x) : x); })
|
229 | .reduce(common_1.unnestR, []));
|
230 | };
|
231 | /**
|
232 | * Gets the sort weight for each segment of a UrlMatcher
|
233 | *
|
234 | * Caches the result as `matcher._cache.weights`
|
235 | */
|
236 | var weights = function (matcher) {
|
237 | return (matcher._cache.weights =
|
238 | matcher._cache.weights ||
|
239 | segments(matcher).map(function (segment) {
|
240 | // Sort slashes first, then static strings, the Params
|
241 | if (segment === '/')
|
242 | return 1;
|
243 | if (predicates_1.isString(segment))
|
244 | return 2;
|
245 | if (segment instanceof param_1.Param)
|
246 | return 3;
|
247 | }));
|
248 | };
|
249 | /**
|
250 | * Pads shorter array in-place (mutates)
|
251 | */
|
252 | var padArrays = function (l, r, padVal) {
|
253 | var len = Math.max(l.length, r.length);
|
254 | while (l.length < len)
|
255 | l.push(padVal);
|
256 | while (r.length < len)
|
257 | r.push(padVal);
|
258 | };
|
259 | var weightsA = weights(a), weightsB = weights(b);
|
260 | padArrays(weightsA, weightsB, 0);
|
261 | var _pairs = common_1.arrayTuples(weightsA, weightsB);
|
262 | var cmp, i;
|
263 | for (i = 0; i < _pairs.length; i++) {
|
264 | cmp = _pairs[i][0] - _pairs[i][1];
|
265 | if (cmp !== 0)
|
266 | return cmp;
|
267 | }
|
268 | return 0;
|
269 | };
|
270 | /**
|
271 | * Creates a new concatenated UrlMatcher
|
272 | *
|
273 | * Builds a new UrlMatcher by appending another UrlMatcher to this one.
|
274 | *
|
275 | * @param url A `UrlMatcher` instance to append as a child of the current `UrlMatcher`.
|
276 | */
|
277 | UrlMatcher.prototype.append = function (url) {
|
278 | this._children.push(url);
|
279 | url._cache = {
|
280 | path: this._cache.path.concat(url),
|
281 | parent: this,
|
282 | pattern: null,
|
283 | };
|
284 | return url;
|
285 | };
|
286 | /** @internal */
|
287 | UrlMatcher.prototype.isRoot = function () {
|
288 | return this._cache.path[0] === this;
|
289 | };
|
290 | /** Returns the input pattern string */
|
291 | UrlMatcher.prototype.toString = function () {
|
292 | return this.pattern;
|
293 | };
|
294 | UrlMatcher.prototype._getDecodedParamValue = function (value, param) {
|
295 | if (predicates_1.isDefined(value)) {
|
296 | if (this.config.decodeParams && !param.type.raw) {
|
297 | if (predicates_1.isArray(value)) {
|
298 | value = value.map(function (paramValue) { return decodeURIComponent(paramValue); });
|
299 | }
|
300 | else {
|
301 | value = decodeURIComponent(value);
|
302 | }
|
303 | }
|
304 | value = param.type.decode(value);
|
305 | }
|
306 | return param.value(value);
|
307 | };
|
308 | /**
|
309 | * Tests the specified url/path against this matcher.
|
310 | *
|
311 | * Tests if the given url matches this matcher's pattern, and returns an object containing the captured
|
312 | * parameter values. Returns null if the path does not match.
|
313 | *
|
314 | * The returned object contains the values
|
315 | * of any search parameters that are mentioned in the pattern, but their value may be null if
|
316 | * they are not present in `search`. This means that search parameters are always treated
|
317 | * as optional.
|
318 | *
|
319 | * #### Example:
|
320 | * ```js
|
321 | * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', {
|
322 | * x: '1', q: 'hello'
|
323 | * });
|
324 | * // returns { id: 'bob', q: 'hello', r: null }
|
325 | * ```
|
326 | *
|
327 | * @param path The URL path to match, e.g. `$location.path()`.
|
328 | * @param search URL search parameters, e.g. `$location.search()`.
|
329 | * @param hash URL hash e.g. `$location.hash()`.
|
330 | * @param options
|
331 | *
|
332 | * @returns The captured parameter values.
|
333 | */
|
334 | UrlMatcher.prototype.exec = function (path, search, hash, options) {
|
335 | var _this = this;
|
336 | if (search === void 0) { search = {}; }
|
337 | if (options === void 0) { options = {}; }
|
338 | var match = memoizeTo(this._cache, 'pattern', function () {
|
339 | return new RegExp([
|
340 | '^',
|
341 | common_1.unnest(_this._cache.path.map(hof_1.prop('_compiled'))).join(''),
|
342 | _this.config.strict === false ? '/?' : '',
|
343 | '$',
|
344 | ].join(''), _this.config.caseInsensitive ? 'i' : undefined);
|
345 | }).exec(path);
|
346 | if (!match)
|
347 | return null;
|
348 | // options = defaults(options, { isolate: false });
|
349 | var allParams = this.parameters(), pathParams = allParams.filter(function (param) { return !param.isSearch(); }), searchParams = allParams.filter(function (param) { return param.isSearch(); }), nPathSegments = this._cache.path.map(function (urlm) { return urlm._segments.length - 1; }).reduce(function (a, x) { return a + x; }), values = {};
|
350 | if (nPathSegments !== match.length - 1)
|
351 | throw new Error("Unbalanced capture group in route '" + this.pattern + "'");
|
352 | function decodePathArray(paramVal) {
|
353 | var reverseString = function (str) { return str.split('').reverse().join(''); };
|
354 | var unquoteDashes = function (str) { return str.replace(/\\-/g, '-'); };
|
355 | var split = reverseString(paramVal).split(/-(?!\\)/);
|
356 | var allReversed = common_1.map(split, reverseString);
|
357 | return common_1.map(allReversed, unquoteDashes).reverse();
|
358 | }
|
359 | for (var i = 0; i < nPathSegments; i++) {
|
360 | var param = pathParams[i];
|
361 | var value = match[i + 1];
|
362 | // if the param value matches a pre-replace pair, replace the value before decoding.
|
363 | for (var j = 0; j < param.replace.length; j++) {
|
364 | if (param.replace[j].from === value)
|
365 | value = param.replace[j].to;
|
366 | }
|
367 | if (value && param.array === true)
|
368 | value = decodePathArray(value);
|
369 | values[param.id] = this._getDecodedParamValue(value, param);
|
370 | }
|
371 | searchParams.forEach(function (param) {
|
372 | var value = search[param.id];
|
373 | for (var j = 0; j < param.replace.length; j++) {
|
374 | if (param.replace[j].from === value)
|
375 | value = param.replace[j].to;
|
376 | }
|
377 | values[param.id] = _this._getDecodedParamValue(value, param);
|
378 | });
|
379 | if (hash)
|
380 | values['#'] = hash;
|
381 | return values;
|
382 | };
|
383 | /**
|
384 | * @internal
|
385 | * Returns all the [[Param]] objects of all path and search parameters of this pattern in order of appearance.
|
386 | *
|
387 | * @returns {Array.<Param>} An array of [[Param]] objects. Must be treated as read-only. If the
|
388 | * pattern has no parameters, an empty array is returned.
|
389 | */
|
390 | UrlMatcher.prototype.parameters = function (opts) {
|
391 | if (opts === void 0) { opts = {}; }
|
392 | if (opts.inherit === false)
|
393 | return this._params;
|
394 | return common_1.unnest(this._cache.path.map(function (matcher) { return matcher._params; }));
|
395 | };
|
396 | /**
|
397 | * @internal
|
398 | * Returns a single parameter from this UrlMatcher by id
|
399 | *
|
400 | * @param id
|
401 | * @param opts
|
402 | * @returns {T|Param|any|boolean|UrlMatcher|null}
|
403 | */
|
404 | UrlMatcher.prototype.parameter = function (id, opts) {
|
405 | var _this = this;
|
406 | if (opts === void 0) { opts = {}; }
|
407 | var findParam = function () {
|
408 | for (var _i = 0, _a = _this._params; _i < _a.length; _i++) {
|
409 | var param = _a[_i];
|
410 | if (param.id === id)
|
411 | return param;
|
412 | }
|
413 | };
|
414 | var parent = this._cache.parent;
|
415 | return findParam() || (opts.inherit !== false && parent && parent.parameter(id, opts)) || null;
|
416 | };
|
417 | /**
|
418 | * Validates the input parameter values against this UrlMatcher
|
419 | *
|
420 | * Checks an object hash of parameters to validate their correctness according to the parameter
|
421 | * types of this `UrlMatcher`.
|
422 | *
|
423 | * @param params The object hash of parameters to validate.
|
424 | * @returns Returns `true` if `params` validates, otherwise `false`.
|
425 | */
|
426 | UrlMatcher.prototype.validates = function (params) {
|
427 | var validParamVal = function (param, val) { return !param || param.validates(val); };
|
428 | params = params || {};
|
429 | // I'm not sure why this checks only the param keys passed in, and not all the params known to the matcher
|
430 | var paramSchema = this.parameters().filter(function (paramDef) { return params.hasOwnProperty(paramDef.id); });
|
431 | return paramSchema.map(function (paramDef) { return validParamVal(paramDef, params[paramDef.id]); }).reduce(common_1.allTrueR, true);
|
432 | };
|
433 | /**
|
434 | * Given a set of parameter values, creates a URL from this UrlMatcher.
|
435 | *
|
436 | * Creates a URL that matches this pattern by substituting the specified values
|
437 | * for the path and search parameters.
|
438 | *
|
439 | * #### Example:
|
440 | * ```js
|
441 | * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
|
442 | * // returns '/user/bob?q=yes'
|
443 | * ```
|
444 | *
|
445 | * @param values the values to substitute for the parameters in this pattern.
|
446 | * @returns the formatted URL (path and optionally search part).
|
447 | */
|
448 | UrlMatcher.prototype.format = function (values) {
|
449 | if (values === void 0) { values = {}; }
|
450 | // Build the full path of UrlMatchers (including all parent UrlMatchers)
|
451 | var urlMatchers = this._cache.path;
|
452 | // Extract all the static segments and Params (processed as ParamDetails)
|
453 | // into an ordered array
|
454 | var pathSegmentsAndParams = urlMatchers
|
455 | .map(UrlMatcher.pathSegmentsAndParams)
|
456 | .reduce(common_1.unnestR, [])
|
457 | .map(function (x) { return (predicates_1.isString(x) ? x : getDetails(x)); });
|
458 | // Extract the query params into a separate array
|
459 | var queryParams = urlMatchers
|
460 | .map(UrlMatcher.queryParams)
|
461 | .reduce(common_1.unnestR, [])
|
462 | .map(getDetails);
|
463 | var isInvalid = function (param) { return param.isValid === false; };
|
464 | if (pathSegmentsAndParams.concat(queryParams).filter(isInvalid).length) {
|
465 | return null;
|
466 | }
|
467 | /**
|
468 | * Given a Param, applies the parameter value, then returns detailed information about it
|
469 | */
|
470 | function getDetails(param) {
|
471 | // Normalize to typed value
|
472 | var value = param.value(values[param.id]);
|
473 | var isValid = param.validates(value);
|
474 | var isDefaultValue = param.isDefaultValue(value);
|
475 | // Check if we're in squash mode for the parameter
|
476 | var squash = isDefaultValue ? param.squash : false;
|
477 | // Allow the Parameter's Type to encode the value
|
478 | var encoded = param.type.encode(value);
|
479 | return { param: param, value: value, isValid: isValid, isDefaultValue: isDefaultValue, squash: squash, encoded: encoded };
|
480 | }
|
481 | // Build up the path-portion from the list of static segments and parameters
|
482 | var pathString = pathSegmentsAndParams.reduce(function (acc, x) {
|
483 | // The element is a static segment (a raw string); just append it
|
484 | if (predicates_1.isString(x))
|
485 | return acc + x;
|
486 | // Otherwise, it's a ParamDetails.
|
487 | var squash = x.squash, encoded = x.encoded, param = x.param;
|
488 | // If squash is === true, try to remove a slash from the path
|
489 | if (squash === true)
|
490 | return acc.match(/\/$/) ? acc.slice(0, -1) : acc;
|
491 | // If squash is a string, use the string for the param value
|
492 | if (predicates_1.isString(squash))
|
493 | return acc + squash;
|
494 | if (squash !== false)
|
495 | return acc; // ?
|
496 | if (encoded == null)
|
497 | return acc;
|
498 | // If this parameter value is an array, encode the value using encodeDashes
|
499 | if (predicates_1.isArray(encoded))
|
500 | return acc + common_1.map(encoded, UrlMatcher.encodeDashes).join('-');
|
501 | // If the parameter type is "raw", then do not encodeURIComponent
|
502 | if (param.raw)
|
503 | return acc + encoded;
|
504 | // Encode the value
|
505 | return acc + encodeURIComponent(encoded);
|
506 | }, '');
|
507 | // Build the query string by applying parameter values (array or regular)
|
508 | // then mapping to key=value, then flattening and joining using "&"
|
509 | var queryString = queryParams
|
510 | .map(function (paramDetails) {
|
511 | var param = paramDetails.param, squash = paramDetails.squash, encoded = paramDetails.encoded, isDefaultValue = paramDetails.isDefaultValue;
|
512 | if (encoded == null || (isDefaultValue && squash !== false))
|
513 | return;
|
514 | if (!predicates_1.isArray(encoded))
|
515 | encoded = [encoded];
|
516 | if (encoded.length === 0)
|
517 | return;
|
518 | if (!param.raw)
|
519 | encoded = common_1.map(encoded, encodeURIComponent);
|
520 | return encoded.map(function (val) { return param.id + "=" + val; });
|
521 | })
|
522 | .filter(common_1.identity)
|
523 | .reduce(common_1.unnestR, [])
|
524 | .join('&');
|
525 | // Concat the pathstring with the queryString (if exists) and the hashString (if exists)
|
526 | return pathString + (queryString ? "?" + queryString : '') + (values['#'] ? '#' + values['#'] : '');
|
527 | };
|
528 | /** @internal */
|
529 | UrlMatcher.nameValidator = /^\w+([-.]+\w+)*(?:\[\])?$/;
|
530 | return UrlMatcher;
|
531 | }());
|
532 | exports.UrlMatcher = UrlMatcher;
|
533 | //# sourceMappingURL=urlMatcher.js.map |
\ | No newline at end of file |