UNPKG

67.4 kBJavaScriptView Raw
1/*!
2 * vue-router v3.0.4
3 * (c) 2019 Evan You
4 * @license MIT
5 */
6'use strict';
7
8/* */
9
10function assert (condition, message) {
11 if (!condition) {
12 throw new Error(("[vue-router] " + message))
13 }
14}
15
16function warn (condition, message) {
17 if (process.env.NODE_ENV !== 'production' && !condition) {
18 typeof console !== 'undefined' && console.warn(("[vue-router] " + message));
19 }
20}
21
22function isError (err) {
23 return Object.prototype.toString.call(err).indexOf('Error') > -1
24}
25
26function extend (a, b) {
27 for (var key in b) {
28 a[key] = b[key];
29 }
30 return a
31}
32
33var View = {
34 name: 'RouterView',
35 functional: true,
36 props: {
37 name: {
38 type: String,
39 default: 'default'
40 }
41 },
42 render: function render (_, ref) {
43 var props = ref.props;
44 var children = ref.children;
45 var parent = ref.parent;
46 var data = ref.data;
47
48 // used by devtools to display a router-view badge
49 data.routerView = true;
50
51 // directly use parent context's createElement() function
52 // so that components rendered by router-view can resolve named slots
53 var h = parent.$createElement;
54 var name = props.name;
55 var route = parent.$route;
56 var cache = parent._routerViewCache || (parent._routerViewCache = {});
57
58 // determine current view depth, also check to see if the tree
59 // has been toggled inactive but kept-alive.
60 var depth = 0;
61 var inactive = false;
62 while (parent && parent._routerRoot !== parent) {
63 if (parent.$vnode && parent.$vnode.data.routerView) {
64 depth++;
65 }
66 if (parent._inactive) {
67 inactive = true;
68 }
69 parent = parent.$parent;
70 }
71 data.routerViewDepth = depth;
72
73 // render previous view if the tree is inactive and kept-alive
74 if (inactive) {
75 return h(cache[name], data, children)
76 }
77
78 var matched = route.matched[depth];
79 // render empty node if no matched route
80 if (!matched) {
81 cache[name] = null;
82 return h()
83 }
84
85 var component = cache[name] = matched.components[name];
86
87 // attach instance registration hook
88 // this will be called in the instance's injected lifecycle hooks
89 data.registerRouteInstance = function (vm, val) {
90 // val could be undefined for unregistration
91 var current = matched.instances[name];
92 if (
93 (val && current !== vm) ||
94 (!val && current === vm)
95 ) {
96 matched.instances[name] = val;
97 }
98 }
99
100 // also register instance in prepatch hook
101 // in case the same component instance is reused across different routes
102 ;(data.hook || (data.hook = {})).prepatch = function (_, vnode) {
103 matched.instances[name] = vnode.componentInstance;
104 };
105
106 // resolve props
107 var propsToPass = data.props = resolveProps(route, matched.props && matched.props[name]);
108 if (propsToPass) {
109 // clone to prevent mutation
110 propsToPass = data.props = extend({}, propsToPass);
111 // pass non-declared props as attrs
112 var attrs = data.attrs = data.attrs || {};
113 for (var key in propsToPass) {
114 if (!component.props || !(key in component.props)) {
115 attrs[key] = propsToPass[key];
116 delete propsToPass[key];
117 }
118 }
119 }
120
121 return h(component, data, children)
122 }
123}
124
125function resolveProps (route, config) {
126 switch (typeof config) {
127 case 'undefined':
128 return
129 case 'object':
130 return config
131 case 'function':
132 return config(route)
133 case 'boolean':
134 return config ? route.params : undefined
135 default:
136 if (process.env.NODE_ENV !== 'production') {
137 warn(
138 false,
139 "props in \"" + (route.path) + "\" is a " + (typeof config) + ", " +
140 "expecting an object, function or boolean."
141 );
142 }
143 }
144}
145
146/* */
147
148var encodeReserveRE = /[!'()*]/g;
149var encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };
150var commaRE = /%2C/g;
151
152// fixed encodeURIComponent which is more conformant to RFC3986:
153// - escapes [!'()*]
154// - preserve commas
155var encode = function (str) { return encodeURIComponent(str)
156 .replace(encodeReserveRE, encodeReserveReplacer)
157 .replace(commaRE, ','); };
158
159var decode = decodeURIComponent;
160
161function resolveQuery (
162 query,
163 extraQuery,
164 _parseQuery
165) {
166 if ( extraQuery === void 0 ) extraQuery = {};
167
168 var parse = _parseQuery || parseQuery;
169 var parsedQuery;
170 try {
171 parsedQuery = parse(query || '');
172 } catch (e) {
173 process.env.NODE_ENV !== 'production' && warn(false, e.message);
174 parsedQuery = {};
175 }
176 for (var key in extraQuery) {
177 parsedQuery[key] = extraQuery[key];
178 }
179 return parsedQuery
180}
181
182function parseQuery (query) {
183 var res = {};
184
185 query = query.trim().replace(/^(\?|#|&)/, '');
186
187 if (!query) {
188 return res
189 }
190
191 query.split('&').forEach(function (param) {
192 var parts = param.replace(/\+/g, ' ').split('=');
193 var key = decode(parts.shift());
194 var val = parts.length > 0
195 ? decode(parts.join('='))
196 : null;
197
198 if (res[key] === undefined) {
199 res[key] = val;
200 } else if (Array.isArray(res[key])) {
201 res[key].push(val);
202 } else {
203 res[key] = [res[key], val];
204 }
205 });
206
207 return res
208}
209
210function stringifyQuery (obj) {
211 var res = obj ? Object.keys(obj).map(function (key) {
212 var val = obj[key];
213
214 if (val === undefined) {
215 return ''
216 }
217
218 if (val === null) {
219 return encode(key)
220 }
221
222 if (Array.isArray(val)) {
223 var result = [];
224 val.forEach(function (val2) {
225 if (val2 === undefined) {
226 return
227 }
228 if (val2 === null) {
229 result.push(encode(key));
230 } else {
231 result.push(encode(key) + '=' + encode(val2));
232 }
233 });
234 return result.join('&')
235 }
236
237 return encode(key) + '=' + encode(val)
238 }).filter(function (x) { return x.length > 0; }).join('&') : null;
239 return res ? ("?" + res) : ''
240}
241
242/* */
243
244var trailingSlashRE = /\/?$/;
245
246function createRoute (
247 record,
248 location,
249 redirectedFrom,
250 router
251) {
252 var stringifyQuery$$1 = router && router.options.stringifyQuery;
253
254 var query = location.query || {};
255 try {
256 query = clone(query);
257 } catch (e) {}
258
259 var route = {
260 name: location.name || (record && record.name),
261 meta: (record && record.meta) || {},
262 path: location.path || '/',
263 hash: location.hash || '',
264 query: query,
265 params: location.params || {},
266 fullPath: getFullPath(location, stringifyQuery$$1),
267 matched: record ? formatMatch(record) : []
268 };
269 if (redirectedFrom) {
270 route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery$$1);
271 }
272 return Object.freeze(route)
273}
274
275function clone (value) {
276 if (Array.isArray(value)) {
277 return value.map(clone)
278 } else if (value && typeof value === 'object') {
279 var res = {};
280 for (var key in value) {
281 res[key] = clone(value[key]);
282 }
283 return res
284 } else {
285 return value
286 }
287}
288
289// the starting route that represents the initial state
290var START = createRoute(null, {
291 path: '/'
292});
293
294function formatMatch (record) {
295 var res = [];
296 while (record) {
297 res.unshift(record);
298 record = record.parent;
299 }
300 return res
301}
302
303function getFullPath (
304 ref,
305 _stringifyQuery
306) {
307 var path = ref.path;
308 var query = ref.query; if ( query === void 0 ) query = {};
309 var hash = ref.hash; if ( hash === void 0 ) hash = '';
310
311 var stringify = _stringifyQuery || stringifyQuery;
312 return (path || '/') + stringify(query) + hash
313}
314
315function isSameRoute (a, b) {
316 if (b === START) {
317 return a === b
318 } else if (!b) {
319 return false
320 } else if (a.path && b.path) {
321 return (
322 a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
323 a.hash === b.hash &&
324 isObjectEqual(a.query, b.query)
325 )
326 } else if (a.name && b.name) {
327 return (
328 a.name === b.name &&
329 a.hash === b.hash &&
330 isObjectEqual(a.query, b.query) &&
331 isObjectEqual(a.params, b.params)
332 )
333 } else {
334 return false
335 }
336}
337
338function isObjectEqual (a, b) {
339 if ( a === void 0 ) a = {};
340 if ( b === void 0 ) b = {};
341
342 // handle null value #1566
343 if (!a || !b) { return a === b }
344 var aKeys = Object.keys(a);
345 var bKeys = Object.keys(b);
346 if (aKeys.length !== bKeys.length) {
347 return false
348 }
349 return aKeys.every(function (key) {
350 var aVal = a[key];
351 var bVal = b[key];
352 // check nested equality
353 if (typeof aVal === 'object' && typeof bVal === 'object') {
354 return isObjectEqual(aVal, bVal)
355 }
356 return String(aVal) === String(bVal)
357 })
358}
359
360function isIncludedRoute (current, target) {
361 return (
362 current.path.replace(trailingSlashRE, '/').indexOf(
363 target.path.replace(trailingSlashRE, '/')
364 ) === 0 &&
365 (!target.hash || current.hash === target.hash) &&
366 queryIncludes(current.query, target.query)
367 )
368}
369
370function queryIncludes (current, target) {
371 for (var key in target) {
372 if (!(key in current)) {
373 return false
374 }
375 }
376 return true
377}
378
379/* */
380
381// work around weird flow bug
382var toTypes = [String, Object];
383var eventTypes = [String, Array];
384
385var Link = {
386 name: 'RouterLink',
387 props: {
388 to: {
389 type: toTypes,
390 required: true
391 },
392 tag: {
393 type: String,
394 default: 'a'
395 },
396 exact: Boolean,
397 append: Boolean,
398 replace: Boolean,
399 activeClass: String,
400 exactActiveClass: String,
401 event: {
402 type: eventTypes,
403 default: 'click'
404 }
405 },
406 render: function render (h) {
407 var this$1 = this;
408
409 var router = this.$router;
410 var current = this.$route;
411 var ref = router.resolve(this.to, current, this.append);
412 var location = ref.location;
413 var route = ref.route;
414 var href = ref.href;
415
416 var classes = {};
417 var globalActiveClass = router.options.linkActiveClass;
418 var globalExactActiveClass = router.options.linkExactActiveClass;
419 // Support global empty active class
420 var activeClassFallback = globalActiveClass == null
421 ? 'router-link-active'
422 : globalActiveClass;
423 var exactActiveClassFallback = globalExactActiveClass == null
424 ? 'router-link-exact-active'
425 : globalExactActiveClass;
426 var activeClass = this.activeClass == null
427 ? activeClassFallback
428 : this.activeClass;
429 var exactActiveClass = this.exactActiveClass == null
430 ? exactActiveClassFallback
431 : this.exactActiveClass;
432 var compareTarget = location.path
433 ? createRoute(null, location, null, router)
434 : route;
435
436 classes[exactActiveClass] = isSameRoute(current, compareTarget);
437 classes[activeClass] = this.exact
438 ? classes[exactActiveClass]
439 : isIncludedRoute(current, compareTarget);
440
441 var handler = function (e) {
442 if (guardEvent(e)) {
443 if (this$1.replace) {
444 router.replace(location);
445 } else {
446 router.push(location);
447 }
448 }
449 };
450
451 var on = { click: guardEvent };
452 if (Array.isArray(this.event)) {
453 this.event.forEach(function (e) { on[e] = handler; });
454 } else {
455 on[this.event] = handler;
456 }
457
458 var data = {
459 class: classes
460 };
461
462 if (this.tag === 'a') {
463 data.on = on;
464 data.attrs = { href: href };
465 } else {
466 // find the first <a> child and apply listener and href
467 var a = findAnchor(this.$slots.default);
468 if (a) {
469 // in case the <a> is a static node
470 a.isStatic = false;
471 var aData = a.data = extend({}, a.data);
472 aData.on = on;
473 var aAttrs = a.data.attrs = extend({}, a.data.attrs);
474 aAttrs.href = href;
475 } else {
476 // doesn't have <a> child, apply listener to self
477 data.on = on;
478 }
479 }
480
481 return h(this.tag, data, this.$slots.default)
482 }
483}
484
485function guardEvent (e) {
486 // don't redirect with control keys
487 if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
488 // don't redirect when preventDefault called
489 if (e.defaultPrevented) { return }
490 // don't redirect on right click
491 if (e.button !== undefined && e.button !== 0) { return }
492 // don't redirect if `target="_blank"`
493 if (e.currentTarget && e.currentTarget.getAttribute) {
494 var target = e.currentTarget.getAttribute('target');
495 if (/\b_blank\b/i.test(target)) { return }
496 }
497 // this may be a Weex event which doesn't have this method
498 if (e.preventDefault) {
499 e.preventDefault();
500 }
501 return true
502}
503
504function findAnchor (children) {
505 if (children) {
506 var child;
507 for (var i = 0; i < children.length; i++) {
508 child = children[i];
509 if (child.tag === 'a') {
510 return child
511 }
512 if (child.children && (child = findAnchor(child.children))) {
513 return child
514 }
515 }
516 }
517}
518
519var _Vue;
520
521function install (Vue) {
522 if (install.installed && _Vue === Vue) { return }
523 install.installed = true;
524
525 _Vue = Vue;
526
527 var isDef = function (v) { return v !== undefined; };
528
529 var registerInstance = function (vm, callVal) {
530 var i = vm.$options._parentVnode;
531 if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
532 i(vm, callVal);
533 }
534 };
535
536 Vue.mixin({
537 beforeCreate: function beforeCreate () {
538 if (isDef(this.$options.router)) {
539 this._routerRoot = this;
540 this._router = this.$options.router;
541 this._router.init(this);
542 Vue.util.defineReactive(this, '_route', this._router.history.current);
543 } else {
544 this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
545 }
546 registerInstance(this, this);
547 },
548 destroyed: function destroyed () {
549 registerInstance(this);
550 }
551 });
552
553 Object.defineProperty(Vue.prototype, '$router', {
554 get: function get () { return this._routerRoot._router }
555 });
556
557 Object.defineProperty(Vue.prototype, '$route', {
558 get: function get () { return this._routerRoot._route }
559 });
560
561 Vue.component('RouterView', View);
562 Vue.component('RouterLink', Link);
563
564 var strats = Vue.config.optionMergeStrategies;
565 // use the same hook merging strategy for route hooks
566 strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created;
567}
568
569/* */
570
571var inBrowser = typeof window !== 'undefined';
572
573/* */
574
575function resolvePath (
576 relative,
577 base,
578 append
579) {
580 var firstChar = relative.charAt(0);
581 if (firstChar === '/') {
582 return relative
583 }
584
585 if (firstChar === '?' || firstChar === '#') {
586 return base + relative
587 }
588
589 var stack = base.split('/');
590
591 // remove trailing segment if:
592 // - not appending
593 // - appending to trailing slash (last segment is empty)
594 if (!append || !stack[stack.length - 1]) {
595 stack.pop();
596 }
597
598 // resolve relative path
599 var segments = relative.replace(/^\//, '').split('/');
600 for (var i = 0; i < segments.length; i++) {
601 var segment = segments[i];
602 if (segment === '..') {
603 stack.pop();
604 } else if (segment !== '.') {
605 stack.push(segment);
606 }
607 }
608
609 // ensure leading slash
610 if (stack[0] !== '') {
611 stack.unshift('');
612 }
613
614 return stack.join('/')
615}
616
617function parsePath (path) {
618 var hash = '';
619 var query = '';
620
621 var hashIndex = path.indexOf('#');
622 if (hashIndex >= 0) {
623 hash = path.slice(hashIndex);
624 path = path.slice(0, hashIndex);
625 }
626
627 var queryIndex = path.indexOf('?');
628 if (queryIndex >= 0) {
629 query = path.slice(queryIndex + 1);
630 path = path.slice(0, queryIndex);
631 }
632
633 return {
634 path: path,
635 query: query,
636 hash: hash
637 }
638}
639
640function cleanPath (path) {
641 return path.replace(/\/\//g, '/')
642}
643
644var isarray = Array.isArray || function (arr) {
645 return Object.prototype.toString.call(arr) == '[object Array]';
646};
647
648/**
649 * Expose `pathToRegexp`.
650 */
651var pathToRegexp_1 = pathToRegexp;
652var parse_1 = parse;
653var compile_1 = compile;
654var tokensToFunction_1 = tokensToFunction;
655var tokensToRegExp_1 = tokensToRegExp;
656
657/**
658 * The main path matching regexp utility.
659 *
660 * @type {RegExp}
661 */
662var PATH_REGEXP = new RegExp([
663 // Match escaped characters that would otherwise appear in future matches.
664 // This allows the user to escape special characters that won't transform.
665 '(\\\\.)',
666 // Match Express-style parameters and un-named parameters with a prefix
667 // and optional suffixes. Matches appear as:
668 //
669 // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
670 // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
671 // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
672 '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
673].join('|'), 'g');
674
675/**
676 * Parse a string for the raw tokens.
677 *
678 * @param {string} str
679 * @param {Object=} options
680 * @return {!Array}
681 */
682function parse (str, options) {
683 var tokens = [];
684 var key = 0;
685 var index = 0;
686 var path = '';
687 var defaultDelimiter = options && options.delimiter || '/';
688 var res;
689
690 while ((res = PATH_REGEXP.exec(str)) != null) {
691 var m = res[0];
692 var escaped = res[1];
693 var offset = res.index;
694 path += str.slice(index, offset);
695 index = offset + m.length;
696
697 // Ignore already escaped sequences.
698 if (escaped) {
699 path += escaped[1];
700 continue
701 }
702
703 var next = str[index];
704 var prefix = res[2];
705 var name = res[3];
706 var capture = res[4];
707 var group = res[5];
708 var modifier = res[6];
709 var asterisk = res[7];
710
711 // Push the current path onto the tokens.
712 if (path) {
713 tokens.push(path);
714 path = '';
715 }
716
717 var partial = prefix != null && next != null && next !== prefix;
718 var repeat = modifier === '+' || modifier === '*';
719 var optional = modifier === '?' || modifier === '*';
720 var delimiter = res[2] || defaultDelimiter;
721 var pattern = capture || group;
722
723 tokens.push({
724 name: name || key++,
725 prefix: prefix || '',
726 delimiter: delimiter,
727 optional: optional,
728 repeat: repeat,
729 partial: partial,
730 asterisk: !!asterisk,
731 pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
732 });
733 }
734
735 // Match any characters still remaining.
736 if (index < str.length) {
737 path += str.substr(index);
738 }
739
740 // If the path exists, push it onto the end.
741 if (path) {
742 tokens.push(path);
743 }
744
745 return tokens
746}
747
748/**
749 * Compile a string to a template function for the path.
750 *
751 * @param {string} str
752 * @param {Object=} options
753 * @return {!function(Object=, Object=)}
754 */
755function compile (str, options) {
756 return tokensToFunction(parse(str, options))
757}
758
759/**
760 * Prettier encoding of URI path segments.
761 *
762 * @param {string}
763 * @return {string}
764 */
765function encodeURIComponentPretty (str) {
766 return encodeURI(str).replace(/[\/?#]/g, function (c) {
767 return '%' + c.charCodeAt(0).toString(16).toUpperCase()
768 })
769}
770
771/**
772 * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
773 *
774 * @param {string}
775 * @return {string}
776 */
777function encodeAsterisk (str) {
778 return encodeURI(str).replace(/[?#]/g, function (c) {
779 return '%' + c.charCodeAt(0).toString(16).toUpperCase()
780 })
781}
782
783/**
784 * Expose a method for transforming tokens into the path function.
785 */
786function tokensToFunction (tokens) {
787 // Compile all the tokens into regexps.
788 var matches = new Array(tokens.length);
789
790 // Compile all the patterns before compilation.
791 for (var i = 0; i < tokens.length; i++) {
792 if (typeof tokens[i] === 'object') {
793 matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
794 }
795 }
796
797 return function (obj, opts) {
798 var path = '';
799 var data = obj || {};
800 var options = opts || {};
801 var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
802
803 for (var i = 0; i < tokens.length; i++) {
804 var token = tokens[i];
805
806 if (typeof token === 'string') {
807 path += token;
808
809 continue
810 }
811
812 var value = data[token.name];
813 var segment;
814
815 if (value == null) {
816 if (token.optional) {
817 // Prepend partial segment prefixes.
818 if (token.partial) {
819 path += token.prefix;
820 }
821
822 continue
823 } else {
824 throw new TypeError('Expected "' + token.name + '" to be defined')
825 }
826 }
827
828 if (isarray(value)) {
829 if (!token.repeat) {
830 throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
831 }
832
833 if (value.length === 0) {
834 if (token.optional) {
835 continue
836 } else {
837 throw new TypeError('Expected "' + token.name + '" to not be empty')
838 }
839 }
840
841 for (var j = 0; j < value.length; j++) {
842 segment = encode(value[j]);
843
844 if (!matches[i].test(segment)) {
845 throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
846 }
847
848 path += (j === 0 ? token.prefix : token.delimiter) + segment;
849 }
850
851 continue
852 }
853
854 segment = token.asterisk ? encodeAsterisk(value) : encode(value);
855
856 if (!matches[i].test(segment)) {
857 throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
858 }
859
860 path += token.prefix + segment;
861 }
862
863 return path
864 }
865}
866
867/**
868 * Escape a regular expression string.
869 *
870 * @param {string} str
871 * @return {string}
872 */
873function escapeString (str) {
874 return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
875}
876
877/**
878 * Escape the capturing group by escaping special characters and meaning.
879 *
880 * @param {string} group
881 * @return {string}
882 */
883function escapeGroup (group) {
884 return group.replace(/([=!:$\/()])/g, '\\$1')
885}
886
887/**
888 * Attach the keys as a property of the regexp.
889 *
890 * @param {!RegExp} re
891 * @param {Array} keys
892 * @return {!RegExp}
893 */
894function attachKeys (re, keys) {
895 re.keys = keys;
896 return re
897}
898
899/**
900 * Get the flags for a regexp from the options.
901 *
902 * @param {Object} options
903 * @return {string}
904 */
905function flags (options) {
906 return options.sensitive ? '' : 'i'
907}
908
909/**
910 * Pull out keys from a regexp.
911 *
912 * @param {!RegExp} path
913 * @param {!Array} keys
914 * @return {!RegExp}
915 */
916function regexpToRegexp (path, keys) {
917 // Use a negative lookahead to match only capturing groups.
918 var groups = path.source.match(/\((?!\?)/g);
919
920 if (groups) {
921 for (var i = 0; i < groups.length; i++) {
922 keys.push({
923 name: i,
924 prefix: null,
925 delimiter: null,
926 optional: false,
927 repeat: false,
928 partial: false,
929 asterisk: false,
930 pattern: null
931 });
932 }
933 }
934
935 return attachKeys(path, keys)
936}
937
938/**
939 * Transform an array into a regexp.
940 *
941 * @param {!Array} path
942 * @param {Array} keys
943 * @param {!Object} options
944 * @return {!RegExp}
945 */
946function arrayToRegexp (path, keys, options) {
947 var parts = [];
948
949 for (var i = 0; i < path.length; i++) {
950 parts.push(pathToRegexp(path[i], keys, options).source);
951 }
952
953 var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
954
955 return attachKeys(regexp, keys)
956}
957
958/**
959 * Create a path regexp from string input.
960 *
961 * @param {string} path
962 * @param {!Array} keys
963 * @param {!Object} options
964 * @return {!RegExp}
965 */
966function stringToRegexp (path, keys, options) {
967 return tokensToRegExp(parse(path, options), keys, options)
968}
969
970/**
971 * Expose a function for taking tokens and returning a RegExp.
972 *
973 * @param {!Array} tokens
974 * @param {(Array|Object)=} keys
975 * @param {Object=} options
976 * @return {!RegExp}
977 */
978function tokensToRegExp (tokens, keys, options) {
979 if (!isarray(keys)) {
980 options = /** @type {!Object} */ (keys || options);
981 keys = [];
982 }
983
984 options = options || {};
985
986 var strict = options.strict;
987 var end = options.end !== false;
988 var route = '';
989
990 // Iterate over the tokens and create our regexp string.
991 for (var i = 0; i < tokens.length; i++) {
992 var token = tokens[i];
993
994 if (typeof token === 'string') {
995 route += escapeString(token);
996 } else {
997 var prefix = escapeString(token.prefix);
998 var capture = '(?:' + token.pattern + ')';
999
1000 keys.push(token);
1001
1002 if (token.repeat) {
1003 capture += '(?:' + prefix + capture + ')*';
1004 }
1005
1006 if (token.optional) {
1007 if (!token.partial) {
1008 capture = '(?:' + prefix + '(' + capture + '))?';
1009 } else {
1010 capture = prefix + '(' + capture + ')?';
1011 }
1012 } else {
1013 capture = prefix + '(' + capture + ')';
1014 }
1015
1016 route += capture;
1017 }
1018 }
1019
1020 var delimiter = escapeString(options.delimiter || '/');
1021 var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
1022
1023 // In non-strict mode we allow a slash at the end of match. If the path to
1024 // match already ends with a slash, we remove it for consistency. The slash
1025 // is valid at the end of a path match, not in the middle. This is important
1026 // in non-ending mode, where "/test/" shouldn't match "/test//route".
1027 if (!strict) {
1028 route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
1029 }
1030
1031 if (end) {
1032 route += '$';
1033 } else {
1034 // In non-ending mode, we need the capturing groups to match as much as
1035 // possible by using a positive lookahead to the end or next path segment.
1036 route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
1037 }
1038
1039 return attachKeys(new RegExp('^' + route, flags(options)), keys)
1040}
1041
1042/**
1043 * Normalize the given path string, returning a regular expression.
1044 *
1045 * An empty array can be passed in for the keys, which will hold the
1046 * placeholder key descriptions. For example, using `/user/:id`, `keys` will
1047 * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
1048 *
1049 * @param {(string|RegExp|Array)} path
1050 * @param {(Array|Object)=} keys
1051 * @param {Object=} options
1052 * @return {!RegExp}
1053 */
1054function pathToRegexp (path, keys, options) {
1055 if (!isarray(keys)) {
1056 options = /** @type {!Object} */ (keys || options);
1057 keys = [];
1058 }
1059
1060 options = options || {};
1061
1062 if (path instanceof RegExp) {
1063 return regexpToRegexp(path, /** @type {!Array} */ (keys))
1064 }
1065
1066 if (isarray(path)) {
1067 return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
1068 }
1069
1070 return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
1071}
1072pathToRegexp_1.parse = parse_1;
1073pathToRegexp_1.compile = compile_1;
1074pathToRegexp_1.tokensToFunction = tokensToFunction_1;
1075pathToRegexp_1.tokensToRegExp = tokensToRegExp_1;
1076
1077/* */
1078
1079// $flow-disable-line
1080var regexpCompileCache = Object.create(null);
1081
1082function fillParams (
1083 path,
1084 params,
1085 routeMsg
1086) {
1087 params = params || {};
1088 try {
1089 var filler =
1090 regexpCompileCache[path] ||
1091 (regexpCompileCache[path] = pathToRegexp_1.compile(path));
1092
1093 // Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
1094 if (params.pathMatch) { params[0] = params.pathMatch; }
1095
1096 return filler(params, { pretty: true })
1097 } catch (e) {
1098 if (process.env.NODE_ENV !== 'production') {
1099 warn(false, ("missing param for " + routeMsg + ": " + (e.message)));
1100 }
1101 return ''
1102 } finally {
1103 // delete the 0 if it was added
1104 delete params[0];
1105 }
1106}
1107
1108/* */
1109
1110function createRouteMap (
1111 routes,
1112 oldPathList,
1113 oldPathMap,
1114 oldNameMap
1115) {
1116 // the path list is used to control path matching priority
1117 var pathList = oldPathList || [];
1118 // $flow-disable-line
1119 var pathMap = oldPathMap || Object.create(null);
1120 // $flow-disable-line
1121 var nameMap = oldNameMap || Object.create(null);
1122
1123 routes.forEach(function (route) {
1124 addRouteRecord(pathList, pathMap, nameMap, route);
1125 });
1126
1127 // ensure wildcard routes are always at the end
1128 for (var i = 0, l = pathList.length; i < l; i++) {
1129 if (pathList[i] === '*') {
1130 pathList.push(pathList.splice(i, 1)[0]);
1131 l--;
1132 i--;
1133 }
1134 }
1135
1136 return {
1137 pathList: pathList,
1138 pathMap: pathMap,
1139 nameMap: nameMap
1140 }
1141}
1142
1143function addRouteRecord (
1144 pathList,
1145 pathMap,
1146 nameMap,
1147 route,
1148 parent,
1149 matchAs
1150) {
1151 var path = route.path;
1152 var name = route.name;
1153 if (process.env.NODE_ENV !== 'production') {
1154 assert(path != null, "\"path\" is required in a route configuration.");
1155 assert(
1156 typeof route.component !== 'string',
1157 "route config \"component\" for path: " + (String(path || name)) + " cannot be a " +
1158 "string id. Use an actual component instead."
1159 );
1160 }
1161
1162 var pathToRegexpOptions = route.pathToRegexpOptions || {};
1163 var normalizedPath = normalizePath(
1164 path,
1165 parent,
1166 pathToRegexpOptions.strict
1167 );
1168
1169 if (typeof route.caseSensitive === 'boolean') {
1170 pathToRegexpOptions.sensitive = route.caseSensitive;
1171 }
1172
1173 var record = {
1174 path: normalizedPath,
1175 regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
1176 components: route.components || { default: route.component },
1177 instances: {},
1178 name: name,
1179 parent: parent,
1180 matchAs: matchAs,
1181 redirect: route.redirect,
1182 beforeEnter: route.beforeEnter,
1183 meta: route.meta || {},
1184 props: route.props == null
1185 ? {}
1186 : route.components
1187 ? route.props
1188 : { default: route.props }
1189 };
1190
1191 if (route.children) {
1192 // Warn if route is named, does not redirect and has a default child route.
1193 // If users navigate to this route by name, the default child will
1194 // not be rendered (GH Issue #629)
1195 if (process.env.NODE_ENV !== 'production') {
1196 if (route.name && !route.redirect && route.children.some(function (child) { return /^\/?$/.test(child.path); })) {
1197 warn(
1198 false,
1199 "Named Route '" + (route.name) + "' has a default child route. " +
1200 "When navigating to this named route (:to=\"{name: '" + (route.name) + "'\"), " +
1201 "the default child route will not be rendered. Remove the name from " +
1202 "this route and use the name of the default child route for named " +
1203 "links instead."
1204 );
1205 }
1206 }
1207 route.children.forEach(function (child) {
1208 var childMatchAs = matchAs
1209 ? cleanPath((matchAs + "/" + (child.path)))
1210 : undefined;
1211 addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs);
1212 });
1213 }
1214
1215 if (route.alias !== undefined) {
1216 var aliases = Array.isArray(route.alias)
1217 ? route.alias
1218 : [route.alias];
1219
1220 aliases.forEach(function (alias) {
1221 var aliasRoute = {
1222 path: alias,
1223 children: route.children
1224 };
1225 addRouteRecord(
1226 pathList,
1227 pathMap,
1228 nameMap,
1229 aliasRoute,
1230 parent,
1231 record.path || '/' // matchAs
1232 );
1233 });
1234 }
1235
1236 if (!pathMap[record.path]) {
1237 pathList.push(record.path);
1238 pathMap[record.path] = record;
1239 }
1240
1241 if (name) {
1242 if (!nameMap[name]) {
1243 nameMap[name] = record;
1244 } else if (process.env.NODE_ENV !== 'production' && !matchAs) {
1245 warn(
1246 false,
1247 "Duplicate named routes definition: " +
1248 "{ name: \"" + name + "\", path: \"" + (record.path) + "\" }"
1249 );
1250 }
1251 }
1252}
1253
1254function compileRouteRegex (path, pathToRegexpOptions) {
1255 var regex = pathToRegexp_1(path, [], pathToRegexpOptions);
1256 if (process.env.NODE_ENV !== 'production') {
1257 var keys = Object.create(null);
1258 regex.keys.forEach(function (key) {
1259 warn(!keys[key.name], ("Duplicate param keys in route with path: \"" + path + "\""));
1260 keys[key.name] = true;
1261 });
1262 }
1263 return regex
1264}
1265
1266function normalizePath (path, parent, strict) {
1267 if (!strict) { path = path.replace(/\/$/, ''); }
1268 if (path[0] === '/') { return path }
1269 if (parent == null) { return path }
1270 return cleanPath(((parent.path) + "/" + path))
1271}
1272
1273/* */
1274
1275function normalizeLocation (
1276 raw,
1277 current,
1278 append,
1279 router
1280) {
1281 var next = typeof raw === 'string' ? { path: raw } : raw;
1282 // named target
1283 if (next._normalized) {
1284 return next
1285 } else if (next.name) {
1286 return extend({}, raw)
1287 }
1288
1289 // relative params
1290 if (!next.path && next.params && current) {
1291 next = extend({}, next);
1292 next._normalized = true;
1293 var params = extend(extend({}, current.params), next.params);
1294 if (current.name) {
1295 next.name = current.name;
1296 next.params = params;
1297 } else if (current.matched.length) {
1298 var rawPath = current.matched[current.matched.length - 1].path;
1299 next.path = fillParams(rawPath, params, ("path " + (current.path)));
1300 } else if (process.env.NODE_ENV !== 'production') {
1301 warn(false, "relative params navigation requires a current route.");
1302 }
1303 return next
1304 }
1305
1306 var parsedPath = parsePath(next.path || '');
1307 var basePath = (current && current.path) || '/';
1308 var path = parsedPath.path
1309 ? resolvePath(parsedPath.path, basePath, append || next.append)
1310 : basePath;
1311
1312 var query = resolveQuery(
1313 parsedPath.query,
1314 next.query,
1315 router && router.options.parseQuery
1316 );
1317
1318 var hash = next.hash || parsedPath.hash;
1319 if (hash && hash.charAt(0) !== '#') {
1320 hash = "#" + hash;
1321 }
1322
1323 return {
1324 _normalized: true,
1325 path: path,
1326 query: query,
1327 hash: hash
1328 }
1329}
1330
1331/* */
1332
1333
1334
1335function createMatcher (
1336 routes,
1337 router
1338) {
1339 var ref = createRouteMap(routes);
1340 var pathList = ref.pathList;
1341 var pathMap = ref.pathMap;
1342 var nameMap = ref.nameMap;
1343
1344 function addRoutes (routes) {
1345 createRouteMap(routes, pathList, pathMap, nameMap);
1346 }
1347
1348 function match (
1349 raw,
1350 currentRoute,
1351 redirectedFrom
1352 ) {
1353 var location = normalizeLocation(raw, currentRoute, false, router);
1354 var name = location.name;
1355
1356 if (name) {
1357 var record = nameMap[name];
1358 if (process.env.NODE_ENV !== 'production') {
1359 warn(record, ("Route with name '" + name + "' does not exist"));
1360 }
1361 if (!record) { return _createRoute(null, location) }
1362 var paramNames = record.regex.keys
1363 .filter(function (key) { return !key.optional; })
1364 .map(function (key) { return key.name; });
1365
1366 if (typeof location.params !== 'object') {
1367 location.params = {};
1368 }
1369
1370 if (currentRoute && typeof currentRoute.params === 'object') {
1371 for (var key in currentRoute.params) {
1372 if (!(key in location.params) && paramNames.indexOf(key) > -1) {
1373 location.params[key] = currentRoute.params[key];
1374 }
1375 }
1376 }
1377
1378 if (record) {
1379 location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""));
1380 return _createRoute(record, location, redirectedFrom)
1381 }
1382 } else if (location.path) {
1383 location.params = {};
1384 for (var i = 0; i < pathList.length; i++) {
1385 var path = pathList[i];
1386 var record$1 = pathMap[path];
1387 if (matchRoute(record$1.regex, location.path, location.params)) {
1388 return _createRoute(record$1, location, redirectedFrom)
1389 }
1390 }
1391 }
1392 // no match
1393 return _createRoute(null, location)
1394 }
1395
1396 function redirect (
1397 record,
1398 location
1399 ) {
1400 var originalRedirect = record.redirect;
1401 var redirect = typeof originalRedirect === 'function'
1402 ? originalRedirect(createRoute(record, location, null, router))
1403 : originalRedirect;
1404
1405 if (typeof redirect === 'string') {
1406 redirect = { path: redirect };
1407 }
1408
1409 if (!redirect || typeof redirect !== 'object') {
1410 if (process.env.NODE_ENV !== 'production') {
1411 warn(
1412 false, ("invalid redirect option: " + (JSON.stringify(redirect)))
1413 );
1414 }
1415 return _createRoute(null, location)
1416 }
1417
1418 var re = redirect;
1419 var name = re.name;
1420 var path = re.path;
1421 var query = location.query;
1422 var hash = location.hash;
1423 var params = location.params;
1424 query = re.hasOwnProperty('query') ? re.query : query;
1425 hash = re.hasOwnProperty('hash') ? re.hash : hash;
1426 params = re.hasOwnProperty('params') ? re.params : params;
1427
1428 if (name) {
1429 // resolved named direct
1430 var targetRecord = nameMap[name];
1431 if (process.env.NODE_ENV !== 'production') {
1432 assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."));
1433 }
1434 return match({
1435 _normalized: true,
1436 name: name,
1437 query: query,
1438 hash: hash,
1439 params: params
1440 }, undefined, location)
1441 } else if (path) {
1442 // 1. resolve relative redirect
1443 var rawPath = resolveRecordPath(path, record);
1444 // 2. resolve params
1445 var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""));
1446 // 3. rematch with existing query and hash
1447 return match({
1448 _normalized: true,
1449 path: resolvedPath,
1450 query: query,
1451 hash: hash
1452 }, undefined, location)
1453 } else {
1454 if (process.env.NODE_ENV !== 'production') {
1455 warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))));
1456 }
1457 return _createRoute(null, location)
1458 }
1459 }
1460
1461 function alias (
1462 record,
1463 location,
1464 matchAs
1465 ) {
1466 var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""));
1467 var aliasedMatch = match({
1468 _normalized: true,
1469 path: aliasedPath
1470 });
1471 if (aliasedMatch) {
1472 var matched = aliasedMatch.matched;
1473 var aliasedRecord = matched[matched.length - 1];
1474 location.params = aliasedMatch.params;
1475 return _createRoute(aliasedRecord, location)
1476 }
1477 return _createRoute(null, location)
1478 }
1479
1480 function _createRoute (
1481 record,
1482 location,
1483 redirectedFrom
1484 ) {
1485 if (record && record.redirect) {
1486 return redirect(record, redirectedFrom || location)
1487 }
1488 if (record && record.matchAs) {
1489 return alias(record, location, record.matchAs)
1490 }
1491 return createRoute(record, location, redirectedFrom, router)
1492 }
1493
1494 return {
1495 match: match,
1496 addRoutes: addRoutes
1497 }
1498}
1499
1500function matchRoute (
1501 regex,
1502 path,
1503 params
1504) {
1505 var m = path.match(regex);
1506
1507 if (!m) {
1508 return false
1509 } else if (!params) {
1510 return true
1511 }
1512
1513 for (var i = 1, len = m.length; i < len; ++i) {
1514 var key = regex.keys[i - 1];
1515 var val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];
1516 if (key) {
1517 // Fix #1994: using * with props: true generates a param named 0
1518 params[key.name || 'pathMatch'] = val;
1519 }
1520 }
1521
1522 return true
1523}
1524
1525function resolveRecordPath (path, record) {
1526 return resolvePath(path, record.parent ? record.parent.path : '/', true)
1527}
1528
1529/* */
1530
1531var positionStore = Object.create(null);
1532
1533function setupScroll () {
1534 // Fix for #1585 for Firefox
1535 // Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678
1536 window.history.replaceState({ key: getStateKey() }, '', window.location.href.replace(window.location.origin, ''));
1537 window.addEventListener('popstate', function (e) {
1538 saveScrollPosition();
1539 if (e.state && e.state.key) {
1540 setStateKey(e.state.key);
1541 }
1542 });
1543}
1544
1545function handleScroll (
1546 router,
1547 to,
1548 from,
1549 isPop
1550) {
1551 if (!router.app) {
1552 return
1553 }
1554
1555 var behavior = router.options.scrollBehavior;
1556 if (!behavior) {
1557 return
1558 }
1559
1560 if (process.env.NODE_ENV !== 'production') {
1561 assert(typeof behavior === 'function', "scrollBehavior must be a function");
1562 }
1563
1564 // wait until re-render finishes before scrolling
1565 router.app.$nextTick(function () {
1566 var position = getScrollPosition();
1567 var shouldScroll = behavior.call(router, to, from, isPop ? position : null);
1568
1569 if (!shouldScroll) {
1570 return
1571 }
1572
1573 if (typeof shouldScroll.then === 'function') {
1574 shouldScroll.then(function (shouldScroll) {
1575 scrollToPosition((shouldScroll), position);
1576 }).catch(function (err) {
1577 if (process.env.NODE_ENV !== 'production') {
1578 assert(false, err.toString());
1579 }
1580 });
1581 } else {
1582 scrollToPosition(shouldScroll, position);
1583 }
1584 });
1585}
1586
1587function saveScrollPosition () {
1588 var key = getStateKey();
1589 if (key) {
1590 positionStore[key] = {
1591 x: window.pageXOffset,
1592 y: window.pageYOffset
1593 };
1594 }
1595}
1596
1597function getScrollPosition () {
1598 var key = getStateKey();
1599 if (key) {
1600 return positionStore[key]
1601 }
1602}
1603
1604function getElementPosition (el, offset) {
1605 var docEl = document.documentElement;
1606 var docRect = docEl.getBoundingClientRect();
1607 var elRect = el.getBoundingClientRect();
1608 return {
1609 x: elRect.left - docRect.left - offset.x,
1610 y: elRect.top - docRect.top - offset.y
1611 }
1612}
1613
1614function isValidPosition (obj) {
1615 return isNumber(obj.x) || isNumber(obj.y)
1616}
1617
1618function normalizePosition (obj) {
1619 return {
1620 x: isNumber(obj.x) ? obj.x : window.pageXOffset,
1621 y: isNumber(obj.y) ? obj.y : window.pageYOffset
1622 }
1623}
1624
1625function normalizeOffset (obj) {
1626 return {
1627 x: isNumber(obj.x) ? obj.x : 0,
1628 y: isNumber(obj.y) ? obj.y : 0
1629 }
1630}
1631
1632function isNumber (v) {
1633 return typeof v === 'number'
1634}
1635
1636function scrollToPosition (shouldScroll, position) {
1637 var isObject = typeof shouldScroll === 'object';
1638 if (isObject && typeof shouldScroll.selector === 'string') {
1639 var el = document.querySelector(shouldScroll.selector);
1640 if (el) {
1641 var offset = shouldScroll.offset && typeof shouldScroll.offset === 'object' ? shouldScroll.offset : {};
1642 offset = normalizeOffset(offset);
1643 position = getElementPosition(el, offset);
1644 } else if (isValidPosition(shouldScroll)) {
1645 position = normalizePosition(shouldScroll);
1646 }
1647 } else if (isObject && isValidPosition(shouldScroll)) {
1648 position = normalizePosition(shouldScroll);
1649 }
1650
1651 if (position) {
1652 window.scrollTo(position.x, position.y);
1653 }
1654}
1655
1656/* */
1657
1658var supportsPushState = inBrowser && (function () {
1659 var ua = window.navigator.userAgent;
1660
1661 if (
1662 (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
1663 ua.indexOf('Mobile Safari') !== -1 &&
1664 ua.indexOf('Chrome') === -1 &&
1665 ua.indexOf('Windows Phone') === -1
1666 ) {
1667 return false
1668 }
1669
1670 return window.history && 'pushState' in window.history
1671})();
1672
1673// use User Timing api (if present) for more accurate key precision
1674var Time = inBrowser && window.performance && window.performance.now
1675 ? window.performance
1676 : Date;
1677
1678var _key = genKey();
1679
1680function genKey () {
1681 return Time.now().toFixed(3)
1682}
1683
1684function getStateKey () {
1685 return _key
1686}
1687
1688function setStateKey (key) {
1689 _key = key;
1690}
1691
1692function pushState (url, replace) {
1693 saveScrollPosition();
1694 // try...catch the pushState call to get around Safari
1695 // DOM Exception 18 where it limits to 100 pushState calls
1696 var history = window.history;
1697 try {
1698 if (replace) {
1699 history.replaceState({ key: _key }, '', url);
1700 } else {
1701 _key = genKey();
1702 history.pushState({ key: _key }, '', url);
1703 }
1704 } catch (e) {
1705 window.location[replace ? 'replace' : 'assign'](url);
1706 }
1707}
1708
1709function replaceState (url) {
1710 pushState(url, true);
1711}
1712
1713/* */
1714
1715function runQueue (queue, fn, cb) {
1716 var step = function (index) {
1717 if (index >= queue.length) {
1718 cb();
1719 } else {
1720 if (queue[index]) {
1721 fn(queue[index], function () {
1722 step(index + 1);
1723 });
1724 } else {
1725 step(index + 1);
1726 }
1727 }
1728 };
1729 step(0);
1730}
1731
1732/* */
1733
1734function resolveAsyncComponents (matched) {
1735 return function (to, from, next) {
1736 var hasAsync = false;
1737 var pending = 0;
1738 var error = null;
1739
1740 flatMapComponents(matched, function (def, _, match, key) {
1741 // if it's a function and doesn't have cid attached,
1742 // assume it's an async component resolve function.
1743 // we are not using Vue's default async resolving mechanism because
1744 // we want to halt the navigation until the incoming component has been
1745 // resolved.
1746 if (typeof def === 'function' && def.cid === undefined) {
1747 hasAsync = true;
1748 pending++;
1749
1750 var resolve = once(function (resolvedDef) {
1751 if (isESModule(resolvedDef)) {
1752 resolvedDef = resolvedDef.default;
1753 }
1754 // save resolved on async factory in case it's used elsewhere
1755 def.resolved = typeof resolvedDef === 'function'
1756 ? resolvedDef
1757 : _Vue.extend(resolvedDef);
1758 match.components[key] = resolvedDef;
1759 pending--;
1760 if (pending <= 0) {
1761 next();
1762 }
1763 });
1764
1765 var reject = once(function (reason) {
1766 var msg = "Failed to resolve async component " + key + ": " + reason;
1767 process.env.NODE_ENV !== 'production' && warn(false, msg);
1768 if (!error) {
1769 error = isError(reason)
1770 ? reason
1771 : new Error(msg);
1772 next(error);
1773 }
1774 });
1775
1776 var res;
1777 try {
1778 res = def(resolve, reject);
1779 } catch (e) {
1780 reject(e);
1781 }
1782 if (res) {
1783 if (typeof res.then === 'function') {
1784 res.then(resolve, reject);
1785 } else {
1786 // new syntax in Vue 2.3
1787 var comp = res.component;
1788 if (comp && typeof comp.then === 'function') {
1789 comp.then(resolve, reject);
1790 }
1791 }
1792 }
1793 }
1794 });
1795
1796 if (!hasAsync) { next(); }
1797 }
1798}
1799
1800function flatMapComponents (
1801 matched,
1802 fn
1803) {
1804 return flatten(matched.map(function (m) {
1805 return Object.keys(m.components).map(function (key) { return fn(
1806 m.components[key],
1807 m.instances[key],
1808 m, key
1809 ); })
1810 }))
1811}
1812
1813function flatten (arr) {
1814 return Array.prototype.concat.apply([], arr)
1815}
1816
1817var hasSymbol =
1818 typeof Symbol === 'function' &&
1819 typeof Symbol.toStringTag === 'symbol';
1820
1821function isESModule (obj) {
1822 return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
1823}
1824
1825// in Webpack 2, require.ensure now also returns a Promise
1826// so the resolve/reject functions may get called an extra time
1827// if the user uses an arrow function shorthand that happens to
1828// return that Promise.
1829function once (fn) {
1830 var called = false;
1831 return function () {
1832 var args = [], len = arguments.length;
1833 while ( len-- ) args[ len ] = arguments[ len ];
1834
1835 if (called) { return }
1836 called = true;
1837 return fn.apply(this, args)
1838 }
1839}
1840
1841/* */
1842
1843var History = function History (router, base) {
1844 this.router = router;
1845 this.base = normalizeBase(base);
1846 // start with a route object that stands for "nowhere"
1847 this.current = START;
1848 this.pending = null;
1849 this.ready = false;
1850 this.readyCbs = [];
1851 this.readyErrorCbs = [];
1852 this.errorCbs = [];
1853};
1854
1855History.prototype.listen = function listen (cb) {
1856 this.cb = cb;
1857};
1858
1859History.prototype.onReady = function onReady (cb, errorCb) {
1860 if (this.ready) {
1861 cb();
1862 } else {
1863 this.readyCbs.push(cb);
1864 if (errorCb) {
1865 this.readyErrorCbs.push(errorCb);
1866 }
1867 }
1868};
1869
1870History.prototype.onError = function onError (errorCb) {
1871 this.errorCbs.push(errorCb);
1872};
1873
1874History.prototype.transitionTo = function transitionTo (location, onComplete, onAbort) {
1875 var this$1 = this;
1876
1877 var route = this.router.match(location, this.current);
1878 this.confirmTransition(route, function () {
1879 this$1.updateRoute(route);
1880 onComplete && onComplete(route);
1881 this$1.ensureURL();
1882
1883 // fire ready cbs once
1884 if (!this$1.ready) {
1885 this$1.ready = true;
1886 this$1.readyCbs.forEach(function (cb) { cb(route); });
1887 }
1888 }, function (err) {
1889 if (onAbort) {
1890 onAbort(err);
1891 }
1892 if (err && !this$1.ready) {
1893 this$1.ready = true;
1894 this$1.readyErrorCbs.forEach(function (cb) { cb(err); });
1895 }
1896 });
1897};
1898
1899History.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {
1900 var this$1 = this;
1901
1902 var current = this.current;
1903 var abort = function (err) {
1904 if (isError(err)) {
1905 if (this$1.errorCbs.length) {
1906 this$1.errorCbs.forEach(function (cb) { cb(err); });
1907 } else {
1908 warn(false, 'uncaught error during route navigation:');
1909 console.error(err);
1910 }
1911 }
1912 onAbort && onAbort(err);
1913 };
1914 if (
1915 isSameRoute(route, current) &&
1916 // in the case the route map has been dynamically appended to
1917 route.matched.length === current.matched.length
1918 ) {
1919 this.ensureURL();
1920 return abort()
1921 }
1922
1923 var ref = resolveQueue(this.current.matched, route.matched);
1924 var updated = ref.updated;
1925 var deactivated = ref.deactivated;
1926 var activated = ref.activated;
1927
1928 var queue = [].concat(
1929 // in-component leave guards
1930 extractLeaveGuards(deactivated),
1931 // global before hooks
1932 this.router.beforeHooks,
1933 // in-component update hooks
1934 extractUpdateHooks(updated),
1935 // in-config enter guards
1936 activated.map(function (m) { return m.beforeEnter; }),
1937 // async components
1938 resolveAsyncComponents(activated)
1939 );
1940
1941 this.pending = route;
1942 var iterator = function (hook, next) {
1943 if (this$1.pending !== route) {
1944 return abort()
1945 }
1946 try {
1947 hook(route, current, function (to) {
1948 if (to === false || isError(to)) {
1949 // next(false) -> abort navigation, ensure current URL
1950 this$1.ensureURL(true);
1951 abort(to);
1952 } else if (
1953 typeof to === 'string' ||
1954 (typeof to === 'object' && (
1955 typeof to.path === 'string' ||
1956 typeof to.name === 'string'
1957 ))
1958 ) {
1959 // next('/') or next({ path: '/' }) -> redirect
1960 abort();
1961 if (typeof to === 'object' && to.replace) {
1962 this$1.replace(to);
1963 } else {
1964 this$1.push(to);
1965 }
1966 } else {
1967 // confirm transition and pass on the value
1968 next(to);
1969 }
1970 });
1971 } catch (e) {
1972 abort(e);
1973 }
1974 };
1975
1976 runQueue(queue, iterator, function () {
1977 var postEnterCbs = [];
1978 var isValid = function () { return this$1.current === route; };
1979 // wait until async components are resolved before
1980 // extracting in-component enter guards
1981 var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
1982 var queue = enterGuards.concat(this$1.router.resolveHooks);
1983 runQueue(queue, iterator, function () {
1984 if (this$1.pending !== route) {
1985 return abort()
1986 }
1987 this$1.pending = null;
1988 onComplete(route);
1989 if (this$1.router.app) {
1990 this$1.router.app.$nextTick(function () {
1991 postEnterCbs.forEach(function (cb) { cb(); });
1992 });
1993 }
1994 });
1995 });
1996};
1997
1998History.prototype.updateRoute = function updateRoute (route) {
1999 var prev = this.current;
2000 this.current = route;
2001 this.cb && this.cb(route);
2002 this.router.afterHooks.forEach(function (hook) {
2003 hook && hook(route, prev);
2004 });
2005};
2006
2007function normalizeBase (base) {
2008 if (!base) {
2009 if (inBrowser) {
2010 // respect <base> tag
2011 var baseEl = document.querySelector('base');
2012 base = (baseEl && baseEl.getAttribute('href')) || '/';
2013 // strip full URL origin
2014 base = base.replace(/^https?:\/\/[^\/]+/, '');
2015 } else {
2016 base = '/';
2017 }
2018 }
2019 // make sure there's the starting slash
2020 if (base.charAt(0) !== '/') {
2021 base = '/' + base;
2022 }
2023 // remove trailing slash
2024 return base.replace(/\/$/, '')
2025}
2026
2027function resolveQueue (
2028 current,
2029 next
2030) {
2031 var i;
2032 var max = Math.max(current.length, next.length);
2033 for (i = 0; i < max; i++) {
2034 if (current[i] !== next[i]) {
2035 break
2036 }
2037 }
2038 return {
2039 updated: next.slice(0, i),
2040 activated: next.slice(i),
2041 deactivated: current.slice(i)
2042 }
2043}
2044
2045function extractGuards (
2046 records,
2047 name,
2048 bind,
2049 reverse
2050) {
2051 var guards = flatMapComponents(records, function (def, instance, match, key) {
2052 var guard = extractGuard(def, name);
2053 if (guard) {
2054 return Array.isArray(guard)
2055 ? guard.map(function (guard) { return bind(guard, instance, match, key); })
2056 : bind(guard, instance, match, key)
2057 }
2058 });
2059 return flatten(reverse ? guards.reverse() : guards)
2060}
2061
2062function extractGuard (
2063 def,
2064 key
2065) {
2066 if (typeof def !== 'function') {
2067 // extend now so that global mixins are applied.
2068 def = _Vue.extend(def);
2069 }
2070 return def.options[key]
2071}
2072
2073function extractLeaveGuards (deactivated) {
2074 return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
2075}
2076
2077function extractUpdateHooks (updated) {
2078 return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
2079}
2080
2081function bindGuard (guard, instance) {
2082 if (instance) {
2083 return function boundRouteGuard () {
2084 return guard.apply(instance, arguments)
2085 }
2086 }
2087}
2088
2089function extractEnterGuards (
2090 activated,
2091 cbs,
2092 isValid
2093) {
2094 return extractGuards(activated, 'beforeRouteEnter', function (guard, _, match, key) {
2095 return bindEnterGuard(guard, match, key, cbs, isValid)
2096 })
2097}
2098
2099function bindEnterGuard (
2100 guard,
2101 match,
2102 key,
2103 cbs,
2104 isValid
2105) {
2106 return function routeEnterGuard (to, from, next) {
2107 return guard(to, from, function (cb) {
2108 next(cb);
2109 if (typeof cb === 'function') {
2110 cbs.push(function () {
2111 // #750
2112 // if a router-view is wrapped with an out-in transition,
2113 // the instance may not have been registered at this time.
2114 // we will need to poll for registration until current route
2115 // is no longer valid.
2116 poll(cb, match.instances, key, isValid);
2117 });
2118 }
2119 })
2120 }
2121}
2122
2123function poll (
2124 cb, // somehow flow cannot infer this is a function
2125 instances,
2126 key,
2127 isValid
2128) {
2129 if (
2130 instances[key] &&
2131 !instances[key]._isBeingDestroyed // do not reuse being destroyed instance
2132 ) {
2133 cb(instances[key]);
2134 } else if (isValid()) {
2135 setTimeout(function () {
2136 poll(cb, instances, key, isValid);
2137 }, 16);
2138 }
2139}
2140
2141/* */
2142
2143var HTML5History = /*@__PURE__*/(function (History$$1) {
2144 function HTML5History (router, base) {
2145 var this$1 = this;
2146
2147 History$$1.call(this, router, base);
2148
2149 var expectScroll = router.options.scrollBehavior;
2150 var supportsScroll = supportsPushState && expectScroll;
2151
2152 if (supportsScroll) {
2153 setupScroll();
2154 }
2155
2156 var initLocation = getLocation(this.base);
2157 window.addEventListener('popstate', function (e) {
2158 var current = this$1.current;
2159
2160 // Avoiding first `popstate` event dispatched in some browsers but first
2161 // history route not updated since async guard at the same time.
2162 var location = getLocation(this$1.base);
2163 if (this$1.current === START && location === initLocation) {
2164 return
2165 }
2166
2167 this$1.transitionTo(location, function (route) {
2168 if (supportsScroll) {
2169 handleScroll(router, route, current, true);
2170 }
2171 });
2172 });
2173 }
2174
2175 if ( History$$1 ) HTML5History.__proto__ = History$$1;
2176 HTML5History.prototype = Object.create( History$$1 && History$$1.prototype );
2177 HTML5History.prototype.constructor = HTML5History;
2178
2179 HTML5History.prototype.go = function go (n) {
2180 window.history.go(n);
2181 };
2182
2183 HTML5History.prototype.push = function push (location, onComplete, onAbort) {
2184 var this$1 = this;
2185
2186 var ref = this;
2187 var fromRoute = ref.current;
2188 this.transitionTo(location, function (route) {
2189 pushState(cleanPath(this$1.base + route.fullPath));
2190 handleScroll(this$1.router, route, fromRoute, false);
2191 onComplete && onComplete(route);
2192 }, onAbort);
2193 };
2194
2195 HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {
2196 var this$1 = this;
2197
2198 var ref = this;
2199 var fromRoute = ref.current;
2200 this.transitionTo(location, function (route) {
2201 replaceState(cleanPath(this$1.base + route.fullPath));
2202 handleScroll(this$1.router, route, fromRoute, false);
2203 onComplete && onComplete(route);
2204 }, onAbort);
2205 };
2206
2207 HTML5History.prototype.ensureURL = function ensureURL (push) {
2208 if (getLocation(this.base) !== this.current.fullPath) {
2209 var current = cleanPath(this.base + this.current.fullPath);
2210 push ? pushState(current) : replaceState(current);
2211 }
2212 };
2213
2214 HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {
2215 return getLocation(this.base)
2216 };
2217
2218 return HTML5History;
2219}(History));
2220
2221function getLocation (base) {
2222 var path = decodeURI(window.location.pathname);
2223 if (base && path.indexOf(base) === 0) {
2224 path = path.slice(base.length);
2225 }
2226 return (path || '/') + window.location.search + window.location.hash
2227}
2228
2229/* */
2230
2231var HashHistory = /*@__PURE__*/(function (History$$1) {
2232 function HashHistory (router, base, fallback) {
2233 History$$1.call(this, router, base);
2234 // check history fallback deeplinking
2235 if (fallback && checkFallback(this.base)) {
2236 return
2237 }
2238 ensureSlash();
2239 }
2240
2241 if ( History$$1 ) HashHistory.__proto__ = History$$1;
2242 HashHistory.prototype = Object.create( History$$1 && History$$1.prototype );
2243 HashHistory.prototype.constructor = HashHistory;
2244
2245 // this is delayed until the app mounts
2246 // to avoid the hashchange listener being fired too early
2247 HashHistory.prototype.setupListeners = function setupListeners () {
2248 var this$1 = this;
2249
2250 var router = this.router;
2251 var expectScroll = router.options.scrollBehavior;
2252 var supportsScroll = supportsPushState && expectScroll;
2253
2254 if (supportsScroll) {
2255 setupScroll();
2256 }
2257
2258 window.addEventListener(supportsPushState ? 'popstate' : 'hashchange', function () {
2259 var current = this$1.current;
2260 if (!ensureSlash()) {
2261 return
2262 }
2263 this$1.transitionTo(getHash(), function (route) {
2264 if (supportsScroll) {
2265 handleScroll(this$1.router, route, current, true);
2266 }
2267 if (!supportsPushState) {
2268 replaceHash(route.fullPath);
2269 }
2270 });
2271 });
2272 };
2273
2274 HashHistory.prototype.push = function push (location, onComplete, onAbort) {
2275 var this$1 = this;
2276
2277 var ref = this;
2278 var fromRoute = ref.current;
2279 this.transitionTo(location, function (route) {
2280 pushHash(route.fullPath);
2281 handleScroll(this$1.router, route, fromRoute, false);
2282 onComplete && onComplete(route);
2283 }, onAbort);
2284 };
2285
2286 HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {
2287 var this$1 = this;
2288
2289 var ref = this;
2290 var fromRoute = ref.current;
2291 this.transitionTo(location, function (route) {
2292 replaceHash(route.fullPath);
2293 handleScroll(this$1.router, route, fromRoute, false);
2294 onComplete && onComplete(route);
2295 }, onAbort);
2296 };
2297
2298 HashHistory.prototype.go = function go (n) {
2299 window.history.go(n);
2300 };
2301
2302 HashHistory.prototype.ensureURL = function ensureURL (push) {
2303 var current = this.current.fullPath;
2304 if (getHash() !== current) {
2305 push ? pushHash(current) : replaceHash(current);
2306 }
2307 };
2308
2309 HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {
2310 return getHash()
2311 };
2312
2313 return HashHistory;
2314}(History));
2315
2316function checkFallback (base) {
2317 var location = getLocation(base);
2318 if (!/^\/#/.test(location)) {
2319 window.location.replace(
2320 cleanPath(base + '/#' + location)
2321 );
2322 return true
2323 }
2324}
2325
2326function ensureSlash () {
2327 var path = getHash();
2328 if (path.charAt(0) === '/') {
2329 return true
2330 }
2331 replaceHash('/' + path);
2332 return false
2333}
2334
2335function getHash () {
2336 // We can't use window.location.hash here because it's not
2337 // consistent across browsers - Firefox will pre-decode it!
2338 var href = window.location.href;
2339 var index = href.indexOf('#');
2340 // empty path
2341 if (index < 0) { return '' }
2342
2343 href = href.slice(index + 1);
2344 // decode the hash but not the search or hash
2345 // as search(query) is already decoded
2346 // https://github.com/vuejs/vue-router/issues/2708
2347 var searchIndex = href.indexOf('?');
2348 if (searchIndex < 0) {
2349 var hashIndex = href.indexOf('#');
2350 if (hashIndex > -1) { href = decodeURI(href.slice(0, hashIndex)) + href.slice(hashIndex); }
2351 else { href = decodeURI(href); }
2352 } else {
2353 if (searchIndex > -1) { href = decodeURI(href.slice(0, searchIndex)) + href.slice(searchIndex); }
2354 }
2355
2356 return href
2357}
2358
2359function getUrl (path) {
2360 var href = window.location.href;
2361 var i = href.indexOf('#');
2362 var base = i >= 0 ? href.slice(0, i) : href;
2363 return (base + "#" + path)
2364}
2365
2366function pushHash (path) {
2367 if (supportsPushState) {
2368 pushState(getUrl(path));
2369 } else {
2370 window.location.hash = path;
2371 }
2372}
2373
2374function replaceHash (path) {
2375 if (supportsPushState) {
2376 replaceState(getUrl(path));
2377 } else {
2378 window.location.replace(getUrl(path));
2379 }
2380}
2381
2382/* */
2383
2384var AbstractHistory = /*@__PURE__*/(function (History$$1) {
2385 function AbstractHistory (router, base) {
2386 History$$1.call(this, router, base);
2387 this.stack = [];
2388 this.index = -1;
2389 }
2390
2391 if ( History$$1 ) AbstractHistory.__proto__ = History$$1;
2392 AbstractHistory.prototype = Object.create( History$$1 && History$$1.prototype );
2393 AbstractHistory.prototype.constructor = AbstractHistory;
2394
2395 AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {
2396 var this$1 = this;
2397
2398 this.transitionTo(location, function (route) {
2399 this$1.stack = this$1.stack.slice(0, this$1.index + 1).concat(route);
2400 this$1.index++;
2401 onComplete && onComplete(route);
2402 }, onAbort);
2403 };
2404
2405 AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {
2406 var this$1 = this;
2407
2408 this.transitionTo(location, function (route) {
2409 this$1.stack = this$1.stack.slice(0, this$1.index).concat(route);
2410 onComplete && onComplete(route);
2411 }, onAbort);
2412 };
2413
2414 AbstractHistory.prototype.go = function go (n) {
2415 var this$1 = this;
2416
2417 var targetIndex = this.index + n;
2418 if (targetIndex < 0 || targetIndex >= this.stack.length) {
2419 return
2420 }
2421 var route = this.stack[targetIndex];
2422 this.confirmTransition(route, function () {
2423 this$1.index = targetIndex;
2424 this$1.updateRoute(route);
2425 });
2426 };
2427
2428 AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {
2429 var current = this.stack[this.stack.length - 1];
2430 return current ? current.fullPath : '/'
2431 };
2432
2433 AbstractHistory.prototype.ensureURL = function ensureURL () {
2434 // noop
2435 };
2436
2437 return AbstractHistory;
2438}(History));
2439
2440/* */
2441
2442
2443
2444var VueRouter = function VueRouter (options) {
2445 if ( options === void 0 ) options = {};
2446
2447 this.app = null;
2448 this.apps = [];
2449 this.options = options;
2450 this.beforeHooks = [];
2451 this.resolveHooks = [];
2452 this.afterHooks = [];
2453 this.matcher = createMatcher(options.routes || [], this);
2454
2455 var mode = options.mode || 'hash';
2456 this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false;
2457 if (this.fallback) {
2458 mode = 'hash';
2459 }
2460 if (!inBrowser) {
2461 mode = 'abstract';
2462 }
2463 this.mode = mode;
2464
2465 switch (mode) {
2466 case 'history':
2467 this.history = new HTML5History(this, options.base);
2468 break
2469 case 'hash':
2470 this.history = new HashHistory(this, options.base, this.fallback);
2471 break
2472 case 'abstract':
2473 this.history = new AbstractHistory(this, options.base);
2474 break
2475 default:
2476 if (process.env.NODE_ENV !== 'production') {
2477 assert(false, ("invalid mode: " + mode));
2478 }
2479 }
2480};
2481
2482var prototypeAccessors = { currentRoute: { configurable: true } };
2483
2484VueRouter.prototype.match = function match (
2485 raw,
2486 current,
2487 redirectedFrom
2488) {
2489 return this.matcher.match(raw, current, redirectedFrom)
2490};
2491
2492prototypeAccessors.currentRoute.get = function () {
2493 return this.history && this.history.current
2494};
2495
2496VueRouter.prototype.init = function init (app /* Vue component instance */) {
2497 var this$1 = this;
2498
2499 process.env.NODE_ENV !== 'production' && assert(
2500 install.installed,
2501 "not installed. Make sure to call `Vue.use(VueRouter)` " +
2502 "before creating root instance."
2503 );
2504
2505 this.apps.push(app);
2506
2507 // set up app destroyed handler
2508 // https://github.com/vuejs/vue-router/issues/2639
2509 app.$once('hook:destroyed', function () {
2510 // clean out app from this.apps array once destroyed
2511 var index = this$1.apps.indexOf(app);
2512 if (index > -1) { this$1.apps.splice(index, 1); }
2513 // ensure we still have a main app or null if no apps
2514 // we do not release the router so it can be reused
2515 if (this$1.app === app) { this$1.app = this$1.apps[0] || null; }
2516 });
2517
2518 // main app previously initialized
2519 // return as we don't need to set up new history listener
2520 if (this.app) {
2521 return
2522 }
2523
2524 this.app = app;
2525
2526 var history = this.history;
2527
2528 if (history instanceof HTML5History) {
2529 history.transitionTo(history.getCurrentLocation());
2530 } else if (history instanceof HashHistory) {
2531 var setupHashListener = function () {
2532 history.setupListeners();
2533 };
2534 history.transitionTo(
2535 history.getCurrentLocation(),
2536 setupHashListener,
2537 setupHashListener
2538 );
2539 }
2540
2541 history.listen(function (route) {
2542 this$1.apps.forEach(function (app) {
2543 app._route = route;
2544 });
2545 });
2546};
2547
2548VueRouter.prototype.beforeEach = function beforeEach (fn) {
2549 return registerHook(this.beforeHooks, fn)
2550};
2551
2552VueRouter.prototype.beforeResolve = function beforeResolve (fn) {
2553 return registerHook(this.resolveHooks, fn)
2554};
2555
2556VueRouter.prototype.afterEach = function afterEach (fn) {
2557 return registerHook(this.afterHooks, fn)
2558};
2559
2560VueRouter.prototype.onReady = function onReady (cb, errorCb) {
2561 this.history.onReady(cb, errorCb);
2562};
2563
2564VueRouter.prototype.onError = function onError (errorCb) {
2565 this.history.onError(errorCb);
2566};
2567
2568VueRouter.prototype.push = function push (location, onComplete, onAbort) {
2569 this.history.push(location, onComplete, onAbort);
2570};
2571
2572VueRouter.prototype.replace = function replace (location, onComplete, onAbort) {
2573 this.history.replace(location, onComplete, onAbort);
2574};
2575
2576VueRouter.prototype.go = function go (n) {
2577 this.history.go(n);
2578};
2579
2580VueRouter.prototype.back = function back () {
2581 this.go(-1);
2582};
2583
2584VueRouter.prototype.forward = function forward () {
2585 this.go(1);
2586};
2587
2588VueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {
2589 var route = to
2590 ? to.matched
2591 ? to
2592 : this.resolve(to).route
2593 : this.currentRoute;
2594 if (!route) {
2595 return []
2596 }
2597 return [].concat.apply([], route.matched.map(function (m) {
2598 return Object.keys(m.components).map(function (key) {
2599 return m.components[key]
2600 })
2601 }))
2602};
2603
2604VueRouter.prototype.resolve = function resolve (
2605 to,
2606 current,
2607 append
2608) {
2609 current = current || this.history.current;
2610 var location = normalizeLocation(
2611 to,
2612 current,
2613 append,
2614 this
2615 );
2616 var route = this.match(location, current);
2617 var fullPath = route.redirectedFrom || route.fullPath;
2618 var base = this.history.base;
2619 var href = createHref(base, fullPath, this.mode);
2620 return {
2621 location: location,
2622 route: route,
2623 href: href,
2624 // for backwards compat
2625 normalizedTo: location,
2626 resolved: route
2627 }
2628};
2629
2630VueRouter.prototype.addRoutes = function addRoutes (routes) {
2631 this.matcher.addRoutes(routes);
2632 if (this.history.current !== START) {
2633 this.history.transitionTo(this.history.getCurrentLocation());
2634 }
2635};
2636
2637Object.defineProperties( VueRouter.prototype, prototypeAccessors );
2638
2639function registerHook (list, fn) {
2640 list.push(fn);
2641 return function () {
2642 var i = list.indexOf(fn);
2643 if (i > -1) { list.splice(i, 1); }
2644 }
2645}
2646
2647function createHref (base, fullPath, mode) {
2648 var path = mode === 'hash' ? '#' + fullPath : fullPath;
2649 return base ? cleanPath(base + '/' + path) : path
2650}
2651
2652VueRouter.install = install;
2653VueRouter.version = '3.0.4';
2654
2655if (inBrowser && window.Vue) {
2656 window.Vue.use(VueRouter);
2657}
2658
2659module.exports = VueRouter;