This commit is contained in:
2023-08-11 10:45:20 +08:00
commit 161ca982f3
31850 changed files with 2706500 additions and 0 deletions

21
node_modules/vue-router/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2013-present Evan You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

138
node_modules/vue-router/README.md generated vendored Normal file
View File

@ -0,0 +1,138 @@
# vue-router [![Build Status](https://img.shields.io/circleci/project/github/vuejs/vue-router/dev.svg)](https://circleci.com/gh/vuejs/vue-router)
> This is vue-router 3.0 which works only with Vue 2.0.
> - For the 1.x router see the [1.0 branch](https://github.com/vuejs/vue-router/tree/1.0).
> - For Vue Router 4 (for Vue 3) see [vuejs/router](https://github.com/vuejs/router).
<h2 align="center">Supporting Vue Router</h2>
Vue Router is part of the Vue Ecosystem and is an MIT-licensed open source project with its ongoing development made possible entirely by the support of Sponsors. If you would like to become a sponsor, please consider:
- [Become a Sponsor on GitHub](https://github.com/sponsors/posva)
- [One-time donation via PayPal](https://paypal.me/posva)
<!--sponsors start-->
<h4 align="center">Gold Sponsors</h4>
<p align="center">
<a href="https://vuejobs.com/?utm_source=vuerouter&utm_campaign=sponsor" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/vuejobs.svg" media="(prefers-color-scheme: dark)" height="72px" alt="VueJobs" />
<img src="https://posva-sponsors.pages.dev/logos/vuejobs.svg" height="72px" alt="VueJobs" />
</picture>
</a>
</p>
<h4 align="center">Silver Sponsors</h4>
<p align="center">
<a href="https://www.vuemastery.com/" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/vuemastery-dark.png" media="(prefers-color-scheme: dark)" height="42px" alt="VueMastery" />
<img src="https://posva-sponsors.pages.dev/logos/vuemastery-light.svg" height="42px" alt="VueMastery" />
</picture>
</a>
<a href="https://www.prefect.io/" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/prefectlogo-dark.svg" media="(prefers-color-scheme: dark)" height="42px" alt="Prefect" />
<img src="https://posva-sponsors.pages.dev/logos/prefectlogo-light.svg" height="42px" alt="Prefect" />
</picture>
</a>
</p>
<h4 align="center">Bronze Sponsors</h4>
<p align="center">
<a href="https://stormier.ninja" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4" media="(prefers-color-scheme: dark)" height="26px" alt="Stanislas Ormières" />
<img src="https://avatars.githubusercontent.com/u/2486424?u=7b0c73ae5d090ce53bf59473094e9606fe082c59&v=4" height="26px" alt="Stanislas Ormières" />
</picture>
</a>
<a href="www.vuejs.de" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4" media="(prefers-color-scheme: dark)" height="26px" alt="Antony Konstantinidis" />
<img src="https://avatars.githubusercontent.com/u/4183726?u=6b50a8ea16de29d2982f43c5640b1db9299ebcd1&v=4" height="26px" alt="Antony Konstantinidis" />
</picture>
</a>
<a href="https://storyblok.com" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/storyblok.png" media="(prefers-color-scheme: dark)" height="26px" alt="Storyblok" />
<img src="https://posva-sponsors.pages.dev/logos/storyblok.png" height="26px" alt="Storyblok" />
</picture>
</a>
<a href="https://nuxtjs.org" target="_blank" rel="noopener noreferrer">
<picture>
<source srcset="https://posva-sponsors.pages.dev/logos/nuxt-dark.svg" media="(prefers-color-scheme: dark)" height="26px" alt="NuxtJS" />
<img src="https://posva-sponsors.pages.dev/logos/nuxt-light.svg" height="26px" alt="NuxtJS" />
</picture>
</a>
</p>
<!--sponsors end-->
---
Get started with the [documentation](http://router.vuejs.org), or play with the [examples](https://github.com/vuejs/vue-router/tree/dev/examples) (see how to run them below).
### Development Setup
```bash
# install deps
npm install
# build dist files
npm run build
# serve examples at localhost:8080
npm run dev
# lint & run all tests
npm test
# serve docs at localhost:8080
npm run docs
```
## Releasing
- `yarn run release`
- Ensure tests are passing `yarn run test`
- Build dist files `VERSION=<the_version> yarn run build`
- Build changelog `yarn run changelog`
- Commit dist files `git add dist CHANGELOG.md && git commit -m "[build $VERSION]"`
- Publish a new version `npm version $VERSION --message "[release] $VERSION"
- Push tags `git push origin refs/tags/v$VERSION && git push`
- Publish to npm `npm publish`
## Questions
For questions and support please use the [Discord chat server](https://chat.vuejs.org) or [the official forum](http://forum.vuejs.org). The issue list of this repo is **exclusively** for bug reports and feature requests.
## Issues
Please make sure to read the [Issue Reporting Checklist](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
## Contribution
Please make sure to read the [Contributing Guide](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md) before making a pull request.
## Changelog
Details changes for each release are documented in the [`CHANGELOG.md file`](https://github.com/vuejs/vue-router/blob/dev/CHANGELOG.md).
## Stay In Touch
- For latest releases and announcements, follow on Twitter: [@vuejs](https://twitter.com/vuejs)
## License
[MIT](http://opensource.org/licenses/MIT)
Copyright (c) 2013-present Evan You
## Special Thanks
<a href="https://www.browserstack.com">
<img src="/assets/browserstack-logo-600x315.png" height="80" title="BrowserStack Logo" alt="BrowserStack Logo" />
</a>
Special thanks to [BrowserStack](https://www.browserstack.com) for letting the maintainers use their service to debug browser specific issues.

1
node_modules/vue-router/composables.d.ts generated vendored Normal file
View File

@ -0,0 +1 @@
export * from './types/composables'

257
node_modules/vue-router/composables.js generated vendored Normal file
View File

@ -0,0 +1,257 @@
/*!
* vue-router v3.6.5
* (c) 2022 Evan You
* @license MIT
*/
'use strict'
Object.defineProperty(exports, '__esModule', { value: true })
var vue = require('vue')
// dev only warn if no current instance
function throwNoCurrentInstance (method) {
if (!vue.getCurrentInstance()) {
throw new Error(
('[vue-router]: Missing current instance. ' + method + '() must be called inside <script setup> or setup().')
)
}
}
function useRouter () {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useRouter')
}
return vue.getCurrentInstance().proxy.$root.$router
}
function useRoute () {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useRoute')
}
var root = vue.getCurrentInstance().proxy.$root
if (!root._$route) {
var route = vue.effectScope(true).run(function () { return vue.shallowReactive(Object.assign({}, root.$router.currentRoute)) }
)
root._$route = route
root.$router.afterEach(function (to) {
Object.assign(route, to)
})
}
return root._$route
}
function onBeforeRouteUpdate (guard) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('onBeforeRouteUpdate')
}
return useFilteredGuard(guard, isUpdateNavigation)
}
function isUpdateNavigation (to, from, depth) {
var toMatched = to.matched
var fromMatched = from.matched
return (
toMatched.length >= depth &&
toMatched
.slice(0, depth + 1)
.every(function (record, i) { return record === fromMatched[i] })
)
}
function isLeaveNavigation (to, from, depth) {
var toMatched = to.matched
var fromMatched = from.matched
return toMatched.length < depth || toMatched[depth] !== fromMatched[depth]
}
function onBeforeRouteLeave (guard) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('onBeforeRouteLeave')
}
return useFilteredGuard(guard, isLeaveNavigation)
}
var noop = function () {}
function useFilteredGuard (guard, fn) {
var instance = vue.getCurrentInstance()
var router = useRouter()
var target = instance.proxy
// find the nearest RouterView to know the depth
while (
target &&
target.$vnode &&
target.$vnode.data &&
target.$vnode.data.routerViewDepth == null
) {
target = target.$parent
}
var depth =
target && target.$vnode && target.$vnode.data
? target.$vnode.data.routerViewDepth
: null
if (depth != null) {
var removeGuard = router.beforeEach(function (to, from, next) {
return fn(to, from, depth) ? guard(to, from, next) : next()
})
vue.onUnmounted(removeGuard)
return removeGuard
}
return noop
}
/* */
function guardEvent (e) {
// don't redirect with control keys
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
// don't redirect when preventDefault called
if (e.defaultPrevented) { return }
// don't redirect on right click
if (e.button !== undefined && e.button !== 0) { return }
// don't redirect if `target="_blank"`
if (e.currentTarget && e.currentTarget.getAttribute) {
var target = e.currentTarget.getAttribute('target')
if (/\b_blank\b/i.test(target)) { return }
}
// this may be a Weex event which doesn't have this method
if (e.preventDefault) {
e.preventDefault()
}
return true
}
function includesParams (outer, inner) {
var loop = function (key) {
var innerValue = inner[key]
var outerValue = outer[key]
if (typeof innerValue === 'string') {
if (innerValue !== outerValue) { return { v: false } }
} else {
if (
!Array.isArray(outerValue) ||
outerValue.length !== innerValue.length ||
innerValue.some(function (value, i) { return value !== outerValue[i] })
) {
return { v: false }
}
}
}
for (var key in inner) {
var returned = loop(key)
if (returned) return returned.v
}
return true
}
// helpers from vue router 4
function isSameRouteLocationParamsValue (a, b) {
return Array.isArray(a)
? isEquivalentArray(a, b)
: Array.isArray(b)
? isEquivalentArray(b, a)
: a === b
}
function isEquivalentArray (a, b) {
return Array.isArray(b)
? a.length === b.length && a.every(function (value, i) { return value === b[i] })
: a.length === 1 && a[0] === b
}
function isSameRouteLocationParams (a, b) {
if (Object.keys(a).length !== Object.keys(b).length) { return false }
for (var key in a) {
if (!isSameRouteLocationParamsValue(a[key], b[key])) { return false }
}
return true
}
function useLink (props) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useLink')
}
var router = useRouter()
var currentRoute = useRoute()
var resolvedRoute = vue.computed(function () { return router.resolve(vue.unref(props.to), currentRoute) })
var activeRecordIndex = vue.computed(function () {
var route = resolvedRoute.value.route
var matched = route.matched
var length = matched.length
var routeMatched = matched[length - 1]
var currentMatched = currentRoute.matched
if (!routeMatched || !currentMatched.length) { return -1 }
var index = currentMatched.indexOf(routeMatched)
if (index > -1) { return index }
// possible parent record
var parentRecord = currentMatched[currentMatched.length - 2]
return (
// we are dealing with nested routes
length > 1 &&
// if the parent and matched route have the same path, this link is
// referring to the empty child. Or we currently are on a different
// child of the same parent
parentRecord && parentRecord === routeMatched.parent
)
})
var isActive = vue.computed(
function () {
return activeRecordIndex.value > -1 &&
includesParams(currentRoute.params, resolvedRoute.value.route.params)
}
)
var isExactActive = vue.computed(
function () {
return activeRecordIndex.value > -1 &&
activeRecordIndex.value === currentRoute.matched.length - 1 &&
isSameRouteLocationParams(currentRoute.params, resolvedRoute.value.route.params)
}
)
var navigate = function (e) {
var href = resolvedRoute.value.route
if (guardEvent(e)) {
return props.replace
? router.replace(href)
: router.push(href)
}
return Promise.resolve()
}
return {
href: vue.computed(function () { return resolvedRoute.value.href }),
route: vue.computed(function () { return resolvedRoute.value.route }),
isExactActive: isExactActive,
isActive: isActive,
navigate: navigate
}
}
exports.isSameRouteLocationParams = isSameRouteLocationParams
exports.onBeforeRouteLeave = onBeforeRouteLeave
exports.onBeforeRouteUpdate = onBeforeRouteUpdate
exports.useLink = useLink
exports.useRoute = useRoute
exports.useRouter = useRouter

244
node_modules/vue-router/composables.mjs generated vendored Normal file
View File

@ -0,0 +1,244 @@
/*!
* vue-router v3.6.5
* (c) 2022 Evan You
* @license MIT
*/
import { getCurrentInstance, effectScope, shallowReactive, onUnmounted, computed, unref } from 'vue';
// dev only warn if no current instance
function throwNoCurrentInstance (method) {
if (!getCurrentInstance()) {
throw new Error(
("[vue-router]: Missing current instance. " + method + "() must be called inside <script setup> or setup().")
)
}
}
function useRouter () {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useRouter');
}
return getCurrentInstance().proxy.$root.$router
}
function useRoute () {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useRoute');
}
var root = getCurrentInstance().proxy.$root;
if (!root._$route) {
var route = effectScope(true).run(function () { return shallowReactive(Object.assign({}, root.$router.currentRoute)); }
);
root._$route = route;
root.$router.afterEach(function (to) {
Object.assign(route, to);
});
}
return root._$route
}
function onBeforeRouteUpdate (guard) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('onBeforeRouteUpdate');
}
return useFilteredGuard(guard, isUpdateNavigation)
}
function isUpdateNavigation (to, from, depth) {
var toMatched = to.matched;
var fromMatched = from.matched;
return (
toMatched.length >= depth &&
toMatched
.slice(0, depth + 1)
.every(function (record, i) { return record === fromMatched[i]; })
)
}
function isLeaveNavigation (to, from, depth) {
var toMatched = to.matched;
var fromMatched = from.matched;
return toMatched.length < depth || toMatched[depth] !== fromMatched[depth]
}
function onBeforeRouteLeave (guard) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('onBeforeRouteLeave');
}
return useFilteredGuard(guard, isLeaveNavigation)
}
var noop = function () {};
function useFilteredGuard (guard, fn) {
var instance = getCurrentInstance();
var router = useRouter();
var target = instance.proxy;
// find the nearest RouterView to know the depth
while (
target &&
target.$vnode &&
target.$vnode.data &&
target.$vnode.data.routerViewDepth == null
) {
target = target.$parent;
}
var depth =
target && target.$vnode && target.$vnode.data
? target.$vnode.data.routerViewDepth
: null;
if (depth != null) {
var removeGuard = router.beforeEach(function (to, from, next) {
return fn(to, from, depth) ? guard(to, from, next) : next()
});
onUnmounted(removeGuard);
return removeGuard
}
return noop
}
/* */
function guardEvent (e) {
// don't redirect with control keys
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
// don't redirect when preventDefault called
if (e.defaultPrevented) { return }
// don't redirect on right click
if (e.button !== undefined && e.button !== 0) { return }
// don't redirect if `target="_blank"`
if (e.currentTarget && e.currentTarget.getAttribute) {
var target = e.currentTarget.getAttribute('target');
if (/\b_blank\b/i.test(target)) { return }
}
// this may be a Weex event which doesn't have this method
if (e.preventDefault) {
e.preventDefault();
}
return true
}
function includesParams (outer, inner) {
var loop = function ( key ) {
var innerValue = inner[key];
var outerValue = outer[key];
if (typeof innerValue === 'string') {
if (innerValue !== outerValue) { return { v: false } }
} else {
if (
!Array.isArray(outerValue) ||
outerValue.length !== innerValue.length ||
innerValue.some(function (value, i) { return value !== outerValue[i]; })
) {
return { v: false }
}
}
};
for (var key in inner) {
var returned = loop( key );
if ( returned ) return returned.v;
}
return true
}
// helpers from vue router 4
function isSameRouteLocationParamsValue (a, b) {
return Array.isArray(a)
? isEquivalentArray(a, b)
: Array.isArray(b)
? isEquivalentArray(b, a)
: a === b
}
function isEquivalentArray (a, b) {
return Array.isArray(b)
? a.length === b.length && a.every(function (value, i) { return value === b[i]; })
: a.length === 1 && a[0] === b
}
function isSameRouteLocationParams (a, b) {
if (Object.keys(a).length !== Object.keys(b).length) { return false }
for (var key in a) {
if (!isSameRouteLocationParamsValue(a[key], b[key])) { return false }
}
return true
}
function useLink (props) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useLink');
}
var router = useRouter();
var currentRoute = useRoute();
var resolvedRoute = computed(function () { return router.resolve(unref(props.to), currentRoute); });
var activeRecordIndex = computed(function () {
var route = resolvedRoute.value.route;
var matched = route.matched;
var length = matched.length;
var routeMatched = matched[length - 1];
var currentMatched = currentRoute.matched;
if (!routeMatched || !currentMatched.length) { return -1 }
var index = currentMatched.indexOf(routeMatched);
if (index > -1) { return index }
// possible parent record
var parentRecord = currentMatched[currentMatched.length - 2];
return (
// we are dealing with nested routes
length > 1 &&
// if the parent and matched route have the same path, this link is
// referring to the empty child. Or we currently are on a different
// child of the same parent
parentRecord && parentRecord === routeMatched.parent
)
});
var isActive = computed(
function () { return activeRecordIndex.value > -1 &&
includesParams(currentRoute.params, resolvedRoute.value.route.params); }
);
var isExactActive = computed(
function () { return activeRecordIndex.value > -1 &&
activeRecordIndex.value === currentRoute.matched.length - 1 &&
isSameRouteLocationParams(currentRoute.params, resolvedRoute.value.route.params); }
);
var navigate = function (e) {
var href = resolvedRoute.value.route;
if (guardEvent(e)) {
return props.replace
? router.replace(href)
: router.push(href)
}
return Promise.resolve()
};
return {
href: computed(function () { return resolvedRoute.value.href; }),
route: computed(function () { return resolvedRoute.value.route; }),
isExactActive: isExactActive,
isActive: isActive,
navigate: navigate
}
}
export { isSameRouteLocationParams, onBeforeRouteLeave, onBeforeRouteUpdate, useLink, useRoute, useRouter };

3159
node_modules/vue-router/dist/vue-router.common.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

3125
node_modules/vue-router/dist/vue-router.esm.browser.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

3159
node_modules/vue-router/dist/vue-router.esm.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

3164
node_modules/vue-router/dist/vue-router.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

11
node_modules/vue-router/dist/vue-router.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

3159
node_modules/vue-router/dist/vue-router.mjs generated vendored Normal file

File diff suppressed because it is too large Load Diff

166
node_modules/vue-router/package.json generated vendored Normal file
View File

@ -0,0 +1,166 @@
{
"_from": "vue-router@3.6.5",
"_id": "vue-router@3.6.5",
"_inBundle": false,
"_integrity": "sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ==",
"_location": "/vue-router",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "vue-router@3.6.5",
"name": "vue-router",
"escapedName": "vue-router",
"rawSpec": "3.6.5",
"saveSpec": null,
"fetchSpec": "3.6.5"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.6.5.tgz",
"_shasum": "95847d52b9a7e3f1361cb605c8e6441f202afad8",
"_spec": "vue-router@3.6.5",
"_where": "C:\\Users\\zhouxueli\\Desktop\\scheduling-app",
"author": {
"name": "Evan You"
},
"bugs": {
"url": "https://github.com/vuejs/vue-router/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Official router for Vue.js 2",
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"@vuepress/plugin-pwa": "^1.5.3",
"@vuepress/theme-vue": "^1.5.3",
"axios": "^0.21.1",
"babel-core": "^6.24.1",
"babel-eslint": "^10.0.2",
"babel-loader": "^7.1.3",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-env": "^1.6.1",
"babel-preset-flow-vue": "^1.0.0",
"browserstack-local": "^1.4.8",
"buble": "^0.19.8",
"chromedriver": "^96.0.0",
"conventional-changelog-cli": "^2.0.11",
"cross-spawn": "^7.0.3",
"css-loader": "^2.1.1",
"dotenv": "^8.2.0",
"es6-promise": "^4.2.8",
"eslint": "^4.19.1",
"eslint-plugin-flowtype": "^2.46.1",
"eslint-plugin-jasmine": "^2.10.1",
"eslint-plugin-vue-libs": "^2.1.0",
"express": "^4.17.1",
"express-urlrewrite": "^1.2.0",
"flow-bin": "^0.66.0",
"geckodriver": "^1.20.0",
"jasmine": "2.8.0",
"lint-staged": "^8.2.0",
"nightwatch": "^1.3.6",
"nightwatch-helpers": "^1.0.0",
"path-to-regexp": "^1.8.0",
"rollup": "^2.34.1",
"rollup-plugin-buble": "^0.19.8",
"rollup-plugin-flow-no-whitespace": "^1.0.0",
"rollup-plugin-replace": "^2.0.0",
"rollup-watch": "^4.0.0",
"selenium-server": "^3.141.59",
"terser": "^4.2.0",
"typescript": "^4.7.0",
"vue": "^2.7.0",
"vue-loader": "^15.9.3",
"vue-server-renderer": "^2.7.0",
"vue-template-compiler": "^2.7.0",
"vuepress": "^1.5.3",
"vuepress-theme-vue": "^1.1.1",
"webpack": "^4.35.2",
"webpack-dev-middleware": "^3.7.0",
"yorkie": "^2.0.0"
},
"exports": {
".": {
"import": {
"node": "./dist/vue-router.mjs",
"default": "./dist/vue-router.esm.js"
},
"require": "./dist/vue-router.common.js",
"types": "./types/index.d.ts"
},
"./composables": {
"import": "./composables.mjs",
"require": "./composables.js",
"types": "./composables.d.ts"
},
"./dist/*": "./dist/*",
"./types/*": "./types/*",
"./package.json": "./package.json"
},
"files": [
"src",
"dist/*.js",
"dist/*.mjs",
"types/*.d.ts",
"composables.mjs",
"composables.js",
"composables.d.ts",
"vetur/tags.json",
"vetur/attributes.json"
],
"gitHooks": {
"pre-commit": "lint-staged",
"commit-msg": "node scripts/verifyCommitMsg.js"
},
"homepage": "https://github.com/vuejs/vue-router#readme",
"jsdelivr": "dist/vue-router.js",
"keywords": [
"vue",
"router",
"routing"
],
"license": "MIT",
"lint-staged": {
"*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"main": "dist/vue-router.common.js",
"module": "dist/vue-router.esm.js",
"name": "vue-router",
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vue-router.git"
},
"scripts": {
"build": "node build/build.js",
"changelog": "conventional-changelog -p angular -r 2 -i CHANGELOG.md -s",
"commit": "git-cz",
"dev": "node examples/server.js",
"dev:dist": "rollup -wm -c build/rollup.dev.config.js",
"docs": "vuepress dev docs",
"docs:build": "vuepress build docs",
"flow": "flow check",
"lint": "eslint src examples test",
"release": "bash scripts/release.sh",
"test": "npm run lint && npm run flow && npm run test:unit && npm run test:e2e && npm run test:types",
"test:e2e": "node test/e2e/runner.js",
"test:e2e:ci": "node test/e2e/runner.js --local -e ie,android44 -c test/e2e/nightwatch.browserstack.js test/e2e/specs/active-links.js",
"test:e2e:ff": "node test/e2e/runner.js -e firefox -c test/e2e/nightwatch.config.js",
"test:e2e:ie9": "node test/e2e/runner.js --local -e ie9 -c test/e2e/nightwatch.browserstack.js --skiptags history,ie9-fail",
"test:types": "tsc -p types/test",
"test:unit": "jasmine JASMINE_CONFIG_PATH=test/unit/jasmine.json"
},
"sideEffects": false,
"typings": "types/index.d.ts",
"unpkg": "dist/vue-router.js",
"version": "3.6.5",
"vetur": {
"tags": "vetur/tags.json",
"attributes": "vetur/attributes.json"
}
}

224
node_modules/vue-router/src/components/link.js generated vendored Normal file
View File

@ -0,0 +1,224 @@
/* @flow */
import { createRoute, isSameRoute, isIncludedRoute } from '../util/route'
import { extend } from '../util/misc'
import { normalizeLocation } from '../util/location'
import { warn } from '../util/warn'
// work around weird flow bug
const toTypes: Array<Function> = [String, Object]
const eventTypes: Array<Function> = [String, Array]
const noop = () => {}
let warnedCustomSlot
let warnedTagProp
let warnedEventProp
export default {
name: 'RouterLink',
props: {
to: {
type: toTypes,
required: true
},
tag: {
type: String,
default: 'a'
},
custom: Boolean,
exact: Boolean,
exactPath: Boolean,
append: Boolean,
replace: Boolean,
activeClass: String,
exactActiveClass: String,
ariaCurrentValue: {
type: String,
default: 'page'
},
event: {
type: eventTypes,
default: 'click'
}
},
render (h: Function) {
const router = this.$router
const current = this.$route
const { location, route, href } = router.resolve(
this.to,
current,
this.append
)
const classes = {}
const globalActiveClass = router.options.linkActiveClass
const globalExactActiveClass = router.options.linkExactActiveClass
// Support global empty active class
const activeClassFallback =
globalActiveClass == null ? 'router-link-active' : globalActiveClass
const exactActiveClassFallback =
globalExactActiveClass == null
? 'router-link-exact-active'
: globalExactActiveClass
const activeClass =
this.activeClass == null ? activeClassFallback : this.activeClass
const exactActiveClass =
this.exactActiveClass == null
? exactActiveClassFallback
: this.exactActiveClass
const compareTarget = route.redirectedFrom
? createRoute(null, normalizeLocation(route.redirectedFrom), null, router)
: route
classes[exactActiveClass] = isSameRoute(current, compareTarget, this.exactPath)
classes[activeClass] = this.exact || this.exactPath
? classes[exactActiveClass]
: isIncludedRoute(current, compareTarget)
const ariaCurrentValue = classes[exactActiveClass] ? this.ariaCurrentValue : null
const handler = e => {
if (guardEvent(e)) {
if (this.replace) {
router.replace(location, noop)
} else {
router.push(location, noop)
}
}
}
const on = { click: guardEvent }
if (Array.isArray(this.event)) {
this.event.forEach(e => {
on[e] = handler
})
} else {
on[this.event] = handler
}
const data: any = { class: classes }
const scopedSlot =
!this.$scopedSlots.$hasNormal &&
this.$scopedSlots.default &&
this.$scopedSlots.default({
href,
route,
navigate: handler,
isActive: classes[activeClass],
isExactActive: classes[exactActiveClass]
})
if (scopedSlot) {
if (process.env.NODE_ENV !== 'production' && !this.custom) {
!warnedCustomSlot && warn(false, 'In Vue Router 4, the v-slot API will by default wrap its content with an <a> element. Use the custom prop to remove this warning:\n<router-link v-slot="{ navigate, href }" custom></router-link>\n')
warnedCustomSlot = true
}
if (scopedSlot.length === 1) {
return scopedSlot[0]
} else if (scopedSlot.length > 1 || !scopedSlot.length) {
if (process.env.NODE_ENV !== 'production') {
warn(
false,
`<router-link> with to="${
this.to
}" is trying to use a scoped slot but it didn't provide exactly one child. Wrapping the content with a span element.`
)
}
return scopedSlot.length === 0 ? h() : h('span', {}, scopedSlot)
}
}
if (process.env.NODE_ENV !== 'production') {
if ('tag' in this.$options.propsData && !warnedTagProp) {
warn(
false,
`<router-link>'s tag prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.`
)
warnedTagProp = true
}
if ('event' in this.$options.propsData && !warnedEventProp) {
warn(
false,
`<router-link>'s event prop is deprecated and has been removed in Vue Router 4. Use the v-slot API to remove this warning: https://next.router.vuejs.org/guide/migration/#removal-of-event-and-tag-props-in-router-link.`
)
warnedEventProp = true
}
}
if (this.tag === 'a') {
data.on = on
data.attrs = { href, 'aria-current': ariaCurrentValue }
} else {
// find the first <a> child and apply listener and href
const a = findAnchor(this.$slots.default)
if (a) {
// in case the <a> is a static node
a.isStatic = false
const aData = (a.data = extend({}, a.data))
aData.on = aData.on || {}
// transform existing events in both objects into arrays so we can push later
for (const event in aData.on) {
const handler = aData.on[event]
if (event in on) {
aData.on[event] = Array.isArray(handler) ? handler : [handler]
}
}
// append new listeners for router-link
for (const event in on) {
if (event in aData.on) {
// on[event] is always a function
aData.on[event].push(on[event])
} else {
aData.on[event] = handler
}
}
const aAttrs = (a.data.attrs = extend({}, a.data.attrs))
aAttrs.href = href
aAttrs['aria-current'] = ariaCurrentValue
} else {
// doesn't have <a> child, apply listener to self
data.on = on
}
}
return h(this.tag, data, this.$slots.default)
}
}
export function guardEvent (e: any) {
// don't redirect with control keys
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return
// don't redirect when preventDefault called
if (e.defaultPrevented) return
// don't redirect on right click
if (e.button !== undefined && e.button !== 0) return
// don't redirect if `target="_blank"`
if (e.currentTarget && e.currentTarget.getAttribute) {
const target = e.currentTarget.getAttribute('target')
if (/\b_blank\b/i.test(target)) return
}
// this may be a Weex event which doesn't have this method
if (e.preventDefault) {
e.preventDefault()
}
return true
}
function findAnchor (children) {
if (children) {
let child
for (let i = 0; i < children.length; i++) {
child = children[i]
if (child.tag === 'a') {
return child
}
if (child.children && (child = findAnchor(child.children))) {
return child
}
}
}
}

