UNPKG

24 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6/**
7 * Regular expression matching all control characters used in regular
8 * expressions. The regular expression is used to match these characters in
9 * path expressions and replace them appropriately so the path expression can
10 * be compiled to a regular expression.
11 *
12 * @const
13 * @type {RegExp}
14 */
15const CONTROL_CHARACTERS_REGEXP = /[\\.+*?^$[\](){}/'#]/g;
16
17/**
18 * Regular expression used to match and remove the starting and trailing
19 * forward slashes from a path expression or a URL path.
20 *
21 * @const
22 * @type {RegExp}
23 */
24const LOOSE_SLASHES_REGEXP = /^\/|\/$/g;
25
26/**
27 * Regular expression used to match the parameter names from a path expression.
28 *
29 * @const
30 * @type {RegExp}
31 */
32const PARAMS_REGEXP_UNIVERSAL = /:\??([\w-]+)/g;
33
34/**
35 * Regular expression used to match the required parameter names from a path expression.
36 *
37 * @const
38 * @type {RegExp}
39 */
40const PARAMS_REGEXP_REQUIRED = /(?:^|\\\/):([a-z0-9]+)(?=\\\/|$)/gi;
41
42/**
43 * Regular expression used to separate a camelCase parameter name
44 *
45 * @const
46 * @type {RegExp}
47 */
48const PARAMS_REGEXP_CORE_NAME = /[a-z0-9]+/i;
49
50/**
51 * Regular expression used to match start of parameter names from a path expression.
52 *
53 * @const
54 * @type {String}
55 */
56const PARAMS_START_PATTERN = '(^|/|[_-])';
57
58/**
59 * Regular expression used to match end of parameter names from a path expression.
60 *
61 * @const
62 * @type {String}
63 */
64const PARAMS_END_PATTERN = '[/?_-]|$';
65
66/**
67 * Regular expression used to never match the parameter names from a path expression.
68 * It's used for wrong parameters order (optional vs. required ones)
69 *
70 * @const
71 * @type {RegExp}
72 */
73const PARAMS_NEVER_MATCH_REGEXP = /$a/;
74
75/**
76 * Regular expression used to match all main parameter names from a path expression.
77 *
78 * @const
79 * @type {RegExp}
80 */
81const PARAMS_MAIN_REGEXP = /(?:\\\/|^):\\\?([a-z0-9]+)(?=\\\/|$)|(?:^|\\\/):([a-z0-9]+)(?=\\\/|$)/gi;
82
83/**
84 * Regular expression used to match the required subparameter names from a path expression.
85 * (e.g. for path '/:paramA-:paramB/:nextParam' are subparametres 'paramA' and 'paramB')
86 *
87 * @const
88 * @type {Object<String, RegExp>}
89 */
90const SUBPARAMS_REQUIRED_REGEXP = {
91 LAST: /([_-]{1})((\w-)?:[a-z0-9]+)(?=\\\/|$)/gi,
92 OTHERS: /(:[a-z0-9]+)(?=[_-]{1})/gi
93};
94
95/**
96 * Regular expression used to match the optional parameter names from a path expression.
97 *
98 * @const
99 * @type {Object<String, RegExp>}
100 */
101const SUBPARAMS_OPT_REGEXP = {
102 LAST: /([_-]{1}(\w-)?:\\\?[a-z0-9]+)(?=\\\/|$)/gi,
103 OTHERS: /(:\\\?[a-z0-9]+)(?=[_-]{1}(\w-)?)/gi
104};
105
106/**
107 * Regular expression used to match the parameter names from a path expression.
108 *
109 * @const
110 * @type {RegExp}
111 */
112const PARAMS_REGEXP_OPT = /(?:^:\\\?([a-z0-9]+)(?=\\\/|$))|(?:(\\\/):\\\?([a-z0-9]+)(?=\\\/|$))/gi; // last part: |(?::\\\?([a-z0-9]+)(?=\\\/|$))
113
114/**
115 * Utility for representing and manipulating a single route in the router's
116 * configuration.
117 */
118class Route {
119 /**
120 * Initializes the route.
121 *
122 * @param {string} name The unique name of this route, identifying it among
123 * the rest of the routes in the application.
124 * @param {string} pathExpression A path expression specifying the URL path
125 * part matching this route (must not contain a query string),
126 * optionally containing named parameter placeholders specified as
127 * {@code :parameterName}.
128 * @param {string} controller The full name of Object Container alias
129 * identifying the controller associated with this route.
130 * @param {string} view The full name or Object Container alias identifying
131 * the view class associated with this route.
132 * @param {{
133 * onlyUpdate: (
134 * boolean|
135 * function(
136 * (string|function(new: Controller, ...*)),
137 * (string|function(
138 * new: React.Component,
139 * Object<string, *>,
140 * ?Object<string, *>
141 * ))
142 * ): boolean
143 * )=,
144 * autoScroll: boolean=,
145 * allowSPA: boolean=,
146 * documentView: ?AbstractDocumentView=,
147 * managedRootView: ?function(new: React.Component)=,
148 * viewAdapter: ?function(new: React.Component)=
149 * }} options The route additional options.
150 */
151 constructor(name, pathExpression, controller, view, options) {
152 /**
153 * The unique name of this route, identifying it among the rest of the
154 * routes in the application.
155 *
156 * @type {string}
157 */
158 this._name = name;
159
160 /**
161 * The original URL path expression from which this route was created.
162 *
163 * @type {string}
164 */
165 this._pathExpression = pathExpression;
166
167 /**
168 * The full name of Object Container alias identifying the controller
169 * associated with this route.
170 *
171 * @type {string}
172 */
173 this._controller = controller;
174
175 /**
176 * The full name or Object Container alias identifying the view class
177 * associated with this route.
178 *
179 * @type {React.Component}
180 */
181 this._view = view;
182
183 /**
184 * The route additional options.
185 *
186 * @type {{
187 * onlyUpdate: (
188 * boolean|
189 * function(
190 * (string|function(new: Controller, ...*)),
191 * (string|function(
192 * new: React.Component,
193 * Object<string, *>,
194 * ?Object<string, *>
195 * ))
196 * ): boolean
197 * ),
198 * autoScroll: boolean,
199 * allowSPA: boolean,
200 * documentView: ?function(new: AbstractDocumentView),
201 * managedRootView: ?function(new: React.Component),
202 * viewAdapter: ?function(new: React.Component)
203 * }}
204 */
205 this._options = Object.assign({
206 onlyUpdate: false,
207 autoScroll: true,
208 allowSPA: true,
209 documentView: null,
210 managedRootView: null,
211 viewAdapter: null
212 }, options);
213
214 /**
215 * The path expression with the trailing slashes trimmed.
216 *
217 * @type {string}
218 */
219 this._trimmedPathExpression = this._getTrimmedPath(pathExpression);
220
221 /**
222 * The names of the parameters in this route.
223 *
224 * @type {string[]}
225 */
226 this._parameterNames = this._getParameterNames(pathExpression);
227
228 /**
229 * Set to {@code true} if this route contains parameters in its path.
230 *
231 * @type {boolean}
232 */
233 this._hasParameters = !!this._parameterNames.length;
234
235 /**
236 * A regexp used to match URL path against this route and extract the
237 * parameter values from the matched URL paths.
238 *
239 * @type {RegExp}
240 */
241 this._matcher = this._compileToRegExp(this._trimmedPathExpression);
242 }
243
244 /**
245 * Creates the URL and query parts of a URL by substituting the route's
246 * parameter placeholders by the provided parameter value.
247 *
248 * The extraneous parameters that do not match any of the route's
249 * placeholders will be appended as the query string.
250 *
251 * @param {Object<string, (number|string)>=} [params={}] The route
252 * parameter values.
253 * @return {string} Path and, if necessary, query parts of the URL
254 * representing this route with its parameters replaced by the
255 * provided parameter values.
256 */
257 toPath(params = {}) {
258 let path = this._pathExpression;
259 let query = [];
260
261 for (let paramName of Object.keys(params)) {
262 if (this._isRequiredParamInPath(path, paramName)) {
263 path = this._substituteRequiredParamInPath(path, paramName, params[paramName]);
264 } else if (this._isOptionalParamInPath(path, paramName)) {
265 path = this._substituteOptionalParamInPath(path, paramName, params[paramName]);
266 } else {
267 const pair = [paramName, params[paramName]];
268 query.push(pair.map(encodeURIComponent).join('='));
269 }
270 }
271 path = this._cleanUnusedOptionalParams(path);
272
273 path = query.length ? path + '?' + query.join('&') : path;
274 path = this._getTrimmedPath(path);
275 return path;
276 }
277
278 /**
279 * Returns the unique identifying name of this route.
280 *
281 * @return {string} The name of the route, identifying it.
282 */
283 getName() {
284 return this._name;
285 }
286
287 /**
288 * Returns the full name of the controller to use when this route is
289 * matched by the current URL, or an Object Container-registered alias of
290 * the controller.
291 *
292 * @return {string} The name of alias of the controller.
293 */
294 getController() {
295 return this._controller;
296 }
297
298 /**
299 * Returns the full name of the view class or an Object
300 * Container-registered alias for the view class, representing the view to
301 * use when this route is matched by the current URL.
302 *
303 * @return {string} The name or alias of the view class.
304 */
305 getView() {
306 return this._view;
307 }
308
309 /**
310 * Return route additional options.
311 *
312 * @return {{
313 * onlyUpdate: (
314 * boolean|
315 * function(
316 * (string|function(new: Controller, ...*)),
317 * (string|function(
318 * new: React.Component,
319 * Object<string, *>,
320 * ?Object<string, *>
321 * ))
322 * ): boolean
323 * ),
324 * autoScroll: boolean,
325 * allowSPA: boolean,
326 * documentView: ?AbstractDocumentView,
327 * managedRootView: ?function(new: React.Component),
328 * viewAdapter: ?function(new: React.Component)
329 * }}
330 */
331 getOptions() {
332 return this._options;
333 }
334
335 /**
336 * Returns the path expression, which is the parametrized pattern matching
337 * the URL paths matched by this route.
338 *
339 * @return {string} The path expression.
340 */
341 getPathExpression() {
342 return this._pathExpression;
343 }
344
345 /**
346 * Tests whether the provided URL path matches this route. The provided
347 * path may contain the query.
348 *
349 * @param {string} path The URL path.
350 * @return {boolean} {@code true} if the provided path matches this route.
351 */
352 matches(path) {
353 let trimmedPath = this._getTrimmedPath(path);
354 return this._matcher.test(trimmedPath);
355 }
356
357 /**
358 * Extracts the parameter values from the provided path. The method
359 * extracts both the in-path parameters and parses the query, allowing the
360 * query parameters to override the in-path parameters.
361 *
362 * The method returns an empty hash object if the path does not match this
363 * route.
364 *
365 * @param {string} path
366 * @return {Object<string, ?string>} Map of parameter names to parameter
367 * values.
368 */
369 extractParameters(path) {
370 let trimmedPath = this._getTrimmedPath(path);
371 let parameters = this._getParameters(trimmedPath);
372 let query = this._getQuery(trimmedPath);
373
374 return Object.assign({}, parameters, query);
375 }
376
377 /**
378 * Replace required parameter placeholder in path with parameter value.
379 *
380 * @param {string} path
381 * @param {string} paramName
382 * @param {string} paramValue
383 * @return {string} New path.
384 */
385 _substituteRequiredParamInPath(path, paramName, paramValue) {
386 return path.replace(new RegExp(`${PARAMS_START_PATTERN}:${paramName}(${PARAMS_END_PATTERN})`), paramValue ? '$1' + encodeURIComponent(paramValue) + '$2' : '');
387 }
388
389 /**
390 * Replace optional param placeholder in path with parameter value.
391 *
392 * @param {string} path
393 * @param {string} paramName
394 * @param {string} paramValue
395 * @return {string} New path.
396 */
397 _substituteOptionalParamInPath(path, paramName, paramValue) {
398 const paramRegexp = `${PARAMS_START_PATTERN}:\\?${paramName}(${PARAMS_END_PATTERN})`;
399 return path.replace(new RegExp(paramRegexp), paramValue ? '$1' + encodeURIComponent(paramValue) + '$2' : '/');
400 }
401
402 /**
403 * Remove unused optional param placeholders in path.
404 *
405 * @param {string} path
406 * @return {string} New path.
407 */
408 _cleanUnusedOptionalParams(path) {
409 let replacedPath = path;
410
411 // remove last subparameters
412 replacedPath = replacedPath.replace(/([_-])(:\?([a-z0-9]+))(?=\/)/gi, '$1');
413
414 // remove parameters
415 replacedPath = replacedPath.replace(/(\/:\?([a-z0-9]+))|(:\?([a-z0-9]+)\/?)/gi, '');
416
417 return replacedPath;
418 }
419
420 /**
421 * Returns true, if paramName is placed in path.
422 *
423 * @param {string} path
424 * @param {string} paramName
425 * @return {boolean}
426 */
427 _isOptionalParamInPath(path, paramName) {
428 const paramRegexp = `${PARAMS_START_PATTERN}:\\?${paramName}(?:${PARAMS_END_PATTERN})`;
429 let regexp = new RegExp(paramRegexp);
430 return regexp.test(path);
431 }
432
433 /**
434 * Returns true, if paramName is placed in path and it's required.
435 *
436 * @param {string} path
437 * @param {string} paramName
438 * @return {boolean}
439 */
440 _isRequiredParamInPath(path, paramName) {
441 let regexp = new RegExp(`:${paramName}`);
442
443 return regexp.test(path);
444 }
445
446 /**
447 * Extract clear parameter name, e.q. '?name' or 'name'
448 *
449 * @param {string} rawParam
450 * @return {string}
451 */
452 _getClearParamName(rawParam) {
453 const regExpr = /\??[a-z0-9]+/i;
454 const paramMatches = rawParam.match(regExpr);
455 const param = paramMatches ? paramMatches[0] : '';
456
457 return param;
458 }
459
460 /**
461 * Get pattern for subparameter.
462 *
463 * @param {string} delimeter Parameters delimeter
464 * @return {string}
465 */
466 _getSubparamPattern(delimeter) {
467 const pattern = `([^${delimeter}?/]+)`;
468
469 return pattern;
470 }
471
472 /**
473 * Check if all optional params are below required ones
474 *
475 * @param {array<string>} allMainParams
476 * @return {boolean}
477 */
478 _checkOptionalParamsOrder(allMainParams) {
479 let optionalLastId = -1;
480
481 const count = allMainParams.length;
482 for (let idx = 0; idx < count; idx++) {
483 const item = allMainParams[idx];
484
485 if (item.substr(0, 1) === '?') {
486 optionalLastId = idx;
487 } else {
488 if (optionalLastId > -1 && idx > optionalLastId) {
489 return false;
490 }
491 }
492 }
493
494 return true;
495 }
496
497 /**
498 * Check if main parametres have correct order.
499 * It means that required param cannot follow optional one.
500 *
501 * @param {string} clearedPathExpr The cleared URL path (removed first and last slash, ...).
502 * @return {Bool} Returns TRUE if order is correct.
503 */
504 _checkParametersOrder(clearedPathExpr) {
505 const mainParamsMatches = clearedPathExpr.match(PARAMS_MAIN_REGEXP) || [];
506 const allMainParamsCleared = mainParamsMatches.map(paramExpr => this._getClearParamName(paramExpr));
507
508 const isCorrectParamOrder = this._checkOptionalParamsOrder(allMainParamsCleared);
509 return isCorrectParamOrder;
510 }
511
512 /**
513 * Convert main optional parameters to capture sequences
514 *
515 * @param {string} path The URL path.
516 * @param {array<string>} optionalParams List of main optimal parameter expressions
517 * @return {string} RegExp pattern.
518 */
519 _replaceOptionalParametersInPath(path, optionalParams) {
520 const pattern = optionalParams.reduce((path, paramExpr, idx, matches) => {
521 const lastIdx = matches.length - 1;
522 const hasSlash = paramExpr.substr(0, 2) === '\\/';
523
524 let separator = '';
525
526 if (idx === 0) {
527 separator = '(?:' + (hasSlash ? '/' : '');
528 } else {
529 separator = hasSlash ? '/?' : '';
530 }
531
532 let regExpr = separator + `([^/?]+)?(?=/|$)?`;
533
534 if (idx === lastIdx) {
535 regExpr += ')?';
536 }
537
538 return path.replace(paramExpr, regExpr);
539 }, path);
540
541 return pattern;
542 }
543
544 /**
545 * Convert required subparameters to capture sequences
546 *
547 * @param {string} path The URL path (route definition).
548 * @param {string} clearedPathExpr The original cleared URL path.
549 * @return {string} RegExp pattern.
550 */
551 _replaceRequiredSubParametersInPath(path, clearedPathExpr) {
552 const requiredSubparamsOthers = clearedPathExpr.match(SUBPARAMS_REQUIRED_REGEXP.OTHERS) || [];
553 const requiredSubparamsLast = clearedPathExpr.match(SUBPARAMS_REQUIRED_REGEXP.LAST) || [];
554
555 path = requiredSubparamsOthers.reduce((pattern, paramExpr) => {
556 const paramIdx = pattern.indexOf(paramExpr) + paramExpr.length;
557 const delimeter = pattern.substr(paramIdx, 1);
558
559 const regExpr = this._getSubparamPattern(delimeter);
560
561 return pattern.replace(paramExpr, regExpr);
562 }, path);
563
564 path = requiredSubparamsLast.reduce((pattern, rawParamExpr) => {
565 const paramExpr = rawParamExpr.substr(1);
566 const regExpr = '([^/?]+)';
567
568 return pattern.replace(paramExpr, regExpr);
569 }, path);
570
571 return path;
572 }
573
574 /**
575 * Convert optional subparameters to capture sequences
576 *
577 * @param {string} path The URL path (route definition).
578 * @param {array<string>} optionalSubparamsOthers List of all subparam. expressions but last ones
579 * @param {array<string>} optionalSubparamsLast List of last subparam. expressions
580 * @return {string} RegExp pattern.
581 */
582 _replaceOptionalSubParametersInPath(path, optionalSubparamsOthers, optionalSubparamsLast) {
583 path = optionalSubparamsOthers.reduce((pattern, paramExpr) => {
584 const paramIdx = pattern.indexOf(paramExpr) + paramExpr.length;
585 const delimeter = pattern.substr(paramIdx, 1);
586 const paramPattern = this._getSubparamPattern(delimeter);
587 const regExpr = paramPattern + '?';
588
589 return pattern.replace(paramExpr, regExpr);
590 }, path);
591
592 path = optionalSubparamsLast.reduce((pattern, rawParamExpr) => {
593 const paramExpr = rawParamExpr.substr(1);
594 const regExpr = '([^/?]+)?';
595
596 return pattern.replace(paramExpr, regExpr);
597 }, path);
598
599 return path;
600 }
601
602 /**
603 * Compiles the path expression to a regular expression that can be used
604 * for easier matching of URL paths against this route, and extracting the
605 * path parameter values from the URL path.
606 *
607 * @param {string} pathExpression The path expression to compile.
608 * @return {RegExp} The compiled regular expression.
609 */
610 _compileToRegExp(pathExpression) {
611 const clearedPathExpr = pathExpression.replace(LOOSE_SLASHES_REGEXP, '').replace(CONTROL_CHARACTERS_REGEXP, '\\$&');
612
613 const requiredMatches = clearedPathExpr.match(PARAMS_REGEXP_REQUIRED) || [];
614 const optionalMatches = clearedPathExpr.match(PARAMS_REGEXP_OPT) || [];
615
616 const optionalSubparamsLast = clearedPathExpr.match(SUBPARAMS_OPT_REGEXP.LAST) || [];
617 const optionalSubparamsOthers = clearedPathExpr.match(SUBPARAMS_OPT_REGEXP.OTHERS) || [];
618 const optionalSubparams = [...optionalSubparamsOthers, ...optionalSubparamsLast];
619
620 const optionalSubparamsCleanNames = optionalSubparams.map(paramExpr => {
621 return this._getClearParamName(paramExpr);
622 });
623
624 const optionalParams = optionalMatches.filter(paramExpr => {
625 const param = this._getClearParamName(paramExpr);
626
627 return !optionalSubparamsCleanNames.includes(param);
628 });
629
630 if (!!requiredMatches.length && !!optionalParams.length) {
631 const isCorrectParamOrder = this._checkParametersOrder(clearedPathExpr);
632
633 if (!isCorrectParamOrder) {
634 return PARAMS_NEVER_MATCH_REGEXP;
635 }
636 }
637
638 // convert required parameters to capture sequences
639 let pattern = requiredMatches.reduce((pattern, rawParamExpr) => {
640 const paramExpr = ':' + this._getClearParamName(rawParamExpr);
641 const regExpr = '([^/?]+)';
642
643 return pattern.replace(paramExpr, regExpr);
644 }, clearedPathExpr);
645
646 pattern = this._replaceOptionalParametersInPath(pattern, optionalParams);
647 pattern = this._replaceRequiredSubParametersInPath(pattern, clearedPathExpr);
648 pattern = this._replaceOptionalSubParametersInPath(pattern, optionalSubparamsOthers, optionalSubparamsLast);
649
650 // add path root
651 pattern = '^\\/' + pattern;
652
653 // add query parameters matcher
654 let pairPattern = '[^=&;]*(?:=[^&;]*)?';
655 pattern += `(?:\\?(?:${pairPattern})(?:[&;]${pairPattern})*)?$`;
656
657 return new RegExp(pattern);
658 }
659
660 /**
661 * Parses the provided path and extract the in-path parameters. The method
662 * decodes the parameters and returns them in a hash object.
663 *
664 * @param {string} path The URL path.
665 * @return {Object<string, string>} The parsed path parameters.
666 */
667 _getParameters(path) {
668 if (!this._hasParameters) {
669 return {};
670 }
671
672 let parameterValues = path.match(this._matcher);
673 if (!parameterValues) {
674 return {};
675 }
676
677 parameterValues.shift(); // remove the match on whole path, and other parts
678
679 return this._extractParameters(parameterValues);
680 }
681
682 /**
683 * Extract parameters from given path.
684 *
685 * @param {string[]} parameterValues
686 * @return {Object<string, ?string>} Params object.
687 */
688 _extractParameters(parameterValues) {
689 let parameters = {};
690
691 const parametersCount = this._parameterNames.length;
692
693 // Cycle for names and values from last to 0
694 for (let i = parametersCount - 1; i >= 0; i--) {
695 let [rawName, rawValue] = [this._parameterNames[i], parameterValues[i]];
696 let cleanParamName = this._cleanOptParamName(rawName);
697
698 const matchesName = cleanParamName.match(PARAMS_REGEXP_CORE_NAME);
699 const currentCoreName = matchesName ? matchesName[0] : '';
700
701 if (currentCoreName) {
702 const value = this._decodeURIParameter(rawValue);
703 parameters[currentCoreName] = value;
704 }
705 }
706
707 return parameters;
708 }
709
710 /**
711 * Decoding parameters.
712 *
713 * @param {string} parameterValue
714 * @return {string} decodedValue
715 */
716 _decodeURIParameter(parameterValue) {
717 let decodedValue;
718 if (parameterValue) {
719 decodedValue = decodeURIComponent(parameterValue);
720 }
721 return decodedValue;
722 }
723
724 /**
725 * Returns optional param name without "?"
726 *
727 * @param {string} paramName Full param name with "?"
728 * @return {string} Strict param name without "?"
729 */
730 _cleanOptParamName(paramName) {
731 return paramName.replace('?', '');
732 }
733
734 /**
735 * Checks if parameter is optional or not.
736 *
737 * @param {string} paramName
738 * @return {boolean} return true if is optional, otherwise false
739 */
740 _isParamOptional(paramName) {
741 return (/\?.+/.test(paramName)
742 );
743 }
744
745 /**
746 * Extracts and decodes the query parameters from the provided URL path and
747 * query.
748 *
749 * @param {string} path The URL path, including the optional query string
750 * (if any).
751 * @return {Object<string, ?string>} Parsed query parameters.
752 */
753 _getQuery(path) {
754 let query = {};
755 let queryStart = path.indexOf('?');
756 let hasQuery = queryStart > -1 && queryStart !== path.length - 1;
757
758 if (hasQuery) {
759 let pairs = path.substring(queryStart + 1).split(/[&;]/);
760
761 for (let parameterPair of pairs) {
762 let pair = parameterPair.split('=');
763 query[decodeURIComponent(pair[0])] = pair.length > 1 ? decodeURIComponent(pair[1]) : true;
764 }
765 }
766
767 return query;
768 }
769
770 /**
771 * Trims the trailing forward slash from the provided URL path.
772 *
773 * @param {string} path The path to trim.
774 * @return {string} Trimmed path.
775 */
776 _getTrimmedPath(path) {
777 return `/${path.replace(LOOSE_SLASHES_REGEXP, '')}`;
778 }
779
780 /**
781 * Extracts the parameter names from the provided path expression.
782 *
783 * @param {string} pathExpression The path expression.
784 * @return {string[]} The names of the parameters defined in the provided
785 * path expression.
786 */
787 _getParameterNames(pathExpression) {
788 let rawNames = pathExpression.match(PARAMS_REGEXP_UNIVERSAL) || [];
789
790 return rawNames.map(rawParameterName => {
791 return rawParameterName.substring(1).replace('?', '');
792 });
793 }
794}
795exports.default = Route;
796
797typeof $IMA !== 'undefined' && $IMA !== null && $IMA.Loader && $IMA.Loader.register('ima/router/Route', [], function (_export, _context) {
798 'use strict';
799 return {
800 setters: [],
801 execute: function () {
802 _export('default', exports.default);
803 }
804 };
805});