UNPKG

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