155
node_modules/vue-router/src/components/view.js generated vendored Normal file
View File

@ -0,0 +1,155 @@
import { warn } from '../util/warn'
import { extend } from '../util/misc'
import { handleRouteEntered } from '../util/route'
export default {
name: 'RouterView',
functional: true,
props: {
name: {
type: String,
default: 'default'
}
},
render (_, { props, children, parent, data }) {
// used by devtools to display a router-view badge
data.routerView = true
// directly use parent context's createElement() function
// so that components rendered by router-view can resolve named slots
const h = parent.$createElement
const name = props.name
const route = parent.$route
const cache = parent._routerViewCache || (parent._routerViewCache = {})
// determine current view depth, also check to see if the tree
// has been toggled inactive but kept-alive.
let depth = 0
let inactive = false
while (parent && parent._routerRoot !== parent) {
const vnodeData = parent.$vnode ? parent.$vnode.data : {}
if (vnodeData.routerView) {
depth++
}
if (vnodeData.keepAlive && parent._directInactive && parent._inactive) {
inactive = true
}
parent = parent.$parent
}
data.routerViewDepth = depth
// render previous view if the tree is inactive and kept-alive
if (inactive) {
const cachedData = cache[name]
const cachedComponent = cachedData && cachedData.component
if (cachedComponent) {
// #2301
// pass props
if (cachedData.configProps) {
fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps)
}
return h(cachedComponent, data, children)
} else {
// render previous empty view
return h()
}
}
const matched = route.matched[depth]
const component = matched && matched.components[name]
// render empty node if no matched route or no config component
if (!matched || !component) {
cache[name] = null
return h()
}
// cache component
cache[name] = { component }
// attach instance registration hook
// this will be called in the instance's injected lifecycle hooks
data.registerRouteInstance = (vm, val) => {
// val could be undefined for unregistration
const current = matched.instances[name]
if (
(val && current !== vm) ||
(!val && current === vm)
) {
matched.instances[name] = val
}
}
// also register instance in prepatch hook
// in case the same component instance is reused across different routes
;(data.hook || (data.hook = {})).prepatch = (_, vnode) => {
matched.instances[name] = vnode.componentInstance
}
// register instance in init hook
// in case kept-alive component be actived when routes changed
data.hook.init = (vnode) => {
if (vnode.data.keepAlive &&
vnode.componentInstance &&
vnode.componentInstance !== matched.instances[name]
) {
matched.instances[name] = vnode.componentInstance
}
// if the route transition has already been confirmed then we weren't
// able to call the cbs during confirmation as the component was not
// registered yet, so we call it here.
handleRouteEntered(route)
}
const configProps = matched.props && matched.props[name]
// save route and configProps in cache
if (configProps) {
extend(cache[name], {
route,
configProps
})
fillPropsinData(component, data, route, configProps)
}
return h(component, data, children)
}
}
function fillPropsinData (component, data, route, configProps) {
// resolve props
let propsToPass = data.props = resolveProps(route, configProps)
if (propsToPass) {
// clone to prevent mutation
propsToPass = data.props = extend({}, propsToPass)
// pass non-declared props as attrs
const attrs = data.attrs = data.attrs || {}
for (const key in propsToPass) {
if (!component.props || !(key in component.props)) {
attrs[key] = propsToPass[key]
delete propsToPass[key]
}
}
}
}
function resolveProps (route, config) {
switch (typeof config) {
case 'undefined':
return
case 'object':
return config
case 'function':
return config(route)
case 'boolean':
return config ? route.params : undefined
default:
if (process.env.NODE_ENV !== 'production') {
warn(
false,
`props in "${route.path}" is a ${typeof config}, ` +
`expecting an object, function or boolean.`
)
}
}
}

