UNPKG

7.27 kBJavaScriptView Raw
1"use strict";
2var async_1 = require('../facade/async');
3var collection_1 = require('../facade/collection');
4var exceptions_1 = require('../facade/exceptions');
5var lang_1 = require('../facade/lang');
6var route_config_impl_1 = require('../route_config/route_config_impl');
7var async_route_handler_1 = require('./route_handlers/async_route_handler');
8var sync_route_handler_1 = require('./route_handlers/sync_route_handler');
9var param_route_path_1 = require('./route_paths/param_route_path');
10var regex_route_path_1 = require('./route_paths/regex_route_path');
11var rules_1 = require('./rules');
12/**
13 * A `RuleSet` is responsible for recognizing routes for a particular component.
14 * It is consumed by `RouteRegistry`, which knows how to recognize an entire hierarchy of
15 * components.
16 */
17var RuleSet = (function () {
18 function RuleSet() {
19 this.rulesByName = new collection_1.Map();
20 // map from name to rule
21 this.auxRulesByName = new collection_1.Map();
22 // map from starting path to rule
23 this.auxRulesByPath = new collection_1.Map();
24 // TODO: optimize this into a trie
25 this.rules = [];
26 // the rule to use automatically when recognizing or generating from this rule set
27 this.defaultRule = null;
28 }
29 /**
30 * Configure additional rules in this rule set from a route definition
31 * @returns {boolean} true if the config is terminal
32 */
33 RuleSet.prototype.config = function (config) {
34 var handler;
35 if (lang_1.isPresent(config.name) && config.name[0].toUpperCase() != config.name[0]) {
36 var suggestedName = config.name[0].toUpperCase() + config.name.substring(1);
37 throw new exceptions_1.BaseException("Route \"" + config.path + "\" with name \"" + config.name + "\" does not begin with an uppercase letter. Route names should be PascalCase like \"" + suggestedName + "\".");
38 }
39 if (config instanceof route_config_impl_1.AuxRoute) {
40 handler = new sync_route_handler_1.SyncRouteHandler(config.component, config.data);
41 var routePath_1 = this._getRoutePath(config);
42 var auxRule = new rules_1.RouteRule(routePath_1, handler, config.name);
43 this.auxRulesByPath.set(routePath_1.toString(), auxRule);
44 if (lang_1.isPresent(config.name)) {
45 this.auxRulesByName.set(config.name, auxRule);
46 }
47 return auxRule.terminal;
48 }
49 var useAsDefault = false;
50 if (config instanceof route_config_impl_1.Redirect) {
51 var routePath_2 = this._getRoutePath(config);
52 var redirector = new rules_1.RedirectRule(routePath_2, config.redirectTo);
53 this._assertNoHashCollision(redirector.hash, config.path);
54 this.rules.push(redirector);
55 return true;
56 }
57 if (config instanceof route_config_impl_1.Route) {
58 handler = new sync_route_handler_1.SyncRouteHandler(config.component, config.data);
59 useAsDefault = lang_1.isPresent(config.useAsDefault) && config.useAsDefault;
60 }
61 else if (config instanceof route_config_impl_1.AsyncRoute) {
62 handler = new async_route_handler_1.AsyncRouteHandler(config.loader, config.data);
63 useAsDefault = lang_1.isPresent(config.useAsDefault) && config.useAsDefault;
64 }
65 var routePath = this._getRoutePath(config);
66 var newRule = new rules_1.RouteRule(routePath, handler, config.name);
67 this._assertNoHashCollision(newRule.hash, config.path);
68 if (useAsDefault) {
69 if (lang_1.isPresent(this.defaultRule)) {
70 throw new exceptions_1.BaseException("Only one route can be default");
71 }
72 this.defaultRule = newRule;
73 }
74 this.rules.push(newRule);
75 if (lang_1.isPresent(config.name)) {
76 this.rulesByName.set(config.name, newRule);
77 }
78 return newRule.terminal;
79 };
80 /**
81 * Given a URL, returns a list of `RouteMatch`es, which are partial recognitions for some route.
82 */
83 RuleSet.prototype.recognize = function (urlParse) {
84 var solutions = [];
85 this.rules.forEach(function (routeRecognizer) {
86 var pathMatch = routeRecognizer.recognize(urlParse);
87 if (lang_1.isPresent(pathMatch)) {
88 solutions.push(pathMatch);
89 }
90 });
91 // handle cases where we are routing just to an aux route
92 if (solutions.length == 0 && lang_1.isPresent(urlParse) && urlParse.auxiliary.length > 0) {
93 return [async_1.PromiseWrapper.resolve(new rules_1.PathMatch(null, null, urlParse.auxiliary))];
94 }
95 return solutions;
96 };
97 RuleSet.prototype.recognizeAuxiliary = function (urlParse) {
98 var routeRecognizer = this.auxRulesByPath.get(urlParse.path);
99 if (lang_1.isPresent(routeRecognizer)) {
100 return [routeRecognizer.recognize(urlParse)];
101 }
102 return [async_1.PromiseWrapper.resolve(null)];
103 };
104 RuleSet.prototype.hasRoute = function (name) { return this.rulesByName.has(name); };
105 RuleSet.prototype.componentLoaded = function (name) {
106 return this.hasRoute(name) && lang_1.isPresent(this.rulesByName.get(name).handler.componentType);
107 };
108 RuleSet.prototype.loadComponent = function (name) {
109 return this.rulesByName.get(name).handler.resolveComponentType();
110 };
111 RuleSet.prototype.generate = function (name, params) {
112 var rule = this.rulesByName.get(name);
113 if (lang_1.isBlank(rule)) {
114 return null;
115 }
116 return rule.generate(params);
117 };
118 RuleSet.prototype.generateAuxiliary = function (name, params) {
119 var rule = this.auxRulesByName.get(name);
120 if (lang_1.isBlank(rule)) {
121 return null;
122 }
123 return rule.generate(params);
124 };
125 RuleSet.prototype._assertNoHashCollision = function (hash, path /** TODO #9100 */) {
126 this.rules.forEach(function (rule) {
127 if (hash == rule.hash) {
128 throw new exceptions_1.BaseException("Configuration '" + path + "' conflicts with existing route '" + rule.path + "'");
129 }
130 });
131 };
132 RuleSet.prototype._getRoutePath = function (config) {
133 if (lang_1.isPresent(config.regex)) {
134 if (lang_1.isFunction(config.serializer)) {
135 return new regex_route_path_1.RegexRoutePath(config.regex, config.serializer, config.regex_group_names);
136 }
137 else {
138 throw new exceptions_1.BaseException("Route provides a regex property, '" + config.regex + "', but no serializer property");
139 }
140 }
141 if (lang_1.isPresent(config.path)) {
142 // Auxiliary routes do not have a slash at the start
143 var path = (config instanceof route_config_impl_1.AuxRoute && config.path.startsWith('/')) ?
144 config.path.substring(1) :
145 config.path;
146 return new param_route_path_1.ParamRoutePath(path);
147 }
148 throw new exceptions_1.BaseException('Route must provide either a path or regex property');
149 };
150 return RuleSet;
151}());
152exports.RuleSet = RuleSet;
153//# sourceMappingURL=rule_set.js.map
\No newline at end of file