UNPKG

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