34
node_modules/vue-router/src/composables/globals.js generated vendored Normal file
View File

@ -0,0 +1,34 @@
import {
getCurrentInstance,
shallowReactive,
effectScope
} from 'vue'
import { throwNoCurrentInstance } from './utils'
export function useRouter () {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useRouter')
}
return getCurrentInstance().proxy.$root.$router
}
export function useRoute () {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useRoute')
}
const root = getCurrentInstance().proxy.$root
if (!root._$route) {
const route = effectScope(true).run(() =>
shallowReactive(Object.assign({}, root.$router.currentRoute))
)
root._$route = route
root.$router.afterEach(to => {
Object.assign(route, to)
})
}
return root._$route
}

68
node_modules/vue-router/src/composables/guards.js generated vendored Normal file
View File

@ -0,0 +1,68 @@
import { getCurrentInstance, onUnmounted } from 'vue'
import { throwNoCurrentInstance } from './utils'
import { useRouter } from './globals'
export function onBeforeRouteUpdate (guard) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('onBeforeRouteUpdate')
}
return useFilteredGuard(guard, isUpdateNavigation)
}
function isUpdateNavigation (to, from, depth) {
const toMatched = to.matched
const fromMatched = from.matched
return (
toMatched.length >= depth &&
toMatched
.slice(0, depth + 1)
.every((record, i) => record === fromMatched[i])
)
}
function isLeaveNavigation (to, from, depth) {
const toMatched = to.matched
const fromMatched = from.matched
return toMatched.length < depth || toMatched[depth] !== fromMatched[depth]
}
export function onBeforeRouteLeave (guard) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('onBeforeRouteLeave')
}
return useFilteredGuard(guard, isLeaveNavigation)
}
const noop = () => {}
function useFilteredGuard (guard, fn) {
const instance = getCurrentInstance()
const router = useRouter()
let target = instance.proxy
// find the nearest RouterView to know the depth
while (
target &&
target.$vnode &&
target.$vnode.data &&
target.$vnode.data.routerViewDepth == null
) {
target = target.$parent
}
const depth =
target && target.$vnode && target.$vnode.data
? target.$vnode.data.routerViewDepth
: null
if (depth != null) {
const removeGuard = router.beforeEach((to, from, next) => {
return fn(to, from, depth) ? guard(to, from, next) : next()
})
onUnmounted(removeGuard)
return removeGuard
}
return noop
}

3
node_modules/vue-router/src/composables/index.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
export * from './guards'
export * from './globals'
export * from './useLink'

113
node_modules/vue-router/src/composables/useLink.js generated vendored Normal file
View File

@ -0,0 +1,113 @@
import { computed, unref } from 'vue'
import { guardEvent } from '../components/link'
import { throwNoCurrentInstance } from './utils'
import { useRouter, useRoute } from './globals'
function includesParams (outer, inner) {
for (const key in inner) {
const innerValue = inner[key]
const outerValue = outer[key]
if (typeof innerValue === 'string') {
if (innerValue !== outerValue) return false
} else {
if (
!Array.isArray(outerValue) ||
outerValue.length !== innerValue.length ||
innerValue.some((value, i) => value !== outerValue[i])
) {
return false
}
}
}
return true
}
// helpers from vue router 4
function isSameRouteLocationParamsValue (a, b) {
return Array.isArray(a)
? isEquivalentArray(a, b)
: Array.isArray(b)
? isEquivalentArray(b, a)
: a === b
}
function isEquivalentArray (a, b) {
return Array.isArray(b)
? a.length === b.length && a.every((value, i) => value === b[i])
: a.length === 1 && a[0] === b
}
export function isSameRouteLocationParams (a, b) {
if (Object.keys(a).length !== Object.keys(b).length) return false
for (const key in a) {
if (!isSameRouteLocationParamsValue(a[key], b[key])) return false
}
return true
}
export function useLink (props) {
if (process.env.NODE_ENV !== 'production') {
throwNoCurrentInstance('useLink')
}
const router = useRouter()
const currentRoute = useRoute()
const resolvedRoute = computed(() => router.resolve(unref(props.to), currentRoute))
const activeRecordIndex = computed(() => {
const route = resolvedRoute.value.route
const { matched } = route
const { length } = matched
const routeMatched = matched[length - 1]
const currentMatched = currentRoute.matched
if (!routeMatched || !currentMatched.length) return -1
const index = currentMatched.indexOf(routeMatched)
if (index > -1) return index
// possible parent record
const parentRecord = currentMatched[currentMatched.length - 2]
return (
// we are dealing with nested routes
length > 1 &&
// if the parent and matched route have the same path, this link is
// referring to the empty child. Or we currently are on a different
// child of the same parent
parentRecord && parentRecord === routeMatched.parent
)
})
const isActive = computed(
() =>
activeRecordIndex.value > -1 &&
includesParams(currentRoute.params, resolvedRoute.value.route.params)
)
const isExactActive = computed(
() =>
activeRecordIndex.value > -1 &&
activeRecordIndex.value === currentRoute.matched.length - 1 &&
isSameRouteLocationParams(currentRoute.params, resolvedRoute.value.route.params)
)
const navigate = e => {
const href = resolvedRoute.value.route
if (guardEvent(e)) {
return props.replace
? router.replace(href)
: router.push(href)
}
return Promise.resolve()
}
return {
href: computed(() => resolvedRoute.value.href),
route: computed(() => resolvedRoute.value.route),
isExactActive,
isActive,
navigate
}
}

11
node_modules/vue-router/src/composables/utils.js generated vendored Normal file
View File

@ -0,0 +1,11 @@
import { getCurrentInstance } from 'vue'
// dev only warn if no current instance
export function throwNoCurrentInstance (method) {
if (!getCurrentInstance()) {
throw new Error(
`[vue-router]: Missing current instance. ${method}() must be called inside <script setup> or setup().`
)
}
}

226
node_modules/vue-router/src/create-matcher.js generated vendored Normal file
View File

@ -0,0 +1,226 @@
/* @flow */
import type VueRouter from './index'
import { resolvePath } from './util/path'
import { assert, warn } from './util/warn'
import { createRoute } from './util/route'
import { fillParams } from './util/params'
import { createRouteMap } from './create-route-map'
import { normalizeLocation } from './util/location'
import { decode } from './util/query'
export type Matcher = {
match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;
addRoutes: (routes: Array<RouteConfig>) => void;
addRoute: (parentNameOrRoute: string | RouteConfig, route?: RouteConfig) => void;
getRoutes: () => Array<RouteRecord>;
};
export function createMatcher (
routes: Array<RouteConfig>,
router: VueRouter
): Matcher {
const { pathList, pathMap, nameMap } = createRouteMap(routes)
function addRoutes (routes) {
createRouteMap(routes, pathList, pathMap, nameMap)
}
function addRoute (parentOrRoute, route) {
const parent = (typeof parentOrRoute !== 'object') ? nameMap[parentOrRoute] : undefined
// $flow-disable-line
createRouteMap([route || parentOrRoute], pathList, pathMap, nameMap, parent)
// add aliases of parent
if (parent && parent.alias.length) {
createRouteMap(
// $flow-disable-line route is defined if parent is
parent.alias.map(alias => ({ path: alias, children: [route] })),
pathList,
pathMap,
nameMap,
parent
)
}
}
function getRoutes () {
return pathList.map(path => pathMap[path])
}
function match (
raw: RawLocation,
currentRoute?: Route,
redirectedFrom?: Location
): Route {
const location = normalizeLocation(raw, currentRoute, false, router)
const { name } = location
if (name) {
const record = nameMap[name]
if (process.env.NODE_ENV !== 'production') {
warn(record, `Route with name '${name}' does not exist`)
}
if (!record) return _createRoute(null, location)
const paramNames = record.regex.keys
.filter(key => !key.optional)
.map(key => key.name)
if (typeof location.params !== 'object') {
location.params = {}
}
if (currentRoute && typeof currentRoute.params === 'object') {
for (const key in currentRoute.params) {
if (!(key in location.params) && paramNames.indexOf(key) > -1) {
location.params[key] = currentRoute.params[key]
}
}
}
location.path = fillParams(record.path, location.params, `named route "${name}"`)
return _createRoute(record, location, redirectedFrom)
} else if (location.path) {
location.params = {}
for (let i = 0; i < pathList.length; i++) {
const path = pathList[i]
const record = pathMap[path]
if (matchRoute(record.regex, location.path, location.params)) {
return _createRoute(record, location, redirectedFrom)
}
}
}
// no match
return _createRoute(null, location)
}
function redirect (
record: RouteRecord,
location: Location
): Route {
const originalRedirect = record.redirect
let redirect = typeof originalRedirect === 'function'
? originalRedirect(createRoute(record, location, null, router))
: originalRedirect
if (typeof redirect === 'string') {
redirect = { path: redirect }
}
if (!redirect || typeof redirect !== 'object') {
if (process.env.NODE_ENV !== 'production') {
warn(
false, `invalid redirect option: ${JSON.stringify(redirect)}`
)
}
return _createRoute(null, location)
}
const re: Object = redirect
const { name, path } = re
let { query, hash, params } = location
query = re.hasOwnProperty('query') ? re.query : query
hash = re.hasOwnProperty('hash') ? re.hash : hash
params = re.hasOwnProperty('params') ? re.params : params
if (name) {
// resolved named direct
const targetRecord = nameMap[name]
if (process.env.NODE_ENV !== 'production') {
assert(targetRecord, `redirect failed: named route "${name}" not found.`)
}
return match({
_normalized: true,
name,
query,
hash,
params
}, undefined, location)
} else if (path) {
// 1. resolve relative redirect
const rawPath = resolveRecordPath(path, record)
// 2. resolve params
const resolvedPath = fillParams(rawPath, params, `redirect route with path "${rawPath}"`)
// 3. rematch with existing query and hash
return match({
_normalized: true,
path: resolvedPath,
query,
hash
}, undefined, location)
} else {
if (process.env.NODE_ENV !== 'production') {
warn(false, `invalid redirect option: ${JSON.stringify(redirect)}`)
}
return _createRoute(null, location)
}
}
function alias (
record: RouteRecord,
location: Location,
matchAs: string
): Route {
const aliasedPath = fillParams(matchAs, location.params, `aliased route with path "${matchAs}"`)
const aliasedMatch = match({
_normalized: true,
path: aliasedPath
})
if (aliasedMatch) {
const matched = aliasedMatch.matched
const aliasedRecord = matched[matched.length - 1]
location.params = aliasedMatch.params
return _createRoute(aliasedRecord, location)
}
return _createRoute(null, location)
}
function _createRoute (
record: ?RouteRecord,
location: Location,
redirectedFrom?: Location
): Route {
if (record && record.redirect) {
return redirect(record, redirectedFrom || location)
}
if (record && record.matchAs) {
return alias(record, location, record.matchAs)
}
return createRoute(record, location, redirectedFrom, router)
}
return {
match,
addRoute,
getRoutes,
addRoutes
}
}
function matchRoute (
regex: RouteRegExp,
path: string,
params: Object
): boolean {
const m = path.match(regex)
if (!m) {
return false
} else if (!params) {
return true
}
for (let i = 1, len = m.length; i < len; ++i) {
const key = regex.keys[i - 1]
if (key) {
// Fix #1994: using * with props: true generates a param named 0
params[key.name || 'pathMatch'] = typeof m[i] === 'string' ? decode(m[i]) : m[i]
}
}
return true
}
function resolveRecordPath (path: string, record: RouteRecord): string {
return resolvePath(path, record.parent ? record.parent.path : '/', true)
}

