1 | (function (global, factory) {
|
2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
3 | typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
4 | (global = global || self, factory(global.Curi = {}));
|
5 | }(this, function (exports) { 'use strict';
|
6 |
|
7 | function pathname(route, params) {
|
8 | return route.methods.pathname(params);
|
9 | }
|
10 |
|
11 | function isAsyncRoute(route) {
|
12 | return typeof route.methods.resolve !== "undefined";
|
13 | }
|
14 | function isExternalRedirect(redirect) {
|
15 | return "externalURL" in redirect;
|
16 | }
|
17 | function isRedirectLocation(redirect) {
|
18 | return "url" in redirect;
|
19 | }
|
20 |
|
21 | function finishResponse(route, match, resolvedResults, router, external) {
|
22 | var _a = resolvedResults || {}, _b = _a.resolved, resolved = _b === void 0 ? null : _b, _c = _a.error, error = _c === void 0 ? null : _c;
|
23 | var response = {
|
24 | data: undefined,
|
25 | body: undefined,
|
26 | meta: undefined
|
27 | };
|
28 | for (var key in match) {
|
29 | response[key] = match[key];
|
30 | }
|
31 | if (!route.methods.respond) {
|
32 | return response;
|
33 | }
|
34 | var results = route.methods.respond({
|
35 | resolved: resolved,
|
36 | error: error,
|
37 | match: match,
|
38 | external: external
|
39 | });
|
40 | if (!results) {
|
41 | {
|
42 | console.warn("\"" + match.name + "\"'s response function did not return anything. Did you forget to include a return statement?");
|
43 | }
|
44 | return response;
|
45 | }
|
46 | {
|
47 | var validProperties_1 = {
|
48 | meta: true,
|
49 | body: true,
|
50 | data: true,
|
51 | redirect: true
|
52 | };
|
53 | Object.keys(results).forEach(function (property) {
|
54 | if (!validProperties_1.hasOwnProperty(property)) {
|
55 | console.warn("\"" + property + "\" is not a valid response property. The valid properties are:\n\n " + Object.keys(validProperties_1).join(", "));
|
56 | }
|
57 | });
|
58 | }
|
59 | response["meta"] = results["meta"];
|
60 | response["body"] = results["body"];
|
61 | response["data"] = results["data"];
|
62 | if (results["redirect"]) {
|
63 | response["redirect"] = createRedirect(results["redirect"], router);
|
64 | }
|
65 | return response;
|
66 | }
|
67 | function createRedirect(redirect, router) {
|
68 | if (isExternalRedirect(redirect)) {
|
69 | return redirect;
|
70 | }
|
71 | var name = redirect.name, params = redirect.params, query = redirect.query, hash = redirect.hash, state = redirect.state;
|
72 | var url = isRedirectLocation(redirect)
|
73 | ? redirect.url
|
74 | : router.url({ name: name, params: params, query: query, hash: hash });
|
75 | return {
|
76 | name: name,
|
77 | params: params,
|
78 | query: query,
|
79 | hash: hash,
|
80 | state: state,
|
81 | url: url
|
82 | };
|
83 | }
|
84 |
|
85 | function createRouter(historyConstructor, routes, options) {
|
86 | if (options === void 0) { options = {}; }
|
87 | var latestResponse;
|
88 | var latestNavigation;
|
89 | var history = historyConstructor(function (pendingNav) {
|
90 | var navigation = {
|
91 | action: pendingNav.action,
|
92 | previous: latestResponse
|
93 | };
|
94 | var matched = routes.match(pendingNav.location);
|
95 | if (!matched) {
|
96 | {
|
97 | console.warn("The current location (" + pendingNav.location.pathname + ") has no matching route, " +
|
98 | 'so a response could not be emitted. A catch-all route ({ path: "(.*)" }) ' +
|
99 | "can be used to match locations with no other matching route.");
|
100 | }
|
101 | pendingNav.finish();
|
102 | finishAndResetNavCallbacks();
|
103 | return;
|
104 | }
|
105 | var route = matched.route, match = matched.match;
|
106 | if (!isAsyncRoute(route)) {
|
107 | finalizeResponseAndEmit(route, match, pendingNav, navigation, null);
|
108 | }
|
109 | else {
|
110 | announceAsyncNav();
|
111 | route.methods
|
112 | .resolve(match, options.external)
|
113 | .then(function (resolved) { return ({ resolved: resolved, error: null }); }, function (error) { return ({ error: error, resolved: null }); })
|
114 | .then(function (resolved) {
|
115 | if (pendingNav.cancelled) {
|
116 | return;
|
117 | }
|
118 | finalizeResponseAndEmit(route, match, pendingNav, navigation, resolved);
|
119 | });
|
120 | }
|
121 | }, options.history || {});
|
122 | function finalizeResponseAndEmit(route, match, pending, navigation, resolved) {
|
123 | asyncNavComplete();
|
124 | pending.finish();
|
125 | var response = finishResponse(route, match, resolved, router, options.external);
|
126 | finishAndResetNavCallbacks();
|
127 | emitImmediate(response, navigation);
|
128 | }
|
129 | var _a = options.invisibleRedirects, invisibleRedirects = _a === void 0 ? false : _a;
|
130 | function emitImmediate(response, navigation) {
|
131 | if (!response.redirect ||
|
132 | !invisibleRedirects ||
|
133 | isExternalRedirect(response.redirect)) {
|
134 | latestResponse = response;
|
135 | latestNavigation = navigation;
|
136 | var emit = { response: response, navigation: navigation, router: router };
|
137 | callObservers(emit);
|
138 | callOneTimersAndSideEffects(emit);
|
139 | }
|
140 | if (response.redirect !== undefined &&
|
141 | !isExternalRedirect(response.redirect)) {
|
142 | history.navigate(response.redirect, "replace");
|
143 | }
|
144 | }
|
145 | function callObservers(emitted) {
|
146 | observers.forEach(function (fn) {
|
147 | fn(emitted);
|
148 | });
|
149 | }
|
150 | function callOneTimersAndSideEffects(emitted) {
|
151 | oneTimers.splice(0).forEach(function (fn) {
|
152 | fn(emitted);
|
153 | });
|
154 | if (options.sideEffects) {
|
155 | options.sideEffects.forEach(function (fn) {
|
156 | fn(emitted);
|
157 | });
|
158 | }
|
159 | }
|
160 |
|
161 | var observers = [];
|
162 | var oneTimers = [];
|
163 | function observe(fn, options) {
|
164 | var _a = (options || {}).initial, initial = _a === void 0 ? true : _a;
|
165 | observers.push(fn);
|
166 | if (latestResponse && initial) {
|
167 | fn({
|
168 | response: latestResponse,
|
169 | navigation: latestNavigation,
|
170 | router: router
|
171 | });
|
172 | }
|
173 | return function () {
|
174 | observers = observers.filter(function (obs) {
|
175 | return obs !== fn;
|
176 | });
|
177 | };
|
178 | }
|
179 | function once(fn, options) {
|
180 | var _a = (options || {}).initial, initial = _a === void 0 ? true : _a;
|
181 | if (latestResponse && initial) {
|
182 | fn({
|
183 | response: latestResponse,
|
184 | navigation: latestNavigation,
|
185 | router: router
|
186 | });
|
187 | }
|
188 | else {
|
189 | oneTimers.push(fn);
|
190 | }
|
191 | }
|
192 |
|
193 | function url(details) {
|
194 | var name = details.name, params = details.params, hash = details.hash, query = details.query;
|
195 | var pathname$1;
|
196 | if (name) {
|
197 | var route = router.route(name);
|
198 | if (route) {
|
199 | pathname$1 = pathname(route, params);
|
200 | }
|
201 | }
|
202 | return history.url({ pathname: pathname$1, hash: hash, query: query });
|
203 | }
|
204 |
|
205 | var cancelCallback;
|
206 | var finishCallback;
|
207 | function navigate(details) {
|
208 | cancelAndResetNavCallbacks();
|
209 | var url = details.url, state = details.state, method = details.method;
|
210 | history.navigate({ url: url, state: state }, method);
|
211 | if (details.cancelled || details.finished) {
|
212 | cancelCallback = details.cancelled;
|
213 | finishCallback = details.finished;
|
214 | return resetCallbacks;
|
215 | }
|
216 | }
|
217 | function cancelAndResetNavCallbacks() {
|
218 | if (cancelCallback) {
|
219 | cancelCallback();
|
220 | }
|
221 | resetCallbacks();
|
222 | }
|
223 | function finishAndResetNavCallbacks() {
|
224 | if (finishCallback) {
|
225 | finishCallback();
|
226 | }
|
227 | resetCallbacks();
|
228 | }
|
229 | function resetCallbacks() {
|
230 | cancelCallback = undefined;
|
231 | finishCallback = undefined;
|
232 | }
|
233 |
|
234 | var cancelWith;
|
235 | var asyncNavNotifiers = [];
|
236 | function cancel(fn) {
|
237 | asyncNavNotifiers.push(fn);
|
238 | return function () {
|
239 | asyncNavNotifiers = asyncNavNotifiers.filter(function (can) {
|
240 | return can !== fn;
|
241 | });
|
242 | };
|
243 | }
|
244 |
|
245 |
|
246 | function announceAsyncNav() {
|
247 | if (asyncNavNotifiers.length && cancelWith === undefined) {
|
248 | cancelWith = function () {
|
249 | history.cancel();
|
250 | asyncNavComplete();
|
251 | cancelAndResetNavCallbacks();
|
252 | };
|
253 | asyncNavNotifiers.forEach(function (fn) {
|
254 | fn(cancelWith);
|
255 | });
|
256 | }
|
257 | }
|
258 | function asyncNavComplete() {
|
259 | if (cancelWith) {
|
260 | cancelWith = undefined;
|
261 | asyncNavNotifiers.forEach(function (fn) {
|
262 | fn();
|
263 | });
|
264 | }
|
265 | }
|
266 | var router = {
|
267 | route: routes.route,
|
268 | history: history,
|
269 | external: options.external,
|
270 | observe: observe,
|
271 | once: once,
|
272 | cancel: cancel,
|
273 | url: url,
|
274 | navigate: navigate,
|
275 | current: function () {
|
276 | return {
|
277 | response: latestResponse,
|
278 | navigation: latestNavigation
|
279 | };
|
280 | },
|
281 | destroy: function () {
|
282 | history.destroy();
|
283 | }
|
284 | };
|
285 | history.current();
|
286 | return router;
|
287 | }
|
288 |
|
289 | |
290 |
|
291 |
|
292 | var pathToRegexp_1 = pathToRegexp;
|
293 | var parse_1 = parse;
|
294 | var compile_1 = compile;
|
295 | var tokensToFunction_1 = tokensToFunction;
|
296 | var tokensToRegExp_1 = tokensToRegExp;
|
297 |
|
298 | |
299 |
|
300 |
|
301 | var DEFAULT_DELIMITER = '/';
|
302 | var DEFAULT_DELIMITERS = './';
|
303 |
|
304 | |
305 |
|
306 |
|
307 |
|
308 |
|
309 | var PATH_REGEXP = new RegExp([
|
310 |
|
311 |
|
312 | '(\\\\.)',
|
313 |
|
314 |
|
315 |
|
316 |
|
317 |
|
318 | '(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?'
|
319 | ].join('|'), 'g');
|
320 |
|
321 | |
322 |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 | function parse (str, options) {
|
329 | var tokens = [];
|
330 | var key = 0;
|
331 | var index = 0;
|
332 | var path = '';
|
333 | var defaultDelimiter = (options && options.delimiter) || DEFAULT_DELIMITER;
|
334 | var delimiters = (options && options.delimiters) || DEFAULT_DELIMITERS;
|
335 | var pathEscaped = false;
|
336 | var res;
|
337 |
|
338 | while ((res = PATH_REGEXP.exec(str)) !== null) {
|
339 | var m = res[0];
|
340 | var escaped = res[1];
|
341 | var offset = res.index;
|
342 | path += str.slice(index, offset);
|
343 | index = offset + m.length;
|
344 |
|
345 |
|
346 | if (escaped) {
|
347 | path += escaped[1];
|
348 | pathEscaped = true;
|
349 | continue
|
350 | }
|
351 |
|
352 | var prev = '';
|
353 | var next = str[index];
|
354 | var name = res[2];
|
355 | var capture = res[3];
|
356 | var group = res[4];
|
357 | var modifier = res[5];
|
358 |
|
359 | if (!pathEscaped && path.length) {
|
360 | var k = path.length - 1;
|
361 |
|
362 | if (delimiters.indexOf(path[k]) > -1) {
|
363 | prev = path[k];
|
364 | path = path.slice(0, k);
|
365 | }
|
366 | }
|
367 |
|
368 |
|
369 | if (path) {
|
370 | tokens.push(path);
|
371 | path = '';
|
372 | pathEscaped = false;
|
373 | }
|
374 |
|
375 | var partial = prev !== '' && next !== undefined && next !== prev;
|
376 | var repeat = modifier === '+' || modifier === '*';
|
377 | var optional = modifier === '?' || modifier === '*';
|
378 | var delimiter = prev || defaultDelimiter;
|
379 | var pattern = capture || group;
|
380 |
|
381 | tokens.push({
|
382 | name: name || key++,
|
383 | prefix: prev,
|
384 | delimiter: delimiter,
|
385 | optional: optional,
|
386 | repeat: repeat,
|
387 | partial: partial,
|
388 | pattern: pattern ? escapeGroup(pattern) : '[^' + escapeString(delimiter) + ']+?'
|
389 | });
|
390 | }
|
391 |
|
392 |
|
393 | if (path || index < str.length) {
|
394 | tokens.push(path + str.substr(index));
|
395 | }
|
396 |
|
397 | return tokens
|
398 | }
|
399 |
|
400 | |
401 |
|
402 |
|
403 |
|
404 |
|
405 |
|
406 |
|
407 | function compile (str, options) {
|
408 | return tokensToFunction(parse(str, options))
|
409 | }
|
410 |
|
411 | |
412 |
|
413 |
|
414 | function tokensToFunction (tokens) {
|
415 |
|
416 | var matches = new Array(tokens.length);
|
417 |
|
418 |
|
419 | for (var i = 0; i < tokens.length; i++) {
|
420 | if (typeof tokens[i] === 'object') {
|
421 | matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
|
422 | }
|
423 | }
|
424 |
|
425 | return function (data, options) {
|
426 | var path = '';
|
427 | var encode = (options && options.encode) || encodeURIComponent;
|
428 |
|
429 | for (var i = 0; i < tokens.length; i++) {
|
430 | var token = tokens[i];
|
431 |
|
432 | if (typeof token === 'string') {
|
433 | path += token;
|
434 | continue
|
435 | }
|
436 |
|
437 | var value = data ? data[token.name] : undefined;
|
438 | var segment;
|
439 |
|
440 | if (Array.isArray(value)) {
|
441 | if (!token.repeat) {
|
442 | throw new TypeError('Expected "' + token.name + '" to not repeat, but got array')
|
443 | }
|
444 |
|
445 | if (value.length === 0) {
|
446 | if (token.optional) continue
|
447 |
|
448 | throw new TypeError('Expected "' + token.name + '" to not be empty')
|
449 | }
|
450 |
|
451 | for (var j = 0; j < value.length; j++) {
|
452 | segment = encode(value[j], token);
|
453 |
|
454 | if (!matches[i].test(segment)) {
|
455 | throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '"')
|
456 | }
|
457 |
|
458 | path += (j === 0 ? token.prefix : token.delimiter) + segment;
|
459 | }
|
460 |
|
461 | continue
|
462 | }
|
463 |
|
464 | if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
465 | segment = encode(String(value), token);
|
466 |
|
467 | if (!matches[i].test(segment)) {
|
468 | throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but got "' + segment + '"')
|
469 | }
|
470 |
|
471 | path += token.prefix + segment;
|
472 | continue
|
473 | }
|
474 |
|
475 | if (token.optional) {
|
476 |
|
477 | if (token.partial) path += token.prefix;
|
478 |
|
479 | continue
|
480 | }
|
481 |
|
482 | throw new TypeError('Expected "' + token.name + '" to be ' + (token.repeat ? 'an array' : 'a string'))
|
483 | }
|
484 |
|
485 | return path
|
486 | }
|
487 | }
|
488 |
|
489 | |
490 |
|
491 |
|
492 |
|
493 |
|
494 |
|
495 | function escapeString (str) {
|
496 | return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
|
497 | }
|
498 |
|
499 | |
500 |
|
501 |
|
502 |
|
503 |
|
504 |
|
505 | function escapeGroup (group) {
|
506 | return group.replace(/([=!:$/()])/g, '\\$1')
|
507 | }
|
508 |
|
509 | |
510 |
|
511 |
|
512 |
|
513 |
|
514 |
|
515 | function flags (options) {
|
516 | return options && options.sensitive ? '' : 'i'
|
517 | }
|
518 |
|
519 | |
520 |
|
521 |
|
522 |
|
523 |
|
524 |
|
525 |
|
526 | function regexpToRegexp (path, keys) {
|
527 | if (!keys) return path
|
528 |
|
529 |
|
530 | var groups = path.source.match(/\((?!\?)/g);
|
531 |
|
532 | if (groups) {
|
533 | for (var i = 0; i < groups.length; i++) {
|
534 | keys.push({
|
535 | name: i,
|
536 | prefix: null,
|
537 | delimiter: null,
|
538 | optional: false,
|
539 | repeat: false,
|
540 | partial: false,
|
541 | pattern: null
|
542 | });
|
543 | }
|
544 | }
|
545 |
|
546 | return path
|
547 | }
|
548 |
|
549 | |
550 |
|
551 |
|
552 |
|
553 |
|
554 |
|
555 |
|
556 |
|
557 | function arrayToRegexp (path, keys, options) {
|
558 | var parts = [];
|
559 |
|
560 | for (var i = 0; i < path.length; i++) {
|
561 | parts.push(pathToRegexp(path[i], keys, options).source);
|
562 | }
|
563 |
|
564 | return new RegExp('(?:' + parts.join('|') + ')', flags(options))
|
565 | }
|
566 |
|
567 | |
568 |
|
569 |
|
570 |
|
571 |
|
572 |
|
573 |
|
574 |
|
575 | function stringToRegexp (path, keys, options) {
|
576 | return tokensToRegExp(parse(path, options), keys, options)
|
577 | }
|
578 |
|
579 | |
580 |
|
581 |
|
582 |
|
583 |
|
584 |
|
585 |
|
586 |
|
587 | function tokensToRegExp (tokens, keys, options) {
|
588 | options = options || {};
|
589 |
|
590 | var strict = options.strict;
|
591 | var start = options.start !== false;
|
592 | var end = options.end !== false;
|
593 | var delimiter = escapeString(options.delimiter || DEFAULT_DELIMITER);
|
594 | var delimiters = options.delimiters || DEFAULT_DELIMITERS;
|
595 | var endsWith = [].concat(options.endsWith || []).map(escapeString).concat('$').join('|');
|
596 | var route = start ? '^' : '';
|
597 | var isEndDelimited = tokens.length === 0;
|
598 |
|
599 |
|
600 | for (var i = 0; i < tokens.length; i++) {
|
601 | var token = tokens[i];
|
602 |
|
603 | if (typeof token === 'string') {
|
604 | route += escapeString(token);
|
605 | isEndDelimited = i === tokens.length - 1 && delimiters.indexOf(token[token.length - 1]) > -1;
|
606 | } else {
|
607 | var capture = token.repeat
|
608 | ? '(?:' + token.pattern + ')(?:' + escapeString(token.delimiter) + '(?:' + token.pattern + '))*'
|
609 | : token.pattern;
|
610 |
|
611 | if (keys) keys.push(token);
|
612 |
|
613 | if (token.optional) {
|
614 | if (token.partial) {
|
615 | route += escapeString(token.prefix) + '(' + capture + ')?';
|
616 | } else {
|
617 | route += '(?:' + escapeString(token.prefix) + '(' + capture + '))?';
|
618 | }
|
619 | } else {
|
620 | route += escapeString(token.prefix) + '(' + capture + ')';
|
621 | }
|
622 | }
|
623 | }
|
624 |
|
625 | if (end) {
|
626 | if (!strict) route += '(?:' + delimiter + ')?';
|
627 |
|
628 | route += endsWith === '$' ? '$' : '(?=' + endsWith + ')';
|
629 | } else {
|
630 | if (!strict) route += '(?:' + delimiter + '(?=' + endsWith + '))?';
|
631 | if (!isEndDelimited) route += '(?=' + delimiter + '|' + endsWith + ')';
|
632 | }
|
633 |
|
634 | return new RegExp(route, flags(options))
|
635 | }
|
636 |
|
637 | |
638 |
|
639 |
|
640 |
|
641 |
|
642 |
|
643 |
|
644 |
|
645 |
|
646 |
|
647 |
|
648 |
|
649 | function pathToRegexp (path, keys, options) {
|
650 | if (path instanceof RegExp) {
|
651 | return regexpToRegexp(path, keys)
|
652 | }
|
653 |
|
654 | if (Array.isArray(path)) {
|
655 | return arrayToRegexp( (path), keys, options)
|
656 | }
|
657 |
|
658 | return stringToRegexp( (path), keys, options)
|
659 | }
|
660 | pathToRegexp_1.parse = parse_1;
|
661 | pathToRegexp_1.compile = compile_1;
|
662 | pathToRegexp_1.tokensToFunction = tokensToFunction_1;
|
663 | pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
|
664 |
|
665 | var withLeadingSlash = function (path) {
|
666 | return path.charAt(0) === "/" ? path : "/" + path;
|
667 | };
|
668 | var withTrailingSlash = function (path) {
|
669 | return path.charAt(path.length - 1) === "/" ? path : path + "/";
|
670 | };
|
671 | var join = function (beginning, end) {
|
672 | return withTrailingSlash(beginning) + end;
|
673 | };
|
674 |
|
675 | function createRoute(props, map, parent) {
|
676 | if (parent === void 0) { parent = {
|
677 | path: "",
|
678 | keys: []
|
679 | }; }
|
680 | {
|
681 | if (props.name in map) {
|
682 | throw new Error("Multiple routes have the name \"" + props.name + "\". Route names must be unique.");
|
683 | }
|
684 | if (props.path.charAt(0) === "/") {
|
685 | throw new Error("Route paths cannot start with a forward slash (/). (Received \"" + props.path + "\")");
|
686 | }
|
687 | }
|
688 | var fullPath = withLeadingSlash(join(parent.path, props.path));
|
689 | var _a = props.pathOptions || {}, _b = _a.match, matchOptions = _b === void 0 ? {} : _b, _c = _a.compile, compileOptions = _c === void 0 ? {} : _c;
|
690 |
|
691 | var exact = matchOptions.end == null || matchOptions.end;
|
692 | if (props.children && props.children.length) {
|
693 | matchOptions.end = false;
|
694 | }
|
695 | var keys = [];
|
696 | var re = pathToRegexp_1(withLeadingSlash(props.path), keys, matchOptions);
|
697 | var keyNames = keys.map(function (key) { return key.name; });
|
698 | if (parent.keys.length) {
|
699 | keyNames = parent.keys.concat(keyNames);
|
700 | }
|
701 | var childRoutes = [];
|
702 | var children = [];
|
703 | if (props.children && props.children.length) {
|
704 | childRoutes = props.children.map(function (child) {
|
705 | return createRoute(child, map, {
|
706 | path: fullPath,
|
707 | keys: keyNames
|
708 | });
|
709 | });
|
710 | children = childRoutes.map(function (child) { return child.public; });
|
711 | }
|
712 | var compiled = pathToRegexp_1.compile(fullPath);
|
713 | var route = {
|
714 | public: {
|
715 | name: props.name,
|
716 | keys: keyNames,
|
717 | parent: undefined,
|
718 | children: children,
|
719 | methods: {
|
720 | resolve: props.resolve,
|
721 | respond: props.respond,
|
722 | pathname: function (params) {
|
723 | return compiled(params, compileOptions);
|
724 | }
|
725 | },
|
726 | extra: props.extra
|
727 | },
|
728 | matching: {
|
729 | re: re,
|
730 | keys: keys,
|
731 | exact: exact,
|
732 | parsers: props.params || {},
|
733 | children: childRoutes
|
734 | }
|
735 | };
|
736 | map[props.name] = route.public;
|
737 | if (childRoutes.length) {
|
738 | childRoutes.forEach(function (child) {
|
739 | child.public.parent = route.public;
|
740 | });
|
741 | }
|
742 | return route;
|
743 | }
|
744 |
|
745 | function matchLocation(location, routes) {
|
746 | for (var i = 0, len = routes.length; i < len; i++) {
|
747 | var routeMatches = matchRoute(routes[i], location.pathname);
|
748 | if (routeMatches.length) {
|
749 | return createMatch(routeMatches, location);
|
750 | }
|
751 | }
|
752 | }
|
753 | function matchRoute(route, pathname) {
|
754 | var _a = route.matching, re = _a.re, children = _a.children, exact = _a.exact;
|
755 | var regExpMatch = re.exec(pathname);
|
756 | if (!regExpMatch) {
|
757 | return [];
|
758 | }
|
759 | var matchedSegment = regExpMatch[0], parsed = regExpMatch.slice(1);
|
760 | var matches = [{ route: route, parsed: parsed }];
|
761 | var remainder = pathname.slice(matchedSegment.length);
|
762 | if (!children.length || remainder === "") {
|
763 | return matches;
|
764 | }
|
765 |
|
766 | var fullSegments = withLeadingSlash(remainder);
|
767 | for (var i = 0, length_1 = children.length; i < length_1; i++) {
|
768 | var matched = matchRoute(children[i], fullSegments);
|
769 | if (matched.length) {
|
770 | return matches.concat(matched);
|
771 | }
|
772 | }
|
773 | return exact ? [] : matches;
|
774 | }
|
775 | function createMatch(routeMatches, location) {
|
776 | var route = routeMatches[routeMatches.length - 1].route.public;
|
777 | return {
|
778 | route: route,
|
779 | match: {
|
780 | location: location,
|
781 | name: route.name,
|
782 | params: routeMatches.reduce(function (params, _a) {
|
783 | var route = _a.route, parsed = _a.parsed;
|
784 | parsed.forEach(function (param, index) {
|
785 | var name = route.matching.keys[index].name;
|
786 | var fn = route.matching.parsers[name] || decodeURIComponent;
|
787 | params[name] = fn(param);
|
788 | });
|
789 | return params;
|
790 | }, {})
|
791 | }
|
792 | };
|
793 | }
|
794 |
|
795 | function prepareRoutes(routes) {
|
796 | var mappedRoutes = {};
|
797 | var prepared = routes.map(function (route) { return createRoute(route, mappedRoutes); });
|
798 | return {
|
799 | match: function (location) {
|
800 | return matchLocation(location, prepared);
|
801 | },
|
802 | route: function (name) {
|
803 | if (!(name in mappedRoutes)) {
|
804 | console.warn("Attempting to use route \"" + name + "\", but no route with that name exists.");
|
805 | }
|
806 | return mappedRoutes[name];
|
807 | }
|
808 | };
|
809 | }
|
810 |
|
811 | function announce(fmt, mode) {
|
812 | if (mode === void 0) { mode = "assertive"; }
|
813 | var announcer = document.createElement("div");
|
814 | announcer.setAttribute("aria-live", mode);
|
815 |
|
816 | announcer.setAttribute("style", [
|
817 | "border: 0 !important;",
|
818 | "clip: rect(1px, 1px, 1px, 1px) !important;",
|
819 | "-webkit-clip-path: inset(50%) !important;",
|
820 | "clip-path: inset(50%) !important;",
|
821 | "height: 1px !important;",
|
822 | "overflow: hidden !important;",
|
823 | "padding: 0 !important;",
|
824 | "position: absolute !important;",
|
825 | "width: 1px !important;",
|
826 | "white-space: nowrap !important;",
|
827 | "top: 0;"
|
828 | ].join(" "));
|
829 | document.body.appendChild(announcer);
|
830 | return function (emitted) {
|
831 | announcer.textContent = fmt(emitted);
|
832 | };
|
833 | }
|
834 |
|
835 | function scroll() {
|
836 | return function (_a) {
|
837 | var response = _a.response, navigation = _a.navigation;
|
838 | if (navigation.action === "pop") {
|
839 | return;
|
840 | }
|
841 |
|
842 | setTimeout(function () {
|
843 | var hash = response.location.hash;
|
844 | if (hash !== "") {
|
845 | var element = document.getElementById(hash);
|
846 | if (element && element.scrollIntoView) {
|
847 | element.scrollIntoView();
|
848 | return;
|
849 | }
|
850 | }
|
851 |
|
852 |
|
853 |
|
854 | window.scrollTo(0, 0);
|
855 | }, 0);
|
856 | };
|
857 | }
|
858 |
|
859 | function title(callback) {
|
860 | return function (emitted) {
|
861 | document.title = callback(emitted);
|
862 | };
|
863 | }
|
864 |
|
865 | exports.announce = announce;
|
866 | exports.createRouter = createRouter;
|
867 | exports.prepareRoutes = prepareRoutes;
|
868 | exports.scroll = scroll;
|
869 | exports.title = title;
|
870 |
|
871 | Object.defineProperty(exports, '__esModule', { value: true });
|
872 |
|
873 | }));
|