UNPKG

@angular/router-deprecated

Version:
269 lines 11.8 kB
"use strict"; var collection_1 = require('../../facade/collection'); var exceptions_1 = require('../../facade/exceptions'); var lang_1 = require('../../facade/lang'); var url_parser_1 = require('../../url_parser'); var utils_1 = require('../../utils'); var route_path_1 = require('./route_path'); /** * Identified by a `...` URL segment. This indicates that the * Route will continue to be matched by child `Router`s. */ var ContinuationPathSegment = (function () { function ContinuationPathSegment() { this.name = ''; this.specificity = ''; this.hash = '...'; } ContinuationPathSegment.prototype.generate = function (params) { return ''; }; ContinuationPathSegment.prototype.match = function (path) { return true; }; return ContinuationPathSegment; }()); /** * Identified by a string not starting with a `:` or `*`. * Only matches the URL segments that equal the segment path */ var StaticPathSegment = (function () { function StaticPathSegment(path) { this.path = path; this.name = ''; this.specificity = '2'; this.hash = path; } StaticPathSegment.prototype.match = function (path) { return path == this.path; }; StaticPathSegment.prototype.generate = function (params) { return this.path; }; return StaticPathSegment; }()); /** * Identified by a string starting with `:`. Indicates a segment * that can contain a value that will be extracted and provided to * a matching `Instruction`. */ var DynamicPathSegment = (function () { function DynamicPathSegment(name) { this.name = name; this.specificity = '1'; this.hash = ':'; } DynamicPathSegment.prototype.match = function (path) { return path.length > 0; }; DynamicPathSegment.prototype.generate = function (params) { if (!collection_1.StringMapWrapper.contains(params.map, this.name)) { throw new exceptions_1.BaseException("Route generator for '" + this.name + "' was not included in parameters passed."); } return encodeDynamicSegment(utils_1.normalizeString(params.get(this.name))); }; DynamicPathSegment.paramMatcher = /^:([^\/]+)$/g; return DynamicPathSegment; }()); /** * Identified by a string starting with `*` Indicates that all the following * segments match this route and that the value of these segments should * be provided to a matching `Instruction`. */ var StarPathSegment = (function () { function StarPathSegment(name) { this.name = name; this.specificity = '0'; this.hash = '*'; } StarPathSegment.prototype.match = function (path) { return true; }; StarPathSegment.prototype.generate = function (params) { return utils_1.normalizeString(params.get(this.name)); }; StarPathSegment.wildcardMatcher = /^\*([^\/]+)$/g; return StarPathSegment; }()); /** * Parses a URL string using a given matcher DSL, and generates URLs from param maps */ var ParamRoutePath = (function () { /** * Takes a string representing the matcher DSL */ function ParamRoutePath(routePath) { this.routePath = routePath; this.terminal = true; this._assertValidPath(routePath); this._parsePathString(routePath); this.specificity = this._calculateSpecificity(); this.hash = this._calculateHash(); var lastSegment = this._segments[this._segments.length - 1]; this.terminal = !(lastSegment instanceof ContinuationPathSegment); } ParamRoutePath.prototype.matchUrl = function (url) { var nextUrlSegment = url; var currentUrlSegment; var positionalParams = {}; var captured = []; for (var i = 0; i < this._segments.length; i += 1) { var pathSegment = this._segments[i]; if (pathSegment instanceof ContinuationPathSegment) { break; } currentUrlSegment = nextUrlSegment; if (lang_1.isPresent(currentUrlSegment)) { // the star segment consumes all of the remaining URL, including matrix params if (pathSegment instanceof StarPathSegment) { positionalParams[pathSegment.name] = currentUrlSegment.toString(); captured.push(currentUrlSegment.toString()); nextUrlSegment = null; break; } captured.push(currentUrlSegment.path); if (pathSegment instanceof DynamicPathSegment) { positionalParams[pathSegment.name] = decodeDynamicSegment(currentUrlSegment.path); } else if (!pathSegment.match(currentUrlSegment.path)) { return null; } nextUrlSegment = currentUrlSegment.child; } else if (!pathSegment.match('')) { return null; } } if (this.terminal && lang_1.isPresent(nextUrlSegment)) { return null; } var urlPath = captured.join('/'); var auxiliary = []; var urlParams = []; var allParams = positionalParams; if (lang_1.isPresent(currentUrlSegment)) { // If this is the root component, read query params. Otherwise, read matrix params. var paramsSegment = url instanceof url_parser_1.RootUrl ? url : currentUrlSegment; if (lang_1.isPresent(paramsSegment.params)) { allParams = collection_1.StringMapWrapper.merge(paramsSegment.params, positionalParams); urlParams = url_parser_1.convertUrlParamsToArray(paramsSegment.params); } else { allParams = positionalParams; } auxiliary = currentUrlSegment.auxiliary; } return new route_path_1.MatchedUrl(urlPath, urlParams, allParams, auxiliary, nextUrlSegment); }; ParamRoutePath.prototype.generateUrl = function (params) { var paramTokens = new utils_1.TouchMap(params); var path = []; for (var i = 0; i < this._segments.length; i++) { var segment = this._segments[i]; if (!(segment instanceof ContinuationPathSegment)) { path.push(segment.generate(paramTokens)); } } var urlPath = path.join('/'); var nonPositionalParams = paramTokens.getUnused(); var urlParams = nonPositionalParams; return new route_path_1.GeneratedUrl(urlPath, urlParams); }; ParamRoutePath.prototype.toString = function () { return this.routePath; }; ParamRoutePath.prototype._parsePathString = function (routePath) { // normalize route as not starting with a "/". Recognition will // also normalize. if (routePath.startsWith('/')) { routePath = routePath.substring(1); } var segmentStrings = routePath.split('/'); this._segments = []; var limit = segmentStrings.length - 1; for (var i = 0; i <= limit; i++) { var segment = segmentStrings[i], match; if (lang_1.isPresent(match = lang_1.RegExpWrapper.firstMatch(DynamicPathSegment.paramMatcher, segment))) { this._segments.push(new DynamicPathSegment(match[1])); } else if (lang_1.isPresent(match = lang_1.RegExpWrapper.firstMatch(StarPathSegment.wildcardMatcher, segment))) { this._segments.push(new StarPathSegment(match[1])); } else if (segment == '...') { if (i < limit) { throw new exceptions_1.BaseException("Unexpected \"...\" before the end of the path for \"" + routePath + "\"."); } this._segments.push(new ContinuationPathSegment()); } else { this._segments.push(new StaticPathSegment(segment)); } } }; ParamRoutePath.prototype._calculateSpecificity = function () { // The "specificity" of a path is used to determine which route is used when multiple routes // match // a URL. Static segments (like "/foo") are the most specific, followed by dynamic segments // (like // "/:id"). Star segments add no specificity. Segments at the start of the path are more // specific // than proceeding ones. // // The code below uses place values to combine the different types of segments into a single // string that we can sort later. Each static segment is marked as a specificity of "2," each // dynamic segment is worth "1" specificity, and stars are worth "0" specificity. var i /** TODO #9100 */, length = this._segments.length, specificity; if (length == 0) { // a single slash (or "empty segment" is as specific as a static segment specificity += '2'; } else { specificity = ''; for (i = 0; i < length; i++) { specificity += this._segments[i].specificity; } } return specificity; }; ParamRoutePath.prototype._calculateHash = function () { // this function is used to determine whether a route config path like `/foo/:id` collides with // `/foo/:name` var i /** TODO #9100 */, length = this._segments.length; var hashParts = []; for (i = 0; i < length; i++) { hashParts.push(this._segments[i].hash); } return hashParts.join('/'); }; ParamRoutePath.prototype._assertValidPath = function (path) { if (lang_1.StringWrapper.contains(path, '#')) { throw new exceptions_1.BaseException("Path \"" + path + "\" should not include \"#\". Use \"HashLocationStrategy\" instead."); } var illegalCharacter = lang_1.RegExpWrapper.firstMatch(ParamRoutePath.RESERVED_CHARS, path); if (lang_1.isPresent(illegalCharacter)) { throw new exceptions_1.BaseException("Path \"" + path + "\" contains \"" + illegalCharacter[0] + "\" which is not allowed in a route config."); } }; ParamRoutePath.RESERVED_CHARS = lang_1.RegExpWrapper.create('//|\\(|\\)|;|\\?|='); return ParamRoutePath; }()); exports.ParamRoutePath = ParamRoutePath; var REGEXP_PERCENT = /%/g; var REGEXP_SLASH = /\//g; var REGEXP_OPEN_PARENT = /\(/g; var REGEXP_CLOSE_PARENT = /\)/g; var REGEXP_SEMICOLON = /;/g; function encodeDynamicSegment(value) { if (lang_1.isBlank(value)) { return null; } value = lang_1.StringWrapper.replaceAll(value, REGEXP_PERCENT, '%25'); value = lang_1.StringWrapper.replaceAll(value, REGEXP_SLASH, '%2F'); value = lang_1.StringWrapper.replaceAll(value, REGEXP_OPEN_PARENT, '%28'); value = lang_1.StringWrapper.replaceAll(value, REGEXP_CLOSE_PARENT, '%29'); value = lang_1.StringWrapper.replaceAll(value, REGEXP_SEMICOLON, '%3B'); return value; } var REGEXP_ENC_SEMICOLON = /%3B/ig; var REGEXP_ENC_CLOSE_PARENT = /%29/ig; var REGEXP_ENC_OPEN_PARENT = /%28/ig; var REGEXP_ENC_SLASH = /%2F/ig; var REGEXP_ENC_PERCENT = /%25/ig; function decodeDynamicSegment(value) { if (lang_1.isBlank(value)) { return null; } value = lang_1.StringWrapper.replaceAll(value, REGEXP_ENC_SEMICOLON, ';'); value = lang_1.StringWrapper.replaceAll(value, REGEXP_ENC_CLOSE_PARENT, ')'); value = lang_1.StringWrapper.replaceAll(value, REGEXP_ENC_OPEN_PARENT, '('); value = lang_1.StringWrapper.replaceAll(value, REGEXP_ENC_SLASH, '/'); value = lang_1.StringWrapper.replaceAll(value, REGEXP_ENC_PERCENT, '%'); return value; } //# sourceMappingURL=param_route_path.js.map