220
node_modules/vue-router/src/create-route-map.js generated vendored Normal file
View File

@ -0,0 +1,220 @@
/* @flow */
import Regexp from 'path-to-regexp'
import { cleanPath } from './util/path'
import { assert, warn } from './util/warn'
export function createRouteMap (
routes: Array<RouteConfig>,
oldPathList?: Array<string>,
oldPathMap?: Dictionary<RouteRecord>,
oldNameMap?: Dictionary<RouteRecord>,
parentRoute?: RouteRecord
): {
pathList: Array<string>,
pathMap: Dictionary<RouteRecord>,
nameMap: Dictionary<RouteRecord>
} {
// the path list is used to control path matching priority
const pathList: Array<string> = oldPathList || []
// $flow-disable-line
const pathMap: Dictionary<RouteRecord> = oldPathMap || Object.create(null)
// $flow-disable-line
const nameMap: Dictionary<RouteRecord> = oldNameMap || Object.create(null)
routes.forEach(route => {
addRouteRecord(pathList, pathMap, nameMap, route, parentRoute)
})
// ensure wildcard routes are always at the end
for (let i = 0, l = pathList.length; i < l; i++) {
if (pathList[i] === '*') {
pathList.push(pathList.splice(i, 1)[0])
l--
i--
}
}
if (process.env.NODE_ENV === 'development') {
// warn if routes do not include leading slashes
const found = pathList
// check for missing leading slash
.filter(path => path && path.charAt(0) !== '*' && path.charAt(0) !== '/')
if (found.length > 0) {
const pathNames = found.map(path => `- ${path}`).join('\n')
warn(false, `Non-nested routes must include a leading slash character. Fix the following routes: \n${pathNames}`)
}
}
return {
pathList,
pathMap,
nameMap
}
}
function addRouteRecord (
pathList: Array<string>,
pathMap: Dictionary<RouteRecord>,
nameMap: Dictionary<RouteRecord>,
route: RouteConfig,
parent?: RouteRecord,
matchAs?: string
) {
const { path, name } = route
if (process.env.NODE_ENV !== 'production') {
assert(path != null, `"path" is required in a route configuration.`)
assert(
typeof route.component !== 'string',
`route config "component" for path: ${String(
path || name
)} cannot be a ` + `string id. Use an actual component instead.`
)
warn(
// eslint-disable-next-line no-control-regex
!/[^\u0000-\u007F]+/.test(path),
`Route with path "${path}" contains unencoded characters, make sure ` +
`your path is correctly encoded before passing it to the router. Use ` +
`encodeURI to encode static segments of your path.`
)
}
const pathToRegexpOptions: PathToRegexpOptions =
route.pathToRegexpOptions || {}
const normalizedPath = normalizePath(path, parent, pathToRegexpOptions.strict)
if (typeof route.caseSensitive === 'boolean') {
pathToRegexpOptions.sensitive = route.caseSensitive
}
const record: RouteRecord = {
path: normalizedPath,
regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
components: route.components || { default: route.component },
alias: route.alias
? typeof route.alias === 'string'
? [route.alias]
: route.alias
: [],
instances: {},
enteredCbs: {},
name,
parent,
matchAs,
redirect: route.redirect,
beforeEnter: route.beforeEnter,
meta: route.meta || {},
props:
route.props == null
? {}
: route.components
? route.props
: { default: route.props }
}
if (route.children) {
// Warn if route is named, does not redirect and has a default child route.
// If users navigate to this route by name, the default child will
// not be rendered (GH Issue #629)
if (process.env.NODE_ENV !== 'production') {
if (
route.name &&
!route.redirect &&
route.children.some(child => /^\/?$/.test(child.path))
) {
warn(
false,
`Named Route '${route.name}' has a default child route. ` +
`When navigating to this named route (:to="{name: '${
route.name
}'}"), ` +
`the default child route will not be rendered. Remove the name from ` +
`this route and use the name of the default child route for named ` +
`links instead.`
)
}
}
route.children.forEach(child => {
const childMatchAs = matchAs
? cleanPath(`${matchAs}/${child.path}`)
: undefined
addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs)
})
}
if (!pathMap[record.path]) {
pathList.push(record.path)
pathMap[record.path] = record
}
if (route.alias !== undefined) {
const aliases = Array.isArray(route.alias) ? route.alias : [route.alias]
for (let i = 0; i < aliases.length; ++i) {
const alias = aliases[i]
if (process.env.NODE_ENV !== 'production' && alias === path) {
warn(
false,
`Found an alias with the same value as the path: "${path}". You have to remove that alias. It will be ignored in development.`
)
// skip in dev to make it work
continue
}
const aliasRoute = {
path: alias,
children: route.children
}
addRouteRecord(
pathList,
pathMap,
nameMap,
aliasRoute,
parent,
record.path || '/' // matchAs
)
}
}
if (name) {
if (!nameMap[name]) {
nameMap[name] = record
} else if (process.env.NODE_ENV !== 'production' && !matchAs) {
warn(
false,
`Duplicate named routes definition: ` +
`{ name: "${name}", path: "${record.path}" }`
)
}
}
}
function compileRouteRegex (
path: string,
pathToRegexpOptions: PathToRegexpOptions
): RouteRegExp {
const regex = Regexp(path, [], pathToRegexpOptions)
if (process.env.NODE_ENV !== 'production') {
const keys: any = Object.create(null)
regex.keys.forEach(key => {
warn(
!keys[key.name],
`Duplicate param keys in route with path: "${path}"`
)
keys[key.name] = true
})
}
return regex
}
function normalizePath (
path: string,
parent?: RouteRecord,
strict?: boolean
): string {
if (!strict) path = path.replace(/\/$/, '')
if (path[0] === '/') return path
if (parent == null) return path
return cleanPath(`${parent.path}/${path}`)
}

3
node_modules/vue-router/src/entries/cjs.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
import VueRouter from '../router'
export default VueRouter

12
node_modules/vue-router/src/entries/esm.js generated vendored Normal file
View File

@ -0,0 +1,12 @@
import VueRouter from '../router'
export const version = '__VERSION__'
export { isNavigationFailure, NavigationFailureType } from '../util/errors'
export { START as START_LOCATION } from '../util/route'
export { default as RouterLink } from '../components/link'
export { default as RouterView } from '../components/view'
// we can't add the other composables here because people could still be using an older version of vue and that would
// create a compilation error trying to import from vue
export default VueRouter

72
node_modules/vue-router/src/history/abstract.js generated vendored Normal file
View File

@ -0,0 +1,72 @@
/* @flow */
import type Router from '../index'
import { History } from './base'
import { NavigationFailureType, isNavigationFailure } from '../util/errors'
export class AbstractHistory extends History {
index: number
stack: Array<Route>
constructor (router: Router, base: ?string) {
super(router, base)
this.stack = []
this.index = -1
}
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.transitionTo(
location,
route => {
this.stack = this.stack.slice(0, this.index + 1).concat(route)
this.index++
onComplete && onComplete(route)
},
onAbort
)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.transitionTo(
location,
route => {
this.stack = this.stack.slice(0, this.index).concat(route)
onComplete && onComplete(route)
},
onAbort
)
}
go (n: number) {
const targetIndex = this.index + n
if (targetIndex < 0 || targetIndex >= this.stack.length) {
return
}
const route = this.stack[targetIndex]
this.confirmTransition(
route,
() => {
const prev = this.current
this.index = targetIndex
this.updateRoute(route)
this.router.afterHooks.forEach(hook => {
hook && hook(route, prev)
})
},
err => {
if (isNavigationFailure(err, NavigationFailureType.duplicated)) {
this.index = targetIndex
}
}
)
}
getCurrentLocation () {
const current = this.stack[this.stack.length - 1]
return current ? current.fullPath : '/'
}
ensureURL () {
// noop
}
}

384
node_modules/vue-router/src/history/base.js generated vendored Normal file
View File

@ -0,0 +1,384 @@
/* @flow */
import { _Vue } from '../install'
import type Router from '../index'
import { inBrowser } from '../util/dom'
import { runQueue } from '../util/async'
import { warn } from '../util/warn'
import { START, isSameRoute, handleRouteEntered } from '../util/route'
import {
flatten,
flatMapComponents,
resolveAsyncComponents
} from '../util/resolve-components'
import {
createNavigationDuplicatedError,
createNavigationCancelledError,
createNavigationRedirectedError,
createNavigationAbortedError,
isError,
isNavigationFailure,
NavigationFailureType
} from '../util/errors'
import { handleScroll } from '../util/scroll'
export class History {
router: Router
base: string
current: Route
pending: ?Route
cb: (r: Route) => void
ready: boolean
readyCbs: Array<Function>
readyErrorCbs: Array<Function>
errorCbs: Array<Function>
listeners: Array<Function>
cleanupListeners: Function
// implemented by sub-classes
+go: (n: number) => void
+push: (loc: RawLocation, onComplete?: Function, onAbort?: Function) => void
+replace: (
loc: RawLocation,
onComplete?: Function,
onAbort?: Function
) => void
+ensureURL: (push?: boolean) => void
+getCurrentLocation: () => string
+setupListeners: Function
constructor (router: Router, base: ?string) {
this.router = router
this.base = normalizeBase(base)
// start with a route object that stands for "nowhere"
this.current = START
this.pending = null
this.ready = false
this.readyCbs = []
this.readyErrorCbs = []
this.errorCbs = []
this.listeners = []
}
listen (cb: Function) {
this.cb = cb
}
onReady (cb: Function, errorCb: ?Function) {
if (this.ready) {
cb()
} else {
this.readyCbs.push(cb)
if (errorCb) {
this.readyErrorCbs.push(errorCb)
}
}
}
onError (errorCb: Function) {
this.errorCbs.push(errorCb)
}
transitionTo (
location: RawLocation,
onComplete?: Function,
onAbort?: Function
) {
let route
// catch redirect option https://github.com/vuejs/vue-router/issues/3201
try {
route = this.router.match(location, this.current)
} catch (e) {
this.errorCbs.forEach(cb => {
cb(e)
})
// Exception should still be thrown
throw e
}
const prev = this.current
this.confirmTransition(
route,
() => {
this.updateRoute(route)
onComplete && onComplete(route)
this.ensureURL()
this.router.afterHooks.forEach(hook => {
hook && hook(route, prev)
})
// fire ready cbs once
if (!this.ready) {
this.ready = true
this.readyCbs.forEach(cb => {
cb(route)
})
}
},
err => {
if (onAbort) {
onAbort(err)
}
if (err && !this.ready) {
// Initial redirection should not mark the history as ready yet
// because it's triggered by the redirection instead
// https://github.com/vuejs/vue-router/issues/3225
// https://github.com/vuejs/vue-router/issues/3331
if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {
this.ready = true
this.readyErrorCbs.forEach(cb => {
cb(err)
})
}
}
}
)
}
confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
const current = this.current
this.pending = route
const abort = err => {
// changed after adding errors with
// https://github.com/vuejs/vue-router/pull/3047 before that change,
// redirect and aborted navigation would produce an err == null
if (!isNavigationFailure(err) && isError(err)) {
if (this.errorCbs.length) {
this.errorCbs.forEach(cb => {
cb(err)
})
} else {
if (process.env.NODE_ENV !== 'production') {
warn(false, 'uncaught error during route navigation:')
}
console.error(err)
}
}
onAbort && onAbort(err)
}
const lastRouteIndex = route.matched.length - 1
const lastCurrentIndex = current.matched.length - 1
if (
isSameRoute(route, current) &&
// in the case the route map has been dynamically appended to
lastRouteIndex === lastCurrentIndex &&
route.matched[lastRouteIndex] === current.matched[lastCurrentIndex]
) {
this.ensureURL()
if (route.hash) {
handleScroll(this.router, current, route, false)
}
return abort(createNavigationDuplicatedError(current, route))
}
const { updated, deactivated, activated } = resolveQueue(
this.current.matched,
route.matched
)
const queue: Array<?NavigationGuard> = [].concat(
// in-component leave guards
extractLeaveGuards(deactivated),
// global before hooks
this.router.beforeHooks,
// in-component update hooks
extractUpdateHooks(updated),
// in-config enter guards
activated.map(m => m.beforeEnter),
// async components
resolveAsyncComponents(activated)
)
const iterator = (hook: NavigationGuard, next) => {
if (this.pending !== route) {
return abort(createNavigationCancelledError(current, route))
}
try {
hook(route, current, (to: any) => {
if (to === false) {
// next(false) -> abort navigation, ensure current URL
this.ensureURL(true)
abort(createNavigationAbortedError(current, route))
} else if (isError(to)) {
this.ensureURL(true)
abort(to)
} else if (
typeof to === 'string' ||
(typeof to === 'object' &&
(typeof to.path === 'string' || typeof to.name === 'string'))
) {
// next('/') or next({ path: '/' }) -> redirect
abort(createNavigationRedirectedError(current, route))
if (typeof to === 'object' && to.replace) {
this.replace(to)
} else {
this.push(to)
}
} else {
// confirm transition and pass on the value
next(to)
}
})
} catch (e) {
abort(e)
}
}
runQueue(queue, iterator, () => {
// wait until async components are resolved before
// extracting in-component enter guards
const enterGuards = extractEnterGuards(activated)
const queue = enterGuards.concat(this.router.resolveHooks)
runQueue(queue, iterator, () => {
if (this.pending !== route) {
return abort(createNavigationCancelledError(current, route))
}
this.pending = null
onComplete(route)
if (this.router.app) {
this.router.app.$nextTick(() => {
handleRouteEntered(route)
})
}
})
})
}
updateRoute (route: Route) {
this.current = route
this.cb && this.cb(route)
}
setupListeners () {
// Default implementation is empty
}
teardown () {
// clean up event listeners
// https://github.com/vuejs/vue-router/issues/2341
this.listeners.forEach(cleanupListener => {
cleanupListener()
})
this.listeners = []
// reset current history route
// https://github.com/vuejs/vue-router/issues/3294
this.current = START
this.pending = null
}
}
function normalizeBase (base: ?string): string {
if (!base) {
if (inBrowser) {
// respect <base> tag
const baseEl = document.querySelector('base')
base = (baseEl && baseEl.getAttribute('href')) || '/'
// strip full URL origin
base = base.replace(/^https?:\/\/[^\/]+/, '')
} else {
base = '/'
}
}
// make sure there's the starting slash
if (base.charAt(0) !== '/') {
base = '/' + base
}
// remove trailing slash
return base.replace(/\/$/, '')
}
function resolveQueue (
current: Array<RouteRecord>,
next: Array<RouteRecord>
): {
updated: Array<RouteRecord>,
activated: Array<RouteRecord>,
deactivated: Array<RouteRecord>
} {
let i
const max = Math.max(current.length, next.length)
for (i = 0; i < max; i++) {
if (current[i] !== next[i]) {
break
}
}
return {
updated: next.slice(0, i),
activated: next.slice(i),
deactivated: current.slice(i)
}
}
function extractGuards (
records: Array<RouteRecord>,
name: string,
bind: Function,
reverse?: boolean
): Array<?Function> {
const guards = flatMapComponents(records, (def, instance, match, key) => {
const guard = extractGuard(def, name)
if (guard) {
return Array.isArray(guard)
? guard.map(guard => bind(guard, instance, match, key))
: bind(guard, instance, match, key)
}
})
return flatten(reverse ? guards.reverse() : guards)
}
function extractGuard (
def: Object | Function,
key: string
): NavigationGuard | Array<NavigationGuard> {
if (typeof def !== 'function') {
// extend now so that global mixins are applied.
def = _Vue.extend(def)
}
return def.options[key]
}
function extractLeaveGuards (deactivated: Array<RouteRecord>): Array<?Function> {
return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
}
function extractUpdateHooks (updated: Array<RouteRecord>): Array<?Function> {
return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
}
function bindGuard (guard: NavigationGuard, instance: ?_Vue): ?NavigationGuard {
if (instance) {
return function boundRouteGuard () {
return guard.apply(instance, arguments)
}
}
}
function extractEnterGuards (
activated: Array<RouteRecord>
): Array<?Function> {
return extractGuards(
activated,
'beforeRouteEnter',
(guard, _, match, key) => {
return bindEnterGuard(guard, match, key)
}
)
}
function bindEnterGuard (
guard: NavigationGuard,
match: RouteRecord,
key: string
): NavigationGuard {
return function routeEnterGuard (to, from, next) {
return guard(to, from, cb => {
if (typeof cb === 'function') {
if (!match.enteredCbs[key]) {
match.enteredCbs[key] = []
}
match.enteredCbs[key].push(cb)
}
next(cb)
})
}
}

