1 |
|
2 |
|
3 | 'use strict';
|
4 |
|
5 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
6 |
|
7 | var pathToRegexp = _interopDefault(require('path-to-regexp'));
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | var cache = new Map();
|
19 |
|
20 | function decodeParam(val) {
|
21 | try {
|
22 | return decodeURIComponent(val);
|
23 | } catch (err) {
|
24 | return val;
|
25 | }
|
26 | }
|
27 |
|
28 | function matchPath(routePath, urlPath, end, parentParams) {
|
29 | var key = routePath + '|' + end;
|
30 | var regexp = cache.get(key);
|
31 |
|
32 | if (!regexp) {
|
33 | var keys = [];
|
34 | regexp = { pattern: pathToRegexp(routePath, keys, { end: end }), keys: keys };
|
35 | cache.set(key, regexp);
|
36 | }
|
37 |
|
38 | var m = regexp.pattern.exec(urlPath);
|
39 | if (!m) {
|
40 | return null;
|
41 | }
|
42 |
|
43 | var path = m[0];
|
44 | var params = Object.create(null);
|
45 |
|
46 | if (parentParams) {
|
47 | Object.assign(params, parentParams);
|
48 | }
|
49 |
|
50 | for (var i = 1; i < m.length; i += 1) {
|
51 | params[regexp.keys[i - 1].name] = m[i] && decodeParam(m[i]);
|
52 | }
|
53 |
|
54 | return { path: path === '' ? '/' : path, keys: regexp.keys.slice(), params: params };
|
55 | }
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | function matchRoute(route, baseUrl, path, parentParams) {
|
67 | var match = void 0;
|
68 | var childMatches = void 0;
|
69 | var childIndex = 0;
|
70 |
|
71 | return {
|
72 | next: function next() {
|
73 | if (!match) {
|
74 | match = matchPath(route.path, path, !route.children, parentParams);
|
75 |
|
76 | if (match) {
|
77 | return {
|
78 | done: false,
|
79 | value: {
|
80 | route: route,
|
81 | baseUrl: baseUrl,
|
82 | path: match.path,
|
83 | keys: match.keys,
|
84 | params: match.params
|
85 | }
|
86 | };
|
87 | }
|
88 | }
|
89 |
|
90 | if (match && route.children) {
|
91 | while (childIndex < route.children.length) {
|
92 | if (!childMatches) {
|
93 | var newPath = path.substr(match.path.length);
|
94 | var childRoute = route.children[childIndex];
|
95 | childRoute.parent = route;
|
96 |
|
97 | childMatches = matchRoute(childRoute, baseUrl + (match.path === '/' ? '' : match.path), newPath.charAt(0) === '/' ? newPath : '/' + newPath, match.params);
|
98 | }
|
99 |
|
100 | var childMatch = childMatches.next();
|
101 | if (!childMatch.done) {
|
102 | return {
|
103 | done: false,
|
104 | value: childMatch.value
|
105 | };
|
106 | }
|
107 |
|
108 | childMatches = null;
|
109 | childIndex += 1;
|
110 | }
|
111 | }
|
112 |
|
113 | return { done: true };
|
114 | }
|
115 | };
|
116 | }
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | function resolveRoute(context, params) {
|
128 | if (typeof context.route.action === 'function') {
|
129 | return context.route.action(context, params);
|
130 | }
|
131 |
|
132 | return null;
|
133 | }
|
134 |
|
135 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
136 |
|
137 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | function isChildRoute(parentRoute, childRoute) {
|
149 | var route = childRoute;
|
150 | while (route) {
|
151 | route = route.parent;
|
152 | if (route === parentRoute) {
|
153 | return true;
|
154 | }
|
155 | }
|
156 | return false;
|
157 | }
|
158 |
|
159 | var Router = function () {
|
160 | function Router(routes) {
|
161 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
162 |
|
163 | _classCallCheck(this, Router);
|
164 |
|
165 | if (Object(routes) !== routes) {
|
166 | throw new TypeError('Invalid routes');
|
167 | }
|
168 |
|
169 | this.baseUrl = options.baseUrl || '';
|
170 | this.resolveRoute = options.resolveRoute || resolveRoute;
|
171 | this.context = Object.assign({ router: this }, options.context);
|
172 | this.root = Array.isArray(routes) ? { path: '/', children: routes, parent: null } : routes;
|
173 | this.root.parent = null;
|
174 | }
|
175 |
|
176 | _createClass(Router, [{
|
177 | key: 'resolve',
|
178 | value: function resolve(pathOrContext) {
|
179 | var context = Object.assign({}, this.context, typeof pathOrContext === 'string' ? { path: pathOrContext } : pathOrContext);
|
180 | var match = matchRoute(this.root, this.baseUrl, context.path.substr(this.baseUrl.length));
|
181 | var resolve = this.resolveRoute;
|
182 | var matches = null;
|
183 | var nextMatches = null;
|
184 |
|
185 | function next(resume) {
|
186 | var parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : matches.value.route;
|
187 |
|
188 | matches = nextMatches || match.next();
|
189 | nextMatches = null;
|
190 |
|
191 | if (!resume) {
|
192 | if (matches.done || !isChildRoute(parent, matches.value.route)) {
|
193 | nextMatches = matches;
|
194 | return Promise.resolve(null);
|
195 | }
|
196 | }
|
197 |
|
198 | if (matches.done) {
|
199 | return Promise.reject(Object.assign(new Error('Page not found'), { context: context, status: 404, statusCode: 404 }));
|
200 | }
|
201 |
|
202 | return Promise.resolve(resolve(Object.assign({}, context, matches.value), matches.value.params)).then(function (result) {
|
203 | if (result !== null && result !== undefined) {
|
204 | return result;
|
205 | }
|
206 |
|
207 | return next(resume, parent);
|
208 | });
|
209 | }
|
210 |
|
211 | context.url = context.path;
|
212 | context.next = next;
|
213 |
|
214 | return next(true, this.root);
|
215 | }
|
216 | }]);
|
217 |
|
218 | return Router;
|
219 | }();
|
220 |
|
221 | Router.pathToRegexp = pathToRegexp;
|
222 | Router.matchPath = matchPath;
|
223 | Router.matchRoute = matchRoute;
|
224 | Router.resolveRoute = resolveRoute;
|
225 |
|
226 | module.exports = Router;
|
227 |
|