152
node_modules/vue-router/src/history/hash.js generated vendored Normal file
View File

@ -0,0 +1,152 @@
/* @flow */
import type Router from '../index'
import { History } from './base'
import { cleanPath } from '../util/path'
import { getLocation } from './html5'
import { setupScroll, handleScroll } from '../util/scroll'
import { pushState, replaceState, supportsPushState } from '../util/push-state'
export class HashHistory extends History {
constructor (router: Router, base: ?string, fallback: boolean) {
super(router, base)
// check history fallback deeplinking
if (fallback && checkFallback(this.base)) {
return
}
ensureSlash()
}
// this is delayed until the app mounts
// to avoid the hashchange listener being fired too early
setupListeners () {
if (this.listeners.length > 0) {
return
}
const router = this.router
const expectScroll = router.options.scrollBehavior
const supportsScroll = supportsPushState && expectScroll
if (supportsScroll) {
this.listeners.push(setupScroll())
}
const handleRoutingEvent = () => {
const current = this.current
if (!ensureSlash()) {
return
}
this.transitionTo(getHash(), route => {
if (supportsScroll) {
handleScroll(this.router, route, current, true)
}
if (!supportsPushState) {
replaceHash(route.fullPath)
}
})
}
const eventType = supportsPushState ? 'popstate' : 'hashchange'
window.addEventListener(
eventType,
handleRoutingEvent
)
this.listeners.push(() => {
window.removeEventListener(eventType, handleRoutingEvent)
})
}
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
this.transitionTo(
location,
route => {
pushHash(route.fullPath)
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
},
onAbort
)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
this.transitionTo(
location,
route => {
replaceHash(route.fullPath)
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
},
onAbort
)
}
go (n: number) {
window.history.go(n)
}
ensureURL (push?: boolean) {
const current = this.current.fullPath
if (getHash() !== current) {
push ? pushHash(current) : replaceHash(current)
}
}
getCurrentLocation () {
return getHash()
}
}
function checkFallback (base) {
const location = getLocation(base)
if (!/^\/#/.test(location)) {
window.location.replace(cleanPath(base + '/#' + location))
return true
}
}
function ensureSlash (): boolean {
const path = getHash()
if (path.charAt(0) === '/') {
return true
}
replaceHash('/' + path)
return false
}
export function getHash (): string {
// We can't use window.location.hash here because it's not
// consistent across browsers - Firefox will pre-decode it!
let href = window.location.href
const index = href.indexOf('#')
// empty path
if (index < 0) return ''
href = href.slice(index + 1)
return href
}
function getUrl (path) {
const href = window.location.href
const i = href.indexOf('#')
const base = i >= 0 ? href.slice(0, i) : href
return `${base}#${path}`
}
function pushHash (path) {
if (supportsPushState) {
pushState(getUrl(path))
} else {
window.location.hash = path
}
}
function replaceHash (path) {
if (supportsPushState) {
replaceState(getUrl(path))
} else {
window.location.replace(getUrl(path))
}
}

100
node_modules/vue-router/src/history/html5.js generated vendored Normal file
View File

@ -0,0 +1,100 @@
/* @flow */
import type Router from '../index'
import { History } from './base'
import { cleanPath } from '../util/path'
import { START } from '../util/route'
import { setupScroll, handleScroll } from '../util/scroll'
import { pushState, replaceState, supportsPushState } from '../util/push-state'
export class HTML5History extends History {
_startLocation: string
constructor (router: Router, base: ?string) {
super(router, base)
this._startLocation = getLocation(this.base)
}
setupListeners () {
if (this.listeners.length > 0) {
return
}
const router = this.router
const expectScroll = router.options.scrollBehavior
const supportsScroll = supportsPushState && expectScroll
if (supportsScroll) {
this.listeners.push(setupScroll())
}
const handleRoutingEvent = () => {
const current = this.current
// Avoiding first `popstate` event dispatched in some browsers but first
// history route not updated since async guard at the same time.
const location = getLocation(this.base)
if (this.current === START && location === this._startLocation) {
return
}
this.transitionTo(location, route => {
if (supportsScroll) {
handleScroll(router, route, current, true)
}
})
}
window.addEventListener('popstate', handleRoutingEvent)
this.listeners.push(() => {
window.removeEventListener('popstate', handleRoutingEvent)
})
}
go (n: number) {
window.history.go(n)
}
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
this.transitionTo(location, route => {
pushState(cleanPath(this.base + route.fullPath))
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
}, onAbort)
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
this.transitionTo(location, route => {
replaceState(cleanPath(this.base + route.fullPath))
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
}, onAbort)
}
ensureURL (push?: boolean) {
if (getLocation(this.base) !== this.current.fullPath) {
const current = cleanPath(this.base + this.current.fullPath)
push ? pushState(current) : replaceState(current)
}
}
getCurrentLocation (): string {
return getLocation(this.base)
}
}
export function getLocation (base: string): string {
let path = window.location.pathname
const pathLowerCase = path.toLowerCase()
const baseLowerCase = base.toLowerCase()
// base="/a" shouldn't turn path="/app" into "/a/pp"
// https://github.com/vuejs/vue-router/issues/3555
// so we ensure the trailing slash in the base
if (base && ((pathLowerCase === baseLowerCase) ||
(pathLowerCase.indexOf(cleanPath(baseLowerCase + '/')) === 0))) {
path = path.slice(base.length)
}
return (path || '/') + window.location.search + window.location.hash
}

3
node_modules/vue-router/src/index.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
import VueRouter from './entries/cjs'
export default VueRouter

52
node_modules/vue-router/src/install.js generated vendored Normal file
View File

@ -0,0 +1,52 @@
import View from './components/view'
import Link from './components/link'
export let _Vue
export function install (Vue) {
if (install.installed && _Vue === Vue) return
install.installed = true
_Vue = Vue
const isDef = v => v !== undefined
const registerInstance = (vm, callVal) => {
let i = vm.$options._parentVnode
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
i(vm, callVal)
}
}
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
Object.defineProperty(Vue.prototype, '$router', {
get () { return this._routerRoot._router }
})
Object.defineProperty(Vue.prototype, '$route', {
get () { return this._routerRoot._route }
})
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}

294
node_modules/vue-router/src/router.js generated vendored Normal file
View File

@ -0,0 +1,294 @@
/* @flow */
import { install } from './install'
import { START } from './util/route'
import { assert, warn } from './util/warn'
import { inBrowser } from './util/dom'
import { cleanPath } from './util/path'
import { createMatcher } from './create-matcher'
import { normalizeLocation } from './util/location'
import { supportsPushState } from './util/push-state'
import { handleScroll } from './util/scroll'
import { isNavigationFailure, NavigationFailureType } from './util/errors'
import { HashHistory } from './history/hash'
import { HTML5History } from './history/html5'
import { AbstractHistory } from './history/abstract'
import type { Matcher } from './create-matcher'
export default class VueRouter {
static install: () => void
static version: string
static isNavigationFailure: Function
static NavigationFailureType: any
static START_LOCATION: Route
app: any
apps: Array<any>
ready: boolean
readyCbs: Array<Function>
options: RouterOptions
mode: string
history: HashHistory | HTML5History | AbstractHistory
matcher: Matcher
fallback: boolean
beforeHooks: Array<?NavigationGuard>
resolveHooks: Array<?NavigationGuard>
afterHooks: Array<?AfterNavigationHook>
constructor (options: RouterOptions = {}) {
if (process.env.NODE_ENV !== 'production') {
warn(this instanceof VueRouter, `Router must be called with the new operator.`)
}
this.app = null
this.apps = []
this.options = options
this.beforeHooks = []
this.resolveHooks = []
this.afterHooks = []
this.matcher = createMatcher(options.routes || [], this)
let mode = options.mode || 'hash'
this.fallback =
mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract'
}
this.mode = mode
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
}
match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route {
return this.matcher.match(raw, current, redirectedFrom)
}
get currentRoute (): ?Route {
return this.history && this.history.current
}
init (app: any /* Vue component instance */) {
process.env.NODE_ENV !== 'production' &&
assert(
install.installed,
`not installed. Make sure to call \`Vue.use(VueRouter)\` ` +
`before creating root instance.`
)
this.apps.push(app)
// set up app destroyed handler
// https://github.com/vuejs/vue-router/issues/2639
app.$once('hook:destroyed', () => {
// clean out app from this.apps array once destroyed
const index = this.apps.indexOf(app)
if (index > -1) this.apps.splice(index, 1)
// ensure we still have a main app or null if no apps
// we do not release the router so it can be reused
if (this.app === app) this.app = this.apps[0] || null
if (!this.app) this.history.teardown()
})
// main app previously initialized
// return as we don't need to set up new history listener
if (this.app) {
return
}
this.app = app
const history = this.history
if (history instanceof HTML5History || history instanceof HashHistory) {
const handleInitialScroll = routeOrError => {
const from = history.current
const expectScroll = this.options.scrollBehavior
const supportsScroll = supportsPushState && expectScroll
if (supportsScroll && 'fullPath' in routeOrError) {
handleScroll(this, routeOrError, from, false)
}
}
const setupListeners = routeOrError => {
history.setupListeners()
handleInitialScroll(routeOrError)
}
history.transitionTo(
history.getCurrentLocation(),
setupListeners,
setupListeners
)
}
history.listen(route => {
this.apps.forEach(app => {
app._route = route
})
})
}
beforeEach (fn: Function): Function {
return registerHook(this.beforeHooks, fn)
}
beforeResolve (fn: Function): Function {
return registerHook(this.resolveHooks, fn)
}
afterEach (fn: Function): Function {
return registerHook(this.afterHooks, fn)
}
onReady (cb: Function, errorCb?: Function) {
this.history.onReady(cb, errorCb)
}
onError (errorCb: Function) {
this.history.onError(errorCb)
}
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
// $flow-disable-line
if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
this.history.push(location, resolve, reject)
})
} else {
this.history.push(location, onComplete, onAbort)
}
}
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
// $flow-disable-line
if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
this.history.replace(location, resolve, reject)
})
} else {
this.history.replace(location, onComplete, onAbort)
}
}
go (n: number) {
this.history.go(n)
}
back () {
this.go(-1)
}
forward () {
this.go(1)
}
getMatchedComponents (to?: RawLocation | Route): Array<any> {
const route: any = to
? to.matched
? to
: this.resolve(to).route
: this.currentRoute
if (!route) {
return []
}
return [].concat.apply(
[],
route.matched.map(m => {
return Object.keys(m.components).map(key => {
return m.components[key]
})
})
)
}
resolve (
to: RawLocation,
current?: Route,
append?: boolean
): {
location: Location,
route: Route,
href: string,
// for backwards compat
normalizedTo: Location,
resolved: Route
} {
current = current || this.history.current
const location = normalizeLocation(to, current, append, this)
const route = this.match(location, current)
const fullPath = route.redirectedFrom || route.fullPath
const base = this.history.base
const href = createHref(base, fullPath, this.mode)
return {
location,
route,
href,
// for backwards compat
normalizedTo: location,
resolved: route
}
}
getRoutes () {
return this.matcher.getRoutes()
}
addRoute (parentOrRoute: string | RouteConfig, route?: RouteConfig) {
this.matcher.addRoute(parentOrRoute, route)
if (this.history.current !== START) {
this.history.transitionTo(this.history.getCurrentLocation())
}
}
addRoutes (routes: Array<RouteConfig>) {
if (process.env.NODE_ENV !== 'production') {
warn(false, 'router.addRoutes() is deprecated and has been removed in Vue Router 4. Use router.addRoute() instead.')
}
this.matcher.addRoutes(routes)
if (this.history.current !== START) {
this.history.transitionTo(this.history.getCurrentLocation())
}
}
}
function registerHook (list: Array<any>, fn: Function): Function {
list.push(fn)
return () => {
const i = list.indexOf(fn)
if (i > -1) list.splice(i, 1)
}
}
function createHref (base: string, fullPath: string, mode) {
var path = mode === 'hash' ? '#' + fullPath : fullPath
return base ? cleanPath(base + '/' + path) : path
}
// We cannot remove this as it would be a breaking change
VueRouter.install = install
VueRouter.version = '__VERSION__'
VueRouter.isNavigationFailure = isNavigationFailure
VueRouter.NavigationFailureType = NavigationFailureType
VueRouter.START_LOCATION = START
if (inBrowser && window.Vue) {
window.Vue.use(VueRouter)
}

18
node_modules/vue-router/src/util/async.js generated vendored Normal file
View File

@ -0,0 +1,18 @@
/* @flow */
export function runQueue (queue: Array<?NavigationGuard>, fn: Function, cb: Function) {
const step = index => {
if (index >= queue.length) {
cb()
} else {
if (queue[index]) {
fn(queue[index], () => {
step(index + 1)
})
} else {
step(index + 1)
}
}
}
step(0)
}

3
node_modules/vue-router/src/util/dom.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
/* @flow */
export const inBrowser = typeof window !== 'undefined'

86
node_modules/vue-router/src/util/errors.js generated vendored Normal file
View File

@ -0,0 +1,86 @@
// When changing thing, also edit router.d.ts
export const NavigationFailureType = {
redirected: 2,
aborted: 4,
cancelled: 8,
duplicated: 16
}
export function createNavigationRedirectedError (from, to) {
return createRouterError(
from,
to,
NavigationFailureType.redirected,
`Redirected when going from "${from.fullPath}" to "${stringifyRoute(
to
)}" via a navigation guard.`
)
}
export function createNavigationDuplicatedError (from, to) {
const error = createRouterError(
from,
to,
NavigationFailureType.duplicated,
`Avoided redundant navigation to current location: "${from.fullPath}".`
)
// backwards compatible with the first introduction of Errors
error.name = 'NavigationDuplicated'
return error
}
export function createNavigationCancelledError (from, to) {
return createRouterError(
from,
to,
NavigationFailureType.cancelled,
`Navigation cancelled from "${from.fullPath}" to "${
to.fullPath
}" with a new navigation.`
)
}
export function createNavigationAbortedError (from, to) {
return createRouterError(
from,
to,
NavigationFailureType.aborted,
`Navigation aborted from "${from.fullPath}" to "${
to.fullPath
}" via a navigation guard.`
)
}
function createRouterError (from, to, type, message) {
const error = new Error(message)
error._isRouter = true
error.from = from
error.to = to
error.type = type
return error
}
const propertiesToLog = ['params', 'query', 'hash']
function stringifyRoute (to) {
if (typeof to === 'string') return to
if ('path' in to) return to.path
const location = {}
propertiesToLog.forEach(key => {
if (key in to) location[key] = to[key]
})
return JSON.stringify(location, null, 2)
}
export function isError (err) {
return Object.prototype.toString.call(err).indexOf('Error') > -1
}
export function isNavigationFailure (err, errorType) {
return (
isError(err) &&
err._isRouter &&
(errorType == null || err.type === errorType)
)
}

69
node_modules/vue-router/src/util/location.js generated vendored Normal file
View File

@ -0,0 +1,69 @@
/* @flow */
import type VueRouter from '../index'
import { parsePath, resolvePath } from './path'
import { resolveQuery } from './query'
import { fillParams } from './params'
import { warn } from './warn'
import { extend } from './misc'
export function normalizeLocation (
raw: RawLocation,
current: ?Route,
append: ?boolean,
router: ?VueRouter
): Location {
let next: Location = typeof raw === 'string' ? { path: raw } : raw
// named target
if (next._normalized) {
return next
} else if (next.name) {
next = extend({}, raw)
const params = next.params
if (params && typeof params === 'object') {
next.params = extend({}, params)
}
return next
}
// relative params
if (!next.path && next.params && current) {
next = extend({}, next)
next._normalized = true
const params: any = extend(extend({}, current.params), next.params)
if (current.name) {
next.name = current.name
next.params = params
} else if (current.matched.length) {
const rawPath = current.matched[current.matched.length - 1].path
next.path = fillParams(rawPath, params, `path ${current.path}`)
} else if (process.env.NODE_ENV !== 'production') {
warn(false, `relative params navigation requires a current route.`)
}
return next
}
const parsedPath = parsePath(next.path || '')
const basePath = (current && current.path) || '/'
const path = parsedPath.path
? resolvePath(parsedPath.path, basePath, append || next.append)
: basePath
const query = resolveQuery(
parsedPath.query,
next.query,
router && router.options.parseQuery
)
let hash = next.hash || parsedPath.hash
if (hash && hash.charAt(0) !== '#') {
hash = `#${hash}`
}
return {
_normalized: true,
path,
query,
hash
}
}

6
node_modules/vue-router/src/util/misc.js generated vendored Normal file
View File

@ -0,0 +1,6 @@
export function extend (a, b) {
for (const key in b) {
a[key] = b[key]
}
return a
}

37
node_modules/vue-router/src/util/params.js generated vendored Normal file
View File

@ -0,0 +1,37 @@
/* @flow */
import { warn } from './warn'
import Regexp from 'path-to-regexp'
// $flow-disable-line
const regexpCompileCache: {
[key: string]: Function
} = Object.create(null)
export function fillParams (
path: string,
params: ?Object,
routeMsg: string
): string {
params = params || {}
try {
const filler =
regexpCompileCache[path] ||
(regexpCompileCache[path] = Regexp.compile(path))
// Fix #2505 resolving asterisk routes { name: 'not-found', params: { pathMatch: '/not-found' }}
// and fix #3106 so that you can work with location descriptor object having params.pathMatch equal to empty string
if (typeof params.pathMatch === 'string') params[0] = params.pathMatch
return filler(params, { pretty: true })
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
// Fix #3072 no warn if `pathMatch` is string
warn(typeof params.pathMatch === 'string', `missing param for ${routeMsg}: ${e.message}`)
}
return ''
} finally {
// delete the 0 if it was added
delete params[0]
}
}

74
node_modules/vue-router/src/util/path.js generated vendored Normal file
View File

@ -0,0 +1,74 @@
/* @flow */
export function resolvePath (
relative: string,
base: string,
append?: boolean
): string {
const firstChar = relative.charAt(0)
if (firstChar === '/') {
return relative
}
if (firstChar === '?' || firstChar === '#') {
return base + relative
}
const stack = base.split('/')
// remove trailing segment if:
// - not appending
// - appending to trailing slash (last segment is empty)
if (!append || !stack[stack.length - 1]) {
stack.pop()
}
// resolve relative path
const segments = relative.replace(/^\//, '').split('/')
for (let i = 0; i < segments.length; i++) {
const segment = segments[i]
if (segment === '..') {
stack.pop()
} else if (segment !== '.') {
stack.push(segment)
}
}
// ensure leading slash
if (stack[0] !== '') {
stack.unshift('')
}
return stack.join('/')
}
export function parsePath (path: string): {
path: string;
query: string;
hash: string;
} {
let hash = ''
let query = ''
const hashIndex = path.indexOf('#')
if (hashIndex >= 0) {
hash = path.slice(hashIndex)
path = path.slice(0, hashIndex)
}
const queryIndex = path.indexOf('?')
if (queryIndex >= 0) {
query = path.slice(queryIndex + 1)
path = path.slice(0, queryIndex)
}
return {
path,
query,
hash
}
}
export function cleanPath (path: string): string {
return path.replace(/\/(?:\s*\/)+/g, '/')
}

46
node_modules/vue-router/src/util/push-state.js generated vendored Normal file
View File

@ -0,0 +1,46 @@
/* @flow */
import { inBrowser } from './dom'
import { saveScrollPosition } from './scroll'
import { genStateKey, setStateKey, getStateKey } from './state-key'
import { extend } from './misc'
export const supportsPushState =
inBrowser &&
(function () {
const ua = window.navigator.userAgent
if (
(ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
ua.indexOf('Mobile Safari') !== -1 &&
ua.indexOf('Chrome') === -1 &&
ua.indexOf('Windows Phone') === -1
) {
return false
}
return window.history && typeof window.history.pushState === 'function'
})()
export function pushState (url?: string, replace?: boolean) {
saveScrollPosition()
// try...catch the pushState call to get around Safari
// DOM Exception 18 where it limits to 100 pushState calls
const history = window.history
try {
if (replace) {
// preserve existing history state as it could be overriden by the user
const stateCopy = extend({}, history.state)
stateCopy.key = getStateKey()
history.replaceState(stateCopy, '', url)
} else {
history.pushState({ key: setStateKey(genStateKey()) }, '', url)
}
} catch (e) {
window.location[replace ? 'replace' : 'assign'](url)
}
}
export function replaceState (url?: string) {
pushState(url, true)
}

113
node_modules/vue-router/src/util/query.js generated vendored Normal file
View File

@ -0,0 +1,113 @@
/* @flow */
import { warn } from './warn'
const encodeReserveRE = /[!'()*]/g
const encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16)
const commaRE = /%2C/g
// fixed encodeURIComponent which is more conformant to RFC3986:
// - escapes [!'()*]
// - preserve commas
const encode = str =>
encodeURIComponent(str)
.replace(encodeReserveRE, encodeReserveReplacer)
.replace(commaRE, ',')
export function decode (str: string) {
try {
return decodeURIComponent(str)
} catch (err) {
if (process.env.NODE_ENV !== 'production') {
warn(false, `Error decoding "${str}". Leaving it intact.`)
}
}
return str
}
export function resolveQuery (
query: ?string,
extraQuery: Dictionary<string> = {},
_parseQuery: ?Function
): Dictionary<string> {
const parse = _parseQuery || parseQuery
let parsedQuery
try {
parsedQuery = parse(query || '')
} catch (e) {
process.env.NODE_ENV !== 'production' && warn(false, e.message)
parsedQuery = {}
}
for (const key in extraQuery) {
const value = extraQuery[key]
parsedQuery[key] = Array.isArray(value)
? value.map(castQueryParamValue)
: castQueryParamValue(value)
}
return parsedQuery
}
const castQueryParamValue = value => (value == null || typeof value === 'object' ? value : String(value))
function parseQuery (query: string): Dictionary<string> {
const res = {}
query = query.trim().replace(/^(\?|#|&)/, '')
if (!query) {
return res
}
query.split('&').forEach(param => {
const parts = param.replace(/\+/g, ' ').split('=')
const key = decode(parts.shift())
const val = parts.length > 0 ? decode(parts.join('=')) : null
if (res[key] === undefined) {
res[key] = val
} else if (Array.isArray(res[key])) {
res[key].push(val)
} else {
res[key] = [res[key], val]
}
})
return res
}
export function stringifyQuery (obj: Dictionary<string>): string {
const res = obj
? Object.keys(obj)
.map(key => {
const val = obj[key]
if (val === undefined) {
return ''
}
if (val === null) {
return encode(key)
}
if (Array.isArray(val)) {
const result = []
val.forEach(val2 => {
if (val2 === undefined) {
return
}
if (val2 === null) {
result.push(encode(key))
} else {
result.push(encode(key) + '=' + encode(val2))
}
})
return result.join('&')
}
return encode(key) + '=' + encode(val)
})
.filter(x => x.length > 0)
.join('&')
: null
return res ? `?${res}` : ''
}

109
node_modules/vue-router/src/util/resolve-components.js generated vendored Normal file
View File

@ -0,0 +1,109 @@
/* @flow */
import { _Vue } from '../install'
import { warn } from './warn'
import { isError } from '../util/errors'
export function resolveAsyncComponents (matched: Array<RouteRecord>): Function {
return (to, from, next) => {
let hasAsync = false
let pending = 0
let error = null
flatMapComponents(matched, (def, _, match, key) => {
// if it's a function and doesn't have cid attached,
// assume it's an async component resolve function.
// we are not using Vue's default async resolving mechanism because
// we want to halt the navigation until the incoming component has been
// resolved.
if (typeof def === 'function' && def.cid === undefined) {
hasAsync = true
pending++
const resolve = once(resolvedDef => {
if (isESModule(resolvedDef)) {
resolvedDef = resolvedDef.default
}
// save resolved on async factory in case it's used elsewhere
def.resolved = typeof resolvedDef === 'function'
? resolvedDef
: _Vue.extend(resolvedDef)
match.components[key] = resolvedDef
pending--
if (pending <= 0) {
next()
}
})
const reject = once(reason => {
const msg = `Failed to resolve async component ${key}: ${reason}`
process.env.NODE_ENV !== 'production' && warn(false, msg)
if (!error) {
error = isError(reason)
? reason
: new Error(msg)
next(error)
}
})
let res
try {
res = def(resolve, reject)
} catch (e) {
reject(e)
}
if (res) {
if (typeof res.then === 'function') {
res.then(resolve, reject)
} else {
// new syntax in Vue 2.3
const comp = res.component
if (comp && typeof comp.then === 'function') {
comp.then(resolve, reject)
}
}
}
}
})
if (!hasAsync) next()
}
}
export function flatMapComponents (
matched: Array<RouteRecord>,
fn: Function
): Array<?Function> {
return flatten(matched.map(m => {
return Object.keys(m.components).map(key => fn(
m.components[key],
m.instances[key],
m, key
))
}))
}
export function flatten (arr: Array<any>): Array<any> {
return Array.prototype.concat.apply([], arr)
}
const hasSymbol =
typeof Symbol === 'function' &&
typeof Symbol.toStringTag === 'symbol'
function isESModule (obj) {
return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
}
// in Webpack 2, require.ensure now also returns a Promise
// so the resolve/reject functions may get called an extra time
// if the user uses an arrow function shorthand that happens to
// return that Promise.
function once (fn) {
let called = false
return function (...args) {
if (called) return
called = true
return fn.apply(this, args)
}
}

151
node_modules/vue-router/src/util/route.js generated vendored Normal file
View File

@ -0,0 +1,151 @@
/* @flow */
import type VueRouter from '../index'
import { stringifyQuery } from './query'
const trailingSlashRE = /\/?$/
export function createRoute (
record: ?RouteRecord,
location: Location,
redirectedFrom?: ?Location,
router?: VueRouter
): Route {
const stringifyQuery = router && router.options.stringifyQuery
let query: any = location.query || {}
try {
query = clone(query)
} catch (e) {}
const route: Route = {
name: location.name || (record && record.name),
meta: (record && record.meta) || {},
path: location.path || '/',
hash: location.hash || '',
query,
params: location.params || {},
fullPath: getFullPath(location, stringifyQuery),
matched: record ? formatMatch(record) : []
}
if (redirectedFrom) {
route.redirectedFrom = getFullPath(redirectedFrom, stringifyQuery)
}
return Object.freeze(route)
}
function clone (value) {
if (Array.isArray(value)) {
return value.map(clone)
} else if (value && typeof value === 'object') {
const res = {}
for (const key in value) {
res[key] = clone(value[key])
}
return res
} else {
return value
}
}
// the starting route that represents the initial state
export const START = createRoute(null, {
path: '/'
})
function formatMatch (record: ?RouteRecord): Array<RouteRecord> {
const res = []
while (record) {
res.unshift(record)
record = record.parent
}
return res
}
function getFullPath (
{ path, query = {}, hash = '' },
_stringifyQuery
): string {
const stringify = _stringifyQuery || stringifyQuery
return (path || '/') + stringify(query) + hash
}
export function isSameRoute (a: Route, b: ?Route, onlyPath: ?boolean): boolean {
if (b === START) {
return a === b
} else if (!b) {
return false
} else if (a.path && b.path) {
return a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') && (onlyPath ||
a.hash === b.hash &&
isObjectEqual(a.query, b.query))
} else if (a.name && b.name) {
return (
a.name === b.name &&
(onlyPath || (
a.hash === b.hash &&
isObjectEqual(a.query, b.query) &&
isObjectEqual(a.params, b.params))
)
)
} else {
return false
}
}
function isObjectEqual (a = {}, b = {}): boolean {
// handle null value #1566
if (!a || !b) return a === b
const aKeys = Object.keys(a).sort()
const bKeys = Object.keys(b).sort()
if (aKeys.length !== bKeys.length) {
return false
}
return aKeys.every((key, i) => {
const aVal = a[key]
const bKey = bKeys[i]
if (bKey !== key) return false
const bVal = b[key]
// query values can be null and undefined
if (aVal == null || bVal == null) return aVal === bVal
// check nested equality
if (typeof aVal === 'object' && typeof bVal === 'object') {
return isObjectEqual(aVal, bVal)
}
return String(aVal) === String(bVal)
})
}
export function isIncludedRoute (current: Route, target: Route): boolean {
return (
current.path.replace(trailingSlashRE, '/').indexOf(
target.path.replace(trailingSlashRE, '/')
) === 0 &&
(!target.hash || current.hash === target.hash) &&
queryIncludes(current.query, target.query)
)
}
function queryIncludes (current: Dictionary<string>, target: Dictionary<string>): boolean {
for (const key in target) {
if (!(key in current)) {
return false
}
}
return true
}
export function handleRouteEntered (route: Route) {
for (let i = 0; i < route.matched.length; i++) {
const record = route.matched[i]
for (const name in record.instances) {
const instance = record.instances[name]
const cbs = record.enteredCbs[name]
if (!instance || !cbs) continue
delete record.enteredCbs[name]
for (let i = 0; i < cbs.length; i++) {
if (!instance._isBeingDestroyed) cbs[i](instance)
}
}
}
}

175
node_modules/vue-router/src/util/scroll.js generated vendored Normal file
View File

@ -0,0 +1,175 @@
/* @flow */
import type Router from '../index'
import { assert } from './warn'
import { getStateKey, setStateKey } from './state-key'
import { extend } from './misc'
const positionStore = Object.create(null)
export function setupScroll () {
// Prevent browser scroll behavior on History popstate
if ('scrollRestoration' in window.history) {
window.history.scrollRestoration = 'manual'
}
// Fix for #1585 for Firefox
// Fix for #2195 Add optional third attribute to workaround a bug in safari https://bugs.webkit.org/show_bug.cgi?id=182678
// Fix for #2774 Support for apps loaded from Windows file shares not mapped to network drives: replaced location.origin with
// window.location.protocol + '//' + window.location.host
// location.host contains the port and location.hostname doesn't
const protocolAndPath = window.location.protocol + '//' + window.location.host
const absolutePath = window.location.href.replace(protocolAndPath, '')
// preserve existing history state as it could be overriden by the user
const stateCopy = extend({}, window.history.state)
stateCopy.key = getStateKey()
window.history.replaceState(stateCopy, '', absolutePath)
window.addEventListener('popstate', handlePopState)
return () => {
window.removeEventListener('popstate', handlePopState)
}
}
export function handleScroll (
router: Router,
to: Route,
from: Route,
isPop: boolean
) {
if (!router.app) {
return
}
const behavior = router.options.scrollBehavior
if (!behavior) {
return
}
if (process.env.NODE_ENV !== 'production') {
assert(typeof behavior === 'function', `scrollBehavior must be a function`)
}
// wait until re-render finishes before scrolling
router.app.$nextTick(() => {
const position = getScrollPosition()
const shouldScroll = behavior.call(
router,
to,
from,
isPop ? position : null
)
if (!shouldScroll) {
return
}
if (typeof shouldScroll.then === 'function') {
shouldScroll
.then(shouldScroll => {
scrollToPosition((shouldScroll: any), position)
})
.catch(err => {
if (process.env.NODE_ENV !== 'production') {
assert(false, err.toString())
}
})
} else {
scrollToPosition(shouldScroll, position)
}
})
}
export function saveScrollPosition () {
const key = getStateKey()
if (key) {
positionStore[key] = {
x: window.pageXOffset,
y: window.pageYOffset
}
}
}
function handlePopState (e) {
saveScrollPosition()
if (e.state && e.state.key) {
setStateKey(e.state.key)
}
}
function getScrollPosition (): ?Object {
const key = getStateKey()
if (key) {
return positionStore[key]
}
}
function getElementPosition (el: Element, offset: Object): Object {
const docEl: any = document.documentElement
const docRect = docEl.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
return {
x: elRect.left - docRect.left - offset.x,
y: elRect.top - docRect.top - offset.y
}
}
function isValidPosition (obj: Object): boolean {
return isNumber(obj.x) || isNumber(obj.y)
}
function normalizePosition (obj: Object): Object {
return {
x: isNumber(obj.x) ? obj.x : window.pageXOffset,
y: isNumber(obj.y) ? obj.y : window.pageYOffset
}
}
function normalizeOffset (obj: Object): Object {
return {
x: isNumber(obj.x) ? obj.x : 0,
y: isNumber(obj.y) ? obj.y : 0
}
}
function isNumber (v: any): boolean {
return typeof v === 'number'
}
const hashStartsWithNumberRE = /^#\d/
function scrollToPosition (shouldScroll, position) {
const isObject = typeof shouldScroll === 'object'
if (isObject && typeof shouldScroll.selector === 'string') {
// getElementById would still fail if the selector contains a more complicated query like #main[data-attr]
// but at the same time, it doesn't make much sense to select an element with an id and an extra selector
const el = hashStartsWithNumberRE.test(shouldScroll.selector) // $flow-disable-line
? document.getElementById(shouldScroll.selector.slice(1)) // $flow-disable-line
: document.querySelector(shouldScroll.selector)
if (el) {
let offset =
shouldScroll.offset && typeof shouldScroll.offset === 'object'
? shouldScroll.offset
: {}
offset = normalizeOffset(offset)
position = getElementPosition(el, offset)
} else if (isValidPosition(shouldScroll)) {
position = normalizePosition(shouldScroll)
}
} else if (isObject && isValidPosition(shouldScroll)) {
position = normalizePosition(shouldScroll)
}
if (position) {
// $flow-disable-line
if ('scrollBehavior' in document.documentElement.style) {
window.scrollTo({
left: position.x,
top: position.y,
// $flow-disable-line
behavior: shouldScroll.behavior
})
} else {
window.scrollTo(position.x, position.y)
}
}
}

22
node_modules/vue-router/src/util/state-key.js generated vendored Normal file
View File

@ -0,0 +1,22 @@
/* @flow */
import { inBrowser } from './dom'
// use User Timing api (if present) for more accurate key precision
const Time =
inBrowser && window.performance && window.performance.now
? window.performance
: Date
export function genStateKey (): string {
return Time.now().toFixed(3)
}
let _key: string = genStateKey()
export function getStateKey () {
return _key
}
export function setStateKey (key: string) {
return (_key = key)
}

14
node_modules/vue-router/src/util/warn.js generated vendored Normal file
View File

@ -0,0 +1,14 @@
/* @flow */
export function assert (condition: any, message: string) {
if (!condition) {
throw new Error(`[vue-router] ${message}`)
}
}
export function warn (condition: any, message: string) {
if (!condition) {
typeof console !== 'undefined' && console.warn(`[vue-router] ${message}`)
}
}

51
node_modules/vue-router/types/composables.d.ts generated vendored Normal file
View File

@ -0,0 +1,51 @@
import type { ComputedRef, Ref } from 'vue'
import type { Route, NavigationGuard, default as VueRouter } from './index'
/**
* Returns the current route location. Equivalent to using `$route` inside templates.
*/
export function useRoute(): Route
/**
* Returns the router instance. Equivalent to using `$router` inside templates.
*/
export function useRouter(): VueRouter
/**
* Add a navigation guard that triggers whenever the current location is about to be updated. Similar to beforeRouteUpdate but can be used in any component. The guard is removed when the component is unmounted.
*
* @param updateGuard
*/
export function onBeforeRouteUpdate(updateGuard: NavigationGuard): void
/**
* Add a navigation guard that triggers whenever the component for the current location is about to be left. Similar to beforeRouteLeave but can be used in any component. The guard is removed when the component is unmounted.
*
* @param leaveGuard
*/
export function onBeforeRouteLeave(leaveGuard: NavigationGuard): void
export interface RouterLinkOptions {
/**
* Route Location the link should navigate to when clicked on.
*/
to: Route | Ref<Route>
/**
* Calls `router.replace` instead of `router.push`.
*/
replace?: boolean
}
/**
* Vue Router 4 `useLink()` function. Note the active behavior is different from Vue Router 3 as highlighted in the
* migration guide (https://router.vuejs.org/guide/migration/index.html#removal-of-the-exact-prop-in-router-link)
*
* @param props - object containing a `to` property with the location
*/
export function useLink({ to, replace }: RouterLinkOptions): {
route: ComputedRef<Route>,
isActive: ComputedRef<boolean>,
isExactActive: ComputedRef<boolean>,
href: ComputedRef<string>,
navigate: () => Promise<void>,
}

23
node_modules/vue-router/types/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,23 @@
import './vue'
import { VueRouter, RouterLink, RouterView, START_LOCATION, NavigationFailureType, isNavigationFailure } from './router'
export default VueRouter
export { RouterView, RouterLink, START_LOCATION, NavigationFailureType, isNavigationFailure }
export type {
RouterMode,
RouteMeta,
RawLocation,
RedirectOption,
RouterOptions,
RouteConfig,
RouteRecord,
RouteRecordPublic,
Location,
Route,
NavigationGuard,
NavigationGuardNext,
NavigationFailure
} from './router'
import './composables'

573
node_modules/vue-router/types/router.d.ts generated vendored Normal file
View File

@ -0,0 +1,573 @@
import Vue, {
PluginFunction,
AsyncComponent,
VNode,
Component as _Component
} from 'vue'
type Component =
| {}
| _Component<any, any, any, any>
| AsyncComponent<any, any, any, any>
type Dictionary<T> = { [key: string]: T }
type ErrorHandler = (err: Error) => void
export type RouterMode = 'hash' | 'history' | 'abstract'
export type RawLocation = string | Location
export type RedirectOption = RawLocation | ((to: Route) => RawLocation)
export type NavigationGuardNext<V extends Vue = Vue> = (
to?: RawLocation | false | ((vm: V) => any) | void
) => void
export type NavigationGuard<V extends Vue = Vue> = (
to: Route,
from: Route,
next: NavigationGuardNext<V>
) => any
/**
* Router instance.
*/
export declare class VueRouter {
constructor(options?: RouterOptions)
app: Vue
/**
* Original options object passed to create the Router
*/
options: RouterOptions
/**
* Configured mode when creating the Router instance.
*/
mode: RouterMode
/**
* Current {@link Route}
*/
currentRoute: Route
/**
* Add a navigation guard that executes before any navigation.
*
* @param guard - navigation guard to add
* @returns a function that removes the registered guard
*
* @example
* ```js
* router.beforeEach((to, from, next) => {
* // must call `next`
* })
* ```
*/
beforeEach(guard: NavigationGuard): () => void
/**
* Add a navigation guard that executes before navigation is about to be resolved. At this state all component have
* been fetched and other navigation guards have been successful.
*
* @param guard - navigation guard to add
* @returns a function that removes the registered guard
*
* @example
* ```js
* router.beforeResolve((to, from, next) => {
* // must call `next`
* })
* ```
*/
beforeResolve(guard: NavigationGuard): () => void
/**
* Add a navigation hook that is executed after every navigation. Returns a function that removes the registered hook.
*
* @param hook - navigation hook to add
* @returns a function that removes the registered guard
*
* @example
* ```js
* router.afterEach((to, from) => {
* console.log('after navigation')
* })
* ```
*/
afterEach(hook: (to: Route, from: Route) => any): () => void
/**
* Programmatically navigate to a new URL by pushing an entry in the history stack.
*
* @param to Route location to navigate to
*/
push(to: RawLocation): Promise<Route>
/**
* Programmatically navigate to a new URL by pushing an entry in the history stack.
*
* @param to Route location to navigate to
* @param onComplete Navigation success callback
* @param onAbort Navigation aborted callback
*/
push(
to: RawLocation,
onComplete?: (route: Route) => void,
onAbort?: ErrorHandler
): void
/**
* Programmatically navigate to a new URL by replacing the current entry in the history stack.
*
* @param to Route location to navigate to
*/
replace(to: RawLocation): Promise<Route>
/**
* Programmatically navigate to a new URL by replacing the current entry in the history stack.
*
* @param to Route location to navigate to
* @param onComplete Navigation success callback
* @param onAbort Navigation aborted callback
*/
replace(
to: RawLocation,
onComplete?: (route: Route) => void,
onAbort?: ErrorHandler
): void
/**
* Allows you to move forward or backward through the history. Calls `history.go()`.
*
* @param delta The position in the history to which you want to move, relative to the current page
*/
go(n: number): void
/**
* Go back in history if possible by calling `history.back()`. Equivalent to `router.go(-1)`.
*/
back(): void
/**
* Go forward in history if possible by calling `history.forward()`. Equivalent to `router.go(1)`.
*/
forward(): void
match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route
getMatchedComponents(to?: RawLocation | Route): Component[]
/**
* This method queues a callback to be called when the router has completed the initial navigation, which means it has
* resolved all async enter hooks and async components that are associated with the initial route.
*
* This is useful in server-side rendering to ensure consistent output on both the server and the client.
* @param cb onReady callback.
* @param errorCb errorCb will be called when the initial route resolution runs into an error (e.g. failed to resolve
* an async component).
*/
onReady(cb: () => void, errorCb?: ErrorHandler): void
/**
* Adds an error handler that is called every time a non caught error happens during navigation. This includes errors
* thrown synchronously and asynchronously, errors returned or passed to `next` in any navigation guard, and errors
* occurred when trying to resolve an async component that is required to render a route.
*
* @param handler - error handler to register
*/
onError(cb: ErrorHandler): void
/**
* @deprecated use {@link addRoute | router.addRoute()} instead
*/
addRoutes(routes: RouteConfig[]): void
/**
* Add a new {@link RouteConfig | route record} as the child of an existing route. If the route has a `name` and there
* is already an existing one with the same one, it overwrites it.
*
* @param parentName - Parent Route Record where `route` should be appended at
* @param route - Route Record to add
*/
addRoute(parentName: string, route: RouteConfig): void
/**
* Add a new {@link RouteConfig | route} to the router. If the route has a `name` and there is already an existing one
* with the same one, it overwrites it.
* @param route - Route Record to add
*/
addRoute(route: RouteConfig): void
/**
* Get the list of all the active route records.
*/
getRoutes(): RouteRecordPublic[]
/**
*
* @param to Route location
* @param current current is the current Route by default (most of the time you don't need to change this)
* @param append allows you to append the path to the `current` route (as with `router-link`)
*/
resolve(
to: RawLocation,
current?: Route,
append?: boolean
): {
location: Location
route: Route
href: string
/**
* backwards compat
*/
normalizedTo: Location
/**
* backwards compat
*/
resolved: Route
}
/**
* @internal
*/
static install: PluginFunction<never>
static version: string
static isNavigationFailure: typeof isNavigationFailure
static NavigationFailureType: {
[k in keyof typeof NavigationFailureType]: NavigationFailureType
}
static START_LOCATION: Route
}
/**
* Enumeration with all possible types for navigation failures.
*
* Can be passed to {@link isNavigationFailure} to check for specific failures.
*/
export enum NavigationFailureType {
/**
* @internal
*/
redirected = 2,
/**
* An aborted navigation is a navigation that failed because a navigation guard returned `false` or called
* `next(false)`
*/
aborted = 4,
/**
* A cancelled navigation is a navigation that failed because a more recent navigation finished started (not
* necessarily finished).
*/
cancelled = 8,
/**
* A duplicated navigation is a navigation that failed because it was initiated while already being at the exact same
* location.
*/
duplicated = 16
}
/**
* Extended Error that contains extra information regarding a failed navigation.
*/
export interface NavigationFailure extends Error {
/**
* Route location we were navigating from
*/
from: Route
/**
* Route location we were navigating to
*/
to: Route
/**
* Type of the navigation. One of {@link NavigationFailureType}
*/
type: NavigationFailureType.aborted | NavigationFailureType.cancelled | NavigationFailureType.duplicated
}
/**
* Check if an object is a {@link NavigationFailure}.
*/
export declare function isNavigationFailure(error: any, type?: NavigationFailureType): error is NavigationFailure
type Position = { x: number; y: number }
type PositionResult = Position | { selector: string; offset?: Position, behavior?: ScrollBehavior } | void
/**
* Options to initialize a {@link VueRouter} instance.
*/
export interface RouterOptions {
routes?: RouteConfig[]
/**
* Configure the router mode.
*
* default: `"hash"` (in browser) | `"abstract"` (in Node.js)
*
* available values: `"hash" | "history" | "abstract"`
* - `"hash"`: uses the URL hash for routing. Works in all Vue-supported browsers, including those that do not support
* HTML5 History API.
* - `"history"`: requires HTML5 History API and server config. See HTML5 History Mode.
* - `"abstract"`: works in all JavaScript environments, e.g. server-side with Node.js. **The router will
* automatically be forced into this mode if no browser API is present.**
*/
mode?: RouterMode
fallback?: boolean
base?: string
/**
* Default class applied to active {@link RouterLink}. If none is provided, `router-link-active` will be applied.
*/
linkActiveClass?: string
/**
* Default class applied to active {@link RouterLink}. If none is provided, `router-link-exact-active` will be
* applied.
*/
linkExactActiveClass?: string
/**
* Custom implementation to parse a query. See its counterpart, {@link stringifyQuery}.
*/
parseQuery?: (query: string) => Object
/**
* Custom implementation to stringify a query object. Should not prepend a leading `?`. {@link parseQuery} counterpart
* to handle query parsing.
*/
stringifyQuery?: (query: Object) => string
/**
* Function to control scrolling when navigating between pages. Can return a Promise to delay scrolling.
*
* For more details see {@link Scroll Behavior}.
*/
scrollBehavior?: (
to: Route,
from: Route,
savedPosition: Position | void
) => PositionResult | Promise<PositionResult> | undefined | null
}
type RoutePropsFunction = (route: Route) => Object
export interface PathToRegexpOptions {
sensitive?: boolean
strict?: boolean
end?: boolean
}
interface _RouteConfigBase {
path: string
name?: string
children?: RouteConfig[]
redirect?: RedirectOption
alias?: string | string[]
meta?: RouteMeta
beforeEnter?: NavigationGuard
caseSensitive?: boolean
pathToRegexpOptions?: PathToRegexpOptions
}
interface RouteConfigSingleView extends _RouteConfigBase {
component?: Component
props?: boolean | Object | RoutePropsFunction
}
interface RouteConfigMultipleViews extends _RouteConfigBase {
components?: Dictionary<Component>
props?: Dictionary<boolean | Object | RoutePropsFunction>
}
export type RouteConfig = RouteConfigSingleView | RouteConfigMultipleViews
export interface RouteRecord {
path: string
regex: RegExp
components: Dictionary<Component>
instances: Dictionary<Vue>
name?: string
parent?: RouteRecord
redirect?: RedirectOption
matchAs?: string
meta: RouteMeta
beforeEnter?: (
route: Route,
redirect: (location: RawLocation) => void,
next: () => void
) => any
props:
| boolean
| Object
| RoutePropsFunction
| Dictionary<boolean | Object | RoutePropsFunction>
}
export interface RouteRecordPublic {
path: string
components: Dictionary<Component>
instances: Dictionary<Vue>
name?: string
redirect?: RedirectOption
meta: any
beforeEnter?: (
route: Route,
redirect: (location: RawLocation) => void,
next: () => void
) => any
props:
| boolean
| Object
| RoutePropsFunction
| Dictionary<boolean | Object | RoutePropsFunction>
}
export interface Location {
name?: string
path?: string
hash?: string
query?: Dictionary<string | (string | null)[] | null | undefined>
params?: Dictionary<string>
append?: boolean
replace?: boolean
}
export interface Route {
path: string
name?: string | null
hash: string
query: Dictionary<string | (string | null)[]>
params: Dictionary<string>
fullPath: string
matched: RouteRecord[]
redirectedFrom?: string
meta?: RouteMeta
}
export interface RouteMeta extends Record<string | number | symbol, any> {}
export interface RouterLinkProps {
/**
* Denotes the target route of the link. When clicked, the value of the `to` prop will be passed to
* `router.push()` internally, so the value can be either a string or a location descriptor object.
*/
to: string | Location
/**
* Setting `replace` prop will call `router.replace()` instead of `router.push()` when clicked, so the navigation will
* not create a new history record.
*
* @default false
*/
replace?: boolean
/**
* Setting `append` prop always appends the relative path to the current path. For example, assuming we are navigating
* from `/a` to a relative link `b`, without `append` we will end up at `/b`, but with append we will end up at
* `/a/b`.
*
* @default false
*/
append?: boolean
/**
* Sometimes we want <RouterLink> to render as another tag, e.g <li>. Then we can use tag prop to specify which tag to
* render to, and it will still listen to click events for navigation.
*
* @default "a"
*/
tag?: string
/**
* Configure the active CSS class applied when the link is active. Note the default value can also be configured
* globally via the `linkActiveClass` router constructor option.
*
* @default "router-link-active"
*/
activeClass?: string
/**
* The default active class matching behavior is **inclusive match**. For example, `<RouterLink to="/a">` will get
* this class applied as long as the current path starts with `/a/` or is `/a`.
*
* @default false
*/
exact?: boolean
/**
* Allows matching only using the `path` section of the url, effectively ignoring the `query` and the `hash` sections.
*
* @default false
*/
exactPath?: boolean
/**
* Configure the active CSS class applied when the link is active with exact path match. Note the default value can
* also be configured globally via the `linkExactPathActiveClass` router constructor option.
*
* @default "router-link-exact-path-active"
*/
exactPathActiveClass?: string
/**
* Specify the event(s) that can trigger the link navigation.
*
* @default 'click'
*/
event?: string | ReadonlyArray<string>
/**
* Configure the active CSS class applied when the link is active with exact match. Note the default value can also be
* configured globally via the `linkExactActiveClass` router constructor option.
*
* @default "router-link-exact-active"
*/
exactActiveClass?: string
/**
* Configure the value of `aria-current` when the link is active with exact match. It must be one of the allowed
* values for [aria-current](https://www.w3.org/TR/wai-aria-1.2/#aria-current) in the ARIA spec. In most cases, the
* default of page should be the best fit.
*
* @default "page"
*/
ariaCurrentValue?:
| 'page'
| 'step'
| 'location'
| 'date'
| 'time'
| 'true'
| 'false'
}
export interface RouterLinkSlotArgument {
/**
* resolved url. This would be the `href` attribute of an `a` element
*/
href: string
/**
* resolved normalized location
*/
route: Route
/**
* function to trigger the navigation. It will automatically prevent events when necessary, the same way `RouterLink`
* does
*/
navigate: (e?: MouseEvent) => Promise<undefined | NavigationFailure>
/**
* `true` if the [active class](https://v3.router.vuejs.org/api/#active-class) should be applied. Allows to apply an
* arbitrary class
*/
isActive: boolean
/**
* `true` if the [exact active class](https://v3.router.vuejs.org/api/#exact-active-class) should be applied. Allows
* to apply an arbitrary class
*/
isExactActive: boolean
}
/**
* Component to render a link that triggers a navigation on click.
*/
export declare const RouterLink: new () => {
$props: RouterLinkProps
$scopedSlots: {
default?: ({
href,
route,
navigate,
isActive,
isExactActive
}: RouterLinkSlotArgument) => VNode[] | undefined
}
}
export interface RouterViewProps {
/**
* When a {@link RouterView | `<RouterView />`} has a name, it will render the component with the corresponding name
* in the matched route record's components option. See [Named
* Views](https://v3.router.vuejs.org/guide/essentials/named-views.html) for an example.
*
* @default "default"
*/
name?: string
}
/**
* Component to display the current route the user is at.
*/
export declare const RouterView: new () => {
$props: RouterViewProps
}
/**
* Initial route location where the router is. Can be used in navigation guards to differentiate the initial navigation.
*/
export declare const START_LOCATION: Route

22
node_modules/vue-router/types/vue.d.ts generated vendored Normal file
View File

@ -0,0 +1,22 @@
/**
* Augment the typings of Vue.js
*/
import Vue from 'vue'
import VueRouter, { Route, NavigationGuard } from './index'
declare module 'vue/types/vue' {
interface Vue {
$router: VueRouter
$route: Route
}
}
declare module 'vue/types/options' {
interface ComponentOptions<V extends Vue> {
router?: VueRouter
beforeRouteEnter?: NavigationGuard<V>
beforeRouteLeave?: NavigationGuard<V>
beforeRouteUpdate?: NavigationGuard<V>
}
}

38
node_modules/vue-router/vetur/attributes.json generated vendored Normal file
View File

@ -0,0 +1,38 @@
{
"name": {
"type": "string",
"description": "When a `<router-view>` has a `name` prop, it will render the component with the corresponding name in the matched route record's components option."
},
"to": {
"description": "Denotes the target route of the link. When clicked, the value of the `to` prop will be internally passed to `router.push()`, so the value can be either a string or a location descriptor object."
},
"append": {
"type": "boolean",
"description": "Setting the append prop always appends the relative path to the current path. For example, assuming we are navigating from /a to a relative link b, without append we will end up at /b, but with append we will end up at /a/b."
},
"tag": {
"description": "Specify which tag to render to, and it will still listen to click events for navigation. By default, an `a` tag is rendered."
},
"event": {
"description": "Specify the event(s) that can trigger the link navigation. By default, the `click` event triggers a navigation."
},
"replace": {
"type": "boolean",
"description": "Call `router.replace()` instead of `router.push()` when the link is clicked, so the navigation replaces the current history entry."
},
"exact": {
"description": "The default active class matching behavior is inclusive match. For example, `<router-link to=\"/a\">` will get this class applied as long as the current path starts with /a/ or is /a.\nOne consequence of this is that `<router-link to=\"/\">` will be active for every route! To force the link into \"exact match mode\", use the exact prop: `<router-link to=\"/\" exact>`"
},
"active-class": {
"type": "string",
"description": "Configure the active CSS class applied when the link is active. Note the default value can also be configured globally via the `linkActiveClass` router constructor option."
},
"exact-active-class": {
"type": "string",
"description": "Configure the active CSS class applied when the link is exactly active. Note the default value can also be configured globally via the `linkExactActiveClass` router constructor option."
},
"aria-current-value": {
"options": ["page", "step", "location", "date", "time", "true", "false"],
"description": "Configure the value of `aria-current` when the link is active with exact match. It must be one of the [allowed values for `aria-current`](https://www.w3.org/TR/wai-aria-1.2/#aria-current) in the ARIA spec. In most cases, the default of `page` should be the best fit."
}
}

20
node_modules/vue-router/vetur/tags.json generated vendored Normal file
View File

@ -0,0 +1,20 @@
{
"router-view": {
"attributes": ["name"],
"description": "Component that renders the matched component for the current location. Components rendered by `<router-view>` can also contain their own `<router-view>` to render nested routes."
},
"router-link": {
"attributes": [
"to",
"replace",
"append",
"tag",
"active-class",
"exact",
"event",
"exact-active-class",
"aria-current-value"
],
"description": "Component that renders an `<a>` with the correct `href` attribute and click listeners to trigger a local navigation when clicked. Can also customize its rendering by providing the `custom` prop and using its `v-slot` API."
}
}