[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\"@babel/preset-env\", {\n      \"exclude\": [\n        \"transform-regenerator\"\n      ]\n    }]\n  ]\n}\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"root\": true,\n  \"extends\": [\n    \"plugin:vue-libs/recommended\"\n  ],\n  \"globals\": {\n    \"__DEV__\": true,\n    \"__VUE_PROD_DEVTOOLS__\": true\n  }\n}\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [yyx990803, kiaking, ktsn]\nopen_collective: vuejs\npatreon: evanyou\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: \"\\U0001F41E Bug report\"\ndescription: Create a report to help us improve\nlabels: ['bug: pending triage']\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n        Please note that Vuex is now in maintenance mode and we will only prioritize critical issues.\n        Consider checking out [Pinia](https://pinia.vuejs.org/) for a more type-friendly and actively\n        maintained alternative.\n  - type: input\n    id: version\n    attributes:\n      label: Version\n      description: What version of Vuex is used in your project?\n    validations:\n      required: true\n  - type: textarea\n    id: bug-description\n    attributes:\n      label: Describe the bug\n      description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!\n      placeholder: Bug description\n    validations:\n      required: true\n  - type: textarea\n    id: reproduction\n    attributes:\n      label: Reproduction\n      description: Steps to reproduce the behavior.\n      placeholder: Reproduction\n    validations:\n      required: true\n  - type: textarea\n    id: expected\n    attributes:\n      label: Expected behavior\n      description: A clear and concise description of what you expected to happen.\n      placeholder: Expected behavior\n    validations:\n      required: true\n  - type: textarea\n    id: additional-context\n    attributes:\n      label: Additional context\n      description: Add any other context or screenshots about the bug report here.\n  - type: checkboxes\n    id: checkboxes\n    attributes:\n      label: Validations\n      description: Before submitting the issue, please make sure you do the following\n      options:\n        - label: Follow our [Code of Conduct](https://vuejs.org/about/coc.html)\n          required: true\n        - label: Read the [docs](https://vuex.vuejs.org/).\n          required: true\n        - label: Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\nIMPORTANT: Please use the following link to create a new issue:\n\n  https://new-issue.vuejs.org/?repo=vuejs/vuex\n\nIf your issue was not created using the app above, it will be closed immediately.\n-->\n"
  },
  {
    "path": ".github/commit-convention.md",
    "content": "## Git Commit Message Convention\n\n> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).\n\n#### TL;DR:\n\nMessages must be matched by the following regex:\n\n``` js\n/^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\\(.+\\))?: .{1,50}/\n```\n\n#### Examples\n\nAppears under \"Features\" header, `store` subheader:\n\n```\nfeat(store): add 'watch' option\n```\n\nAppears under \"Bug Fixes\" header, `module` subheader, with a link to issue #28:\n\n```\nfix(module): handle state overwrite\n\nclose #28\n```\n\nAppears under \"Performance Improvements\" header, and under \"Breaking Changes\" with the breaking change explanation:\n\n```\nperf: improve store getters performance by removing 'foo' option\n\nBREAKING CHANGE: The 'foo' option has been removed.\n```\n\nThe following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the \"Reverts\" header.\n\n```\nrevert: feat(store): add 'watch' option\n\nThis reverts commit 667ecc1654a317a13331b17617d973392f415f02.\n```\n\n### Full Message Format\n\nA commit message consists of a **header**, **body** and **footer**.  The header has a **type**, **scope** and **subject**:\n\n```\n<type>(<scope>): <subject>\n<BLANK LINE>\n<body>\n<BLANK LINE>\n<footer>\n```\n\nThe **header** is mandatory and the **scope** of the header is optional.\n\n### Revert\n\nIf the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.\n\n### Type\n\nIf the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.\n\nOther prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.\n\n### Scope\n\nThe scope could be anything specifying the place of the commit change. For example `core`, `compiler`, `ssr`, `v-model`, `transition` etc...\n\n### Subject\n\nThe subject contains a succinct description of the change:\n\n* use the imperative, present tense: \"change\" not \"changed\" nor \"changes\"\n* don't capitalize the first letter\n* no dot (.) at the end\n\n### Body\n\nJust as in the **subject**, use the imperative, present tense: \"change\" not \"changed\" nor \"changes\".\nThe body should include the motivation for the change and contrast this with previous behavior.\n\n### Footer\n\nThe footer should contain any information about **Breaking Changes** and is also the place to\nreference GitHub issues that this commit **Closes**.\n\n**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.\n"
  },
  {
    "path": ".github/contributing.md",
    "content": "# Vuex Contributing Guide\n\nHi! We're really excited that you are interested in contributing to Vuex. Before submitting your contribution, please make sure to take a moment and read through the following guidelines:\n\n- [Code of Conduct](https://github.com/vuejs/vue/blob/dev/.github/CODE_OF_CONDUCT.md)\n- [Issue Reporting Guidelines](#issue-reporting-guidelines)\n- [Pull Request Guidelines](#pull-request-guidelines)\n\n## Issue Reporting Guidelines\n\n- Always use [https://new-issue.vuejs.org/](https://new-issue.vuejs.org/) to create new issues.\n\n## Pull Request Guidelines\n\n- The `master` branch is just a snapshot of the latest stable release. All development should be done in dedicated branches. **Do not submit PRs against the `master` branch.**\n\n- Checkout a topic branch from the relevant branch, e.g. `dev`, and merge back against that branch.\n\n- Work in the `src` folder and **DO NOT** checkin `dist` in the commits.\n\n- If adding a new feature:\n\n  - Add accompanying test case.\n  - Provide a convincing reason to add this feature. Ideally, you should open a suggestion issue first and have it approved before working on it.\n\n- If fixing bug:\n\n  - If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update state re-evaluation (fix #3899)`.\n  - Provide a detailed description of the bug in the PR. Live demo preferred.\n\n- It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging.\n\n- Make sure tests pass!\n\n- Commit messages must follow the [commit message convention](./commit-convention.md) so that changelogs can be automatically generated.\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: 'ci'\non:\n  push:\n    branches:\n      - '**'\n  pull_request:\n    branches:\n      - main\n\npermissions:\n  contents: read # to fetch code (actions/checkout)\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n\n      - name: Set node version to 16\n        uses: actions/setup-node@v2\n        with:\n          node-version: 16\n\n      - name: Install deps\n        uses: bahmutov/npm-install@v1\n\n      - name: Run tests\n        run: npm test\n"
  },
  {
    "path": ".gitignore",
    "content": "/dist\n/coverage\n/docs/.vitepress/dist\n/test/e2e/reports\n/test/e2e/screenshots\n*.log\n.DS_Store\nnode_modules\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# [4.1.0](https://github.com/vuejs/vuex/compare/v4.0.2...v4.1.0) (2022-10-14)\n\n### Vue Core Version Requirement Change\n\n**This release contains an important fix ([#1883](https://github.com/vuejs/vuex/pull/1883)) that relies on the `effectScope` API from Vue core, which is only available in Vue 3.2+.**\n\n### Bug Fixes\n\n* **build:** node deprecated warning in export module ([#2048](https://github.com/vuejs/vuex/issues/2048)) ([397e9fb](https://github.com/vuejs/vuex/commit/397e9fba45c8b4ec0c4a33d2578e34829bd348d7))\n* getters being destroyed on component destroy ([#1878](https://github.com/vuejs/vuex/issues/1878)) ([#1883](https://github.com/vuejs/vuex/issues/1883)) ([b2f851f](https://github.com/vuejs/vuex/commit/b2f851f427aa872d1e4f5a4774e07c4c69562789))\n\n\n\n## [4.0.2](https://github.com/vuejs/vuex/compare/v4.0.1...v4.0.2) (2021-06-17)\n\n### Bug Fixes\n\n* **devtools:** fix no getters displayed on root module + better getters inspector ([#1986](https://github.com/vuejs/vuex/issues/1986)) ([bc20295](https://github.com/vuejs/vuex/commit/bc20295331eb2bee40d6ae779d1ada31c542604c))\n* **build:** cjs build failing due to `__VUE_PROD_DEVTOOLS__` defined ([#1991](https://github.com/vuejs/vuex/issues/1991)) ([#1992](https://github.com/vuejs/vuex/issues/1992)) ([7151622](https://github.com/vuejs/vuex/commit/7151622d646968686546f1c4c80f7575c9b99176))\n\n## [4.0.1](https://github.com/vuejs/vuex/compare/v4.0.0...v4.0.1) (2021-05-24)\n\n### Features\n\n* dx: add devtools integration ([#1949](https://github.com/vuejs/vuex/pull/1949))\n\n# [4.0.0](https://github.com/vuejs/vuex/compare/v4.0.0-rc.2...v4.0.0) (2021-02-02)\n\nThis is the official Vuex 4 release.\n\nThe focus for Vuex 4 is compatibility. Vuex 4 supports Vue 3, and it provides the exact same API as Vuex 3, so users can reuse their existing Vuex code with Vue 3.\n\nThere are a few breaking changes described in a later section, so please check them out.\n\nYou can find basic usage with both Option and Composition API in the `example` directory.\n\nIt's still released under `next` tag in NPM package as same as Vue 3. We're planning to remove `next` tag once Vue 3 is ready to remove it.\n\nThere have been a lot of contribution to make Vuex 4 stable. Thank you all for your very much appreciated help. It wouldn't have been possible without this wonderful Vue community!\n\n## Documentation\n\nTo check out docs, visit [next.vuex.vuejs.org](https://next.vuex.vuejs.org/).\n\n## Breaking changes\n\n### Installation process has changed\n\nTo align with the new Vue 3 initialization process, the installation process of Vuex has changed.\n\nTo create a new store instance, users are now encouraged to use the newly introduced `createStore` function.\n\n```js\nimport { createStore } from 'vuex'\n\nexport const store = createStore({\n  state() {\n    return {\n      count: 1\n    }\n  }\n})\n```\n\n> Whilst this is not technically a breaking change, you may still use the `new Store(...)` syntax, we recommend this approach to align with Vue 3 and Vue Router Next.\n\nTo install Vuex to a Vue instance, pass the store instance instead of Vuex.\n\n```js\nimport { createApp } from 'vue'\nimport { store } from './store'\nimport App from './App.vue'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n```\n\n### Bundles are now aligned with Vue 3\n\nThe following bundles are generated to align with Vue 3 bundles:\n\n- `vuex.global(.prod).js`\n  - For direct use with `<script src=\"...\">` in the browser. Exposes the Vuex global.\n  - Global build is built as IIFE, and not UMD, and is only meant for direct use with `<script src=\"...\">`.\n  - Contains hard-coded prod/dev branches and the prod build is pre-minified. Use the `.prod.js` files for production.\n- `vuex.esm-browser(.prod).js`\n  - For use with native ES module imports (including module supporting browsers via `<script type=\"module\">`.\n- `vuex.esm-bundler.js`\n  - For use with bundlers such as `webpack`, `rollup` and `parcel`.\n  - Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler).\n  - Does not ship minified builds (to be done together with the rest of the code after bundling).\n- `vuex.cjs.js`\n  - For use in Node.js server-side rendering with `require()`.\n\n### Typings for `ComponentCustomProperties`\n\nVuex 4 removes its global typings for `this.$store` within Vue Component to solve [issue #994](https://github.com/vuejs/vuex/issues/994). When used with TypeScript, you must declare your own module augmentation.\n\nPlace the following code in your project to allow `this.$store` to be typed correctly:\n\n```ts\n// vuex-shim.d.ts\n\nimport { ComponentCustomProperties } from 'vue'\nimport { Store } from 'vuex'\n\ndeclare module '@vue/runtime-core' {\n  // Declare your own store states.\n  interface State {\n    count: number\n  }\n\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\n### `createLogger` function is exported from the core module\n\nIn Vuex 3, `createLogger` function was exported from `vuex/dist/logger` but it's now included in the core package. You should import the function directly from `vuex` package.\n\n```js\nimport { createLogger } from 'vuex'\n```\n\n### Bug Fixes Included Since 4.0.0-rc.2\n\n* export missing `storeKey` ([4ab2947](https://github.com/vuejs/vuex/commit/4ab294793a2c20ea6040f01f316618682df61fff))\n* fix tree shaking notworking in webpack bundle ([#1906](https://github.com/vuejs/vuex/issues/1906)) ([#1907](https://github.com/vuejs/vuex/issues/1907)) ([aeddf7a](https://github.com/vuejs/vuex/commit/aeddf7a7c618eda7f316f8a6ace8d21eb96c29ff))\n\n# [4.0.0-rc.2](https://github.com/vuejs/vuex/compare/v4.0.0-rc.1...v4.0.0-rc.2) (2020-11-25)\n\n### Bug Fixes\n\n* fix getters stop working when component is destroyed ([#1884](https://github.com/vuejs/vuex/issues/1884)) ([c3a695e](https://github.com/vuejs/vuex/commit/c3a695e10682ab1b7288e72669861c9ca959df76))\n* stop throwing an error on `hasModule` when parent does not exists ([#1850](https://github.com/vuejs/vuex/issues/1850)) ([f76d72d](https://github.com/vuejs/vuex/commit/f76d72d6c1f7cd30de9d459e23c371890c56f463))\n\n### Features\n\n* **build:** enable named esm module import on node.js >= 14 ([4f4a909](https://github.com/vuejs/vuex/commit/4f4a9096b46aa61580c32371adb19445157ba80c))\n\n# [4.0.0-rc.1](https://github.com/vuejs/vuex/compare/v4.0.0-beta.4...v4.0.0-rc.1) (2020-10-30)\n\n\n### Bug Fixes\n\n* fix getters getting re-evaluated on every access ([#1823](https://github.com/vuejs/vuex/issues/1823)) ([#1860](https://github.com/vuejs/vuex/issues/1860)) ([0006765](https://github.com/vuejs/vuex/commit/0006765ca3c5641ef732bad9df58e01f05c6f19c))\n* **types:** add lost argument of useStore ([#1803](https://github.com/vuejs/vuex/issues/1803)) ([657afe3](https://github.com/vuejs/vuex/commit/657afe3db42c8d1d721216955fc2be3132e9fe6c))\n\n\n### Features\n\n* **types:** adding logger type for logger plugin ([#1853](https://github.com/vuejs/vuex/issues/1853)) ([cb3198d](https://github.com/vuejs/vuex/commit/cb3198d5998bdb11ef05dfa5ef98d5c5fa873089))\n\n\n\n## [3.5.1](https://github.com/vuejs/vuex/compare/v4.0.0-beta.3...v3.5.1) (2020-06-29)\n\n\n\n# [4.0.0-beta.4](https://github.com/vuejs/vuex/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2020-06-29)\n\n\n### Bug Fixes\n\n* **types:** add missing `logger.d.ts` file to the package ([#1789](https://github.com/vuejs/vuex/issues/1789)) ([a477334](https://github.com/vuejs/vuex/commit/a477334b909913f6a92bdbedcf4a3016a62eab7a))\n* warn when unregistering non existing module ([#1786](https://github.com/vuejs/vuex/issues/1786)) ([7cec79d](https://github.com/vuejs/vuex/commit/7cec79d339b874ec41f35891c891dfd27460c1d3))\n\n\n\n# [3.5.0](https://github.com/vuejs/vuex/compare/v4.0.0-beta.2...v3.5.0) (2020-06-29)\n\n\n\n# [4.0.0-beta.3](https://github.com/vuejs/vuex/compare/v4.0.0-beta.2...v4.0.0-beta.3) (2020-06-29)\n\n\n### Bug Fixes\n\n* UMD bundle containing `process.env` flag ([#1749](https://github.com/vuejs/vuex/issues/1749)) ([0fea8c4](https://github.com/vuejs/vuex/commit/0fea8c44060d08b3b421f1ddaa809fdffbc89b00))\n\n\n### Features\n\n* include `createLogger` function in core export ([afa566d](https://github.com/vuejs/vuex/commit/afa566d7f7b8e516389463b437fbfcb9eafdbd1b))\n* include logger plugin to the core export ([#1783](https://github.com/vuejs/vuex/issues/1783)) ([04e2bd8](https://github.com/vuejs/vuex/commit/04e2bd8b3509c67398a6fe73a3d53660069feca8))\n\n\n\n# [3.4.0](https://github.com/vuejs/vuex/compare/4.0.0-beta.2...v3.4.0) (2020-05-11)\n\n\n\n# [4.0.0-beta.2](https://github.com/vuejs/vuex/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2020-05-11)\n\n\n### Bug Fixes\n\n- types: add `useStore` function ([#1736](https://github.com/vuejs/vuex/issues/1736)) [#1739](https://github.com/vuejs/vuex/issues/1736)\n- build: fix `iife` build containing `process.env`.\n\n# [4.0.0-beta.1](https://github.com/vuejs/vuex/compare/v3.3.0...v4.0.0-beta.1) (2020-04-25)\n\n### Features\n\n- Added TypeScript support.\n\n### Breaking Changes\n\n#### Bundles are now aligned with Vue 3\n\nThe bundles are generated as below to align with Vue 3 bundles.\n\n- `vuex.global(.prod).js`\n  - For direct use via `<script src=\"...\">` in the browser. Exposes the Vuex global.\n  - Note that global builds are not UMD builds. They are built as IIFEs and is only meant for direct use via `<script src=\"...\">`.\n  - Contains hard-coded prod/dev branches, and the prod build is pre-minified. Use the `.prod.js` files for production.\n- `vuex.esm-browser(.prod).js`\n  - For usage via native ES modules imports (in browser via `<script type=\"module\">`.\n- `vuex.esm-bundler.js`\n  - For use with bundlers like `webpack`, `rollup` and `parcel`.\n  - Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler).\n  - Does not ship minified builds (to be done together with the rest of the code after bundling).\n- `vuex.cjs.js`\n  - For use in Node.js server-side rendering via `require()`.\n\n#### Typings for `ComponentCustomProperties`\n\nVuex 4 removes its global typings for `this.$store` within Vue Component due to solving [issue #994](https://github.com/vuejs/vuex/issues/994). When using TypeScript, you must provide your own augment declaration.\n\nPlease place the following code in your project to have `this.$store` working.\n\n```ts\n// vuex-shim.d.ts\n\ndeclare module \"@vue/runtime-core\" {\n  // Declare your own store states.\n  interface State {\n    count: number\n  }\n\n  interface ComponentCustomProperties {\n    $store: Store<State>;\n  }\n}\n```\n\n# [4.0.0-alpha.1](https://github.com/vuejs/vuex/compare/v3.1.3...v4.0.0-alpha.1) (2020-03-15)\n\n\nThis is the Vue 3 compatible version of Vuex. The focus is compatibility, and it provides the exact same API as Vuex 3, so users can reuse their existing Vuex code for Vue 3.\n\n## Status: Alpha\n\nAll Vuex 3 feature works. There are a few breaking changes described in a later section, so please check them out. You can find basic usage with both option and composition API at `example` folder.\n\nPlease note that it's still unstable, and there might be bugs. Please provide us feedback if you find anything. You may use [vue-next-webpack-preview](https://github.com/vuejs/vue-next-webpack-preview) to test out Vue 3 with Vuex 4.\n\n## Breaking changes\n\n### Installation process has changed\n\nTo align with the new Vue 3 initialization process, the installation process of Vuex has changed as well.\n\nYou should use a new `createStore` function to create a new store instance.\n\n```js\nimport { createStore } from 'vuex'\n\nconst store = createStore({\n  state () {\n    return {\n      count: 1\n    }\n  }\n})\n```\n\n> This is technically not a breaking change because you could still use `new Store(...)` syntax. However, to align with Vue 3 and also with Vue Router Next, we recommend users to use `createStore` function instead.\n\nThen to install Vuex to Vue app instance, pass the store instance instead of Vuex.\n\n```js\nimport { createApp } from 'vue'\nimport store from './store'\nimport App from './APP.vue'\n\nconst app = createApp(Counter)\n\napp.use(store)\n\napp.mount('#app')\n```\n\n## Kown issues\n\n- The code is kept as close to Vuex 3 code base as possible, and there're plenty of places where we should refactor. However, we are waiting for all of the test cases to pass before doing so (some tests require Vue 3 update).\n- TypeScript support is not ready yet. Please use JS environment to test this for now.\n\n\n# [3.4.0](https://github.com/vuejs/vuex/compare/v3.3.0...v3.4.0) (2020-05-11)\n\n\n### Features\n\n* Allow action subscribers to catch rejections. ([#1740](https://github.com/vuejs/vuex/issues/1740)) ([6ebbe64](https://github.com/vuejs/vuex/commit/6ebbe64c5821d19e55a41dc8b1d81cfce6cbd195)), closes [#1489](https://github.com/vuejs/vuex/issues/1489) [#1558](https://github.com/vuejs/vuex/issues/1558) [#1625](https://github.com/vuejs/vuex/issues/1625)\n\n\n# [3.3.0](https://github.com/vuejs/vuex/compare/v3.2.0...v3.3.0) (2020-04-25)\n\n\n### Bug Fixes\n\n* Prepend devtool handler ([#1358](https://github.com/vuejs/vuex/issues/1358)) ([a39d076](https://github.com/vuejs/vuex/commit/a39d0767e4041cdd5cf8050774106c01d39024e0)), closes [vuejs/vue-devtools#678](https://github.com/vuejs/vue-devtools/issues/678)\n* **types:** Add `devtools` to store options type ([#1478](https://github.com/vuejs/vuex/issues/1478)) ([38c11dc](https://github.com/vuejs/vuex/commit/38c11dcbaea7d7e661a1623cabb5aef7c6e47ba7))\n\n\n### Features\n\n* Add `prepend` option for `subscribe` and `subscribeAction` ([#1358](https://github.com/vuejs/vuex/issues/1358)) ([a39d076](https://github.com/vuejs/vuex/commit/a39d0767e4041cdd5cf8050774106c01d39024e0))\n* **logger:** `createLogger` can optionally log actions ([#987](https://github.com/vuejs/vuex/issues/987)) ([18be128](https://github.com/vuejs/vuex/commit/18be128ad933d1fca6da05c060f7664ce0c819ae))\n\n\n\n# [3.2.0](https://github.com/vuejs/vuex/compare/v3.1.3...v3.2.0) (2020-04-19)\n\n\n### Features\n\n* add Store#hasModule(path) API ([#834](https://github.com/vuejs/vuex/issues/834)) ([d65d142](https://github.com/vuejs/vuex/commit/d65d14276e87aca17cfbd3fbf4af9e8dbb808f24))\n\n\n\n## [3.1.3](https://github.com/vuejs/vuex/compare/v3.1.2...v3.1.3) (2020-03-09)\n\n\n### Bug Fixes\n\n* Prevent invalidating subscription iterator  ([#1438](https://github.com/vuejs/vuex/issues/1438)) ([e012653](https://github.com/vuejs/vuex/commit/e0126533301febf66072f1865cf9a77778cf2176))\n\n\n\n## [3.1.2](https://github.com/vuejs/vuex/compare/v3.1.1...v3.1.2) (2019-11-10)\n\n\n### Bug Fixes\n\n* tweak mapping helper warning message ([#1641](https://github.com/vuejs/vuex/issues/1641)) ([e60bc76](https://github.com/vuejs/vuex/commit/e60bc76154bb05c12b24342617b946d9a6e2f476))\n* **types:** avoid broadening vue instance type when using map helpers ([#1639](https://github.com/vuejs/vuex/issues/1639)) ([9a96720](https://github.com/vuejs/vuex/commit/9a9672050bcfee198c379069ec0e1b03ca6cb965))\n* add warnings when the different namespaced modules has the same names… ([#1554](https://github.com/vuejs/vuex/issues/1554)) ([91f3e69](https://github.com/vuejs/vuex/commit/91f3e69ed9e290cf91f8885c6d5ae2c97fa7ab81))\n* Should vuex mapState print error message [#1093](https://github.com/vuejs/vuex/issues/1093) ([#1297](https://github.com/vuejs/vuex/issues/1297)) ([e5ca2d5](https://github.com/vuejs/vuex/commit/e5ca2d52e89a126bd48bd8a6003be77379960ea9))\n* Warn about conflicts between state and module ([#1365](https://github.com/vuejs/vuex/issues/1365)) ([538ee58](https://github.com/vuejs/vuex/commit/538ee5803bbca2fc8077208fb30c8d56d8be5cae))\n* **docs:** Clearify state object type ([#1601](https://github.com/vuejs/vuex/issues/1601)) ([de06f76](https://github.com/vuejs/vuex/commit/de06f76380e7429489c0eb15acc8e0b34a383860))\n\n\n### Performance Improvements\n\n* Implementing a cache for the gettersProxy object creation ([#1546](https://github.com/vuejs/vuex/issues/1546)) ([4003382](https://github.com/vuejs/vuex/commit/40033825b7259c2e9b702bdf94e0b24ed4511d7c))\n\n\n\n## [3.1.1](https://github.com/vuejs/vuex/compare/v3.1.0...v3.1.1) (2019-05-08)\n\n\n### Bug Fixes\n\n* Memory leak happening while using registerModule/u… ([#1508](https://github.com/vuejs/vuex/issues/1508)) ([cb9986a](https://github.com/vuejs/vuex/commit/cb9986ae5a62e002a1d876e881ee5f31dd410888)), closes [issue#1507](https://github.com/issue/issues/1507)\n* **types:** Make mutation and action payload optional in definition file ([#1517](https://github.com/vuejs/vuex/issues/1517)) ([0e109e2](https://github.com/vuejs/vuex/commit/0e109e2a38dafdc0c2bd6bd3892bc66cfe252b16)), closes [#1491](https://github.com/vuejs/vuex/issues/1491)\n\n\n### Features\n\n* **devtool:** allow usage in non-browser environments ([#1404](https://github.com/vuejs/vuex/issues/1404)) ([665455f](https://github.com/vuejs/vuex/commit/665455f8daf8512e7adbf63c2842bc0b1e39efdb))\n* **esm build:** build ES modules for browser ([#1533](https://github.com/vuejs/vuex/issues/1533)) ([d7c7f98](https://github.com/vuejs/vuex/commit/d7c7f9844831f98c5c9aaca213746c4ccc5d6929))\n\n\n\n# [3.1.0](https://github.com/vuejs/vuex/compare/v3.0.1...v3.1.0) (2019-01-17)\n\n\n### Bug Fixes\n\n* **types:** add helpers to default export type declaration as in sources ([#1408](https://github.com/vuejs/vuex/issues/1408)) ([404d0de](https://github.com/vuejs/vuex/commit/404d0de9531322a1a462e53dfd858d20f0bd99af))\n* **types:** add type annotation for the context of actions ([#1322](https://github.com/vuejs/vuex/issues/1322)) ([d1b5c66](https://github.com/vuejs/vuex/commit/d1b5c66961ab53e0172cbc706ff616227bcb5c77))\n* **types:** allow a function type for root `state` option ([#1132](https://github.com/vuejs/vuex/issues/1132)) ([d39791b](https://github.com/vuejs/vuex/commit/d39791bd05830b1889705761ef5779449e35e97f))\n* Add key to v-for ([#1369](https://github.com/vuejs/vuex/issues/1369)) ([a9bd047](https://github.com/vuejs/vuex/commit/a9bd047ea147cacfcb4003946aeebccd2c5e1e4e))\n* avoid to call root state function twice ([#1034](https://github.com/vuejs/vuex/issues/1034)) ([86677eb](https://github.com/vuejs/vuex/commit/86677ebcbfaecf712f339b73a568150fc9fd5f5e))\n* fix [#1032](https://github.com/vuejs/vuex/issues/1032), relax vue typing in helpers ([#1044](https://github.com/vuejs/vuex/issues/1044)) ([7c7ed1d](https://github.com/vuejs/vuex/commit/7c7ed1d37ee8a5058082d763d80529e5fef86a0b))\n\n\n### Features\n\n* add ability to turn off devtools on vuex by passing an off options ([#1407](https://github.com/vuejs/vuex/issues/1407)) ([be75d41](https://github.com/vuejs/vuex/commit/be75d41cf54d50177a7db7e9218e8d1c820ae830))\n* ensure errors in action subscribers do not break actions ([acd7249](https://github.com/vuejs/vuex/commit/acd72492eaffff3661f75860a3d7ab37b73c3906))\n\n\n### Reverts\n\n* Revert \"Update util find (#1205)\" (fix #1286) ([273bf86](https://github.com/vuejs/vuex/commit/273bf86b330ee580a73176c300919996b7d9c2c3)), closes [#1286](https://github.com/vuejs/vuex/issues/1286)\n\n\n\n## [3.0.1](https://github.com/vuejs/vuex/compare/v3.0.0...v3.0.1) (2017-11-01)\n\n\n\n# [3.0.0](https://github.com/vuejs/vuex/compare/v2.5.0...v3.0.0) (2017-10-11)\n\n\n### Features\n\n* **typings:** adapt to the new Vue typings ([#909](https://github.com/vuejs/vuex/issues/909)) ([65dbfec](https://github.com/vuejs/vuex/commit/65dbfec40d5fe7aac05aab333c7b70768997ca7f))\n\n\n### BREAKING CHANGES\n\n* **typings:** It is no longer compatible with the old Vue typings\n\n* chore(package): bump typescript and vue core typings\n\n* chore: bump vue\n\n* Update package.json\n\n\n\n# [2.5.0](https://github.com/vuejs/vuex/compare/v2.4.1...v2.5.0) (2017-10-11)\n\n\n### Bug Fixes\n\n* initialize root state as an empty object if state function returns no value ([#927](https://github.com/vuejs/vuex/issues/927)) ([0e9756b](https://github.com/vuejs/vuex/commit/0e9756b93c5de8e03286d93f0b50af5f8dfd3bac))\n\n\n### Features\n\n* add logger plugin logger config support ([#771](https://github.com/vuejs/vuex/issues/771)) ([804c3bb](https://github.com/vuejs/vuex/commit/804c3bbd2e60f11412f5a7cb7694969f8f6c215c))\n* preserve state with registerModule ([#837](https://github.com/vuejs/vuex/issues/837)) ([4c1841e](https://github.com/vuejs/vuex/commit/4c1841e79e63ca0ca95d0cc1b218fde258f23c20))\n* root actions in namespaced modules ([#941](https://github.com/vuejs/vuex/issues/941)) ([73189eb](https://github.com/vuejs/vuex/commit/73189eb35509de7d49bd2b577900ad560d37dcb0))\n* subscribeAction ([#960](https://github.com/vuejs/vuex/issues/960)) ([a8326b1](https://github.com/vuejs/vuex/commit/a8326b1bd77158e7e5903eed4cc98b52599e3dbd))\n\n\n\n## [2.4.1](https://github.com/vuejs/vuex/compare/v2.4.0...v2.4.1) (2017-09-27)\n\n\n### Bug Fixes\n\n* allow installation on extended Vue copies ([c87b72f](https://github.com/vuejs/vuex/commit/c87b72f2ff7f65e708c4b59a752ef234d0f28d1f))\n* link to details of mutations in components ([#930](https://github.com/vuejs/vuex/issues/930)) ([e82782b](https://github.com/vuejs/vuex/commit/e82782ba81c398dd5b78a195257a9d1c3a6d85ef))\n* move auto installation code into the store constructor ([#914](https://github.com/vuejs/vuex/issues/914)) ([852ac43](https://github.com/vuejs/vuex/commit/852ac43ea4813ecaeb1e5106c4a29c74e57c2fd7))\n\n\n### Features\n\n* allow to passing functions in mapActions/mapMutations (fix [#750](https://github.com/vuejs/vuex/issues/750)) ([#924](https://github.com/vuejs/vuex/issues/924)) ([be15f32](https://github.com/vuejs/vuex/commit/be15f32c0077d8fe9bafa38c1b319b655cfd5f86))\n\n\n\n# [2.4.0](https://github.com/vuejs/vuex/compare/v2.3.0...v2.4.0) (2017-08-29)\n\n\n### Bug Fixes\n\n* **typings:** watch() returns an unwatch function ([#922](https://github.com/vuejs/vuex/issues/922)) ([a4bd081](https://github.com/vuejs/vuex/commit/a4bd0816838cc4a843d833363b9aa412c1256e5e))\n* add missing typings and docs of createNamespacedHelpers ([#910](https://github.com/vuejs/vuex/issues/910)) ([7ad573b](https://github.com/vuejs/vuex/commit/7ad573bba59d23dbd66e3a25e6614296aeb98d42))\n\n\n### Features\n\n* **store:** bind mutation and action handlers to store ([#872](https://github.com/vuejs/vuex/issues/872)) ([67da622](https://github.com/vuejs/vuex/commit/67da6225552e46266ed059c7f0d0128294cd08ed))\n\n\n### Performance Improvements\n\n* do not connect devtools if Vue.config.devtools == false ([#881](https://github.com/vuejs/vuex/issues/881)) ([dd7f817](https://github.com/vuejs/vuex/commit/dd7f8178d93e6121a447c410b9c652f40cd80937))\n\n\n\n# [2.3.0](https://github.com/vuejs/vuex/compare/v2.2.1...v2.3.0) (2017-04-13)\n\n\n* Add '-loader' suffix to webpack config (#722) ([84b4634](https://github.com/vuejs/vuex/commit/84b463438ea4133f7f326dc18212e3d4b7b5a177)), closes [#722](https://github.com/vuejs/vuex/issues/722)\n\n\n### BREAKING CHANGES\n\n* It's no longer allowed to omit the '-loader' suffix when using loaders. You need to specify 'babel-loader' instead of 'babel'.\nMy version of webpack: 2.2.0-rc.3\nAdding the '-loader' suffix fixed the problem.\nNot sure though how safe it is to use 'babel-loader' instead of 'babel' with previous webpack versions...\n\n\n\n## [2.2.1](https://github.com/vuejs/vuex/compare/v2.2.0...v2.2.1) (2017-02-26)\n\n\n\n# [2.2.0](https://github.com/vuejs/vuex/compare/v2.1.2...v2.2.0) (2017-02-26)\n\n\n\n## [2.1.2](https://github.com/vuejs/vuex/compare/v2.1.1...v2.1.2) (2017-02-06)\n\n\n### Reverts\n\n* Revert \"Update modules.md (#534)\" ([5e145b3](https://github.com/vuejs/vuex/commit/5e145b3a2d45977b52cfff41b3b663f629d67e74)), closes [#534](https://github.com/vuejs/vuex/issues/534)\n\n\n\n## [2.1.1](https://github.com/vuejs/vuex/compare/v2.1.0...v2.1.1) (2016-12-17)\n\n\n\n# [2.1.0](https://github.com/vuejs/vuex/compare/v2.0.0...v2.1.0) (2016-12-16)\n\n\n\n# [2.0.0](https://github.com/vuejs/vuex/compare/v2.0.0-rc.6...v2.0.0) (2016-09-30)\n\n\n\n# [2.0.0-rc.6](https://github.com/vuejs/vuex/compare/v2.0.0-rc.5...v2.0.0-rc.6) (2016-09-24)\n\n\n\n# [2.0.0-rc.5](https://github.com/vuejs/vuex/compare/v2.0.0-rc.4...v2.0.0-rc.5) (2016-08-15)\n\n\n\n# [2.0.0-rc.4](https://github.com/vuejs/vuex/compare/v2.0.0-rc.3...v2.0.0-rc.4) (2016-08-05)\n\n\n\n# [2.0.0-rc.3](https://github.com/vuejs/vuex/compare/v2.0.0-rc.1...v2.0.0-rc.3) (2016-07-11)\n\n\n\n# [2.0.0-rc.1](https://github.com/vuejs/vuex/compare/v1.0.0-rc...v2.0.0-rc.1) (2016-07-05)\n\n\n\n# [1.0.0-rc](https://github.com/vuejs/vuex/compare/v0.8.2...v1.0.0-rc) (2016-07-01)\n\n\n\n## [0.8.2](https://github.com/vuejs/vuex/compare/v0.8.1...v0.8.2) (2016-06-28)\n\n\n\n## [0.8.1](https://github.com/vuejs/vuex/compare/v0.8.0...v0.8.1) (2016-06-28)\n\n\n\n# [0.8.0](https://github.com/vuejs/vuex/compare/v0.7.1...v0.8.0) (2016-06-23)\n\n\n\n## [0.7.1](https://github.com/vuejs/vuex/compare/v0.7.0...v0.7.1) (2016-06-22)\n\n\n\n# [0.7.0](https://github.com/vuejs/vuex/compare/v0.6.3...v0.7.0) (2016-06-21)\n\n\n\n## [0.6.3](https://github.com/vuejs/vuex/compare/v0.6.2...v0.6.3) (2016-04-23)\n\n\n\n## [0.6.2](https://github.com/vuejs/vuex/compare/v0.6.1...v0.6.2) (2016-03-08)\n\n\n\n## [0.6.1](https://github.com/vuejs/vuex/compare/v0.6.0...v0.6.1) (2016-03-07)\n\n\n\n# [0.6.0](https://github.com/vuejs/vuex/compare/v0.5.1...v0.6.0) (2016-03-07)\n\n\n\n## [0.5.1](https://github.com/vuejs/vuex/compare/v0.5.0...v0.5.1) (2016-03-04)\n\n\n\n# [0.5.0](https://github.com/vuejs/vuex/compare/v0.4.2...v0.5.0) (2016-03-04)\n\n\n\n## [0.4.2](https://github.com/vuejs/vuex/compare/v0.4.1...v0.4.2) (2016-03-02)\n\n\n\n## [0.4.1](https://github.com/vuejs/vuex/compare/v0.4.0...v0.4.1) (2016-03-01)\n\n\n\n# [0.4.0](https://github.com/vuejs/vuex/compare/v0.3.0...v0.4.0) (2016-03-01)\n\n\n\n# [0.3.0](https://github.com/vuejs/vuex/compare/4a22523b8cf4a1954ec95a0083ddef6c085f4905...v0.3.0) (2016-02-16)\n\n\n### Bug Fixes\n\n* **api:** fix typo ([4a22523](https://github.com/vuejs/vuex/commit/4a22523b8cf4a1954ec95a0083ddef6c085f4905))\n* **forms:** fix typo ([50094a6](https://github.com/vuejs/vuex/commit/50094a604f32d00ceb784a3fbf07c82c502faca2))\n\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015-present Evan You\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Vuex\n\n[![npm](https://img.shields.io/npm/v/vuex.svg)](https://npmjs.com/package/vuex)\n[![ci status](https://github.com/vuejs/vuex/actions/workflows/ci.yml/badge.svg)](https://github.com/vuejs/vuex/actions/workflows/ci.yml)\n\n---\n\n**Pinia is now the new default**\n\nThe official state management library for Vue has changed to [Pinia](https://pinia.vuejs.org). Pinia has almost the exact same or enhanced API as Vuex 5, described in [Vuex 5 RFC](https://github.com/vuejs/rfcs/pull/271). You could simply consider Pinia as Vuex 5 with a different name. Pinia also works with Vue 2.x as well.\n\nVuex 3 and 4 will still be maintained. However, it's unlikely to add new functionalities to it. Vuex and Pinia can be installed in the same project. If you're migrating existing Vuex app to Pinia, it might be a suitable option. However, if you're planning to start a new project, we highly recommend using Pinia instead.\n\n---\n\nVuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue's official [devtools extension](https://github.com/vuejs/vue-devtools) to provide advanced features such as zero-config time-travel debugging and state snapshot export / import.\n\nLearn more about Vuex at \"[What is Vuex?](https://vuex.vuejs.org/)\", or get started by looking into [full documentation](http://vuex.vuejs.org/).\n\n## Documentation\n\nTo check out docs, visit [vuex.vuejs.org](https://vuex.vuejs.org/).\n\n## Examples\n\nYou may find example applications built with Vuex under the `examples` directory.\n\nRunning the examples:\n\n```bash\n$ npm install\n$ npm run dev # serve examples at localhost:8080\n```\n\n## Questions\n\nFor 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.\n\n## Issues\n\nPlease make sure to read the [Issue Reporting Checklist](https://github.com/vuejs/vuex/blob/main/.github/contributing.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.\n\n## Changelog\n\nDetailed changes for each release are documented in the [release notes](https://github.com/vuejs/vuex/releases).\n\n## Stay In Touch\n\nFor latest releases and announcements, follow on Twitter: [@vuejs](https://twitter.com/vuejs).\n\n## Contribution\n\nPlease make sure to read the [Contributing Guide](https://github.com/vuejs/vuex/blob/main/.github/contributing.md) before making a pull request.\n\n## License\n\n[MIT](http://opensource.org/licenses/MIT)\n\nCopyright (c) 2015-present Evan You\n"
  },
  {
    "path": "docs/.vitepress/config.js",
    "content": "module.exports = {\n  lang: 'en-US',\n  title: 'Vuex',\n  description: 'Centralized State Management for Vue.js',\n\n  locales: {\n    '/': {\n      lang: 'en-US',\n      title: 'Vuex',\n      description: 'Centralized State Management for Vue.js'\n    },\n    '/zh/': {\n      lang: 'zh-CN',\n      title: 'Vuex',\n      description: 'Vue.js 的中心化状态管理方案'\n    },\n    '/ja/': {\n      lang: 'ja',\n      title: 'Vuex',\n      description: 'Vue.js のための集中状態管理'\n    },\n    '/ptbr/': {\n      lang: 'pt-BR',\n      title: 'Vuex',\n      description: 'Gerenciamento de Estado Centralizado para Vue.js'\n    }\n  },\n\n  head: [\n    ['link', { rel: 'icon', href: `/logo.png` }],\n    ['link', { rel: 'apple-touch-icon', href: `/icons/apple-touch-icon-152x152.png` }],\n    ['link', { rel: 'mask-icon', href: '/icons/safari-pinned-tab.svg', color: '#3eaf7c' }],\n    ['meta', { name: 'msapplication-TileImage', content: '/icons/msapplication-icon-144x144.png' }]\n  ],\n\n  themeConfig: {\n    repo: 'vuejs/vuex',\n    docsDir: 'docs',\n    docsBranch: 'main',\n\n    editLinks: true,\n\n    locales: {\n      '/': {\n        label: 'English',\n        selectText: 'Languages',\n        editLinkText: 'Edit this page on GitHub',\n        lastUpdated: 'Last Updated',\n\n        nav: [\n          { text: 'Guide', link: '/guide/' },\n          { text: 'API Reference', link: '/api/' },\n          { text: 'Release Notes', link: 'https://github.com/vuejs/vuex/releases' },\n          {\n            text: 'v4.x',\n            items: [\n              { text: 'v3.x', link: 'https://v3.vuex.vuejs.org/' }\n            ]\n          }\n        ],\n\n        sidebar: [\n          {\n            text: 'Introduction',\n            children: [\n              { text: 'What is Vuex?', link: '/' },\n              { text: 'Installation', link: '/installation' },\n              { text: 'Getting Started', link: '/guide/' }\n            ]\n          },\n          {\n            text: 'Core Concepts',\n            children: [\n              { text: 'State', link: '/guide/state' },\n              { text: 'Getters', link: '/guide/getters' },\n              { text: 'Mutations', link: '/guide/mutations' },\n              { text: 'Actions', link: '/guide/actions' },\n              { text: 'Modules', link: '/guide/modules' }\n            ]\n          },\n          {\n            text: 'Advanced',\n            children: [\n              { text: 'Application Structure', link: '/guide/structure' },\n              { text: 'Composition API', link: '/guide/composition-api' },\n              { text: 'Plugins', link: '/guide/plugins' },\n              { text: 'Strict Mode', link: '/guide/strict' },\n              { text: 'Form Handling', link: '/guide/forms' },\n              { text: 'Testing', link: '/guide/testing' },\n              { text: 'Hot Reloading', link: '/guide/hot-reload' },\n              { text: 'TypeScript Support', link: '/guide/typescript-support' },\n            ]\n          },\n          {\n            text: 'Migration Guide',\n            children: [\n              { text: 'Migrating to 4.0 from 3.x', link: '/guide/migrating-to-4-0-from-3-x' }\n            ]\n          }\n        ]\n      },\n\n      '/zh/': {\n        label: '简体中文',\n        selectText: '选择语言',\n        editLinkText: '在 GitHub 上编辑此页',\n        lastUpdated: '最近更新时间',\n\n        nav: [\n          { text: '指南', link: '/zh/guide/' },\n          { text: 'API 参考', link: '/zh/api/' },\n          { text: '更新记录', link: 'https://github.com/vuejs/vuex/releases' },\n          {\n            text: 'v4.x',\n            items: [\n              { text: 'v3.x', link: 'https://v3.vuex.vuejs.org/zh' }\n            ]\n          }\n        ],\n\n        sidebar: [\n          {\n            text: '介绍',\n            children: [\n              { text: 'Vuex 是什么?', link: '/zh/' },\n              { text: '安装', link: '/zh/installation' },\n              { text: '开始', link: '/zh/guide/' }\n            ]\n          },\n          {\n            text: '核心概念',\n            children: [\n              { text: 'State', link: '/zh/guide/state' },\n              { text: 'Getter', link: '/zh/guide/getters' },\n              { text: 'Mutation', link: '/zh/guide/mutations' },\n              { text: 'Action', link: '/zh/guide/actions' },\n              { text: 'Module', link: '/zh/guide/modules' }\n            ]\n          },\n          {\n            text: '进阶',\n            children: [\n              { text: '项目结构', link: '/zh/guide/structure' },\n              { text: '组合式 API', link: '/zh/guide/composition-api' },\n              { text: '插件', link: '/zh/guide/plugins' },\n              { text: '严格模式', link: '/zh/guide/strict' },\n              { text: '表单处理', link: '/zh/guide/forms' },\n              { text: '测试', link: '/zh/guide/testing' },\n              { text: '热重载', link: '/zh/guide/hot-reload' },\n              { text: 'TypeScript 支持', link: '/zh/guide/typescript-support' },\n            ]\n          },\n          {\n            text: '迁移指南',\n            children: [\n              { text: '从 3.x 迁移到 4.0', link: '/zh/guide/migrating-to-4-0-from-3-x' }\n            ]\n          }\n        ]\n      },\n\n      '/ja/': {\n        label: '日本語',\n        selectText: '言語',\n        editLinkText: 'GitHub 上でこのページを編集する',\n        lastUpdated: '最終更新日時',\n\n        nav: [\n          { text: 'ガイド', link: '/ja/guide/' },\n          { text: 'API リファレンス', link: '/ja/api/' },\n          { text: 'リリースノート', link: 'https://github.com/vuejs/vuex/releases' },\n          {\n            text: 'v4.x',\n            items: [\n              { text: 'v3.x', link: 'https://v3.vuex.vuejs.org/ja' }\n            ]\n          }\n        ],\n\n        sidebar: [\n          {\n            text: 'はじめに',\n            children: [\n              { text: 'Vuex とは何か？', link: '/ja/' },\n              { text: 'インストール', link: '/ja/installation' },\n              { text: 'Vuex 入門', link: '/ja/guide/' }\n            ]\n          },\n          {\n            text: 'コアコンセプト',\n            children: [\n              { text: 'ステート', link: '/ja/guide/state' },\n              { text: 'ゲッター', link: '/ja/guide/getters' },\n              { text: 'ミューテーション', link: '/ja/guide/mutations' },\n              { text: 'アクション', link: '/ja/guide/actions' },\n              { text: 'モジュール', link: '/ja/guide/modules' }\n            ]\n          },\n          {\n            text: '高度な活用',\n            children: [\n              { text: 'アプリケーションの構造', link: '/ja/guide/structure' },\n              { text: 'Composition API', link: '/ja/guide/composition-api' },\n              { text: 'プラグイン', link: '/ja/guide/plugins' },\n              { text: '厳格モード', link: '/ja/guide/strict' },\n              { text: 'フォームの扱い', link: '/ja/guide/forms' },\n              { text: 'テスト', link: '/ja/guide/testing' },\n              { text: 'ホットリローディング', link: '/ja/guide/hot-reload' },\n              { text: 'TypeScript サポート', link: '/ja/guide/typescript-support' },\n            ]\n          },\n          {\n            text: '移行 ガイド',\n            children: [\n              { text: '3.x から 4.0 への移行', link: '/ja/guide/migrating-to-4-0-from-3-x' }\n            ]\n          }\n        ]\n      },\n\n      '/ptbr/': {\n        label: 'Português',\n        selectText: 'Idiomas',\n        editLinkText: 'Edite esta página no GitHub',\n        lastUpdated: 'Última Atualização',\n\n        nav: [\n          { text: 'Guia', link: '/ptbr/guide/' },\n          { text: 'Referência da API', link: '/ptbr/api/' },\n          { text: 'Notas de Lançamento', link: 'https://github.com/vuejs/vuex/releases' },\n          {\n            text: 'v4.x',\n            items: [\n              { text: 'v3.x', link: 'https://v3.vuex.vuejs.org/ptbr/' }\n            ]\n          }\n        ],\n\n        sidebar: [\n          {\n            text: 'Introdução',\n            children: [\n              { text: 'O que é Vuex?', link: '/ptbr/' },\n              { text: 'Instalação', link: '/ptbr/installation' },\n              { text: 'Começando', link: '/ptbr/guide/' }\n            ]\n          },\n          {\n            text: 'Conceitos Básicos',\n            children: [\n              { text: 'Estado', link: '/ptbr/guide/state' },\n              { text: 'Getters', link: '/ptbr/guide/getters' },\n              { text: 'Mutações', link: '/ptbr/guide/mutations' },\n              { text: 'Ações', link: '/ptbr/guide/actions' },\n              { text: 'Módulos', link: '/ptbr/guide/modules' }\n            ]\n          },\n          {\n            text: 'Avançado',\n            children: [\n              { text: 'Estrutura da Aplicação', link: '/ptbr/guide/structure' },\n              { text: 'Composition API', link: '/ptbr/guide/composition-api' },\n              { text: 'Plugins', link: '/ptbr/guide/plugins' },\n              { text: 'Modo Strict', link: '/ptbr/guide/strict' },\n              { text: 'Manipulação de Formulários', link: '/ptbr/guide/forms' },\n              { text: 'Testando', link: '/ptbr/guide/testing' },\n              { text: 'Hot Reloading', link: '/ptbr/guide/hot-reload' },\n              { text: 'Suporte ao TypeScript', link: '/ptbr/guide/typescript-support' },\n            ]\n          },\n          {\n            text: 'Guia de Migração',\n            children: [\n              { text: 'Migrando do 3.x para 4.0', link: '/ptbr/guide/migrating-to-4-0-from-3-x' }\n            ]\n          }\n        ]\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "docs/.vitepress/styles/styles.css",
    "content": ".scrimba {\n  position: relative;\n  margin-top: 16px;\n  border-radius: 2px;\n  padding: 1em 1.25em;\n  color: #486491;\n  background-color: #e7ecf3;\n}\n\n.scrimba a {\n  position: relative;\n  padding-left: 36px;\n  color: #486491 !important;\n}\n\n.scrimba a::before {\n  position: absolute;\n  top: -5px;\n  left: -4px;\n  display: block;\n  border-radius: 50%;\n  width: 30px;\n  height: 30px;\n  background-color: #73abfe;\n  content: \"\";\n}\n\n.scrimba a::after {\n  position: absolute;\n  top: 5px;\n  left: 8px;\n  display: block;\n  border-top: 5px solid transparent;\n  border-bottom: 5px solid transparent;\n  border-left: 8px solid #ffffff;\n  width: 0;\n  height: 0;\n  content: \"\";\n}\n"
  },
  {
    "path": "docs/.vitepress/theme/index.js",
    "content": "import '../styles/styles.css'\n\nimport DefaultTheme from 'vitepress/dist/client/theme-default'\n\nexport default {\n  ...DefaultTheme\n}\n"
  },
  {
    "path": "docs/api/index.md",
    "content": "---\nsidebar: auto\n---\n\n# API Reference\n\n## Store\n\n### createStore\n\n- `createStore<S>(options: StoreOptions<S>): Store<S>`\n\n  Creates a new store.\n\n  ```js\n  import { createStore } from 'vuex'\n\n  const store = createStore({ ...options })\n  ```\n\n## Store Constructor Options\n\n### state\n\n- type: `Object | Function`\n\n  The root state object for the Vuex store. [Details](../guide/state.md)\n\n  If you pass a function that returns an object, the returned object is used as the root state. This is useful when you want to reuse the state object especially for module reuse. [Details](../guide/modules.md#module-reuse)\n\n### mutations\n\n- type: `{ [type: string]: Function }`\n\n  Register mutations on the store. The handler function always receives `state` as the first argument (will be module local state if defined in a module), and receives a second `payload` argument if there is one.\n\n  [Details](../guide/mutations.md)\n\n### actions\n\n- type: `{ [type: string]: Function }`\n\n  Register actions on the store. The handler function receives a `context` object that exposes the following properties:\n\n  ```js\n  {\n    state,      // same as `store.state`, or local state if in modules\n    rootState,  // same as `store.state`, only in modules\n    commit,     // same as `store.commit`\n    dispatch,   // same as `store.dispatch`\n    getters,    // same as `store.getters`, or local getters if in modules\n    rootGetters // same as `store.getters`, only in modules\n  }\n  ```\n\n  And also receives a second `payload` argument if there is one.\n\n  [Details](../guide/actions.md)\n\n### getters\n\n- type: `{ [key: string]: Function }`\n\n  Register getters on the store. The getter function receives the following arguments:\n\n  ```\n  state,     // will be module local state if defined in a module.\n  getters    // same as store.getters\n  ```\n\n  Specific when defined in a module\n\n  ```\n  state,       // will be module local state if defined in a module.\n  getters,     // module local getters of the current module\n  rootState,   // global state\n  rootGetters  // all getters\n  ```\n\n  Registered getters are exposed on `store.getters`.\n\n  [Details](../guide/getters.md)\n\n### modules\n\n- type: `Object`\n\n  An object containing sub modules to be merged into the store, in the shape of:\n\n  ```js\n  {\n    key: {\n      state,\n      namespaced?,\n      mutations?,\n      actions?,\n      getters?,\n      modules?\n    },\n    ...\n  }\n  ```\n\n  Each module can contain `state` and `mutations` similar to the root options. A module's state will be attached to the store's root state using the module's key. A module's mutations and getters will only receives the module's local state as the first argument instead of the root state, and module actions' `context.state` will also point to the local state.\n\n  [Details](../guide/modules.md)\n\n### plugins\n\n- type: `Array<Function>`\n\n  An array of plugin functions to be applied to the store. The plugin simply receives the store as the only argument and can either listen to mutations (for outbound data persistence, logging, or debugging) or dispatch mutations (for inbound data e.g. websockets or observables).\n\n  [Details](../guide/plugins.md)\n\n### strict\n\n- type: `boolean`\n- default: `false`\n\n  Force the Vuex store into strict mode. In strict mode any mutations to Vuex state outside of mutation handlers will throw an Error.\n\n  [Details](../guide/strict.md)\n\n### devtools\n\n- type: `boolean`\n\n  Turn the devtools on or off for a particular Vuex instance. For instance, passing `false` tells the Vuex store to not subscribe to devtools plugin. Useful when you have multiple stores on a single page.\n\n  ```js\n  {\n    devtools: false\n  }\n  ```\n\n## Store Instance Properties\n\n### state\n\n- type: `Object`\n\n  The root state. Read only.\n\n### getters\n\n- type: `Object`\n\n  Exposes registered getters. Read only.\n\n## Store Instance Methods\n\n### commit\n\n-  `commit(type: string, payload?: any, options?: Object)`\n-  `commit(mutation: Object, options?: Object)`\n\n  Commit a mutation. `options` can have `root: true` that allows to commit root mutations in [namespaced modules](../guide/modules.md#namespacing). [Details](../guide/mutations.md)\n\n### dispatch\n\n-  `dispatch(type: string, payload?: any, options?: Object): Promise<any>`\n-  `dispatch(action: Object, options?: Object): Promise<any>`\n\n  Dispatch an action. `options` can have `root: true` that allows to dispatch root actions in [namespaced modules](../guide/modules.md#namespacing). Returns a Promise that resolves all triggered action handlers. [Details](../guide/actions.md)\n\n### replaceState\n\n-  `replaceState(state: Object)`\n\n  Replace the store's root state. Use this only for state hydration / time-travel purposes.\n\n### watch\n\n-  `watch(fn: Function, callback: Function, options?: Object): Function`\n\n  Reactively watch `fn`'s return value, and call the callback when the value changes. `fn` receives the store's state as the first argument, and getters as the second argument. Accepts an optional options object that takes the same options as [Vue's `vm.$watch` method](https://vuejs.org/v2/api/#vm-watch).\n\n  To stop watching, call the returned unwatch function.\n\n### subscribe\n\n-  `subscribe(handler: Function, options?: Object): Function`\n\n  Subscribe to store mutations. The `handler` is called after every mutation and receives the mutation descriptor and post-mutation state as arguments.\n\n  ```js\n  const unsubscribe = store.subscribe((mutation, state) => {\n    console.log(mutation.type)\n    console.log(mutation.payload)\n  })\n\n  // you may call unsubscribe to stop the subscription\n  unsubscribe()\n  ```\n\n  By default, new handler is added to the end of the chain, so it will be executed after other handlers that were added before. This can be overridden by adding `prepend: true` to `options`, which will add the handler to the beginning of the chain.\n\n  ```js\n  store.subscribe(handler, { prepend: true })\n  ```\n\n  The `subscribe` method will return an `unsubscribe` function, which should be called when the subscription is no longer needed. For example, you might subscribe to a Vuex Module and unsubscribe when you unregister the module. Or you might call `subscribe` from inside a Vue Component and then destroy the component later. In these cases, you should remember to unsubscribe the subscription manually.\n\n  Most commonly used in plugins. [Details](../guide/plugins.md)\n\n### subscribeAction\n\n-  `subscribeAction(handler: Function, options?: Object): Function`\n\n  Subscribe to store actions. The `handler` is called for every dispatched action and receives the action descriptor and current store state as arguments.\n  The `subscribe` method will return an `unsubscribe` function, which should be called when the subscription is no longer needed. For example, when unregistering a Vuex module or before destroying a Vue component.\n\n  ```js\n  const unsubscribe = store.subscribeAction((action, state) => {\n    console.log(action.type)\n    console.log(action.payload)\n  })\n\n  // you may call unsubscribe to stop the subscription\n  unsubscribe()\n  ```\n\n  By default, new handler is added to the end of the chain, so it will be executed after other handlers that were added before. This can be overridden by adding `prepend: true` to `options`, which will add the handler to the beginning of the chain.\n\n  ```js\n  store.subscribeAction(handler, { prepend: true })\n  ```\n\n  The `subscribeAction` method will return an `unsubscribe` function, which should be called when the subscription is no longer needed. For example, you might subscribe to a Vuex Module and unsubscribe when you unregister the module. Or you might call `subscribeAction` from inside a Vue Component and then destroy the component later. In these cases, you should remember to unsubscribe the subscription manually.\n\n  `subscribeAction` can also specify whether the subscribe handler should be called *before* or *after* an action dispatch (the default behavior is *before*):\n\n  ```js\n  store.subscribeAction({\n    before: (action, state) => {\n      console.log(`before action ${action.type}`)\n    },\n    after: (action, state) => {\n      console.log(`after action ${action.type}`)\n    }\n  })\n  ```\n\n  `subscribeAction` can also specify an `error` handler to catch an error thrown when an action is dispatched. The function will receive an `error` object as the third argument.\n\n  ```js\n  store.subscribeAction({\n    error: (action, state, error) => {\n      console.log(`error action ${action.type}`)\n      console.error(error)\n    }\n  })\n  ```\n\n  The `subscribeAction` method is most commonly used in plugins. [Details](../guide/plugins.md)\n\n### registerModule\n\n-  `registerModule(path: string | Array<string>, module: Module, options?: Object)`\n\n  Register a dynamic module. [Details](../guide/modules.md#dynamic-module-registration)\n\n  `options` can have `preserveState: true` that allows to preserve the previous state. Useful with Server Side Rendering.\n\n### unregisterModule\n\n-  `unregisterModule(path: string | Array<string>)`\n\n  Unregister a dynamic module. [Details](../guide/modules.md#dynamic-module-registration)\n\n### hasModule\n\n- `hasModule(path: string | Array<string>): boolean`\n\n  Check if the module with the given name is already registered. [Details](../guide/modules.md#dynamic-module-registration)\n\n### hotUpdate\n\n-  `hotUpdate(newOptions: Object)`\n\n  Hot swap new actions and mutations. [Details](../guide/hot-reload.md)\n\n## Component Binding Helpers\n\n### mapState\n\n-  `mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  Create component computed options that return the sub tree of the Vuex store. [Details](../guide/state.md#the-mapstate-helper)\n\n  The first argument can optionally be a namespace string. [Details](../guide/modules.md#binding-helpers-with-namespace)\n\n  The second object argument's members can be a function. `function(state: any)`\n\n### mapGetters\n\n-  `mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`\n\n  Create component computed options that return the evaluated value of a getter. [Details](../guide/getters.md#the-mapgetters-helper)\n\n  The first argument can optionally be a namespace string. [Details](../guide/modules.md#binding-helpers-with-namespace)\n\n### mapActions\n\n-  `mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  Create component methods options that dispatch an action. [Details](../guide/actions.md#dispatching-actions-in-components)\n\n  The first argument can optionally be a namespace string. [Details](../guide/modules.md#binding-helpers-with-namespace)\n\n  The second object argument's members can be a function. `function(dispatch: function, ...args: any[])`\n\n### mapMutations\n\n-  `mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  Create component methods options that commit a mutation. [Details](../guide/mutations.md#committing-mutations-in-components)\n\n  The first argument can optionally be a namespace string. [Details](../guide/modules.md#binding-helpers-with-namespace)\n\n  The second object argument's members can be a function. `function(commit: function, ...args: any[])`\n\n### createNamespacedHelpers\n\n-  `createNamespacedHelpers(namespace: string): Object`\n\n  Create namespaced component binding helpers. The returned object contains `mapState`, `mapGetters`, `mapActions` and `mapMutations` that are bound with the given namespace. [Details](../guide/modules.md#binding-helpers-with-namespace)\n\n## Composable Functions\n\n### useStore\n\n- `useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;`\n\n  Fetches the injected store when called inside the `setup` hook. When using the Composition API, you can retrieve the store by calling this method.\n\n  ```js\n  import { useStore } from 'vuex'\n\n  export default {\n    setup () {\n      const store = useStore()\n    }\n  }\n  ```\n\n  TypeScript users can use an injection key to retrieve a typed store. In order for this to work, you must define the injection key and pass it along with the store when installing the store instance to the Vue app.\n\n  First, declare the injection key using Vue's `InjectionKey` interface.\n\n  ```ts\n  // store.ts\n  import { InjectionKey } from 'vue'\n  import { createStore, Store } from 'vuex'\n\n  export interface State {\n    count: number\n  }\n\n  export const key: InjectionKey<Store<State>> = Symbol()\n\n  export const store = createStore<State>({\n    state: {\n      count: 0\n    }\n  })\n  ```\n\n  Then, pass the defined key as the second argument for the `app.use` method.\n\n  ```ts\n  // main.ts\n  import { createApp } from 'vue'\n  import { store, key } from './store'\n\n  const app = createApp({ ... })\n\n  app.use(store, key)\n\n  app.mount('#app')\n  ```\n\n  Finally, you can pass the key to the `useStore` method to retrieve the typed store instance.\n\n  ```ts\n  // in a vue component\n  import { useStore } from 'vuex'\n  import { key } from './store'\n\n  export default {\n    setup () {\n      const store = useStore(key)\n\n      store.state.count // typed as number\n    }\n  }\n  ```\n"
  },
  {
    "path": "docs/guide/actions.md",
    "content": "# Actions\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c6ggR3cG\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nActions are similar to mutations, the differences being that:\n\n- Instead of mutating the state, actions commit mutations.\n- Actions can contain arbitrary asynchronous operations.\n\nLet's register a simple action:\n\n``` js\nconst store = createStore({\n  state: {\n    count: 0\n  },\n  mutations: {\n    increment (state) {\n      state.count++\n    }\n  },\n  actions: {\n    increment (context) {\n      context.commit('increment')\n    }\n  }\n})\n```\n\nAction handlers receive a context object which exposes the same set of methods/properties on the store instance, so you can call `context.commit` to commit a mutation, or access the state and getters via `context.state` and `context.getters`. We can even call other actions with `context.dispatch`. We will see why this context object is not the store instance itself when we introduce [Modules](modules.md) later.\n\nIn practice, we often use ES2015 [argument destructuring](https://github.com/lukehoban/es6features#destructuring) to simplify the code a bit (especially when we need to call `commit` multiple times):\n\n``` js\nactions: {\n  increment ({ commit }) {\n    commit('increment')\n  }\n}\n```\n\n## Dispatching Actions\n\nActions are triggered with the `store.dispatch` method:\n\n``` js\nstore.dispatch('increment')\n```\n\nThis may look silly at first sight: if we want to increment the count, why don't we just call `store.commit('increment')` directly? Remember that **mutations have to be synchronous**. Actions don't. We can perform **asynchronous** operations inside an action:\n\n``` js\nactions: {\n  incrementAsync ({ commit }) {\n    setTimeout(() => {\n      commit('increment')\n    }, 1000)\n  }\n}\n```\n\nActions support the same payload format and object-style dispatch:\n\n``` js\n// dispatch with a payload\nstore.dispatch('incrementAsync', {\n  amount: 10\n})\n\n// dispatch with an object\nstore.dispatch({\n  type: 'incrementAsync',\n  amount: 10\n})\n```\n\nA more practical example of real-world actions would be an action to checkout a shopping cart, which involves **calling an async API** and **committing multiple mutations**:\n\n``` js\nactions: {\n  checkout ({ commit, state }, products) {\n    // save the items currently in the cart\n    const savedCartItems = [...state.cart.added]\n    // send out checkout request, and optimistically\n    // clear the cart\n    commit(types.CHECKOUT_REQUEST)\n    // the shop API accepts a success callback and a failure callback\n    shop.buyProducts(\n      products,\n      // handle success\n      () => commit(types.CHECKOUT_SUCCESS),\n      // handle failure\n      () => commit(types.CHECKOUT_FAILURE, savedCartItems)\n    )\n  }\n}\n```\n\nNote we are performing a flow of asynchronous operations, and recording the side effects (state mutations) of the action by committing them.\n\n## Dispatching Actions in Components\n\nYou can dispatch actions in components with `this.$store.dispatch('xxx')`, or use the `mapActions` helper which maps component methods to `store.dispatch` calls (requires root `store` injection):\n\n``` js\nimport { mapActions } from 'vuex'\n\nexport default {\n  // ...\n  methods: {\n    ...mapActions([\n      'increment', // map `this.increment()` to `this.$store.dispatch('increment')`\n\n      // `mapActions` also supports payloads:\n      'incrementBy' // map `this.incrementBy(amount)` to `this.$store.dispatch('incrementBy', amount)`\n    ]),\n    ...mapActions({\n      add: 'increment' // map `this.add()` to `this.$store.dispatch('increment')`\n    })\n  }\n}\n```\n\n## Composing Actions\n\nActions are often asynchronous, so how do we know when an action is done? And more importantly, how can we compose multiple actions together to handle more complex async flows?\n\nThe first thing to know is that `store.dispatch` can handle Promise returned by the triggered action handler and it also returns Promise:\n\n``` js\nactions: {\n  actionA ({ commit }) {\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        commit('someMutation')\n        resolve()\n      }, 1000)\n    })\n  }\n}\n```\n\nNow you can do:\n\n``` js\nstore.dispatch('actionA').then(() => {\n  // ...\n})\n```\n\nAnd also in another action:\n\n``` js\nactions: {\n  // ...\n  actionB ({ dispatch, commit }) {\n    return dispatch('actionA').then(() => {\n      commit('someOtherMutation')\n    })\n  }\n}\n```\n\nFinally, if we make use of [async / await](https://tc39.github.io/ecmascript-asyncawait/), we can compose our actions like this:\n\n``` js\n// assuming `getData()` and `getOtherData()` return Promises\n\nactions: {\n  async actionA ({ commit }) {\n    commit('gotData', await getData())\n  },\n  async actionB ({ dispatch, commit }) {\n    await dispatch('actionA') // wait for `actionA` to finish\n    commit('gotOtherData', await getOtherData())\n  }\n}\n```\n\n> It's possible for a `store.dispatch` to trigger multiple action handlers in different modules. In such a case the returned value will be a Promise that resolves when all triggered handlers have been resolved.\n"
  },
  {
    "path": "docs/guide/composition-api.md",
    "content": "# Composition API\n\nTo access the store within the `setup` hook, you can call the `useStore` function. This is the equivalent of retrieving `this.$store` within a component using the Option API.\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n  }\n}\n```\n\n## Accessing State and Getters\n\nIn order to access state and getters, you will want to create `computed` references to retain reactivity. This is the equivalent of creating computed properties using the Option API.\n\n```js\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      // access a state in computed function\n      count: computed(() => store.state.count),\n\n      // access a getter in computed function\n      double: computed(() => store.getters.double)\n    }\n  }\n}\n```\n\n## Accessing Mutations and Actions\n\nWhen accessing mutations and actions, you can simply provide the `commit` and `dispatch` method inside the `setup` hook.\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      // access a mutation\n      increment: () => store.commit('increment'),\n\n      // access an action\n      asyncIncrement: () => store.dispatch('asyncIncrement')\n    }\n  }\n}\n```\n\n## Examples\n\nCheck out the [Composition API example](https://github.com/vuejs/vuex/tree/4.0/examples/composition) to see example applications utilizing Vuex and Vue's Composition API.\n"
  },
  {
    "path": "docs/guide/forms.md",
    "content": "# Form Handling\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKRgEC9\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nWhen using Vuex in strict mode, it could be a bit tricky to use `v-model` on a piece of state that belongs to Vuex:\n\n``` html\n<input v-model=\"obj.message\">\n```\n\nAssuming `obj` is a computed property that returns an Object from the store, the `v-model` here will attempt to directly mutate `obj.message` when the user types in the input. In strict mode, this will result in an error because the mutation is not performed inside an explicit Vuex mutation handler.\n\nThe \"Vuex way\" to deal with it is binding the `<input>`'s value and call a method on the `input` or `change` event:\n\n``` html\n<input :value=\"message\" @input=\"updateMessage\">\n```\n\n``` js\n// ...\ncomputed: {\n  ...mapState({\n    message: state => state.obj.message\n  })\n},\nmethods: {\n  updateMessage (e) {\n    this.$store.commit('updateMessage', e.target.value)\n  }\n}\n```\n\nAnd here's the mutation handler:\n\n``` js\n// ...\nmutations: {\n  updateMessage (state, message) {\n    state.obj.message = message\n  }\n}\n```\n\n## Two-way Computed Property\n\nAdmittedly, the above is quite a bit more verbose than `v-model` + local state, and we lose some of the useful features from `v-model` as well. An alternative approach is using a two-way computed property with a setter:\n\n``` html\n<input v-model=\"message\">\n```\n\n``` js\n// ...\ncomputed: {\n  message: {\n    get () {\n      return this.$store.state.obj.message\n    },\n    set (value) {\n      this.$store.commit('updateMessage', value)\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/guide/getters.md",
    "content": "# Getters\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c2Be7TB\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nSometimes we may need to compute derived state based on store state, for example filtering through a list of items and counting them:\n\n``` js\ncomputed: {\n  doneTodosCount () {\n    return this.$store.state.todos.filter(todo => todo.done).length\n  }\n}\n```\n\nIf more than one component needs to make use of this, we have to either duplicate the function, or extract it into a shared helper and import it in multiple places - both are less than ideal.\n\nVuex allows us to define \"getters\" in the store. You can think of them as computed properties for stores.\n\n::: warning WARNING\nAs of Vue 3.0, the getter's result is **not cached** as the computed property does. This is a known issue that requires Vue 3.1 to be released. You can learn more at [PR #1878](https://github.com/vuejs/vuex/pull/1878).\n:::\n\nGetters will receive the state as their 1st argument:\n\n``` js\nconst store = createStore({\n  state: {\n    todos: [\n      { id: 1, text: '...', done: true },\n      { id: 2, text: '...', done: false }\n    ]\n  },\n  getters: {\n    doneTodos (state) {\n      return state.todos.filter(todo => todo.done)\n    }\n  }\n})\n```\n\n## Property-Style Access\n\nThe getters will be exposed on the `store.getters` object, and you access values as properties:\n\n``` js\nstore.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]\n```\n\nGetters will also receive other getters as the 2nd argument:\n\n``` js\ngetters: {\n  // ...\n  doneTodosCount (state, getters) {\n    return getters.doneTodos.length\n  }\n}\n```\n\n``` js\nstore.getters.doneTodosCount // -> 1\n```\n\nWe can now easily make use of it inside any component:\n\n``` js\ncomputed: {\n  doneTodosCount () {\n    return this.$store.getters.doneTodosCount\n  }\n}\n```\n\nNote that getters accessed as properties are cached as part of Vue's reactivity system.\n\n## Method-Style Access\n\nYou can also pass arguments to getters by returning a function. This is particularly useful when you want to query an array in the store:\n\n```js\ngetters: {\n  // ...\n  getTodoById: (state) => (id) => {\n    return state.todos.find(todo => todo.id === id)\n  }\n}\n```\n\n``` js\nstore.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }\n```\n\nNote that getters accessed via methods will run each time you call them, and the result is not cached.\n\n## The `mapGetters` Helper\n\nThe `mapGetters` helper simply maps store getters to local computed properties:\n\n``` js\nimport { mapGetters } from 'vuex'\n\nexport default {\n  // ...\n  computed: {\n    // mix the getters into computed with object spread operator\n    ...mapGetters([\n      'doneTodosCount',\n      'anotherGetter',\n      // ...\n    ])\n  }\n}\n```\n\nIf you want to map a getter to a different name, use an object:\n\n``` js\n...mapGetters({\n  // map `this.doneCount` to `this.$store.getters.doneTodosCount`\n  doneCount: 'doneTodosCount'\n})\n```\n"
  },
  {
    "path": "docs/guide/hot-reload.md",
    "content": "# Hot Reloading\n\nVuex supports hot-reloading mutations, modules, actions and getters during development, using webpack's [Hot Module Replacement API](https://webpack.js.org/guides/hot-module-replacement/). You can also use it in Browserify with the [browserify-hmr](https://github.com/AgentME/browserify-hmr/) plugin.\n\nFor mutations and modules, you need to use the `store.hotUpdate()` API method:\n\n``` js\n// store.js\nimport { createStore } from 'vuex'\nimport mutations from './mutations'\nimport moduleA from './modules/a'\n\nconst state = { ... }\n\nconst store = createStore({\n  state,\n  mutations,\n  modules: {\n    a: moduleA\n  }\n})\n\nif (module.hot) {\n  // accept actions and mutations as hot modules\n  module.hot.accept(['./mutations', './modules/a'], () => {\n    // require the updated modules\n    // have to add .default here due to babel 6 module output\n    const newMutations = require('./mutations').default\n    const newModuleA = require('./modules/a').default\n    // swap in the new modules and mutations\n    store.hotUpdate({\n      mutations: newMutations,\n      modules: {\n        a: newModuleA\n      }\n    })\n  })\n}\n```\n\nCheckout the [counter-hot example](https://github.com/vuejs/vuex/tree/main/examples/counter-hot) to play with hot-reload.\n\n## Dynamic module hot reloading\n\nIf you use modules exclusively, you can use `require.context` to load and hot reload all modules dynamically.\n\n```js\n// store.js\nimport { createStore } from 'vuex'\n\n// Load all modules.\nfunction loadModules() {\n  const context = require.context(\"./modules\", false, /([a-z_]+)\\.js$/i)\n\n  const modules = context\n    .keys()\n    .map((key) => ({ key, name: key.match(/([a-z_]+)\\.js$/i)[1] }))\n    .reduce(\n      (modules, { key, name }) => ({\n        ...modules,\n        [name]: context(key).default\n      }),\n      {}\n    )\n\n  return { context, modules }\n}\n\nconst { context, modules } = loadModules()\n\nconst store = createStore({\n  modules\n})\n\nif (module.hot) {\n  // Hot reload whenever any module changes.\n  module.hot.accept(context.id, () => {\n    const { modules } = loadModules()\n\n    store.hotUpdate({\n      modules\n    })\n  })\n}\n```\n"
  },
  {
    "path": "docs/guide/index.md",
    "content": "# Getting Started\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cMPa2Uk\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nAt the center of every Vuex application is the **store**. A \"store\" is basically a container that holds your application **state**. There are two things that make a Vuex store different from a plain global object:\n\n1. Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes.\n\n2. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly **committing mutations**. This ensures every state change leaves a track-able record, and enables tooling that helps us better understand our applications.\n\n## The Simplest Store\n\n:::tip NOTE\nWe will be using ES2015 syntax for code examples for the rest of the docs. If you haven't picked it up, [you should](https://babeljs.io/docs/learn-es2015/)!\n:::\n\nAfter [installing](../installation.md) Vuex, let's create a store. It is pretty straightforward - just provide an initial state object, and some mutations:\n\n```js\nimport { createApp } from 'vue'\nimport { createStore } from 'vuex'\n\n// Create a new store instance.\nconst store = createStore({\n  state () {\n    return {\n      count: 0\n    }\n  },\n  mutations: {\n    increment (state) {\n      state.count++\n    }\n  }\n})\n\nconst app = createApp({ /* your root component */ })\n\n// Install the store instance as a plugin\napp.use(store)\n```\n\nNow, you can access the state object as `store.state`, and trigger a state change with the `store.commit` method:\n\n```js\nstore.commit('increment')\n\nconsole.log(store.state.count) // -> 1\n```\n\nIn a Vue component, you can access the store as `this.$store`. Now we can commit a mutation using a component method:\n\n```js\nmethods: {\n  increment() {\n    this.$store.commit('increment')\n    console.log(this.$store.state.count)\n  }\n}\n```\n\nAgain, the reason we are committing a mutation instead of changing `store.state.count` directly, is because we want to explicitly track it. This simple convention makes your intention more explicit, so that you can reason about state changes in your app better when reading the code. In addition, this gives us the opportunity to implement tools that can log every mutation, take state snapshots, or even perform time travel debugging.\n\nUsing store state in a component simply involves returning the state within a computed property, because the store state is reactive. Triggering changes simply means committing mutations in component methods.\n\nNext, we will discuss each core concept in much finer details, starting with [State](state.md).\n"
  },
  {
    "path": "docs/guide/migrating-to-4-0-from-3-x.md",
    "content": "# Migrating to 4.0 from 3.x\n\nAlmost all Vuex 4 APIs have remained unchanged from Vuex 3. However, there are still a few breaking changes that you must fix.\n\n- [Breaking Changes](#breaking-changes)\n  - [Installation process](#installation-process)\n  - [TypeScript support](#typescript-support)\n  - [Bundles are now aligned with Vue 3](#bundles-are-now-aligned-with-vue-3)\n  - [\"createLogger\" function is exported from the core module](#createlogger-function-is-exported-from-the-core-module)\n- [New Features](#new-features)\n  - [New \"useStore\" composition function](#new-usestore-composition-function)\n\n## Breaking Changes\n\n### Installation process\n\nTo align with the new Vue 3 initialization process, the installation process of Vuex has changed. To create a new store, users are now encouraged to use the newly introduced createStore function.\n\n```js\nimport { createStore } from 'vuex'\n\nexport const store = createStore({\n  state () {\n    return {\n      count: 1\n    }\n  }\n})\n```\n\nTo install Vuex to a Vue instance, pass the `store` instead of Vuex.\n\n```js\nimport { createApp } from 'vue'\nimport { store } from './store'\nimport App from './App.vue'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n```\n\n:::tip NOTE\nWhilst this is not technically a breaking change, you may still use the `new Store(...)` syntax, we recommend this approach to align with Vue 3 and Vue Router Next.\n:::\n\n### TypeScript support\n\nVuex 4 removes its global typings for `this.$store` within a Vue component to solve [issue #994](https://github.com/vuejs/vuex/issues/994). When used with TypeScript, you must declare your own module augmentation.\n\nPlace the following code in your project to allow `this.$store` to be typed correctly:\n\n```ts\n// vuex-shim.d.ts\n\nimport { ComponentCustomProperties } from 'vue'\nimport { Store } from 'vuex'\n\ndeclare module 'vue' {\n  // Declare your own store states.\n  interface State {\n    count: number\n  }\n\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\nYou can learn more in the [TypeScript Support](./typescript-support) section.\n\n### Bundles are now aligned with Vue 3\n\nThe following bundles are generated to align with Vue 3 bundles:\n\n- `vuex.global(.prod).js`\n  - For direct use with `<script src=\"...\">` in the browser. Exposes the Vuex global.\n  - Global build is built as IIFE, and not UMD, and is only meant for direct use with `<script src=\"...\">`.\n  - Contains hard-coded prod/dev branches and the prod build is pre-minified. Use the `.prod.js` files for production.\n- `vuex.esm-browser(.prod).js`\n  - For use with native ES module imports (including module supporting browsers via `<script type=\"module\">`.\n- `vuex.esm-bundler.js`\n  - For use with bundlers such as `webpack`, `rollup` and `parcel`.\n  - Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler).\n  - Does not ship minified builds (to be done together with the rest of the code after bundling).\n- `vuex.cjs.js`\n  - For use in Node.js server-side rendering with `require()`.\n\n### `createLogger` function is exported from the core module\n\nIn Vuex 3, `createLogger` function was exported from `vuex/dist/logger` but it's now included in the core package. The function should be imported directly from the `vuex` package.\n\n```js\nimport { createLogger } from 'vuex'\n```\n\n## New Features\n\n### New `useStore` composition function\n\nVuex 4 introduces a new API to interact with the store in Composition API. You can use the `useStore` composition function to retrieve the store within the component `setup` hook.\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n  }\n}\n```\n\nYou can learn more in the [Composition API](./composition-api) section.\n"
  },
  {
    "path": "docs/guide/modules.md",
    "content": "# Modules\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKK4psq\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nDue to using a single state tree, all states of our application are contained inside one big object. However, as our application grows in scale, the store can get really bloated.\n\nTo help with that, Vuex allows us to divide our store into **modules**. Each module can contain its own state, mutations, actions, getters, and even nested modules - it's fractal all the way down:\n\n```js\nconst moduleA = {\n  state: () => ({ ... }),\n  mutations: { ... },\n  actions: { ... },\n  getters: { ... }\n}\n\nconst moduleB = {\n  state: () => ({ ... }),\n  mutations: { ... },\n  actions: { ... }\n}\n\nconst store = createStore({\n  modules: {\n    a: moduleA,\n    b: moduleB\n  }\n})\n\nstore.state.a // -> `moduleA`'s state\nstore.state.b // -> `moduleB`'s state\n```\n\n## Module Local State\n\nInside a module's mutations and getters, the first argument received will be **the module's local state**.\n\n```js\nconst moduleA = {\n  state: () => ({\n    count: 0\n  }),\n  mutations: {\n    increment (state) {\n      // `state` is the local module state\n      state.count++\n    }\n  },\n  getters: {\n    doubleCount (state) {\n      return state.count * 2\n    }\n  }\n}\n```\n\nSimilarly, inside module actions, `context.state` will expose the local state, and root state will be exposed as `context.rootState`:\n\n```js\nconst moduleA = {\n  // ...\n  actions: {\n    incrementIfOddOnRootSum ({ state, commit, rootState }) {\n      if ((state.count + rootState.count) % 2 === 1) {\n        commit('increment')\n      }\n    }\n  }\n}\n```\n\nAlso, inside module getters, the root state will be exposed as their 3rd argument:\n\n```js\nconst moduleA = {\n  // ...\n  getters: {\n    sumWithRootCount (state, getters, rootState) {\n      return state.count + rootState.count\n    }\n  }\n}\n```\n\n## Namespacing\n\nBy default, actions and mutations are still registered under the **global namespace** - this allows multiple modules to react to the same action/mutation type. Getters are also registered in the global namespace by default. However, this currently has no functional purpose (it's as is to avoid breaking changes). You must be careful not to define two getters with the same name in different, non-namespaced modules, resulting in an error.\n\nIf you want your modules to be more self-contained or reusable, you can mark it as namespaced with `namespaced: true`. When the module is registered, all of its getters, actions and mutations will be automatically namespaced based on the path the module is registered at. For example:\n\n```js\nconst store = createStore({\n  modules: {\n    account: {\n      namespaced: true,\n\n      // module assets\n      state: () => ({ ... }), // module state is already nested and not affected by namespace option\n      getters: {\n        isAdmin () { ... } // -> getters['account/isAdmin']\n      },\n      actions: {\n        login () { ... } // -> dispatch('account/login')\n      },\n      mutations: {\n        login () { ... } // -> commit('account/login')\n      },\n\n      // nested modules\n      modules: {\n        // inherits the namespace from parent module\n        myPage: {\n          state: () => ({ ... }),\n          getters: {\n            profile () { ... } // -> getters['account/profile']\n          }\n        },\n\n        // further nest the namespace\n        posts: {\n          namespaced: true,\n\n          state: () => ({ ... }),\n          getters: {\n            popular () { ... } // -> getters['account/posts/popular']\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nNamespaced getters and actions will receive localized `getters`, `dispatch` and `commit`. In other words, you can use the module assets without writing prefix in the same module. Toggling between namespaced or not does not affect the code inside the module.\n\n### Accessing Global Assets in Namespaced Modules\n\nIf you want to use global state and getters, `rootState` and `rootGetters` are passed as the 3rd and 4th arguments to getter functions, and also exposed as properties on the `context` object passed to action functions.\n\nTo dispatch actions or commit mutations in the global namespace, pass `{ root: true }` as the 3rd argument to `dispatch` and `commit`.\n\n```js\nmodules: {\n  foo: {\n    namespaced: true,\n\n    getters: {\n      // `getters` is localized to this module's getters\n      // you can use rootGetters via 4th argument of getters\n      someGetter (state, getters, rootState, rootGetters) {\n        getters.someOtherGetter // -> 'foo/someOtherGetter'\n        rootGetters.someOtherGetter // -> 'someOtherGetter'\n        rootGetters['bar/someOtherGetter'] // -> 'bar/someOtherGetter'\n      },\n      someOtherGetter: state => { ... }\n    },\n\n    actions: {\n      // dispatch and commit are also localized for this module\n      // they will accept `root` option for the root dispatch/commit\n      someAction ({ dispatch, commit, getters, rootGetters }) {\n        getters.someGetter // -> 'foo/someGetter'\n        rootGetters.someGetter // -> 'someGetter'\n        rootGetters['bar/someGetter'] // -> 'bar/someGetter'\n\n        dispatch('someOtherAction') // -> 'foo/someOtherAction'\n        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'\n\n        commit('someMutation') // -> 'foo/someMutation'\n        commit('someMutation', null, { root: true }) // -> 'someMutation'\n      },\n      someOtherAction (ctx, payload) { ... }\n    }\n  }\n}\n```\n\n### Register Global Action in Namespaced Modules\n\nIf you want to register global actions in namespaced modules, you can mark it with `root: true` and place the action definition to function `handler`. For example:\n\n```js\n{\n  actions: {\n    someOtherAction ({dispatch}) {\n      dispatch('someAction')\n    }\n  },\n  modules: {\n    foo: {\n      namespaced: true,\n\n      actions: {\n        someAction: {\n          root: true,\n          handler (namespacedContext, payload) { ... } // -> 'someAction'\n        }\n      }\n    }\n  }\n}\n```\n\n### Binding Helpers with Namespace\n\nWhen binding a namespaced module to components with the `mapState`, `mapGetters`, `mapActions` and `mapMutations` helpers, it can get a bit verbose:\n\n```js\ncomputed: {\n  ...mapState({\n    a: state => state.some.nested.module.a,\n    b: state => state.some.nested.module.b\n  }),\n  ...mapGetters([\n    'some/nested/module/someGetter', // -> this['some/nested/module/someGetter']\n    'some/nested/module/someOtherGetter', // -> this['some/nested/module/someOtherGetter']\n  ])\n},\nmethods: {\n  ...mapActions([\n    'some/nested/module/foo', // -> this['some/nested/module/foo']()\n    'some/nested/module/bar' // -> this['some/nested/module/bar']()\n  ])\n}\n```\n\nIn such cases, you can pass the module namespace string as the first argument to the helpers so that all bindings are done using that module as the context. The above can be simplified to:\n\n```js\ncomputed: {\n  ...mapState('some/nested/module', {\n    a: state => state.a,\n    b: state => state.b\n  }),\n  ...mapGetters('some/nested/module', [\n    'someGetter', // -> this.someGetter\n    'someOtherGetter', // -> this.someOtherGetter\n  ])\n},\nmethods: {\n  ...mapActions('some/nested/module', [\n    'foo', // -> this.foo()\n    'bar' // -> this.bar()\n  ])\n}\n```\n\nFurthermore, you can create namespaced helpers by using `createNamespacedHelpers`. It returns an object having new component binding helpers that are bound with the given namespace value:\n\n```js\nimport { createNamespacedHelpers } from 'vuex'\n\nconst { mapState, mapActions } = createNamespacedHelpers('some/nested/module')\n\nexport default {\n  computed: {\n    // look up in `some/nested/module`\n    ...mapState({\n      a: state => state.a,\n      b: state => state.b\n    })\n  },\n  methods: {\n    // look up in `some/nested/module`\n    ...mapActions([\n      'foo',\n      'bar'\n    ])\n  }\n}\n```\n\n### Caveat for Plugin Developers\n\nYou may care about unpredictable namespacing for your modules when you create a [plugin](plugins.md) that provides the modules and let users add them to a Vuex store. Your modules will be also namespaced if the plugin users add your modules under a namespaced module. To adapt this situation, you may need to receive a namespace value via your plugin option:\n\n```js\n// get namespace value via plugin option\n// and returns Vuex plugin function\nexport function createPlugin (options = {}) {\n  return function (store) {\n    // add namespace to plugin module's types\n    const namespace = options.namespace || ''\n    store.dispatch(namespace + 'pluginAction')\n  }\n}\n```\n\n## Dynamic Module Registration\n\nYou can register a module **after** the store has been created with the `store.registerModule` method:\n\n```js\nimport { createStore } from 'vuex'\n\nconst store = createStore({ /* options */ })\n\n// register a module `myModule`\nstore.registerModule('myModule', {\n  // ...\n})\n\n// register a nested module `nested/myModule`\nstore.registerModule(['nested', 'myModule'], {\n  // ...\n})\n```\n\nThe module's state will be exposed as `store.state.myModule` and `store.state.nested.myModule`.\n\nDynamic module registration makes it possible for other Vue plugins to also leverage Vuex for state management by attaching a module to the application's store. For example, the [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) library integrates vue-router with vuex by managing the application's route state in a dynamically attached module.\n\nYou can also remove a dynamically registered module with `store.unregisterModule(moduleName)`. Note you cannot remove static modules (declared at store creation) with this method.\n\nNote that you may check if the module is already registered to the store or not via `store.hasModule(moduleName)` method. One thing to keep in mind is that nested modules should be passed as arrays for both the `registerModule` and `hasModule` and not as a string with the path to the module.\n\n### Preserving state\n\nIt may be likely that you want to preserve the previous state when registering a new module, such as preserving state from a Server Side Rendered app. You can achieve this with `preserveState` option: `store.registerModule('a', module, { preserveState: true })`\n\nWhen you set `preserveState: true`, the module is registered, actions, mutations and getters are added to the store, but the state is not. It's assumed that your store state already contains state for that module and you don't want to overwrite it.\n\n## Module Reuse\n\nSometimes we may need to create multiple instances of a module, for example:\n\n- Creating multiple stores that use the same module (e.g. To [avoid stateful singletons in the SSR](https://ssr.vuejs.org/en/structure.html#avoid-stateful-singletons) when the `runInNewContext` option is `false` or `'once'`);\n- Register the same module multiple times in the same store.\n\nIf we use a plain object to declare the state of the module, then that state object will be shared by reference and cause cross store/module state pollution when it's mutated.\n\nThis is actually the exact same problem with `data` inside Vue components. So the solution is also the same - use a function for declaring module state (supported in 2.3.0+):\n\n```js\nconst MyReusableModule = {\n  state: () => ({\n    foo: 'bar'\n  }),\n  // mutations, actions, getters...\n}\n```\n"
  },
  {
    "path": "docs/guide/mutations.md",
    "content": "# Mutations\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/ckMZp4HN\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nThe only way to actually change state in a Vuex store is by committing a mutation. Vuex mutations are very similar to events: each mutation has a string **type** and a **handler**. The handler function is where we perform actual state modifications, and it will receive the state as the first argument:\n\n```js\nconst store = createStore({\n  state: {\n    count: 1\n  },\n  mutations: {\n    increment (state) {\n      // mutate state\n      state.count++\n    }\n  }\n})\n```\n\nYou cannot directly call a mutation handler. Think of it more like event registration: \"When a mutation with type `increment` is triggered, call this handler.\" To invoke a mutation handler, you need to call `store.commit` with its type:\n\n```js\nstore.commit('increment')\n```\n\n## Commit with Payload\n\nYou can pass an additional argument to `store.commit`, which is called the **payload** for the mutation:\n\n```js\n// ...\nmutations: {\n  increment (state, n) {\n    state.count += n\n  }\n}\n```\n\n```js\nstore.commit('increment', 10)\n```\n\nIn most cases, the payload should be an object so that it can contain multiple fields, and the recorded mutation will also be more descriptive:\n\n```js\n// ...\nmutations: {\n  increment (state, payload) {\n    state.count += payload.amount\n  }\n}\n```\n\n```js\nstore.commit('increment', {\n  amount: 10\n})\n```\n\n## Object-Style Commit\n\nAn alternative way to commit a mutation is by directly using an object that has a `type` property:\n\n```js\nstore.commit({\n  type: 'increment',\n  amount: 10\n})\n```\n\nWhen using object-style commit, the entire object will be passed as the payload to mutation handlers, so the handler remains the same:\n\n```js\nmutations: {\n  increment (state, payload) {\n    state.count += payload.amount\n  }\n}\n```\n\n## Using Constants for Mutation Types\n\nIt is a commonly seen pattern to use constants for mutation types in various Flux implementations. This allows the code to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application:\n\n```js\n// mutation-types.js\nexport const SOME_MUTATION = 'SOME_MUTATION'\n```\n\n```js\n// store.js\nimport { createStore } from 'vuex'\nimport { SOME_MUTATION } from './mutation-types'\n\nconst store = createStore({\n  state: { ... },\n  mutations: {\n    // we can use the ES2015 computed property name feature\n    // to use a constant as the function name\n    [SOME_MUTATION] (state) {\n      // mutate state\n    }\n  }\n})\n```\n\nWhether to use constants is largely a preference - it can be helpful in large projects with many developers, but it's totally optional if you don't like them.\n\n## Mutations Must Be Synchronous\n\nOne important rule to remember is that **mutation handler functions must be synchronous**. Why? Consider the following example:\n\n```js\nmutations: {\n  someMutation (state) {\n    api.callAsyncMethod(() => {\n      state.count++\n    })\n  }\n}\n```\n\nNow imagine we are debugging the app and looking at the devtool's mutation logs. For every mutation logged, the devtool will need to capture a \"before\" and \"after\" snapshots of the state. However, the asynchronous callback inside the example mutation above makes that impossible: the callback is not called yet when the mutation is committed, and there's no way for the devtool to know when the callback will actually be called - any state mutation performed in the callback is essentially un-trackable!\n\n## Committing Mutations in Components\n\nYou can commit mutations in components with `this.$store.commit('xxx')`, or use the `mapMutations` helper which maps component methods to `store.commit` calls (requires root `store` injection):\n\n```js\nimport { mapMutations } from 'vuex'\n\nexport default {\n  // ...\n  methods: {\n    ...mapMutations([\n      'increment', // map `this.increment()` to `this.$store.commit('increment')`\n\n      // `mapMutations` also supports payloads:\n      'incrementBy' // map `this.incrementBy(amount)` to `this.$store.commit('incrementBy', amount)`\n    ]),\n    ...mapMutations({\n      add: 'increment' // map `this.add()` to `this.$store.commit('increment')`\n    })\n  }\n}\n```\n\n## On to Actions\n\nAsynchronicity combined with state mutation can make your program very hard to reason about. For example, when you call two methods both with async callbacks that mutate the state, how do you know when they are called and which callback was called first? This is exactly why we want to separate the two concepts. In Vuex, **mutations are synchronous transactions**:\n\n```js\nstore.commit('increment')\n// any state change that the \"increment\" mutation may cause\n// should be done at this moment.\n```\n\nTo handle asynchronous operations, let's introduce [Actions](actions.md).\n"
  },
  {
    "path": "docs/guide/plugins.md",
    "content": "# Plugins\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cvp8ZkCR\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nVuex stores accept the `plugins` option that exposes hooks for each mutation. A Vuex plugin is simply a function that receives the store as the only argument:\n\n```js\nconst myPlugin = (store) => {\n  // called when the store is initialized\n  store.subscribe((mutation, state) => {\n    // called after every mutation.\n    // The mutation comes in the format of `{ type, payload }`.\n  })\n}\n```\n\nAnd can be used like this:\n\n```js\nconst store = createStore({\n  // ...\n  plugins: [myPlugin]\n})\n```\n\n## Committing Mutations Inside Plugins\n\nPlugins are not allowed to directly mutate state - similar to your components, they can only trigger changes by committing mutations.\n\nBy committing mutations, a plugin can be used to sync a data source to the store. For example, to sync a websocket data source to the store (this is just a contrived example, in reality the `createWebSocketPlugin` function can take some additional options for more complex tasks):\n\n```js\nexport default function createWebSocketPlugin (socket) {\n  return (store) => {\n    socket.on('data', data => {\n      store.commit('receiveData', data)\n    })\n    store.subscribe(mutation => {\n      if (mutation.type === 'UPDATE_DATA') {\n        socket.emit('update', mutation.payload)\n      }\n    })\n  }\n}\n```\n\n```js\nconst plugin = createWebSocketPlugin(socket)\n\nconst store = createStore({\n  state,\n  mutations,\n  plugins: [plugin]\n})\n```\n\n## Taking State Snapshots\n\nSometimes a plugin may want to receive \"snapshots\" of the state, and also compare the post-mutation state with pre-mutation state. To achieve that, you will need to perform a deep-copy on the state object:\n\n```js\nconst myPluginWithSnapshot = (store) => {\n  let prevState = _.cloneDeep(store.state)\n  store.subscribe((mutation, state) => {\n    let nextState = _.cloneDeep(state)\n\n    // compare `prevState` and `nextState`...\n\n    // save state for next mutation\n    prevState = nextState\n  })\n}\n```\n\n**Plugins that take state snapshots should be used only during development.** When using webpack or Browserify, we can let our build tools handle that for us:\n\n```js\nconst store = createStore({\n  // ...\n  plugins: process.env.NODE_ENV !== 'production'\n    ? [myPluginWithSnapshot]\n    : []\n})\n```\n\nThe plugin will be used by default. For production, you will need [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) for webpack or [envify](https://github.com/hughsk/envify) for Browserify to convert the value of `process.env.NODE_ENV !== 'production'` to `false` for the final build.\n\n## Built-in Logger Plugin\n\nVuex comes with a logger plugin for common debugging usage:\n\n```js\nimport { createLogger } from 'vuex'\n\nconst store = createStore({\n  plugins: [createLogger()]\n})\n```\n\nThe `createLogger` function takes a few options:\n\n```js\nconst logger = createLogger({\n  collapsed: false, // auto-expand logged mutations\n  filter (mutation, stateBefore, stateAfter) {\n    // returns `true` if a mutation should be logged\n    // `mutation` is a `{ type, payload }`\n    return mutation.type !== \"aBlocklistedMutation\"\n  },\n  actionFilter (action, state) {\n    // same as `filter` but for actions\n    // `action` is a `{ type, payload }`\n    return action.type !== \"aBlocklistedAction\"\n  },\n  transformer (state) {\n    // transform the state before logging it.\n    // for example return only a specific sub-tree\n    return state.subTree\n  },\n  mutationTransformer (mutation) {\n    // mutations are logged in the format of `{ type, payload }`\n    // we can format it any way we want.\n    return mutation.type\n  },\n  actionTransformer (action) {\n    // Same as mutationTransformer but for actions\n    return action.type\n  },\n  logActions: true, // Log Actions\n  logMutations: true, // Log mutations\n  logger: console, // implementation of the `console` API, default `console`\n})\n```\n\nThe logger file can also be included directly via a `<script>` tag, and will expose the `createVuexLogger` function globally.\n\nNote the logger plugin takes state snapshots, so use it only during development.\n"
  },
  {
    "path": "docs/guide/state.md",
    "content": "# State\n\n## Single State Tree\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cWw3Zhb\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nVuex uses a **single state tree** - that is, this single object contains all your application level state and serves as the \"single source of truth.\" This also means usually you will have only one store for each application. A single state tree makes it straightforward to locate a specific piece of state, and allows us to easily take snapshots of the current app state for debugging purposes.\n\nThe single state tree does not conflict with modularity - in later chapters we will discuss how to split your state and mutations into sub modules.\n\nThe data you store in Vuex follows the same rules as the `data` in a Vue instance, ie the state object must be plain. **See also:** [Vue#data](https://v3.vuejs.org/api/options-data.html#data-2).\n\n## Getting Vuex State into Vue Components\n\nSo how do we display state inside the store in our Vue components? Since Vuex stores are reactive, the simplest way to \"retrieve\" state from it is simply returning some store state from within a [computed property](https://vuejs.org/guide/computed.html):\n\n```js\n// let's create a Counter component\nconst Counter = {\n  template: `<div>{{ count }}</div>`,\n  computed: {\n    count () {\n      return store.state.count\n    }\n  }\n}\n```\n\nWhenever `store.state.count` changes, it will cause the computed property to re-evaluate, and trigger associated DOM updates.\n\nHowever, this pattern causes the component to rely on the global store singleton. When using a module system, it requires importing the store in every component that uses store state, and also requires mocking when testing the component.\n\nVuex \"injects\" the store into all child components from the root component through Vue's plugin system, and will be available on them as `this.$store`. Let's update our `Counter` implementation:\n\n```js\nconst Counter = {\n  template: `<div>{{ count }}</div>`,\n  computed: {\n    count () {\n      return this.$store.state.count\n    }\n  }\n}\n```\n\n## The `mapState` Helper\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c8Pz7BSK\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nWhen a component needs to make use of multiple store state properties or getters, declaring all these computed properties can get repetitive and verbose. To deal with this we can make use of the `mapState` helper which generates computed getter functions for us, saving us some keystrokes:\n\n```js\n// in full builds helpers are exposed as Vuex.mapState\nimport { mapState } from 'vuex'\n\nexport default {\n  // ...\n  computed: mapState({\n    // arrow functions can make the code very succinct!\n    count: state => state.count,\n\n    // passing the string value 'count' is same as `state => state.count`\n    countAlias: 'count',\n\n    // to access local state with `this`, a normal function must be used\n    countPlusLocalState (state) {\n      return state.count + this.localCount\n    }\n  })\n}\n```\n\nWe can also pass a string array to `mapState` when the name of a mapped computed property is the same as a state sub tree name.\n\n```js\ncomputed: mapState([\n  // map this.count to store.state.count\n  'count'\n])\n```\n\n## Object Spread Operator\n\nNote that `mapState` returns an object. How do we use it in combination with other local computed properties? Normally, we'd have to use a utility to merge multiple objects into one so that we can pass the final object to `computed`. However with the [object spread operator](https://github.com/tc39/proposal-object-rest-spread), we can greatly simplify the syntax:\n\n```js\ncomputed: {\n  localComputed () { /* ... */ },\n  // mix this into the outer object with the object spread operator\n  ...mapState({\n    // ...\n  })\n}\n```\n\n## Components Can Still Have Local State\n\nUsing Vuex doesn't mean you should put **all** the state in Vuex. Although putting more state into Vuex makes your state mutations more explicit and debuggable, sometimes it could also make the code more verbose and indirect. If a piece of state strictly belongs to a single component, it could be just fine leaving it as local state. You should weigh the trade-offs and make decisions that fit the development needs of your app.\n"
  },
  {
    "path": "docs/guide/strict.md",
    "content": "# Strict Mode\n\nTo enable strict mode, simply pass in `strict: true` when creating a Vuex store:\n\n```js\nconst store = createStore({\n  // ...\n  strict: true\n})\n```\n\nIn strict mode, whenever Vuex state is mutated outside of mutation handlers, an error will be thrown. This ensures that all state mutations can be explicitly tracked by debugging tools.\n\n## Development vs. Production\n\n**Do not enable strict mode when deploying for production!** Strict mode runs a synchronous deep watcher on the state tree for detecting inappropriate mutations, and it can be quite expensive when you make large amount of mutations to the state. Make sure to turn it off in production to avoid the performance cost.\n\nSimilar to plugins, we can let the build tools handle that:\n\n```js\nconst store = createStore({\n  // ...\n  strict: process.env.NODE_ENV !== 'production'\n})\n```\n"
  },
  {
    "path": "docs/guide/structure.md",
    "content": "# Application Structure\n\nVuex doesn't really restrict how you structure your code. Rather, it enforces a set of high-level principles:\n\n1. Application-level state is centralized in the store.\n\n2. The only way to mutate the state is by committing **mutations**, which are synchronous transactions.\n\n3. Asynchronous logic should be encapsulated in, and can be composed with **actions**.\n\nAs long as you follow these rules, it's up to you how to structure your project. If your store file gets too big, simply start splitting the actions, mutations and getters into separate files.\n\nFor any non-trivial app, we will likely need to leverage modules. Here's an example project structure:\n\n```bash\n├── index.html\n├── main.js\n├── api\n│   └── ... # abstractions for making API requests\n├── components\n│   ├── App.vue\n│   └── ...\n└── store\n    ├── index.js          # where we assemble modules and export the store\n    ├── actions.js        # root actions\n    ├── mutations.js      # root mutations\n    └── modules\n        ├── cart.js       # cart module\n        └── products.js   # products module\n```\n\nAs a reference, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/4.0/examples/classic/shopping-cart).\n"
  },
  {
    "path": "docs/guide/testing.md",
    "content": "# Testing\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cPGkpJhq\" target=\"_blank\" rel=\"noopener noreferrer\">Try this lesson on Scrimba</a></div>\n\nThe main parts we want to unit test in Vuex are mutations and actions.\n\n## Testing Mutations\n\nMutations are very straightforward to test, because they are just functions that completely rely on their arguments. One trick is that if you are using ES2015 modules and put your mutations inside your `store.js` file, in addition to the default export, you should also export the mutations as a named export:\n\n```js\nconst state = { ... }\n\n// export `mutations` as a named export\nexport const mutations = { ... }\n\nexport default createStore({\n  state,\n  mutations\n})\n```\n\nExample testing a mutation using Mocha + Chai (you can use any framework/assertion libraries you like):\n\n```js\n// mutations.js\nexport const mutations = {\n  increment: state => state.count++\n}\n```\n\n```js\n// mutations.spec.js\nimport { expect } from 'chai'\nimport { mutations } from './store'\n\n// destructure assign `mutations`\nconst { increment } = mutations\n\ndescribe('mutations', () => {\n  it('INCREMENT', () => {\n    // mock state\n    const state = { count: 0 }\n    // apply mutation\n    increment(state)\n    // assert result\n    expect(state.count).to.equal(1)\n  })\n})\n```\n\n## Testing Actions\n\nActions can be a bit more tricky because they may call out to external APIs. When testing actions, we usually need to do some level of mocking - for example, we can abstract the API calls into a service and mock that service inside our tests. In order to easily mock dependencies, we can use webpack and [inject-loader](https://github.com/plasticine/inject-loader) to bundle our test files.\n\nExample testing an async action:\n\n```js\n// actions.js\nimport shop from '../api/shop'\n\nexport const getAllProducts = ({ commit }) => {\n  commit('REQUEST_PRODUCTS')\n  shop.getProducts(products => {\n    commit('RECEIVE_PRODUCTS', products)\n  })\n}\n```\n\n```js\n// actions.spec.js\n\n// use require syntax for inline loaders.\n// with inject-loader, this returns a module factory\n// that allows us to inject mocked dependencies.\nimport { expect } from 'chai'\nconst actionsInjector = require('inject-loader!./actions')\n\n// create the module with our mocks\nconst actions = actionsInjector({\n  '../api/shop': {\n    getProducts (cb) {\n      setTimeout(() => {\n        cb([ /* mocked response */ ])\n      }, 100)\n    }\n  }\n})\n\n// helper for testing action with expected mutations\nconst testAction = (action, payload, state, expectedMutations, done) => {\n  let count = 0\n\n  // mock commit\n  const commit = (type, payload) => {\n    const mutation = expectedMutations[count]\n\n    try {\n      expect(type).to.equal(mutation.type)\n      expect(payload).to.deep.equal(mutation.payload)\n    } catch (error) {\n      done(error)\n    }\n\n    count++\n    if (count >= expectedMutations.length) {\n      done()\n    }\n  }\n\n  // call the action with mocked store and arguments\n  action({ commit, state }, payload)\n\n  // check if no mutations should have been dispatched\n  if (expectedMutations.length === 0) {\n    expect(count).to.equal(0)\n    done()\n  }\n}\n\ndescribe('actions', () => {\n  it('getAllProducts', done => {\n    testAction(actions.getAllProducts, null, {}, [\n      { type: 'REQUEST_PRODUCTS' },\n      { type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } }\n    ], done)\n  })\n})\n```\n\nIf you have spies available in your testing environment (for example via [Sinon.JS](http://sinonjs.org/)), you can use them instead of the `testAction` helper:\n\n```js\ndescribe('actions', () => {\n  it('getAllProducts', () => {\n    const commit = sinon.spy()\n    const state = {}\n\n    actions.getAllProducts({ commit, state })\n\n    expect(commit.args).to.deep.equal([\n      ['REQUEST_PRODUCTS'],\n      ['RECEIVE_PRODUCTS', { /* mocked response */ }]\n    ])\n  })\n})\n```\n\n## Testing Getters\n\nIf your getters have complicated computation, it is worth testing them. Getters are also very straightforward to test for the same reason as mutations.\n\nExample testing a getter:\n\n```js\n// getters.js\nexport const getters = {\n  filteredProducts (state, { filterCategory }) {\n    return state.products.filter(product => {\n      return product.category === filterCategory\n    })\n  }\n}\n```\n\n```js\n// getters.spec.js\nimport { expect } from 'chai'\nimport { getters } from './getters'\n\ndescribe('getters', () => {\n  it('filteredProducts', () => {\n    // mock state\n    const state = {\n      products: [\n        { id: 1, title: 'Apple', category: 'fruit' },\n        { id: 2, title: 'Orange', category: 'fruit' },\n        { id: 3, title: 'Carrot', category: 'vegetable' }\n      ]\n    }\n    // mock getter\n    const filterCategory = 'fruit'\n\n    // get the result from the getter\n    const result = getters.filteredProducts(state, { filterCategory })\n\n    // assert the result\n    expect(result).to.deep.equal([\n      { id: 1, title: 'Apple', category: 'fruit' },\n      { id: 2, title: 'Orange', category: 'fruit' }\n    ])\n  })\n})\n```\n\n## Running Tests\n\nIf your mutations and actions are written properly, the tests should have no direct dependency on Browser APIs after proper mocking. Thus you can simply bundle the tests with webpack and run it directly in Node. Alternatively, you can use `mocha-loader` or Karma + `karma-webpack` to run the tests in real browsers.\n\n### Running in Node\n\nCreate the following webpack config (together with proper [`.babelrc`](https://babeljs.io/docs/usage/babelrc/)):\n\n```js\n// webpack.config.js\nmodule.exports = {\n  entry: './test.js',\n  output: {\n    path: __dirname,\n    filename: 'test-bundle.js'\n  },\n  module: {\n    loaders: [\n      {\n        test: /\\.js$/,\n        loader: 'babel-loader',\n        exclude: /node_modules/\n      }\n    ]\n  }\n}\n```\n\nThen:\n\n``` bash\nwebpack\nmocha test-bundle.js\n```\n\n### Running in Browser\n\n1. Install `mocha-loader`.\n2. Change the `entry` from the webpack config above to `'mocha-loader!babel-loader!./test.js'`.\n3. Start `webpack-dev-server` using the config.\n4. Go to `localhost:8080/webpack-dev-server/test-bundle`.\n\n### Running in Browser with Karma + karma-webpack\n\nConsult the setup in [vue-loader documentation](https://vue-loader.vuejs.org/en/workflow/testing.html).\n"
  },
  {
    "path": "docs/guide/typescript-support.md",
    "content": "# TypeScript Support\n\nVuex provides its typings so you can use TypeScript to write a store definition. You don't need any special TypeScript configuration for Vuex. Please follow [Vue's basic TypeScript setup](https://v3.vuejs.org/guide/typescript-support.html) to configure your project.\n\nHowever, if you're writing your Vue components in TypeScript, there're a few steps to follow that require for you to correctly provide typings for a store.\n\n## Typing `$store` Property in Vue Component\n\nVuex doesn't provide typings for `this.$store` property out of the box. When used with TypeScript, you must declare your own module augmentation.\n\nTo do so, declare custom typings for Vue's `ComponentCustomProperties` by adding a declaration file in your project folder:\n\n```ts\n// vuex.d.ts\nimport { Store } from 'vuex'\n\ndeclare module 'vue' {\n  // declare your own store states\n  interface State {\n    count: number\n  }\n\n  // provide typings for `this.$store`\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\n## Typing `useStore` Composition Function\n\nWhen you're writing your Vue component in Composition API, you will most likely want `useStore` to return the typed store. For `useStore` to correctly return the typed store, you must:\n\n1. Define the typed `InjectionKey`.\n2. Provide the typed `InjectionKey` when installing a store to the Vue app.\n3. Pass the typed `InjectionKey` to the `useStore` method.\n\nLet's tackle this step by step. First, define the key using Vue's `InjectionKey` interface along with your own store typing definition:\n\n```ts\n// store.ts\nimport { InjectionKey } from 'vue'\nimport { createStore, Store } from 'vuex'\n\n// define your typings for the store state\nexport interface State {\n  count: number\n}\n\n// define injection key\nexport const key: InjectionKey<Store<State>> = Symbol()\n\nexport const store = createStore<State>({\n  state: {\n    count: 0\n  }\n})\n```\n\nNext, pass the defined injection key when installing the store to the Vue app:\n\n```ts\n// main.ts\nimport { createApp } from 'vue'\nimport { store, key } from './store'\n\nconst app = createApp({ ... })\n\n// pass the injection key\napp.use(store, key)\n\napp.mount('#app')\n```\n\nFinally, you can pass the key to the `useStore` method to retrieve the typed store.\n\n```ts\n// in a vue component\nimport { useStore } from 'vuex'\nimport { key } from './store'\n\nexport default {\n  setup () {\n    const store = useStore(key)\n\n    store.state.count // typed as number\n  }\n}\n```\n\nUnder the hood, Vuex installs the store to the Vue app using Vue's [Provide/Inject](https://v3.vuejs.org/api/composition-api.html#provide-inject) feature which is why the injection key is an important factor.\n\n### Simplifying `useStore` usage\n\nHaving to import `InjectionKey` and passing it to `useStore` everywhere it's used can quickly become a repetitive task. To simplify matters, you can define your own composable function to retrieve a typed store:\n\n```ts\n// store.ts\nimport { InjectionKey } from 'vue'\nimport { createStore, useStore as baseUseStore, Store } from 'vuex'\n\nexport interface State {\n  count: number\n}\n\nexport const key: InjectionKey<Store<State>> = Symbol()\n\nexport const store = createStore<State>({\n  state: {\n    count: 0\n  }\n})\n\n// define your own `useStore` composition function\nexport function useStore () {\n  return baseUseStore(key)\n}\n```\n\nNow, by importing your own composable function, you can retrieve the typed store **without** having to provide the injection key and its typing:\n\n```ts\n// in a vue component\nimport { useStore } from './store'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    store.state.count // typed as number\n  }\n}\n```\n"
  },
  {
    "path": "docs/index.md",
    "content": "# What is Vuex?\n\n::: tip Pinia is now the new default\n\nThe official state management library for Vue has changed to [Pinia](https://pinia.vuejs.org). Pinia has almost the exact same or enhanced API as Vuex 5, described in [Vuex 5 RFC](https://github.com/vuejs/rfcs/pull/271). You could simply consider Pinia as Vuex 5 with a different name. Pinia also works with Vue 2.x as well.\n\nVuex 3 and 4 will still be maintained. However, it's unlikely to add new functionalities to it. Vuex and Pinia can be installed in the same project. If you're migrating existing Vuex app to Pinia, it might be a suitable option. However, if you're planning to start a new project, we highly recommend using Pinia instead.\n:::\n\nVuex is a **state management pattern + library** for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.\n\n## What is a \"State Management Pattern\"?\n\nLet's start with a simple Vue counter app:\n\n```js\nconst Counter = {\n  // state\n  data () {\n    return {\n      count: 0\n    }\n  },\n  // view\n  template: `\n    <div>{{ count }}</div>\n  `,\n  // actions\n  methods: {\n    increment () {\n      this.count++\n    }\n  }\n}\n\ncreateApp(Counter).mount('#app')\n```\n\nIt is a self-contained app with the following parts:\n\n- The **state**, the source of truth that drives our app;\n- The **view**, a declarative mapping of the **state**;\n- The **actions**, the possible ways the state could change in reaction to user inputs from the **view**.\n\nThis is a simple representation of the concept of \"one-way data flow\":\n\n<p style=\"text-align: center; margin: 2em\">\n  <img style=\"width:100%; max-width:450px;\" src=\"/flow.png\">\n</p>\n\nHowever, the simplicity quickly breaks down when we have **multiple components that share a common state**:\n\n- Multiple views may depend on the same piece of state.\n- Actions from different views may need to mutate the same piece of state.\n\nFor problem one, passing props can be tedious for deeply nested components, and simply doesn't work for sibling components. For problem two, we often find ourselves resorting to solutions such as reaching for direct parent/child instance references or trying to mutate and synchronize multiple copies of the state via events. Both of these patterns are brittle and quickly lead to unmaintainable code.\n\nSo why don't we extract the shared state out of the components, and manage it in a global singleton? With this, our component tree becomes a big \"view\", and any component can access the state or trigger actions, no matter where they are in the tree!\n\nBy defining and separating the concepts involved in state management and enforcing rules that maintain independence between views and states, we give our code more structure and maintainability.\n\nThis is the basic idea behind Vuex, inspired by [Flux](https://facebook.github.io/flux/docs/overview), [Redux](http://redux.js.org/) and [The Elm Architecture](https://guide.elm-lang.org/architecture/). Unlike the other patterns, Vuex is also a library implementation tailored specifically for Vue.js to take advantage of its granular reactivity system for efficient updates.\n\nIf you want to learn Vuex in an interactive way you can check out this [Vuex course on Scrimba](https://scrimba.com/g/gvuex), which gives you a mix of screencast and code playground that you can pause and play around with anytime.\n\n![vuex](/vuex.png)\n\n## When Should I Use It?\n\nVuex helps us deal with shared state management with the cost of more concepts and boilerplate. It's a trade-off between short term and long term productivity.\n\nIf you've never built a large-scale SPA and jump right into Vuex, it may feel verbose and daunting. That's perfectly normal - if your app is simple, you will most likely be fine without Vuex. A simple [store pattern](https://v3.vuejs.org/guide/state-management.html#simple-state-management-from-scratch) may be all you need. But if you are building a medium-to-large-scale SPA, chances are you have run into situations that make you think about how to better handle state outside of your Vue components, and Vuex will be the natural next step for you. There's a good quote from Dan Abramov, the author of Redux:\n\n> Flux libraries are like glasses: you’ll know when you need them.\n"
  },
  {
    "path": "docs/installation.md",
    "content": "# Installation\n\n## Direct Download / CDN\n\n[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) provides NPM-based CDN links. The above link will always point to the latest release on NPM. You can also use a specific version/tag via URLs like `https://unpkg.com/vuex@4.0.0/dist/vuex.global.js`.\n<!--/email_off-->\n\nInclude `vuex` after Vue and it will install itself automatically:\n\n```html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vuex.js\"></script>\n```\n\n## NPM\n\n```bash\nnpm install vuex@next --save\n```\n\n## Yarn\n\n```bash\nyarn add vuex@next --save\n```\n\n## Dev Build\n\nYou will have to clone directly from GitHub and build `vuex` yourself if you want to use the latest dev build.\n\n```bash\ngit clone https://github.com/vuejs/vuex.git node_modules/vuex\ncd node_modules/vuex\nyarn\nyarn build\n```\n"
  },
  {
    "path": "docs/ja/api/index.md",
    "content": "---\nsidebar: auto\n---\n\n# API リファレンス\n\n## Store\n\n### createStore\n\n- `createStore<S>(options: StoreOptions<S>): Store<S>`\n\n  新しいストアを作成します。\n\n  ```js\n  import { createStore } from 'vuex'\n\n  const store = createStore({ ...options })\n  ```\n\n## Store コンストラクタオプション\n\n### state\n\n- 型: `Object | Function`\n  ストアのための ルートステートオブジェクトです。 [詳細](../guide/state.md)\n\n  オブジェクトを返す関数を渡す場合、返されたオブジェクトはルートステートとして使用されます。これは特にモジュールの再利用のためにステートオブジェクトを再利用する場合に便利です。[詳細](../guide/modules.md#モジュールの再利用)\n\n### mutations\n\n- 型: `{ [type: string]: Function }`\n\n  ストアにミューテーションを登録します。ハンドラ関数は第 1 引数に `state` を常に受け取り(モジュール内で定義されていれば、モジュールのローカルステートを受け取り)、指定されていれば第 2 引数に `payload` を受け取ります。\n\n  [詳細](../guide/mutations.md)\n\n### actions\n\n- 型: `{ [type: string]: Function }`\n\n  ストアにアクションを登録します。ハンドラ関数は次のプロパティを持つ `context` オブジェクトを受け取ります。:\n\n  ```js\n  {\n    state,      // `store.state` と同じか、モジュール内にあればローカルステート\n    rootState,  // `store.state` と同じ。ただしモジュール内に限る\n    commit,     // `store.commit` と同じ\n    dispatch,   // `store.dispatch` と同じ\n    getters,    // `store.getters` と同じか、モジュール内にあればローカルゲッター\n    rootGetters // `store.getters` と同じ。ただしモジュール内に限る\n  }\n  ```\n\n  そして、第 2 引数の `payload` があれば、それを受け取ります。\n\n  [詳細](../guide/actions.md)\n\n### getters\n\n- 型: `{ [key: string]: Function }`\n\n  ストアにゲッターを登録します. ゲッター関数は次の引数を受け取ります:\n\n  ```\n  state,     // モジュール内で定義されていればモジュールのローカルステート\n  getters    // store.getters と同じ\n  ```\n\n  モジュールで定義されたときの仕様\n\n  ```\n  state,       // モジュールで定義された場合、モジュールのローカルステート\n  getters,     // 現在のモジュールのモジュールのローカルゲッター\n  rootState,   // グローバルステート\n  rootGetters  // 全てのゲッター\n  ```\n\n  登録されたゲッターは `store.getters` 上に公開されます。\n\n  [詳細](../guide/getters.md)\n\n### modules\n\n- 型: `Object`\n\n  サブモジュールを含む次のような形式のオブジェクトはストアにマージされます。\n\n  ```js\n  {\n    key: {\n      state,\n      namespaced?,\n      mutations?,\n      actions?,\n      getters?,\n      modules?\n    },\n    ...\n  }\n  ```\n\n  各モジュールは、ルートオプションに似た `state` と `mutations` を含むことができます。モジュールの状態は、モジュールのキーを使って、ストアのルートステートに結合されます。モジュールのミューテーションとゲッターは、第 1 引数としてルートステートの代わりに、モジュールのローカルステートだけを受け取り、モジュールのアクションの `context.state` もローカルステートを指すようになります。\n\n  [詳細](../guide/modules.md)\n\n### plugins\n\n- 型: `Array<Function>`\n\n  プラグイン関数の配列は、ストアに適用されます。このプラグインは、ストアだけを引数として受け取り、外部への永続化、ロギング、デバッギングのために、ミューテーションを監視するか、または、 websocket や observable のような外から渡されるデータのためにミューテーションをディスパッチします。\n\n  [詳細](../guide/plugins.md)\n\n### strict\n\n- 型: `boolean`\n- デフォルト: `false`\n\n  Vuex ストアを厳格モードにします。厳格モードでは、ミューテーションハンドラ以外で、 Vuex の状態の変更を行うと、エラーが投げられます。\n\n  [詳細](../guide/strict.md)\n\n### devtools\n\n- 型: `boolean`\n\n  特定の Vuex インスタンスに対して開発ツールをオン、またはオフにします。インスタンスに false を渡すと、開発ツールのプラグインを購読しないように Vuex ストアに伝えます。1 ページに複数のストアがある時に便利です。\n\n  ```js\n  {\n    devtools: false\n  }\n  ```\n\n## Store インスタンスプロパティ\n\n### state\n\n- 型: `Object`\n\n  ルートステート、読み取り専用です。\n\n### getters\n\n- 型: `Object`\n\n  登録されているゲッターを公開します。読み取り専用です。\n\n## Store インスタンスメソッド\n\n### commit\n\n-  `commit(type: string, payload?: any, options?: Object)`\n-  `commit(mutation: Object, options?: Object)`\n\n  ミューテーションをコミットします。`options` は[名前空間付きモジュール](../guide/modules.md#名前空間)で root なミューテーションにコミットできる `root: true` を持つことできます。[詳細](../guide/mutations.md)\n\n### dispatch\n\n-  `dispatch(type: string, payload?: any, options?: Object): Promise<any>`\n-  `dispatch(action: Object, options?: Object): Promise<any>`\n\n  アクションをディスパッチします。`options` は[名前空間付きモジュール](../guide/modules.md#名前空間)で root なアクションにディスパッチできる `root: true` を持つことできます。 すべてのトリガーされたアクションハンドラを解決するPromiseを返します。[詳細](../guide/actions.md)\n\n### replaceState\n\n-  `replaceState(state: Object)`\n\n  ストアのルートステートを置き換えます。これは、ステートのハイドレーションやタイムトラベルのためだけに利用すべきです。\n\n### watch\n\n-  `watch(fn: Function, callback: Function, options?: Object): Function`\n\n  `fn`が返す値をリアクティブに監視し、値が変わった時にコールバックを呼びます。`fn`は最初の引数としてストアのステートを、2番目の引数としてゲッターを受け取ります。 [Vue の`vm.$watch`メソッド](https://jp.vuejs.org/v2/api/#watch)と同じオプションをオプションのオブジェクトとして受け付けます。\n\n  監視を止める場合は、返された unwatch 関数を呼び出します。\n\n### subscribe\n\n-  `subscribe(handler: Function, options?: Object): Function`\n\n  ストアへのミューテーションを購読します。`handler` は、全てのミューテーションの後に呼ばれ、引数として、ミューテーション ディスクリプタとミューテーション後の状態を受け取ります。\n\n  ```js\n  const unsubscribe = store.subscribe((mutation, state) => {\n    console.log(mutation.type)\n    console.log(mutation.payload)\n  })\n  ```\n\n  デフォルトでは、新しい `handler` はチェーンの最後に登録されます。つまり、先に追加された他の `handler` が呼び出された後に実行されます。`prepend: true` を `options` に設定することで、`handler` をチェーンの最初に登録することができます。\n\n  ```js\n  store.subscribe(handler, { prepend: true })\n  ```\n\n  購読を停止するには、返された unsubscribe 関数呼び出します。\n\n  プラグインの中でもっともよく利用されます。[詳細](../guide/plugins.md)\n\n### subscribeAction\n\n-  `subscribeAction(handler: Function, options?: Object): Function`\n\n  スストアアクションを購読します。`handler` はディスパッチされたアクションごとに呼び出され、アクション記述子と現在のストア状態を引数として受け取ります:\n\n  ```js\n  const unsubscribe = store.subscribeAction((action, state) => {\n    console.log(action.type)\n    console.log(action.payload)\n  })\n  ```\n\n  デフォルトでは、新しい `handler` はチェーンの最後に登録されます。つまり、先に追加された他の `handler` が呼び出された後に実行されます。`prepend: true` を `options` に設定することで、`handler` をチェーンの最初に登録することができます。\n\n  ```js\n  store.subscribeAction(handler, { prepend: true })\n  ```\n\n  購読を停止するには、返された unsubscribe 関数を呼び出します。\n\n  `subscribeAction` は購読ハンドラがアクションディスパッチの*前 (before)*、または*後 (after)* に呼びだすべきかどうか(デフォルトの動作は、*before* です)指定することもできます。\n\n  ```js\n  store.subscribeAction({\n    before: (action, state) => {\n      console.log(`before action ${action.type}`)\n    },\n    after: (action, state) => {\n      console.log(`after action ${action.type}`)\n    }\n  })\n  ```\n\n  `subscribeAction` は `error` ハンドラを指定することもできます。このハンドラは、アクションディスパッチの中で投げられたエラーをキャッチすることができます。`error` ハンドラは投げられた `error` オブジェクトを第 3 引数として受け取ります。\n\n  ```js\n  store.subscribeAction({\n    error: (action, state, error) => {\n      console.log(`error action ${action.type}`)\n      console.error(error)\n    }\n  })\n  ```\n\n  `subscribeAction` メソッドはプラグインで最も一般的に使用されます。[詳細](../guide/plugins.md)\n\n### registerModule\n\n-  `registerModule(path: string | Array<string>, module: Module, options?: Object)`\n\n   動的なモジュールを登録します。[詳細](../guide/modules.md#dynamic-module-registration)\n\n  `options` は前の状態を保存する `preserveState: true` を持つことができます。サーバサイドレンダリングに役立ちます。\n\n### unregisterModule\n\n-  `unregisterModule(path: string | Array<string>)`\n\n  動的なモジュールを解除します。[詳細](../guide/modules.md#dynamic-module-registration)\n\n### hasModule\n\n- `hasModule(path: string | Array<string>): boolean`\n\n  動的なモジュールがすでに登録されているかどうかを確認します。[詳細](../guide/modules.md#dynamic-module-registration)\n\n### hotUpdate\n\n-  `hotUpdate(newOptions: Object)`\n\n  新しいアクションとミューテーションをホットスワップします。[詳細](../guide/hot-reload.md)\n\n## コンポーネントをバインドするヘルパー\n\n### mapState\n\n-  `mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  ストアのサブツリーを返すコンポーネントの computed オプションを作成します。[詳細](../guide/state.md#the-mapstate-helper)\n\n  第 1 引数は、オプションで名前空間文字列にすることができます。[詳細](../guide/modules.md#binding-helpers-with-namespace)\n\n  第 2 引数のオブジェクトのメンバーには関数 `function(state: any)` を指定できます。\n\n### mapGetters\n\n-  `mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`\n\n  ゲッターの評価後の値を返すコンポーネントの computed オプションを作成します。[詳細](../guide/getters.md#the-mapgetters-helper)\n\n  第 1 引数は、オプションで名前空間文字列にすることができます。[詳細](../guide/modules.md#binding-helpers-with-namespace)\n\n### mapActions\n\n-  `mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  アクションをディスパッチするコンポーネントの methods オプションを作成します。[詳細](../guide/actions.md#dispatching-actions-in-components)\n\n  第 1 引数は、オプションで名前空間文字列にすることができます。[詳細](../guide/modules.md#binding-helpers-with-namespace)\n\n  第 2 引数のオブジェクトのメンバーには関数 `function(dispatch: function, ...args: any[])` を指定できます。\n\n### mapMutations\n\n-  `mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  ミューテーションをコミットするコンポーネントの methods オプションを作成します。[詳細](../guide/mutations.md#commiting-mutations-in-components)\n\n  第 1 引数は、オプションで名前空間文字列にすることができます。[詳細](../guide/modules.md#binding-helpers-with-namespace)\n\n  第 2 引数のオブジェクトのメンバーには関数 `function(commit: function, ...args: any[])` を指定できます。\n\n### createNamespacedHelpers\n\n-  `createNamespacedHelpers(namespace: string): Object`\n\n  名前空間付けられたコンポーネントバインディングのヘルパーを作成します。返されるオブジェクトは指定された名前空間にバインドされた `mapState`、`mapGetters`、`mapActions` そして `mapMutations` が含まれます。[詳細はこちら](../guide/modules.md#binding-helpers-with-namespace)\n\n## Composable 関数\n\n### useStore\n\n- `useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;`\n\n  `setup` フックの中で呼ばれた時に、Vue App インスタンスにインストールされたストアを取得します。Composition API を使用する時、このメソッドを呼ぶことでストアを取得することができます。\n\n  ```js\n  import { useStore } from 'vuex'\n\n  export default {\n    setup () {\n      const store = useStore()\n    }\n  }\n  ```\n\n  TypeScript ユーザーは、 `InjectionKey` を使って型付けされたストアを取得することができます。そのためには、ストアインスタンスを Vue App インスタンスにインストールする時、`InjectionKey` を定義してストアと一緒に渡す必要があります。\n\n  まず、Vue の `InjectionKey` インターフェースを使って、 `InjectionKey` を宣言します。\n\n  ```ts\n  // store.ts\n  import { InjectionKey } from 'vue'\n  import { createStore, Store } from 'vuex'\n\n  export interface State {\n    count: number\n  }\n\n  export const key: InjectionKey<Store<State>> = Symbol()\n\n  export const store = createStore<State>({\n    state: {\n      count: 0\n    }\n  })\n  ```\n\n  次に、定義したキーを `app.use` メソッドの第2引数に渡します。\n\n  ```ts\n  // main.ts\n  import { createApp } from 'vue'\n  import { store, key } from './store'\n\n  const app = createApp({ ... })\n\n  app.use(store, key)\n\n  app.mount('#app')\n  ```\n\n  最後に、`useStore` 関数にキーを渡すことで、型付けされたストアインスタンスを取得することができます。\n\n  ```ts\n  // vue component 内\n  import { useStore } from 'vuex'\n  import { key } from './store'\n\n  export default {\n    setup () {\n      const store = useStore(key)\n\n      store.state.count // number として型付け\n    }\n  }\n  ```\n"
  },
  {
    "path": "docs/ja/guide/actions.md",
    "content": "# アクション\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c6ggR3cG\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\nアクションはミューテーションと似ていますが、下記の点で異なります:\n\n- アクションは、状態を変更するのではなく、ミューテーションをコミットします。\n- アクションは任意の非同期処理を含むことができます。\n\nシンプルなアクションを登録してみましょう:\n\n``` js\nconst store = createStore({\n  state: {\n    count: 0\n  },\n  mutations: {\n    increment (state) {\n      state.count++\n    }\n  },\n  actions: {\n    increment (context) {\n      context.commit('increment')\n    }\n  }\n})\n```\n\nアクションハンドラはストアインスタンスのメソッドやプロパティのセットと同じものを呼び出せるコンテキストオブジェクトを受け取ります。したがって `context.commit` を呼び出すことでミューテーションをコミットできます。あるいは `context.state` や `context.getters` で、状態やゲッターにアクセスできます。他のアクションも `context.dispatch` で呼ぶこともできます。なぜコンテキストオブジェクトがストアインスタンスそのものではないのかは、後ほど[モジュール](modules.md)で説明します。\n\n実際にはコードを少しシンプルにするために ES2015 の[引数分割束縛（argument destructuring）](https://github.com/lukehoban/es6features#destructuring)がよく使われます（特に `commit` を複数回呼び出す必要があるとき）:\n\n``` js\nactions: {\n  increment ({ commit }) {\n    commit('increment')\n  }\n}\n```\n\n## アクションのディスパッチ\n\nアクションは `store.dispatch` がトリガーとなって実行されます:\n\n``` js\nstore.dispatch('increment')\n```\n\nこれは一見ばかげて見えるかもしれません。つまり、カウントをインクリメントしたいときに、どうして直接 `store.commit('increment')` を呼び出してミューテーションをコミットしないのか、と。**ミューテーションは同期的でなければならない**というのを覚えていますか？アクションはそうではありません。アクションの中では**非同期**の操作を行うことができます。\n\n``` js\nactions: {\n  incrementAsync ({ commit }) {\n    setTimeout(() => {\n      commit('increment')\n    }, 1000)\n  }\n}\n```\n\nアクションはペイロード形式とオブジェクトスタイルのディスパッチをサポートします:\n\n``` js\n// ペイロードを使ってディスパッチする\nstore.dispatch('incrementAsync', {\n  amount: 10\n})\n\n// オブジェクトを使ってディスパッチする\nstore.dispatch({\n  type: 'incrementAsync',\n  amount: 10\n})\n```\n\nより実践的な例として、ショッピングカートをチェックアウトするアクションを挙げます。このアクションは**非同期な API の呼び出し**と、**複数のミューテーションのコミット**をします:\n\n``` js\nactions: {\n  checkout ({ commit, state }, products) {\n    // 現在のカート内の商品を保存する\n    const savedCartItems = [...state.cart.added]\n    // チェックアウトのリクエストを送信し、楽観的にカート内をクリアする\n    commit(types.CHECKOUT_REQUEST)\n    // shop API は成功時のコールバックと失敗時のコールバックを受け取る\n    shop.buyProducts(\n      products,\n      // 成功時の処理\n      () => commit(types.CHECKOUT_SUCCESS),\n      // 失敗時の処理\n      () => commit(types.CHECKOUT_FAILURE, savedCartItems)\n    )\n  }\n}\n```\n\n一連の非同期の処理を実行しつつ、ミューテーションのコミットによってのみ副作用（状態の変更）を与えていることに注意してください。\n\n## コンポーネント内でのアクションのディスパッチ\n\n`this.$store.dispatch('xxx')` でコンポーネント内でアクションをディスパッチできます。あるいはコンポーネントのメソッドを `store.dispatch` にマッピングする `mapActions` ヘルパーを使うこともできます（ルートの `store` の注入が必要です）:\n\n``` js\nimport { mapActions } from 'vuex'\n\nexport default {\n  // ...\n  methods: {\n    ...mapActions([\n      'increment', // `this.increment()` を `this.$store.dispatch('increment')` にマッピングする('increment')`\n\n      // `mapActions` もペイロードをサポートする:\n      'incrementBy' // `this.incrementBy(amount)` を `this.$store.dispatch('incrementBy', amount)` にマッピングする\n    ]),\n    ...mapActions({\n      add: 'increment' // `this.add()` を `this.$store.dispatch('increment')` にマッピングする\n    })\n  }\n}\n```\n\n## アクションを構成する\n\nアクションはしばしば非同期処理を行いますが、アクションが完了したことをどうやって知れば良いのでしょう？そしてもっと重要なことは、さらに複雑な非同期処理を取り扱うために、どうやって複数のアクションを構成させるかということです。\n\nまず知っておくべきことは `store.dispatch` がトリガーされたアクションハンドラによって返された Promise を処理できることと、`store.dispatch` もまた Promise を返すことです。\n\n``` js\nactions: {\n  actionA ({ commit }) {\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        commit('someMutation')\n        resolve()\n      }, 1000)\n    })\n  }\n}\n```\n\nすると次のようにできます:\n\n``` js\nstore.dispatch('actionA').then(() => {\n  // ...\n})\n```\n\nまた別のアクションで下記のように書くと:\n\n``` js\nactions: {\n  // ...\n  actionB ({ dispatch, commit }) {\n    return dispatch('actionA').then(() => {\n      commit('someOtherMutation')\n    })\n  }\n}\n```\n\n最終的に [async / await](https://tc39.github.io/ecmascript-asyncawait/) を使用することで、次のようにアクションを組み合わせることができます:\n\n``` js\n// `getData()` と `getOtherData()` が Promise を返すことを想定している\n\nactions: {\n  async actionA ({ commit }) {\n    commit('gotData', await getData())\n  },\n  async actionB ({ dispatch, commit }) {\n    await dispatch('actionA') // `actionA` が完了するのを待機する\n    commit('gotOtherData', await getOtherData())\n  }\n}\n```\n\n> `store.dispatch` で異なるモジュール内の複数のアクションハンドラをトリガーすることができます。そのようなケースでは、全てのトリガーされたハンドラが解決されたときに解決する Promise が戻り値として返ってくることになります。\n"
  },
  {
    "path": "docs/ja/guide/composition-api.md",
    "content": "# Composition API\n\n`setup` フックの中でストアにアクセスするには、`useStore` 関数を呼び出します。これは、Option API を使って、コンポーネント内で `this.$store` を取得するのと同等です。\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n  }\n}\n```\n\n## ステートとゲッターへのアクセス\n\nステートやゲッターにアクセスするためには、リアクティビティを保持するために `computed` による参照を作成する必要があります。これは、Option API を使って、算出プロパティを作成するのと同じことです。\n\n```js\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      // computed 関数のステートにアクセスします\n      count: computed(() => store.state.count),\n\n      // computed 関数のゲッターにアクセスします\n      double: computed(() => store.getters.double)\n    }\n  }\n}\n```\n\n## ミューテーションとアクションへのアクセス\n\nミューテーションとアクションにアクセスするには、`setup` フック内で `commit` と `dispatch` 関数を呼び出します。\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      // ミューテーションにアクセスする\n      increment: () => store.commit('increment'),\n\n      // アクションにアクセスする\n      asyncIncrement: () => store.dispatch('asyncIncrement')\n    }\n  }\n}\n```\n\n## Composition API での実装例\n\nVuex と Vue の Composition API を利用したアプリケーションの例は、[Composition API example](https://github.com/vuejs/vuex/tree/4.0/examples/composition) をご覧ください。\n"
  },
  {
    "path": "docs/ja/guide/forms.md",
    "content": "# フォームの扱い\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKRgEC9\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\n厳格モードで Vuex を使用するとき、Vuex に属する状態の一部で `v-model` を使用するのは少しトリッキーです:\n\n``` html\n<input v-model=\"obj.message\">\n```\n\n`obj` がストアからオブジェクトを返す算出プロパティ (computed property) と仮定すると、`v-model` は input でユーザーが入力するとき、直接 `obj.message` を変更します。厳格モードでは、この変更は明示的に Vuex のミューテーションハンドラ内部で処理されていないため、エラーを投げます。\n\nそれに対処するための \"Vuex way\" は、`<input>` の値をバインディングし、`input` または `change` イベントでアクションを呼び出すことです:\n\n``` html\n<input :value=\"message\" @input=\"updateMessage\">\n```\n``` js\n// ...\ncomputed: {\n  ...mapState({\n    message: state => state.obj.message\n  })\n},\nmethods: {\n  updateMessage (e) {\n    this.$store.commit('updateMessage', e.target.value)\n  }\n}\n```\n\nミューテーションのハンドラは以下のようになります:\n\n``` js\n// ...\nmutations: {\n  updateMessage (state, message) {\n    state.obj.message = message\n  }\n}\n```\n\n## 双方向算出プロパティ\n\n確かに、上記の例は単純な `v-model` と ローカルステートよりもかなり冗長で、`v-model` のいくつかの有用な機能が使えません。代わりに、セッターで双方向算出プロパティを使うアプローチがあります。\n\n``` html\n<input v-model=\"message\">\n```\n``` js\ncomputed: {\n  message: {\n    get () {\n      return this.$store.state.obj.message\n    },\n    set (value) {\n      this.$store.commit('updateMessage', value)\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/ja/guide/getters.md",
    "content": "# ゲッター\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c2Be7TB\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\n例えば項目のリストをフィルタリングしたりカウントするときのように、ストアの状態を算出したいときがあります。\n\n``` js\ncomputed: {\n  doneTodosCount () {\n    return this.$store.state.todos.filter(todo => todo.done).length\n  }\n}\n```\n\nもしこの関数を複数のコンポーネントで利用したくなったら、関数をコピーするか、あるいは関数を共用のヘルパーに切り出して複数の場所でインポートする必要があります。しかし、どちらも理想的とはいえません。\n\nVuex を利用するとストア内に \"ゲッター\" を定義することができます。それらをストアの算出プロパティと考えることができます。\n\n::: warning 警告\nVue 3.0 では、ゲッターの結果は算出プロパティのように**キャッシュされません**。これは既知の問題で、Vue 3.2 がリリースされる必要があります。詳細は [PR #1878](https://github.com/vuejs/vuex/pull/1883) をご確認ください。\n:::\n\nゲッターは第1引数として、state を受け取ります:\n\n``` js\nconst store = createStore({\n  state: {\n    todos: [\n      { id: 1, text: '...', done: true },\n      { id: 2, text: '...', done: false }\n    ]\n  },\n  getters: {\n    doneTodos (state) {\n      return state.todos.filter(todo => todo.done)\n    }\n  }\n})\n```\n\n## プロパティスタイルアクセス\n\nゲッターは `store.getters` オブジェクトから取り出され、プロパティとしてアクセスすることができます:\n\n``` js\nstore.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]\n```\n\nゲッターは第2引数として他のゲッターを受け取ります:\n\n``` js\ngetters: {\n  // ...\n  doneTodosCount (state, getters) {\n    return getters.doneTodos.length\n  }\n}\n```\n\n``` js\nstore.getters.doneTodosCount // -> 1\n```\n\nどのコンポーネントの内部でも簡単にゲッターを利用することができます:\n\n``` js\ncomputed: {\n  doneTodosCount () {\n    return this.$store.getters.doneTodosCount\n  }\n}\n```\n\nプロパティとしてアクセスされるゲッターは Vue のリアクティブシステムの一部としてキャッシュされるという点に留意してください。\n\n## メソッドスタイルアクセス\n\n関数を返り値にすることで、ゲッターに引数を渡すこともできます。これは特にストアの中の配列を検索する時に役立ちます：\n```js\ngetters: {\n  // ...\n  getTodoById: (state) => (id) => {\n    return state.todos.find(todo => todo.id === id)\n  }\n}\n```\n\n``` js\nstore.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }\n```\n\nメソッドによってアクセスされるゲッターは呼び出す度に実行され、その結果はキャッシュされない点に留意してください。\n\n## `mapGetters` ヘルパー\n\n`mapGetters` ヘルパーはストアのゲッターをローカルの算出プロパティにマッピングさせます:\n\n``` js\nimport { mapGetters } from 'vuex'\n\nexport default {\n  // ...\n  computed: {\n    // ゲッターを、スプレッド演算子（object spread operator）を使って computed に組み込む\n    ...mapGetters([\n      'doneTodosCount',\n      'anotherGetter',\n      // ...\n    ])\n  }\n}\n```\n\nゲッターを異なる名前でマッピングさせたいときはオブジェクトを使います:\n\n``` js\n...mapGetters({\n  // `this.doneCount` を `this.$store.getters.doneTodosCount` にマッピングさせる\n  doneCount: 'doneTodosCount'\n})\n```\n"
  },
  {
    "path": "docs/ja/guide/hot-reload.md",
    "content": "# ホットリローディング\n\nVuex は webpack の [Hot Module Replacement API](https://webpack.js.org/guides/hot-module-replacement/) を使用することで、アプリケーションの開発を行っている間のミューテーション、モジュール、アクション、ゲッターのホットリローディングをサポートします。Browserify では [browserify-hmr](https://github.com/AgentME/browserify-hmr/) プラグインを使用することができます。\n\nミューテーションとモジュールのホットリローディングのために、`store.hotUpdate()`  API メソッドを利用する必要があります:\n\n``` js\n// store.js\nimport { createStore } from 'vuex'\nimport mutations from './mutations'\nimport moduleA from './modules/a'\n\nconst state = { ... }\n\nconst store = createStore({\n  state,\n  mutations,\n  modules: {\n    a: moduleA\n  }\n})\n\nif (module.hot) {\n  // ホットモジュールとしてアクションとモジュールを受け付けます\n  module.hot.accept(['./mutations', './modules/a'], () => {\n    // 更新されたモジュールをインポートする\n    // babel 6 のモジュール出力のため、ここでは .default を追加しなければならない\n    const newMutations = require('./mutations').default\n    const newModuleA = require('./modules/a').default\n    // 新しいモジュールとミューテーションにスワップ\n    store.hotUpdate({\n      mutations: newMutations,\n      modules: {\n        a: newModuleA\n      }\n    })\n  })\n}\n```\n\nホットリローディングを試したい場合は、[counter-hot example](https://github.com/vuejs/vuex/tree/main/examples/counter-hot)をチェックアウトしてください。\n\n## 動的モジュールホットリローディング\n\nもしストアでモジュールだけを使用している場合には、`require.context` を使って全てのモジュールを動的に読み込むこともできます。\n\n```js\n// store.js\nimport { createStore } from 'vuex'\n\n// 全てのモジュールをロードする\nfunction loadModules() {\n  const context = require.context(\"./modules\", false, /([a-z_]+)\\.js$/i)\n\n  const modules = context\n    .keys()\n    .map((key) => ({ key, name: key.match(/([a-z_]+)\\.js$/i)[1] }))\n    .reduce(\n      (modules, { key, name }) => ({\n        ...modules,\n        [name]: context(key).default\n      }),\n      {}\n    )\n\n  return { context, modules }\n}\n\nconst { context, modules } = loadModules()\n\nconst store = createStore({\n  modules\n})\n\nif (module.hot) {\n  // モジュールに変更があった場合にホットリロードする\n  module.hot.accept(context.id, () => {\n    const { modules } = loadModules()\n\n    store.hotUpdate({\n      modules\n    })\n  })\n}\n```\n"
  },
  {
    "path": "docs/ja/guide/index.md",
    "content": "# Vuex 入門\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cMPa2Uk\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\nVuex アプリケーションの中心にあるものは**ストア**です。\"ストア\" は、基本的にアプリケーションの **状態（state）** を保持するコンテナです。単純なグローバルオブジェクトとの違いが 2つあります。\n\n1. Vuex ストアはリアクティブです。Vue コンポーネントがストアから状態を取り出すとき、もしストアの状態が変化したら、ストアはリアクティブかつ効率的に更新を行います。\n\n2. ストアの状態を直接変更することはできません。明示的に**ミューテーションをコミットする**ことによってのみ、ストアの状態を変更します。これによって、全ての状態の変更について追跡可能な記録を残すことが保証され、ツールでのアプリケーションの動作の理解を助けます。\n\n## シンプルなストア\n\n:::tip 注意\n私たちは、このドキュメントのコード例に ES2015 のシンタックスを利用しています。 もし触れたことがなければ、[ぜひ触れてください](https://babeljs.io/docs/learn-es2015/)！\n:::\n\nVuex を[インストール](../installation.md) してから、ストアをつくってみましょう。Vuex ストアの作成は、とても簡単です。ストアオブジェクトの初期状態と、いくつかのミューテーションを準備するだけです。\n\n```js\nimport { createApp } from 'vue'\nimport { createStore } from 'vuex'\n\n// 新しいストアインスタンスを作成します\nconst store = createStore({\n  state () {\n    return {\n      count: 0\n    }\n  },\n  mutations: {\n    increment (state) {\n      state.count++\n    }\n  }\n})\n\nconst app = createApp({ /* ルートコンポーネント */ })\n\n// プラグインとしてストアインスタンスをインストールします\napp.use(store)\n```\n\nこれで `store.state` でストアオブジェクトの状態を参照でき、また `store.commit` メソッドで状態の変更を行うことができます。\n\n```js\nstore.commit('increment')\n\nconsole.log(store.state.count) // -> 1\n```\n\nVue コンポーネントでは、`this.$store` としてストアにアクセスできます。それでは、コンポーネントのメソッドを使ってミューテーションをコミットしてみましょう。\n\n```js\nmethods: {\n  increment() {\n    this.$store.commit('increment')\n    console.log(this.$store.state.count)\n  }\n}\n```\n\nそして `store.state.count` を直接変更する代わりにミューテーションをコミットする理由は、状態の変更を明確に追跡したいからです。このシンプルな規約は、あなたのコードの意図をさらに明確にし、コードを読んだ時にアプリケーションの状態の変更について、論理的に考えることができるようにします。加えて、私たちに全ての変更のログを取ったり、状態のスナップショットを取ったり、タイムトラベルデバッグを行うようなツールを実装する余地を与えてくれます。\n\nストアオブジェクトの状態はリアクティブなので、ストアの状態をコンポーネント内で使うには算出プロパティ内でただ状態を返せば良いです。コンポーネントメソッドでミューテーションをコミットすることによって状態の変更を行います。\n\nこれから Vuex のコアコンセプトについて詳しく説明していきます。まずは[状態（state）](state.md)からはじめましょう。\n"
  },
  {
    "path": "docs/ja/guide/migrating-to-4-0-from-3-x.md",
    "content": "# 3.x から 4.0 への移行\n\nほとんどすべての Vuex 4 の API は、Vuex 3 から変更されていません。しかし、修正が必要な破壊的変更がいくつかあります。\n\n- [破壊的変更](#破壊的変更)\n  - [インストール手順](#インストール手順)\n  - [TypeScript サポート](#typescript-サポート)\n  - [バンドルが Vue 3 に対応しました](#バンドルが-vue-3-に対応しました)\n  - [\"createLogger\" 関数はコアモジュールからエクスポートされます](#createlogger-関数はコアモジュールからエクスポートされます)\n- [新機能](#新機能)\n  - [新しい \"useStore\" 合成関数](#新しい-usestore-合成関数)\n\n## 破壊的変更\n\n### インストール手順\n\n新しい Vue 3 の初期化の手順に合わせて、Vuex のインストール手順が変更されました。新しいストアを作成するには、新しく導入された createStore 関数を使用することが推奨されます。\n\n```js\nimport { createStore } from 'vuex'\n\nexport const store = createStore({\n  state () {\n    return {\n      count: 1\n    }\n  }\n})\n```\n\nVueインスタンスにVuexをインストールするには、Vuexではなく`store`を渡します。\n\n```js\nimport { createApp } from 'vue'\nimport { store } from './store'\nimport App from './App.vue'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n```\n\n:::tip 注意\n厳密にはこれは破壊的変更ではなく、まだ `new Store(...)` 構文を使用することができますが、Vue 3 と Vue Router Next に合わせるためにこの方法を推奨します。\n:::\n\n### TypeScript サポート\n\nVuex 4 は、[issue #994](https://github.com/vuejs/vuex/issues/994) を解決するために、Vue コンポーネント内の `this.$store` のグローバルな型付けを削除します。TypeScript で使用する場合は、独自のモジュール拡張を宣言する必要があります。\n\n次のコードをあなたのプロジェクトに配置して、`this.$store` が正しく型付けされるようにしてください。\n\n```ts\n// vuex-shim.d.ts\n\nimport { ComponentCustomProperties } from 'vue'\nimport { Store } from 'vuex'\n\ndeclare module 'vue' {\n  // ストアのステートを宣言する\n  interface State {\n    count: number\n  }\n\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\n詳細は、[TypeScript サポート](./typescript-support) セクションをご覧ください.\n\n### バンドルが Vue 3 に対応しました\n\n以下のバンドルは、Vue 3 のバンドルに合わせて生成されます。\n\n- `vuex.global(.prod).js`\n  - ブラウザの `<script src=\"...\">` で直接使用します。Vuexのグローバルを公開しています。\n  - グローバルビルドは UMD ではなく IIFE としてビルドされており、`<script src=\"...\">` での直接使用のみを想定しています。\n  - ハードコードされた prod/dev ブランチが含まれており、prod ビルドはあらかじめ minify されています。本番環境では、`.prod.js` ファイルを使用してください。\n- `vuex.esm-browser(.prod).js`\n  - ネイティブの ES モジュールのインポート（`<script type=\"module\">` でブラウザをサポートするモジュールを含む）で使用されます。\n- `vuex.esm-bundler.js`\n  - `webpack`, `rollup`, `parcel` などのバンドラーで使用されます。\n  - `process.env.NODE_ENV` のガードを持つ prod/dev ブランチを残します(バンドラーで置き換える必要があります)。\n  - minify されたビルドは出荷されません（バンドル後に他のコードと一緒に行われます）。\n- `vuex.cjs.js`\n  - Node.js のサーバーサイドレンダリングで、`require()`を使って使用されます。\n\n### \"createLogger\" 関数はコアモジュールからエクスポートされます\n\nVuex 3では、`createLogger` 関数は `vuex/dist/logger` からエクスポートされていましたが、現在は core パッケージに含まれています。この関数は `vuex` パッケージから直接インポートする必要があります。\n\n```js\nimport { createLogger } from 'vuex'\n```\n\n## 新機能\n\n### 新しい \"useStore\" 合成関数\n\nVuex 4 では、Composition API でストアを操作するための新しい API が導入されました。合成関数の `useStore` を使って、コンポーネントの `setup` フック内でストアを取得することができます。\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n  }\n}\n```\n\n詳細は、[Composition API](./composition-api)のセクションをご覧ください。\n"
  },
  {
    "path": "docs/ja/guide/modules.md",
    "content": "# モジュール\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKK4psq\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\n単一ステートツリーを使うため、アプリケーションの全ての状態は、一つの大きなストアオブジェクトに内包されます。しかしながら、アプリケーションが大きくなるにつれて、ストアオブジェクトは膨れ上がってきます。\n\nそのような場合に役立てるため Vuex ではストアを**モジュール**に分割できるようになっています。それぞれのモジュールは、モジュール自身の状態（state）、ミューテーション、アクション、ゲッター、モジュールさえも内包できます（モジュールをネストできます）- トップからボトムまでフラクタル構造です:\n\n```js\nconst moduleA = {\n  state: () => ({ ... }),\n  mutations: { ... },\n  actions: { ... },\n  getters: { ... }\n}\n\nconst moduleB = {\n  state: () => ({ ... }),\n  mutations: { ... },\n  actions: { ... }\n}\n\nconst store = createStore({\n  modules: {\n    a: moduleA,\n    b: moduleB\n  }\n})\n\nstore.state.a // -> `moduleA` のステート\nstore.state.b // -> `moduleB` のステート\n```\n\n## モジュールのローカルステート\n\nモジュールのミューテーションやゲッターの中では、渡される第 1 引数は**モジュールのローカルステート**です。\n\n```js\nconst moduleA = {\n  state: () => ({\n    count: 0\n  }),\n  mutations: {\n    increment (state) {\n      // `state` はモジュールのローカルステート\n      state.count++\n    }\n  },\n  getters: {\n    doubleCount (state) {\n      return state.count * 2\n    }\n  }\n}\n```\n\n同様に、モジュールのアクションの中では `context.state` はローカルステートにアクセスでき、ルートのステートは `context.rootState` でアクセスできます:\n\n```js\nconst moduleA = {\n  // ...\n  actions: {\n    incrementIfOddOnRootSum ({ state, commit, rootState }) {\n      if ((state.count + rootState.count) % 2 === 1) {\n        commit('increment')\n      }\n    }\n  }\n}\n```\n\nまた、モジュールのゲッターの中では、ルートのステートは第3引数でアクセスできます:\n\n```js\nconst moduleA = {\n  // ...\n  getters: {\n    sumWithRootCount (state, getters, rootState) {\n      return state.count + rootState.count\n    }\n  }\n}\n```\n\n## 名前空間\n\nデフォルトでは、モジュール内部のアクション、ミューテーション、そしてゲッターは**グローバル名前空間**の元で登録されます - これにより、複数のモジュールが同じミューテーション/アクションタイプに反応することができます。\n\nモジュールをより自己完結型にまた再利用可能なものにしたい場合は、それを `namespaced: true` によって名前空間に分けることができます。モジュールが登録されると、そのゲッター、アクション、およびミューテーションのすべてが、モジュールが登録されているパスに基づいて自動的に名前空間に入れられます。例えば:\n\n```js\nconst store = createStore({\n  modules: {\n    account: {\n      namespaced: true,\n\n      // モジュールのアセット\n      state: () => ({ ... }), // モジュールステートはすでにネストされており、名前空間のオプションによって影響を受けません\n      getters: {\n        isAdmin () { ... } // -> getters['account/isAdmin']\n      },\n      actions: {\n        login () { ... } // -> dispatch('account/login')\n      },\n      mutations: {\n        login () { ... } // -> commit('account/login')\n      },\n\n      // ネストされたモジュール\n      modules: {\n        // 親モジュールから名前空間を継承する\n        myPage: {\n          state: () => ({ ... }),\n          getters: {\n            profile () { ... } // -> getters['account/profile']\n          }\n        },\n\n        // さらに名前空間をネストする\n        posts: {\n          namespaced: true,\n\n          state: () => ({ ... }),\n          getters: {\n            popular () { ... } // -> getters['account/posts/popular']\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n名前空間のゲッターとアクションは、ローカライズされた `getters`、`dispatch`、`commit` を受け取ります。言い換えれば、同じモジュールに接頭辞 (prefix) を書き込まずに、モジュールアセットを使用することができます。名前空間オプションの切り替えは、モジュール内のコードには影響しません。\n\n### 名前空間付きモジュールでのグローバルアセットへのアクセス\n\nグローバルステートとゲッターを使いたい場合、`rootState` と `rootGetters` はゲッター関数の第3引数と第4引数として渡され、アクション関数に渡される `context` オブジェクトのプロパティとしても公開されます。\n\nアクションをディスパッチするか、グローバル名前空間にミューテーションをコミットするには、`dispatch` と `commit` の3番目の引数として `{root: true}` を渡します。\n\n```js\nmodules: {\n  foo: {\n    namespaced: true,\n\n    getters: {\n      // `getters` はこのモジュールのゲッターにローカライズされています\n      // ゲッターの第4引数経由で rootGetters を使うことができます\n      someGetter (state, getters, rootState, rootGetters) {\n        getters.someOtherGetter // -> 'foo/someOtherGetter'\n        rootGetters.someOtherGetter // -> 'someOtherGetter'\n        rootGetters['bar/someOtherGetter'] // -> 'bar/someOtherGetter'\n      },\n      someOtherGetter: state => { ... }\n    },\n\n    actions: {\n      // ディスパッチとコミットもこのモジュール用にローカライズされています\n      // ルートディスパッチ/コミットの `root` オプションを受け入れます\n      someAction ({ dispatch, commit, getters, rootGetters }) {\n        getters.someGetter // -> 'foo/someGetter'\n        rootGetters.someGetter // -> 'someGetter'\n        rootGetters['bar/someGetter'] // -> 'bar/someGetter'\n\n        dispatch('someOtherAction') // -> 'foo/someOtherAction'\n        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'\n\n        commit('someMutation') // -> 'foo/someMutation'\n        commit('someMutation', null, { root: true }) // -> 'someMutation'\n      },\n      someOtherAction (ctx, payload) { ... }\n    }\n  }\n}\n```\n\n### 名前空間付きモジュールでのグローバルアクションへの登録\n\n名前空間付きモジュールでグローバルアクションに登録したい場合、`root: true` でそれをマークでき、そしてアクション定義を `handler` 関数に置くことができます。例えば:\n\n```js\n{\n  actions: {\n    someOtherAction ({dispatch}) {\n      dispatch('someAction')\n    }\n  },\n  modules: {\n    foo: {\n      namespaced: true,\n\n      actions: {\n        someAction: {\n          root: true,\n          handler (namespacedContext, payload) { ... } // -> 'someAction'\n        }\n      }\n    }\n  }\n}\n```\n\n### 名前空間によるバインディングヘルパー\n\n`mapState`、`mapGetters`、`mapActions`、そして `mapMutations` ヘルパーを使って名前空間付きモジュールをコンポーネントにバインディングするとき、少し冗長になります:\n\n```js\ncomputed: {\n  ...mapState({\n    a: state => state.some.nested.module.a,\n    b: state => state.some.nested.module.b\n  }),\n  ...mapGetters([\n    'some/nested/module/someGetter', // -> this['some/nested/module/someGetter']\n    'some/nested/module/someOtherGetter', // -> this['some/nested/module/someOtherGetter']\n  ])\n},\nmethods: {\n  ...mapActions([\n    'some/nested/module/foo', // -> this['some/nested/module/foo']()\n    'some/nested/module/bar' // -> this['some/nested/module/bar']()\n  ])\n}\n```\n\nこのような場合は、第1引数としてモジュールの名前空間文字列をヘルパーに渡すことで、そのモジュールをコンテキストとして使用してすべてのバインディングを行うことができます。上記は次のように単純化できます。\n\n```js\ncomputed: {\n  ...mapState('some/nested/module', {\n    a: state => state.a,\n    b: state => state.b\n  }),\n  ...mapGetters('some/nested/module', [\n    'someGetter', // -> this.someGetter\n    'someOtherGetter', // -> this.someOtherGetter\n  ])\n},\nmethods: {\n  ...mapActions('some/nested/module', [\n    'foo', // -> this.foo()\n    'bar' // -> this.bar()\n  ])\n}\n```\n\nさらに、`createNamespacedHelpers` を使用することによって名前空間付けされたヘルパーを作成できます。指定された名前空間の値にバインドされた新しいコンポーネントバインディングヘルパーを持つオブジェクトを返します:\n\n```js\nimport { createNamespacedHelpers } from 'vuex'\n\nconst { mapState, mapActions } = createNamespacedHelpers('some/nested/module')\n\nexport default {\n  computed: {\n    // `some/nested/module` を調べます\n    ...mapState({\n      a: state => state.a,\n      b: state => state.b\n    })\n  },\n  methods: {\n    // `some/nested/module` を調べます\n    ...mapActions([\n      'foo',\n      'bar'\n    ])\n  }\n}\n```\n\n### プラグイン開発者向けの注意事項\n\nモジュールを提供する[プラグイン](plugins.md)を作成し、ユーザーがそれらを Vuex ストアに追加できるようにすると、モジュールの予測できない名前空間が気になるかもしれません。あなたのモジュールは、プラグインユーザーが名前空間付きモジュールの元にモジュールを追加すると、その名前空間に属するようになります。この状況に適応するには、プラグインオプションを使用して名前空間の値を受け取る必要があります。\n\n```js\n// プラグインオプションで名前空間値を取得し、\n// そして、Vuex プラグイン関数を返す\nexport function createPlugin (options = {}) {\n  return function (store) {\n    // 名前空間をプラグインモジュールの型に追加する\n    const namespace = options.namespace || ''\n    store.dispatch(namespace + 'pluginAction')\n  }\n}\n```\n\n## 動的にモジュールを登録する\n\nストアが作られた**後**に `store.registerModule` メソッドを使って、モジュールを登録できます:\n\n```js\nimport { createStore } from 'vuex'\n\nconst store = createStore({ /* options */ })\n\n// `myModule` モジュールを登録します\nstore.registerModule('myModule', {\n  // ...\n})\n\n// ネストされた `nested/myModule` モジュールを登録します\nstore.registerModule(['nested', 'myModule'], {\n  // ...\n})\n```\n\nモジュールのステートには `store.state.myModule` と `store.state.nested.myModule` でアクセスします。\n\n動的なモジュール登録があることで、他の Vue プラグインが、モジュールをアプリケーションのストアに付属させることで、状態の管理に Vuex を活用できます。例えば [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) ライブラリは、動的に付属させたモジュール内部でアプリケーションのルーティングのステートを管理することで vue-router と vuex を統合しています。\n\n`store.unregisterModule(moduleName)` を呼び出せば、動的に登録したモジュールを削除できます。ただしストア作成（store creation）の際に宣言された、静的なモジュールはこのメソッドで削除できないことに注意してください。\n\nまた、すでにモジュールが登録されているかどうかを `store.hasModule(moduleName)` メソッドを使って確認することができます。 One thing to keep in mind is that nested modules should be passed as arrays for both the `registerModule` and `hasModule` and not as a string with the path to the module.\n留意すべき点は、入れ子になっているモジュールは、`registerModule` と `hasModule` の両方に、モジュールへのパスを文字列として渡すのではなく、配列として渡す必要があるということです。\n\n### ステートの保持\n\nサーバサイドレンダリングされたアプリケーションから状態を保持するなど、新しいモジュールを登録するときに、以前の状態を保持したい場合があります。`preserveState` オプション（`store.registerModule('a', module, { preserveState: true })`）でこれを実現できます。\n\n`preserveState: true` を設定した場合、モジュールを登録する際に、アクション、ミューテーション、そしてゲッターは追加されますがステートは追加されません。これはストアのステートはすでにモジュールのステートを登録しているので、それを上書きしないようにするためです。\n\n## モジュールの再利用\n\n時どき、モジュールの複数インスタンスを作成する必要があるかもしれません。例えば:\n\n- 同じモジュールを使用する複数のストアを作成する(例: `runInNewContext` オプションが `false` または `'once'` のとき、[SSR でステートフルなシングルトンを避けるためです](https://ssr.vuejs.org/ja/structure.html#ステートフルなシングルトンの回避)。)\n- 同じストアに同じモジュールを複数回登録する\n\nモジュールの状態を宣言するために単純なオブジェクトを使用すると、その状態オブジェクトは参照によって共有され、変更時にクロスストア/モジュールの状態汚染を引き起こします。\n\nこれは、実際には Vue コンポーネント内部の `data` と全く同じ問題です。従って解決策も同じです。モジュールの状態を宣言するために関数を使用してください (2.3.0 以降でサポートされます):\n\n```js\nconst MyReusableModule = {\n  state: () => ({\n    foo: 'bar'\n  }),\n  // ミューテーション、アクション、ゲッター...\n}\n```\n"
  },
  {
    "path": "docs/ja/guide/mutations.md",
    "content": "# ミューテーション\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/ckMZp4HN\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\n実際に Vuex のストアの状態を変更できる唯一の方法は、ミューテーションをコミットすることです。Vuex のミューテーションはイベントにとても近い概念です: 各ミューテーションは**タイプ**と**ハンドラ**を持ちます。ハンドラ関数は Vuex の状態（state）を第1引数として取得し、実際に状態の変更を行います:\n\n```js\nconst store = createStore({\n  state: {\n    count: 1\n  },\n  mutations: {\n    increment (state) {\n      // 状態を変更する\n      state.count++\n    }\n  }\n})\n```\n\n直接ミューテーションハンドラを呼び出すことはできません。この mutations オプションは、どちらかいうと \"タイプが `increment` のミューテーションがトリガーされたときに、このハンドラが呼ばれる\" といったイベント登録のようなものです。ミューテーションハンドラを起動するためにはミューテーションのタイプを指定して `store.commit` を呼び出す必要があります:\n\n```js\nstore.commit('increment')\n```\n\n## 追加の引数を渡してコミットする\n\n`store.commit` に追加の引数を渡すこともできます。この追加の引数は、特定のミューテーションに対する**ペイロード**と呼びます:\n\n```js\n// ...\nmutations: {\n  increment (state, n) {\n    state.count += n\n  }\n}\n```\n\n```js\nstore.commit('increment', 10)\n```\n\nほとんどの場合、ペイロードはオブジェクトにすべきです。そうすることで複数のフィールドを含められるようになり、またミューテーションがより記述的に記録されるようになります:\n\n```js\n// ...\nmutations: {\n  increment (state, payload) {\n    state.count += payload.amount\n  }\n}\n```\n\n```js\nstore.commit('increment', {\n  amount: 10\n})\n```\n\n## オブジェクトスタイルのコミット\n\nまた `type` プロパティを持つオブジェクトを使って、ミューテーションをコミットすることもできます:\n\n```js\nstore.commit({\n  type: 'increment',\n  amount: 10\n})\n```\n\nオブジェクトスタイルでコミットするとき、オブジェクト全体がペイロードとしてミューテーションハンドラに渡されます。したがってハンドラの例は上記と同じです:\n\n```js\nmutations: {\n  increment (state, payload) {\n    state.count += payload.amount\n  }\n}\n```\n\n## ミューテーション・タイプに定数を使用する\n\nいろいろな Flux 実装において、ミューテーション・タイプに定数を使用することが共通して見られるパターンです。これはコードに対してリントツールのようなツールを利用できるという利点があり、また単一ファイルに全ての定数を設定することによって、共同で作業する人に、アプリケーション全体で何のミューテーションが可能であるかを一目見ただけで理解できるようにします:\n\n```js\n// mutation-types.js\nexport const SOME_MUTATION = 'SOME_MUTATION'\n```\n\n```js\n// store.js\nimport { createStore } from 'vuex'\nimport { SOME_MUTATION } from './mutation-types'\n\nconst store = createStore({\n  state: { ... },\n  mutations: {\n    // 定数を関数名として使用できる ES2015 の算出プロパティ名（computed property name）機能を使用できます\n    [SOME_MUTATION] (state) {\n      // 状態を変更する\n    }\n  }\n})\n```\n\n定数を使用するかどうかは好みの問題です。多くの開発者による大規模なプロジェクトで役に立ちますが、完全にオプションなので、もしお気に召さなければ使用しなくても構いません。\n\n## ミューテーションは同期的でなければならない\n\nひとつの重要なルールを覚えておきましょう。それは**ミューテーションハンドラ関数は同期的でなければならない**ということです。なぜか？次の例で考えてみましょう:\n\n```js\nmutations: {\n  someMutation (state) {\n    api.callAsyncMethod(() => {\n      state.count++\n    })\n  }\n}\n```\n\nいま、開発ツールのミューテーションのログを見ながら、アプリケーションのデバッグを行っていることを想像してください。全てのミューテーションをログに記録するためには、ミューテーションの前後の状態のスナップショットを捕捉することが必要です。しかし、上の例にあるミューテーション内の非同期コールバックは、それを不可能にします: そのコールバックは、ミューテーションがコミットされた時点ではまだ呼び出されていません。そして、コールバックが実際にいつ呼び出されるかを、開発ツールは知る術がありません。いかなる状態変更でも、コールバック内で起きる場合は本質的に追跡不可能です。\n\n## コンポーネント内におけるミューテーションのコミット\n\n`this.$store.commit('xxx')` と書くか、もしくはコンポーネントのメソッドを `store.commit` にマッピングする `mapMutations` ヘルパーを呼び出すこと（ルートの `store` の注入が必要）で、コンポーネント内でミューテーションをコミットできます:\n\n```js\nimport { mapMutations } from 'vuex'\n\nexport default {\n  // ...\n  methods: {\n    ...mapMutations([\n      'increment', // `this.increment()` を `this.$store.commit('increment')` にマッピングする\n\n      // mapMutations はペイロードサポートする:\n      'incrementBy' // `this.incrementBy(amount)` を `this.$store.commit('incrementBy', amount)` にマッピングする\n    ]),\n    ...mapMutations({\n      add: 'increment' // `this.add()` を `this.$store.commit('increment')` にマッピングする\n    })\n  }\n}\n```\n\n## アクションへ向けて\n\n状態変更を非同期に組み合わせることは、プログラムの動きを予測することを非常に困難にします。例えば、状態を変更する非同期コールバックを持った 2つのメソッドを両方呼び出すとき、それらがいつ呼び出されたか、どちらが先に呼び出されたかを、どうやって知ればよいのでしょう？これがまさに、状態変更と非同期の 2つの概念を分離したいという理由です。Vuex では**全てのミューテーションは同期的に行う**という作法になっています:\n\n```js\nstore.commit('increment')\n// \"increment\" ミューテーションによる状態変更は、この時点で行われるべきです\n```\n\n非同期的な命令を扱うために[アクション](actions.md)を見てみましょう。\n"
  },
  {
    "path": "docs/ja/guide/plugins.md",
    "content": "# プラグイン \n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cvp8ZkCR\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\nVuex ストア は、各ミューテーションへのフックを公開する `plugins` オプションを受け付けます。 Vuex プラグインは、単一の引数としてストアを受けつけるただの関数です:\n\n```js\nconst myPlugin = (store) => {\n  // ストアが初期化されたときに呼ばれます\n  store.subscribe((mutation, state) => {\n    // それぞれのミューテーションの後に呼ばれます\n    // ミューテーションは `{ type, payload }` の形式で提供されます\n  })\n}\n```\n\nそして、このように利用することができます:\n\n```js\nconst store = createStore({\n  // ...\n  plugins: [myPlugin]\n})\n```\n\n## プラグイン内でのミューテーションのコミット\n\nプラグインは直接、状態を変更できません。これはコンポーネントに似ています。プラグインはコンポーネント同様に、ミューテーションのコミットをトリガーすることで状態を変更できます。\n\nミューテーションのコミットによるストアとデータソースの同期をプラグインで実現できます。 websocket データソースとストアを例にします (これは不自然で作為的な例です。実際には `createWebSocketPlugin` 関数は、さらに複雑なタスクのために追加でいくつかのオプションを受け取れます):\n\n```js\nexport default function createWebSocketPlugin (socket) {\n  return (store) => {\n    socket.on('data', data => {\n      store.commit('receiveData', data)\n    })\n    store.subscribe(mutation => {\n      if (mutation.type === 'UPDATE_DATA') {\n        socket.emit('update', mutation.payload)\n      }\n    })\n  }\n}\n```\n\n```js\nconst plugin = createWebSocketPlugin(socket)\n\nconst store = createStore({\n  state,\n  mutations,\n  plugins: [plugin]\n})\n```\n\n## 状態のスナップショットを撮る\n\n時々、状態の\"スナップショット\"を撮って、ミューテーション前後の状態を比較したくなることがあるでしょう。それを実現するために、状態オブジェクトのディープコピーを行う必要があります:\n\n```js\nconst myPluginWithSnapshot = (store) => {\n  let prevState = _.cloneDeep(store.state)\n  store.subscribe((mutation, state) => {\n    let nextState = _.cloneDeep(state)\n\n    // `prevState` と `nextState` を比較...\n\n    // 次のミューテーションのために状態を保存\n    prevState = nextState\n  })\n}\n```\n\n**状態のスナップショットを撮るプラグインはアプリケーションの開発の間だけ使われるべきです。**  webpack や Browserify を使っていれば、ビルドツールにそれを処理させることができます:\n\n```js\nconst store = createStore({\n  // ...\n  plugins: process.env.NODE_ENV !== 'production'\n    ? [myPluginWithSnapshot]\n    : []\n})\n```\n\n上のように記述すれば、プラグインはデフォルトで利用されることになります。本番環境( production ) では、 `process.env.NODE_ENV !== 'production'` を `false` に置き換えるために、 webpack では[DefinePlugin](https://webpack.js.org/plugins/define-plugin/) 、 Browserify では[envify](https://github.com/hughsk/envify) が必要になります。\n\n## ビルトインロガープラグイン\n\nVuex には、一般的なデバッグに利用する用途の備え付けのロガープラグインがあります。\n\n```js\nimport { createLogger } from 'vuex'\n\nconst store = createStore({\n  plugins: [createLogger()]\n})\n```\n\n`createLogger` 関数はいくつかのオプションを受け取ります:\n\n```js\nconst logger = createLogger({\n  collapsed: false, // ログ出力されたミューテーションを自動で展開します\n  filter (mutation, stateBefore, stateAfter) {\n    // ミューテーションを記録する必要がある場合は、`true` を返します\n    // `mutation` は `{ type, payload }` です\n    return mutation.type !== \"aBlocklistedMutation\"\n  },\n  actionFilter (action, state) {\n    // `filter` と同等ですが、アクション用です\n    // `action` は `{ type, payloed }` です\n    return action.type !== \"aBlocklistedAction\"\n  },\n  transformer (state) {\n    // ロギングの前に、状態を変換します\n    // 例えば、特定のサブツリーのみを返します\n    return state.subTree\n  },\n  mutationTransformer (mutation) {\n    // ミューテーションは、`{ type, payload }` の形式でログ出力されます\n    // 任意の方法でそれをフォーマットできます\n    return mutation.type\n  },\n  actionTransformer (action) {\n    // `mutationTransformer` と同等ですが、アクション用です\n    return action.type\n  },\n  logActions: true, // アクションログを出力します。\n  logMutations: true, // ミューテーションログを出力します。\n  logger: console, // `console` API の実装, デフォルトは `console`\n})\n```\n\nロガーファイルは、他にも `<script>` タグで直接読み込むことができ、`createVuexLogger` 関数がグローバルに公開されます。\n\nロガープラグインは、状態のスナップショットを撮ることに注意しましょう。スナップショットを撮ることはコストがかかるため、開発中だけ利用してください。\n"
  },
  {
    "path": "docs/ja/guide/state.md",
    "content": "# ステート\n\n## 単一ステートツリー\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cWw3Zhb\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\nVuex は **単一ステートツリー (single state tree)** を使います。つまり、この単一なオブジェクトはアプリケーションレベルの状態が全て含まれており、\"信頼できる唯一の情報源 (single source of truth)\" として機能します。これは、通常、アプリケーションごとに1つしかストアは持たないことを意味します。単一ステートツリーは状態の特定の部分を見つけること、デバッグのために現在のアプリケーションの状態のスナップショットを撮ることを容易にします。\n\n単一ステートツリーはモジュール性と競合しません。以降の章で、アプリケーションの状態とミューテーション(変更)をサブモジュールに分割する方法について説明します。\n\nVuexに保存するデータは、Vueインスタンスの `data` と同じルールに従います。つまり、ステートオブジェクトはプレーンでなければなりません。[Vue#data](https://v3.ja.vuejs.org/api/options-data.html#data-2)も参照してください。\n\n## Vuex の状態を Vue コンポーネントに入れる\n\nストアにある状態を Vue コンポーネント に表示するにはどうすればよいのでしょう？　Vuex ストア はリアクティブなので、ストアから状態を\"取り出す\"一番シンプルな方法は、単純にいくつかのストアの状態を [算出プロパティ](https://jp.vuejs.org/guide/computed.html) で返すことです。\n\n```js\n// Counter コンポーネントをつくってみましょう\nconst Counter = {\n  template: `<div>{{ count }}</div>`,\n  computed: {\n    count () {\n      return store.state.count\n    }\n  }\n}\n```\n\n`store.state.count` が変わるたび、算出プロパティの再評価が発生し、関連した DOM の更新をトリガーします。\n\nしかし、このパターンでは、コンポーネントがグローバルストアシングルトンに依存してしまいます。 モジュールシステムを使っているとき、ストアの状態を使っているすべてのコンポーネントでインポートが必要です。また、コンポーネントのテストのときにモック化が必要となります。\n\nVuex は Vue のプラグインシステムを通じて、ルートコンポーネントからすべての子コンポーネントにストアを \"注入\" し、それらのコンポーネントでは `this.$store` として利用できるようになります。それでは `Counter` の実装を変更しましょう:\n\n```js\nconst Counter = {\n  template: `<div>{{ count }}</div>`,\n  computed: {\n    count () {\n      return this.$store.state.count\n    }\n  }\n}\n```\n\n## `mapState` ヘルパー\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c8Pz7BSK\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\nコンポーネントが複数のストアのステートプロパティやゲッターを必要としているとき、これらすべてにおいて、算出プロパティを宣言することは繰り返しで冗長です。これに対処するため、算出ゲッター関数を生成し、いくつかのキーストロークを省くのに役立つ `mapState` ヘルパーを使うことができます:\n\n```js\n// 完全ビルドでは、ヘルパーは Vuex.mapState として公開されています\nimport { mapState } from 'vuex'\n\nexport default {\n  // ...\n  computed: mapState({\n    // アロー関数は、コードをとても簡潔にできます！\n    count: state => state.count,\n\n    // 文字列を渡すことは、`state => state.count` と同じです\n    countAlias: 'count',\n\n    // `this` からローカルステートを参照するときは、通常の関数を使わなければいけません\n    countPlusLocalState (state) {\n      return state.count + this.localCount\n    }\n  })\n}\n```\n\nマップされた算出プロパティの名前がステートサブツリーの名前と同じ場合は、文字列配列を `mapState` に渡すこともできます。\n\n```js\ncomputed: mapState([\n  // map this.count to store.state.count\n  'count'\n])\n```\n\n## オブジェクトスプレッド演算子\n\n`mapState` はオブジェクトを返すことに注意しましょう。どうやって、他のローカル算出プロパティと組み合わせるのでしょうか？ 通常、最終的にひとつのオブジェクトを `computed` に渡せるように、複数のオブジェクトをひとつにマージするユーティリティを使わなければいけません。しかし、[オブジェクトスプレッド演算子](https://github.com/tc39/proposal-object-rest-spread)で、シンタックスをかなり単純にできます:\n\n```js\ncomputed: {\n  localComputed () { /* ... */ },\n  // オブジェクトスプレット演算子で、外のオブジェクトとこのオブジェクトを混ぜる\n  ...mapState({\n    // ...\n  })\n}\n```\n\n## コンポーネントはまだローカルステートを持つことできる\n\nVuex を使うということは、**全て**の状態を Vuex の中に置くべき、というわけではありません。多くの状態を Vuex に置くことで、状態の変更がさらに明示的、デバッグ可能になりますが、ときにはコードを冗長でまわりくどいものにします。状態の一部がひとつのコンポーネントだけに属している場合は、それをローカルの状態として残しておくとよいでしょう。あなたは、トレードオフを考慮した上で、あなたのアプリの開発ニーズに合った決定をすべきです。\n"
  },
  {
    "path": "docs/ja/guide/strict.md",
    "content": "# 厳格モード\n\n厳格（strict）モードを有効にするには Vuex store を作成するときに、ただ `strict: true` を指定するだけです:\n\n```js\nconst store = createStore({\n  // ...\n  strict: true\n})\n```\n\n厳格モードでは Vuex の状態がミューテーションハンドラの外部で変更されたら、エラーを投げるようになります。これで全ての状態変更がデバッギングツールで明示的に追跡できることが保証されます。\n\n## 開発環境 vs 本番環境\n\n**本番環境で厳格モードを有効にしてデプロイしてはいけません！** 厳格モードでは不適切なミューテーションを検出するためにステートツリーに対して深い監視を実行します。パフォーマンスコストを回避するために本番環境では無効にしてください。\n\nプラグインと同様に、ビルドツールに処理させることができます:\n\n```js\nconst store = createStore({\n  // ...\n  strict: process.env.NODE_ENV !== 'production'\n})\n```\n"
  },
  {
    "path": "docs/ja/guide/structure.md",
    "content": "# アプリケーションの構造\n\nVuex は実際のところ、あなたがコードを構造化する方法を制限しません。もっと正確に言うと、それより高いレベルの原理原則を適用させます:\n\n1. アプリケーションレベルの状態はストアに集約されます。\n\n2. 状態を変更する唯一の方法は、同期的に処理を行う**ミューテーション**をコミットすることのみです。\n\n3. 非同期的なロジックはカプセル化されるべきであり、それは**アクション**によって構成されます。\n\nこれらのルールに従っている限り、プロジェクトをどのように構造化するかはあなた次第です。もしストアファイルが大きくなり過ぎたら、単純にアクションやミューテーション、ゲッターをそれぞれ別のファイルに切り出すことができます。\n\nそれなりに手の込んだアプリケーションであれば、モジュールを活用する必要が出てきそうです。プロジェクトの構造の例は以下のようになります:\n\n```bash\n├── index.html\n├── main.js\n├── api\n│   └── ... # API 呼び出しを抽象化する\n├── components\n│   ├── App.vue\n│   └── ...\n└── store\n    ├── index.js          # モジュールを集めてストアをエクスポートする\n    ├── actions.js        # アクションのルートファイル\n    ├── mutations.js      # ミューテーションのルートファイル\n    └── modules\n        ├── cart.js       # cart モジュール\n        └── products.js   # products モジュール\n```\n\n参考として [Shopping Cart Example](https://github.com/vuejs/vuex/tree/4.0/examples/classic/shopping-cart) をみてみるのもよいでしょう。\n"
  },
  {
    "path": "docs/ja/guide/testing.md",
    "content": "# テスト\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cPGkpJhq\" target=\"_blank\" rel=\"noopener noreferrer\">Scrimba のレッスンを試す</a></div>\n\n私たちが Vuex でユニットテストしたい主な部分はミューテーションとアクションです。\n\n## ミューテーションのテスト\n\nミューテーションは完全に引数に依存しているだけの関数であるため、テストするのがとても簡単です。効果的なやり方として、もし ES2015 のモジュールを使っていて `store.js` ファイルの中にミューテーションがあるなら、デフォルトエクスポートに加えて、名前付きエクスポートでミューテーションをエクスポートできます。\n\n```js\nconst state = { ... }\n\n// 名前付きエクスポートでミューテーションをエクスポートする\nexport const mutations = { ... }\n\nexport default createStore({\n  state,\n  mutations\n})\n```\n\nMocha + Chai を使用してミューテーションをテストする例です（あなたの好きな任意のフレームワーク/アサーションライブラリを使用できます）:\n\n```js\n// mutations.js\nexport const mutations = {\n  increment: state => state.count++\n}\n```\n\n```js\n// mutations.spec.js\nimport { expect } from 'chai'\nimport { mutations } from './store'\n\n// ミューテーションの分割束縛\nconst { increment } = mutations\n\ndescribe('mutations', () => {\n  it('INCREMENT', () => {\n    // ステートのモック\n    const state = { count: 0 }\n    // ミューテーションを適用する\n    increment(state)\n    // 結果を検証する\n    expect(state.count).to.equal(1)\n  })\n})\n```\n\n## アクションのテスト\n\nアクションは外部の API を呼び出す可能性があるため、ミューテーションのテストよりも少し注意が必要です。アクションをテストするとき、通常、いくつかの段階でモックを作る必要があります。例えば API 呼び出しをサービスとして抽象化し、そしてテストの内部ではそのサービスをモックにすることができます。簡単に依存関係をモック化するために、webpack と [inject-loader](https://github.com/plasticine/inject-loader) を使ってテストファイルをバンドルすることができます。\n\n非同期なアクションのテストの例:\n\n```js\n// actions.js\nimport shop from '../api/shop'\n\nexport const getAllProducts = ({ commit }) => {\n  commit('REQUEST_PRODUCTS')\n  shop.getProducts(products => {\n    commit('RECEIVE_PRODUCTS', products)\n  })\n}\n```\n\n```js\n// actions.spec.js\n\n// inline loader のために require 構文を使用する\n// ここでは inject-loader を使って、モック化された依存関係を注入できるようにするモジュールファクトリーを返す\nimport { expect } from 'chai'\nconst actionsInjector = require('inject-loader!./actions')\n\n// モックによってモジュールを作成する\nconst actions = actionsInjector({\n  '../api/shop': {\n    getProducts (cb) {\n      setTimeout(() => {\n        cb([ /* レスポンスのモック */ ])\n      }, 100)\n    }\n  }\n})\n\n// 期待されるミューテーションをアクションが呼び出すかをテストするためのヘルパー\nconst testAction = (action, payload, state, expectedMutations, done) => {\n  let count = 0\n\n  // コミットをモックする\n  const commit = (type, payload) => {\n    const mutation = expectedMutations[count]\n\n    try {\n      expect(type).to.equal(mutation.type)\n      expect(payload).to.deep.equal(mutation.payload)\n    } catch (error) {\n      done(error)\n    }\n\n    count++\n    if (count >= expectedMutations.length) {\n      done()\n    }\n  }\n\n  // モック化したストアと引数でアクションを呼び出す\n  action({ commit, state }, payload)\n\n  // 呼び出されるべきミューテーションが残っていないか確認する\n  if (expectedMutations.length === 0) {\n    expect(count).to.equal(0)\n    done()\n  }\n}\n\ndescribe('actions', () => {\n  it('getAllProducts', done => {\n    testAction(actions.getAllProducts, null, {}, [\n      { type: 'REQUEST_PRODUCTS' },\n      { type: 'RECEIVE_PRODUCTS', payload: { /* レスポンスのモック */ } }\n    ], done)\n  })\n})\n```\n\nテスト環境において利用可能なスパイがあるのなら(例えば[Sinon.JS](http://sinonjs.org/))、`testAction` ヘルパーの代わりにそれらを使用できます:\n\n```js\ndescribe('actions', () => {\n  it('getAllProducts', () => {\n    const commit = sinon.spy()\n    const state = {}\n\n    actions.getAllProducts({ commit, state })\n\n    expect(commit.args).to.deep.equal([\n      ['REQUEST_PRODUCTS'],\n      ['RECEIVE_PRODUCTS', { /* レスポンスのモック */ }]\n    ])\n  })\n})\n```\n\n## ゲッターのテスト\n\nもしゲッターが複雑な計算を行っているならば、テストコードを書く価値があります。ゲッターはミューテーションと同様の理由でテストしやすいです。\n\nゲッターのテストの例:\n\n```js\n// getters.js\nexport const getters = {\n  filteredProducts (state, { filterCategory }) {\n    return state.products.filter(product => {\n      return product.category === filterCategory\n    })\n  }\n}\n```\n\n```js\n// getters.spec.js\nimport { expect } from 'chai'\nimport { getters } from './getters'\n\ndescribe('getters', () => {\n  it('filteredProducts', () => {\n    // ステートをモックする\n    const state = {\n      products: [\n        { id: 1, title: 'Apple', category: 'fruit' },\n        { id: 2, title: 'Orange', category: 'fruit' },\n        { id: 3, title: 'Carrot', category: 'vegetable' }\n      ]\n    }\n    // ゲッターをモックする\n    const filterCategory = 'fruit'\n\n    // ゲッターから結果を受け取る\n    const result = getters.filteredProducts(state, { filterCategory })\n\n    // 結果を検証する\n    expect(result).to.deep.equal([\n      { id: 1, title: 'Apple', category: 'fruit' },\n      { id: 2, title: 'Orange', category: 'fruit' }\n    ])\n  })\n})\n```\n\n## テストの実行\n\nミューテーションやアクションが適切に書かれている場合は、適切にモック化された後、テストコードはブラウザの API に直接依存関係を持つことはないでしょう。したがって、単純に webpack でテストをバンドルでき、それを直接 Node で実行できます。別の方法として、本当のブラウザでテストを実行するためには `mocha-loader` または Karma + `karma-webpack` を使用できます。\n\n### Node での実行\n\n以下のような webpack の設定を作成します（[`.babelrc`](https://babeljs.io/docs/usage/babelrc/) もあわせて使います）:\n\n```js\n// webpack.config.js\nmodule.exports = {\n  entry: './test.js',\n  output: {\n    path: __dirname,\n    filename: 'test-bundle.js'\n  },\n  module: {\n    loaders: [\n      {\n        test: /\\.js$/,\n        loader: 'babel-loader',\n        exclude: /node_modules/\n      }\n    ]\n  }\n}\n```\n\nそれから下記コマンドを実行します:\n\n``` bash\nwebpack\nmocha test-bundle.js\n```\n\n### ブラウザでの実行\n\n1. `mocha-loader` をインストールする\n2. 上記 webpack 設定から `entry` を `'mocha-loader!babel-loader!./test.js'` に変更する\n3. 設定を使用して `webpack-dev-server` を開始する\n4. ブラウザで `localhost:8080/webpack-dev-server/test-bundle` を開く\n\n### Karma + karma-webpack を使ったブラウザでの実行\n\n[vue-loader ドキュメント](https://vue-loader.vuejs.org/ja/workflow/testing.html) 内のセットアップ方法を参考にしてください。\n"
  },
  {
    "path": "docs/ja/guide/typescript-support.md",
    "content": "# TypeScript サポート\n\nVuex は型付けを提供しているので、TypeScript を使ってストア定義を書くことができます。Vuex には特別な TypeScript の設定は必要ありません。[Vue の基本的な TypeScript の設定](https://v3.ja.vuejs.org/guide/typescript-support.html) に従ってプロジェクトの設定を行ってください。\n\nしかし、Vue コンポーネントを TypeScript で書いている場合は、ストアの型付けを正しく行うために必要な手順がいくつかあります。\n\n## Vue コンポーネントでの `$store` プロパティの型付け\n\nVuex はすぐに使用できる `this.$store` プロパティの型付けを提供していません。TypeScriptと併用する場合は、独自のモジュール拡張を宣言する必要があります。\n\nプロジェクトフォルダに宣言ファイルを追加して、Vue の `ComponentCustomProperties` のカスタム型付けを宣言します。\n\n```ts\n// vuex.d.ts\nimport { ComponentCustomProperties } from 'vue'\nimport { Store } from 'vuex'\n\ndeclare module 'vue' {\n  // ストアのステートを宣言する\n  interface State {\n    count: number\n  }\n\n  // `this.$store` の型付けを提供する\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\n## `useStore` 関数の型付け\n\nComposition API で Vue コンポーネントを記述する際には、ほとんどの場合、`useStore`が型付けされたストアを返すようにしたいでしょう。`useStore` が正しく型付けされたストアを返すためには次のことが必要です。\n\n1. 型付けされた `InjectionKey` を定義する。\n2. ストアをインストールする際に、型付けされた `InjectionKey` を Vue App インスタンスに渡す。\n3. 型付けされた `InjectionKey` を `useStore` メソッドに渡す。\n\nそれでは、順を追って説明していきます。まずは、Vue の `InjectionKey` インターフェースを使って独自のストアの型定義とともにキーを定義します。\n\n```ts\n// store.ts\nimport { InjectionKey } from 'vue'\nimport { createStore, Store } from 'vuex'\n\n// ストアのステートに対して型を定義します\nexport interface State {\n  count: number\n}\n\n// インジェクションキーを定義します\nexport const key: InjectionKey<Store<State>> = Symbol()\n\nexport const store = createStore<State>({\n  state: {\n    count: 0\n  }\n})\n```\n\n次に、ストアのインストール時に定義した `InjectionKey` を Vue App インスタンスに渡します。\n\n```ts\n// main.ts\nimport { createApp } from 'vue'\nimport { store, key } from './store'\n\nconst app = createApp({ ... })\n\n// pass the injection key\napp.use(store, key)\n\napp.mount('#app')\n```\n\n最後に、このキーを `useStore` メソッドに渡すことで型付けされたストアを取得することができます。\n\n```ts\n// in a vue component\nimport { useStore } from 'vuex'\nimport { key } from './store'\n\nexport default {\n  setup () {\n    const store = useStore(key)\n\n    store.state.count // typed as number\n  }\n}\n```\n\n内部的には、Vuex は Vue の [Provide/Inject](https://v3.ja.vuejs.org/api/composition-api.html#provide-inject) 機能を使って Vue App インスタンスにストアをインストールします。これが、 `InjectionKey` によって型定義を提供できる理由です。\n\n### `useStore` 使用方法の簡略化\n\n`useStore` 関数を使うたびに `InjectionKey` をインポートして、 `useStore` へ渡さなければならないのは少し面倒かもしれません。その場合、型付けされたストアを取得する独自の関数を定義すると良いでしょう。\n\n```ts\n// store.ts\nimport { InjectionKey } from 'vue'\nimport { createStore, useStore as baseUseStore, Store } from 'vuex'\n\nexport interface State {\n  count: number\n}\n\nexport const key: InjectionKey<Store<State>> = Symbol()\n\nexport const store = createStore<State>({\n  state: {\n    count: 0\n  }\n})\n\n// 独自の `useStore` 関数を定義します\nexport function useStore () {\n  return baseUseStore(key)\n}\n```\n\nこの関数を使用することで、 `InjectionKey` とその型を提供しなくても、型付けされたストアを取得することができます。\n\n```ts\n// vue component 内\nimport { useStore } from './store'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    store.state.count // number として型付け\n  }\n}\n```\n"
  },
  {
    "path": "docs/ja/index.md",
    "content": "# Vuex とは何か？\n\n::: tip 注意\nこれは、Vue 3 で動作する Vuex 4 のためのドキュメントです。Vue 2 で動作する Vuex 3 のドキュメントをお探しの方は、[こちらをご覧ください](https://vuex.vuejs.org/ja/)。\n:::\n\nVuex は Vue.js アプリケーションのための **状態管理パターン + ライブラリ**です。\nこれは予測可能な方法によってのみ状態の変異を行うというルールを保証し、アプリケーション内の全てのコンポーネントのための集中型のストアとして機能します。\n\n## \"状態管理パターン\"とはなんですか？\n\n単純な Vue で作られたカウンターアプリをみてみましょう:\n\n```js\nconst Counter = {\n  // state\n  data () {\n    return {\n      count: 0\n    }\n  },\n  // view\n  template: `\n    <div>{{ count }}</div>\n  `,\n  // actions\n  methods: {\n    increment () {\n      this.count++\n    }\n  }\n}\n\ncreateApp(Counter).mount('#app')\n```\n\nこれはいくつかの要素をアプリ自身に含んでいます:\n\n- **状態**、これは私達のアプリを動かす信頼できる情報源(the source of truth)です。\n- **ビュー**、これは**状態**のただの宣言的なマッピングです。\n- **アクション**、これは**ビュー**からのユーザー入力に反応して、状態の変更を可能にする方法です。\n\nこれらは\"単方向データフロー\"のコンセプトの極めてシンプルな責務です:\n\n<p style=\"text-align: center; margin: 2em\">\n  <img style=\"width:100%; max-width:450px;\" src=\"/flow.png\">\n</p>\n\nしかし、単純さは、**共通の状態を共有する複数のコンポーネントを持ったときに**、すぐに破綻します:\n\n- 複数のビューが同じ状態に依存することがあります。\n- 異なるビューからのアクションで、同じ状態を変更する必要があります。\n\n一つ目は、プロパティ (props) として深く入れ子になったコンポーネントに渡すのは面倒で、兄弟コンポーネントでは単純に機能しません。二つ目は、親子のインスタンスを直接参照したり、イベントを介して複数の状態のコピーを変更、同期することを試みるソリューションに頼っていることがよくあります。これらのパターンは、いずれも脆く、すぐにメンテナンスが困難なコードに繋がります。\n\nでは、コンポーネントから共有している状態を抽出し、それをグローバルシングルトンで管理するのはどうでしょうか？ これにより、コンポーネントツリーは大きな \"ビュー\" となり、どのコンポーネントもツリー内のどこにあっても状態にアクセスしたり、アクションをトリガーできます!\n\nさらに、状態管理に関わる概念を定義、分離し、特定のルールを敷くことで、コードの構造と保守性を向上させることができます。\n\nこれが Vuex の背景にある基本的なアイディアであり、[Flux](https://facebook.github.io/flux/docs/overview)、 [Redux](http://redux.js.org/) そして [The Elm Architecture](https://guide.elm-lang.org/architecture/)から影響を受けています。\n他のパターンと異なるのは、Vuex は効率的な更新のために、Vue.js の粒度の細かいリアクティビティシステムを利用するよう特別に調整して実装されたライブラリだということです。\n\nあなたがもし対話型の方法でVuexを学びたいのであれば、[Scrimba](https://scrimba.com/g/gvuex)のVuexコースをぜひ試してみてください。\n\n![vuex](/vuex.png)\n\n## いつ、Vuexを使うべきでしょうか？\n\nVuex は、共有状態の管理に役立ちますが、さらに概念やボイラープレートのコストがかかります。これは、短期的生産性と長期的生産性のトレードオフです。\n\nもし、あなたが大規模な SPA を構築することなく、Vuex を導入した場合、冗長で気が遠くなるように感じるかもしれません。そう感じることは全く普通です。あなたのアプリがシンプルであれば、Vuex なしで問題ないでしょう。単純な [ストアパターン](https://v3.ja.vuejs.org/guide/state-management.html#simple-state-management-from-scratch) が必要なだけかもしれません。しかし、今あなたが中規模から大規模の SPA を構築しているなら、Vue コンポーネントの外の状態をもっとうまく扱えないか考えなくてはならない状況にあるかもしれません。その場合 Vuex は次のステップとして最適でしょう。これは Redux の作者、Dan Abramov からの良い引用です:\n\n> Flux ライブラリは眼鏡のようなものです: あなたが必要な時にいつでも分かるのです。\n"
  },
  {
    "path": "docs/ja/installation.md",
    "content": "# インストール\n\n## 直接ダウンロードする / CDN\n\n[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) で NPM ベースの CDN リンクが提供されています。上記リンクは常に NPM の最新のリリースを指します。`https://unpkg.com/vuex@4.0.0/dist/vuex.global.js` のような URL によって特定のバージョン/タグを利用することもできます。\n<!--/email_off-->\n\nVue のあとで `vuex` を取り込むと自動的に Vuex が導入されます:\n\n```html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vuex.js\"></script>\n```\n\n## NPM\n\n```bash\nnpm install vuex@next --save\n```\n\n## Yarn\n\n```bash\nyarn add vuex@next --save\n```\n\n## 開発版ビルド\n\n最新の開発版ビルドを利用したい場合には、 GitHub から直接クローンし `vuex` を自身でビルドする必要があります。\n\n```bash\ngit clone https://github.com/vuejs/vuex.git node_modules/vuex\ncd node_modules/vuex\nyarn\nyarn build\n```\n"
  },
  {
    "path": "docs/ptbr/api/index.md",
    "content": "---\nsidebar: auto\n---\n\n# Referência da API\n\n## Store\n\n### createStore\n\n- `createStore<S>(options: StoreOptions<S>): Store<S>`\n\n  Cria um novo _store_.\n\n  ```js\n  import { createStore } from 'vuex'\n\n  const store = createStore({ ...options })\n  ```\n\n## Opções do Construtor Store\n\n### state (estado)\n\n- type: `Object | Function`\n\n  O objeto raiz de estado para o _store_ Vuex. [Detalhes](../guide/state.md)\n\n  Se você passar uma função que retorna um objeto, o objeto retornado é usado como o estado raiz. Isso é útil quando você deseja reutilizar o objeto de estado, especialmente para reutilização de módulos. [Detalhes](../guide/modules.md#reutilizacao-do-modulo)\n\n### mutations (mutações)\n\n- type: `{ [type: string]: Function }`\n\n  Registra mutações no _store_. A função manipuladora (ou _handler_) sempre recebe _state_ como o 1º argumento (será o estado local do módulo se definido em um módulo) e receberá um 2º argumento _payload_ se houver um.\n\n  [Detalhes](../guide/mutations.md)\n\n### actions (ações)\n\n- type: `{ [type: string]: Function }`\n\n  Registra ações no _store_. A função manipuladora (ou _handler_) recebe um objeto _context_ que expõe as seguintes propriedades:\n\n  ```js\n  {\n    state,      // o mesmo que `store.state`, ou estado local se estiver em módulos\n    rootState,  // o mesmo que `store.state`, apenas em módulos\n    commit,     // o mesmo que `store.commit`\n    dispatch,   // o mesmo que `store.dispatch`\n    getters,    // o mesmo que `store.getters`, ou getters locais se estiver em módulos\n    rootGetters // o mesmo que `store.getters`, apenas em módulos\n  }\n  ```\n\n  E também recebe um 2º argumento _payload_ se houver um.\n\n  [Detalhes](../guide/actions.md)\n\n### getters\n\n- type: `{ [key: string]: Function }`\n\n  Registra os _getters_ no _store_. A função _getter_ recebe os seguintes argumentos:\n\n  ```\n  state,     // será estado local do módulo se definido em um módulo.\n  getters    // o mesmo que store.getters\n  ```\n\n  Especificamente quando definido em um módulo\n\n  ```\n  state,       // será estado local do módulo se definido em um módulo.\n  getters,     // módulo de getters locais do módulo atual.\n  rootState,   // estado global\n  rootGetters  // todos os getters\n  ```\n\n  Os _getters_ registrados estão expostos em `store.getters`.\n\n  [Detalhes](../guide/getters.md)\n\n### modules (módulos)\n\n- type: `Object`\n\n  Um objeto contendo sub módulos a serem incorporados no _store_, de forma que:\n\n  ```js\n  {\n    key: {\n      state,\n      namespaced?,\n      mutations?,\n      actions?,\n      getters?,\n      modules?\n    },\n    ...\n  }\n  ```\n\n  Cada módulo pode conter _state_ e _mutations_ semelhantes às opções raiz. O estado de um módulo será anexado ao estado da raiz do _store_ usando a chave do módulo. As mutações e _getters_ de um módulo receberão apenas o estado local do módulo como o 1º argumento em vez do estado da raiz, e as ações do módulo _context.state_ também apontarão para o estado local.\n\n  [Detalhes](../guide/modules.md)\n\n### plugins\n\n- type: `Array<Function>`\n\n  Um _Array_ de funções de plug-in a serem aplicadas no _store_. O plug-in simplesmente recebe o _store_ como o único argumento e pode ouvir mutações (para persistência de dados de saída, registro ou depuração) ou despachar mutações (para dados de entrada, por exemplo, _websockets_ ou _observables_).\n\n  [Detalhes](../guide/plugins.md)\n\n### strict\n\n- type: `boolean`\n- default: `false`\n\n  Força o _store_ Vuex a rodar mo modo estrito. No modo estrito, qualquer mutação ao estado do Vuex fora dos manipuladores de mutação acusará um erro.\n\n  [Detalhes](../guide/strict.md)\n\n### devtools\n\n- type: `boolean`\n\n  Ative ou desative o _devtools_ para uma determinada instância Vuex. Passar `false` à instância diz ao _store_ Vuex para não se integrar ao _devtools_. Bem útil quando se tem vários _stores_ em uma _single_ _page_.\n\n  ```js\n  {\n    devtools: false\n  }\n  ```\n\n## Propriedades da Instância Store\n\n### state (estado)\n\n- type: `Object`\n\n  O estado raiz. Apenas leitura.\n\n### getters\n\n- type: `Object`\n\n  Expõe os _getters_ registrados. Apenas leitura.\n\n## Métodos da Instância Store\n\n### commit\n\n-  `commit(type: string, payload?: any, options?: Object)`\n-  `commit(mutation: Object, options?: Object)`\n\n  Confirma (ou faz um _Commit_ de) uma mutação. _options_ pode ter `root: true` que permite confirmar mutações da raiz em [módulos namespaced](../guide/modules.md#namespacing). [Detalhes](../guide/mutations.md)\n\n### dispatch\n\n-  `dispatch(type: string, payload?: any, options?: Object): Promise<any>`\n-  `dispatch(action: Object, options?: Object): Promise<any>`\n\n  Despacha uma ação. _options_ pode ter `root: true` que permite despachar ações para raiz em [módulos namespaced](../guide/modules.md#namespacing). Retorna um _Promise_ que resolve todos os manipuladores de ação acionados. [Detalhes](../guide/actions.md)\n\n### replaceState\n\n-  `replaceState(state: Object)`\n\n  Substitue o estado da raiz do _store_. Use isso apenas para fins de _hydration_ / _time-travel_.\n\n### watch\n\n-  `watch(fn: Function, callback: Function, options?: Object): Function`\n\n  Visualiza de forma reativa um valor de retorno de `fn`, e chama o _callback_ para o retorno de chamada quando o valor for alterado. O `fn` recebe o estado do _store_ como o 1º argumento, e os _getters_ como o 2º argumento. Aceita um objeto de opções opcional que leva as mesmas opções que o [método vm.$watch do Vue](https://vuejs.org/v2/api/#vm-watch).\n\n  Para parar um _watch_, chame a função _unwatch_ retornada.\n\n### subscribe\n\n-  `subscribe(handler: Function, options?: Object): Function`\n\n  Assinatura para as mutações do _store_. O `manipulador` é chamado após cada mutação e recebe o descritor da mutação e o estado pós-mutação como argumentos:\n\n  ```js\n  const unsubscribe = store.subscribe((mutation, state) => {\n    console.log(mutation.type)\n    console.log(mutation.payload)\n  })\n\n  // you may call unsubscribe to stop the subscription\n  unsubscribe()\n  ```\n\n  Por padrão, o novo manipulador é adicionado ao final da cadeia, então ele será executado após outros manipuladores que foram adicionados antes. Isso pode ser sobrescrito adicionando `prepend: true` a _options_, que irá adicionar o manipulador ao início da cadeia.\n\n  ```js\n  store.subscribe(handler, { prepend: true })\n  ```\n\n  O método _subscribe_ retornará uma função _unsubscribe_, que deve ser chamada quando a assinatura não for mais necessária. Por exemplo, você pode assinar um Módulo Vuex e cancelar a assinatura ao cancelar o registro do módulo. Ou você pode chamar _subscribe_ de dentro de um componente Vue e então destruir o componente mais tarde. Nesses casos, você deve se lembrar de cancelar a assinatura manualmente.\n\n  Mais comumente usado em plugins. [Detalhes](../guide/plugins.md)\n\n### subscribeAction\n\n-  `subscribeAction(handler: Function, options?: Object): Function`\n\n  Assinatura para as ações do _store_. O `manipulador` é chamado para cada ação despachada e recebe o descritor da ação e o estado de armazenamento atual como argumentos.\n  O método _subscribe_ retornará uma função _unsubscribe_, que deve ser chamada quando a assinatura não for mais necessária. Por exemplo, ao cancelar o registro de um módulo Vuex ou antes de destruir um componente Vue.\n\n  ```js\n  const unsubscribe = store.subscribeAction((action, state) => {\n    console.log(action.type)\n    console.log(action.payload)\n  })\n\n  // you may call unsubscribe to stop the subscription\n  unsubscribe()\n  ```\n\n  Por padrão, o novo manipulador é adicionado ao final da cadeia, então ele será executado após outros manipuladores que foram adicionados antes. Isso pode ser sobrescrito adicionando `prepend: true` a _options_, que irá adicionar o manipulador ao início da cadeia.\n\n  ```js\n  store.subscribeAction(handler, { prepend: true })\n  ```\n\n  O método _subscribeAction_ retornará uma função _unsubscribe_, que deve ser chamada quando a assinatura não for mais necessária. Por exemplo, você pode assinar um Módulo Vuex e cancelar a assinatura ao cancelar o registro do módulo. Ou você pode chamar _subscribeAction_ de dentro de um componente Vue e então destruir o componente mais tarde. Nesses casos, você deve se lembrar de cancelar a assinatura manualmente.\n\n  _subscribeAction_ também pode especificar se a função manipuladora da assinatura deve ser chamada *antes* ou *depois* de um despacho de ação (o comportamento padrão é *antes*):\n\n  ```js\n  store.subscribeAction({\n    before: (action, state) => {\n      console.log(`before action ${action.type}`)\n    },\n    after: (action, state) => {\n      console.log(`after action ${action.type}`)\n    }\n  })\n  ```\n\n  _subscribeAction_ também pode especificar uma função manipuladora _error_ para capturar um erro lançado quando uma ação é despachada. A função receberá um objeto _error_ como 3º argumento.\n\n  ```js\n  store.subscribeAction({\n    error: (action, state, error) => {\n      console.log(`error action ${action.type}`)\n      console.error(error)\n    }\n  })\n  ```\n\n  O método _subscribeAction_ é mais comumente usado em plugins. [Detalhes](../guide/plugins.md)\n\n### registerModule\n\n-  `registerModule(path: string | Array<string>, module: Module, options?: Object)`\n\n  Registra um módulo dinâmico. [Detalhes](../guide/modules.md#registro-de-modulo-dinamico)\n\n  _options_ podem ter `preserveState: true` que permite preservar o estado anterior. Bem útil quando fazemos renderização do lado do servidor (_server-side-rendering_).\n\n### unregisterModule\n\n-  `unregisterModule(path: string | Array<string>)`\n\n  Cancela o registro de um módulo dinâmico. [Detalhes](../guide/modules.md#registro-de-modulo-dinamico)\n\n### hasModule\n\n- `hasModule(path: string | Array<string>): boolean`\n\n  Verifica se o módulo com o nome fornecido já foi registrado. [Detalhes](../guide/modules.md#registro-de-modulo-dinamico)\n\n### hotUpdate\n\n-  `hotUpdate(newOptions: Object)`\n\n  Faz _hot_ _swap_ de novas ações e mutações [Detalhes](../guide/hot-reload.md)\n\n## Métodos Auxiliares de Vinculação aos Componentes\n\n### mapState\n\n-  `mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  Cria dados computados do componente que retornam a subárvore do _store_ Vuex. [Detalhes](../guide/state.md#o-auxiliar-mapstate)\n\n  O 1º argumento pode ser opcionalmente uma _String_ com _namespace_. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)\n\n  O segundo objeto que compõem os argumentos pode ser uma função. `function(state: any)`\n\n### mapGetters\n\n-  `mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`\n\n  Cria dados computados do componente que retornam o valor calculado de um _getter_. [Detalhes](../guide/getters.md#o-auxiliar-mapgetters)\n\n  O 1º argumento pode ser opcionalmente uma _String_ com _namespace_. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)\n\n### mapActions\n\n-  `mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  Cria opções de métodos nos componentes que despacham uma ação. [Detalhes](../guide/actions.md#despachando-acoes-em-componentes)\n\n  O 1º argumento pode ser opcionalmente uma _String_ com _namespace_. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)\n\n  O segundo objeto que compõem os argumentos pode ser uma função. `function(dispatch: function, ...args: any[])`\n\n### mapMutations\n\n-  `mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  Cria opções de métodos nos componentes que confirmam (ou fazem um _commit_ de) uma mutação. [Detalhes](../guide/mutations.md#confirmando-ou-fazendo-commits-de-mutacoes-em-componentes)\n\n  O 1º argumento pode ser opcionalmente uma _String_ com _namespace_. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)\n\n  O segundo objeto que compõem os argumentos pode ser uma função. `function(commit: function, ...args: any[])`\n\n### createNamespacedHelpers\n\n-  `createNamespacedHelpers(namespace: string): Object`\n\n  Cria métodos auxiliares de componentes vinculados por um nome. O objeto retornado conterá `mapState`, `mapGetters`, `mapActions` e `mapMutations`, que estão vinculados ao _namespace_ fornecido. [Detalhes](../guide/modules.md#vinculando-metodos-auxiliares-com-namespace)\n\n## Funções de Composição\n\n### useStore\n\n- `useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;`\n\n  Busca o _store_ injetado quando chamado dentro do gatilho (ou _hook_) _setup_. Ao usar a API de composição, você pode recuperar o _store_ chamando este método.\n\n  ```js\n  import { useStore } from 'vuex'\n\n  export default {\n    setup () {\n      const store = useStore()\n    }\n  }\n  ```\n\n  Os usuários do TypeScript podem usar uma _injection_ _key_ para recuperar um _store_ tipado. Para que isso funcione, você deve definir a _injection_ _key_ e passá-la junto com o _store_ ao instalar a instância do _store_ na aplicação Vue.\n\n  Primeiro, declare a _injection_ _key_ usando a interface `InjectionKey` do Vue.\n\n  ```ts\n  // store.ts\n  import { InjectionKey } from 'vue'\n  import { createStore, Store } from 'vuex'\n\n  export interface State {\n    count: number\n  }\n\n  export const key: InjectionKey<Store<State>> = Symbol()\n\n  export const store = createStore<State>({\n    state: {\n      count: 0\n    }\n  })\n  ```\n\n  Então, passe a _key_ definida como o 2º argumento para o método `app.use`.\n\n  ```ts\n  // main.ts\n  import { createApp } from 'vue'\n  import { store, key } from './store'\n\n  const app = createApp({ ... })\n\n  app.use(store, key)\n\n  app.mount('#app')\n  ```\n\n  Finalmente, você pode passar a _key_ para o método _useStore_ para recuperar a instância tipada do _store_.\n\n  ```ts\n  // no componente vue\n  import { useStore } from 'vuex'\n  import { key } from './store'\n\n  export default {\n    setup () {\n      const store = useStore(key)\n\n      store.state.count // tipado como número\n    }\n  }\n  ```\n"
  },
  {
    "path": "docs/ptbr/guide/actions.md",
    "content": "# Actions\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c6ggR3cG\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nAs ações são semelhantes às mutações, as diferenças são as seguintes:\n\n- Em vez de mudar o estado, as ações confirmam (ou fazem _commit_ de) mutações.\n- As ações podem conter operações assíncronas arbitrárias.\n\nVamos registrar uma ação simples:\n\n``` js\nconst store = createStore({\n  state: {\n    count: 0\n  },\n  mutations: {\n    increment (state) {\n      state.count++\n    }\n  },\n  actions: {\n    increment (context) {\n      context.commit('increment')\n    }\n  }\n})\n```\n\nAs funções manipuladoras de ação recebem um objeto _context_ que expõe o mesmo conjunto de métodos/propriedades na instância do _store_, para que você possa chamar `context.commit` para confirmar uma mutação ou acessar o estado e os _getters_ através do `context.state` e do `context.getters`. Podemos até chamar outras ações com `context.dispatch`. Veremos por que esse objeto _context_ não é a própria instância do _store_ quando apresentarmos [Módulos](modules.md) mais tarde.\n\nNa prática, muitas vezes usamos ES2015 [desestruturação de argumentos](https://github.com/lukehoban/es6features#destructuring) para simplificar um pouco o código (especialmente quando precisamos usar _commit_ várias vezes):\n\n``` js\nactions: {\n  increment ({ commit }) {\n    commit('increment')\n  }\n}\n```\n\n## Despachando Ações\n\nAs ações são disparadas com o método `store.dispatch`:\n\n``` js\nstore.dispatch('increment')\n```\n\nIsso pode parecer óbvio à primeira vista: se quisermos incrementar a contagem, por que não chamamos `store.commit('increment')` diretamente? Você se lembra que **as mutações devem ser síncronas**? As ações não. Podemos executar operações **assíncronas** dentro de uma ação:\n\n``` js\nactions: {\n  incrementAsync ({ commit }) {\n    setTimeout(() => {\n      commit('increment')\n    }, 1000)\n  }\n}\n```\n\nAs ações suportam o mesmo formato de _payload_ e despacho estilo-objeto:\n\n``` js\n// despacho com payload\nstore.dispatch('incrementAsync', {\n  amount: 10\n})\n\n// despacho com objeto\nstore.dispatch({\n  type: 'incrementAsync',\n  amount: 10\n})\n```\n\nUm exemplo mais prático de ações reais seria uma ação para fazer _checkout_ de um carrinho de compras, que envolve **chamar uma API assíncrona** e **confirmar múltiplas mutações**:\n\n``` js\nactions: {\n  checkout ({ commit, state }, products) {\n    // salva os itens que estão no carrinho\n    const savedCartItems = [...state.cart.added]\n    // enviar solicitação de checkout e com otimismo\n    // limpa o carrinho\n    commit(types.CHECKOUT_REQUEST)\n    // a API da loja aceita um callback de sucesso e um callback de falha\n    shop.buyProducts(\n      products,\n      // callback em caso de sucesso\n      () => commit(types.CHECKOUT_SUCCESS),\n      // callback em caso de falha\n      () => commit(types.CHECKOUT_FAILURE, savedCartItems)\n    )\n  }\n}\n```\n\nObserve que estamos realizando um fluxo de operações assíncronas, e gravando os efeitos colaterais (mutações de estado) da ação confirmando-os (ou fazendo _commit_ deles).\n\n## Despachando Ações em Componentes\n\nVocê pode despachar ações em componentes com `this.$store.dispatch('xxx')`, ou usar o auxiliar _mapActions_ que mapeia métodos do componente para chamadas do `store.dispatch` (esta ação requer a injeção do _store_ na instância raiz):\n\n``` js\nimport { mapActions } from 'vuex'\n\nexport default {\n  // ...\n  methods: {\n    ...mapActions([\n      'increment', // mapeia `this.increment()` para `this.$store.dispatch('increment')`\n\n      // `mapActions` também suporta payloads:\n      'incrementBy' // mapeia `this.incrementBy(amount)` para `this.$store.dispatch('incrementBy', amount)`\n    ]),\n    ...mapActions({\n      add: 'increment' // mapeia `this.add()` para `this.$store.dispatch('increment')`\n    })\n  }\n}\n```\n\n## Composição de Ações\n\nAs ações geralmente são assíncronas, então como sabemos quando uma ação é realizada? E mais importante, como podemos compor ações múltiplas em conjunto para lidar com fluxos assíncronos mais complexos?\n\nA primeira coisa a saber é que o `store.dispatch` pode manipular a _Promise_ retornada pela função manipuladora de ação acionada que também retorna _Promise_:\n\n``` js\nactions: {\n  actionA ({ commit }) {\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        commit('someMutation')\n        resolve()\n      }, 1000)\n    })\n  }\n}\n```\n\nAgora você pode fazer:\n\n``` js\nstore.dispatch('actionA').then(() => {\n  // ...\n})\n```\n\nE também em outra ação:\n\n``` js\nactions: {\n  // ...\n  actionB ({ dispatch, commit }) {\n    return dispatch('actionA').then(() => {\n      commit('someOtherMutation')\n    })\n  }\n}\n```\n\nFinalmente, se fizermos uso de [async / await](https://tc39.github.io/ecmascript-asyncawait/), podemos compor nossas ações desta maneira:\n\n``` js\n// assumindo que `getData()` e `getOtherData()` retornam Promises\n\nactions: {\n  async actionA ({ commit }) {\n    commit('gotData', await getData())\n  },\n  async actionB ({ dispatch, commit }) {\n    await dispatch('actionA') // espera que `actionA` termine\n    commit('gotOtherData', await getOtherData())\n  }\n}\n```\n\n> É possível para um `store.dispatch` disparar várias funções manipuladoras de ação em diferentes módulos. Neste caso, o valor retornado será uma _Promise_ que se resolve quando todas as outras funções manipuladoras disparadas forem resolvidas.\n"
  },
  {
    "path": "docs/ptbr/guide/composition-api.md",
    "content": "# API de Composição (ou Composition API)\n\nPara acessar o _store_ dentro do gatilho (ou _hook_) `setup`, você pode chamar a função `useStore`. Isso é o equivalente a recuperar `this.$store` dentro de um componente usando a API de Opções (ou _Option_ API).\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n  }\n}\n```\n\n## Acessando Estado e Getters\n\nPara acessar o estado e os _getters_, você deve criar referências `computed` para reter a reatividade. Isso é o equivalente a criar dados computados usando a API de Opções (ou _Option_ API).\n\n```js\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      // acessar um estado em uma função de dados computados\n      count: computed(() => store.state.count),\n\n      // acessar um getter em uma função de dados computados\n      double: computed(() => store.getters.double)\n    }\n  }\n}\n```\n\n## Acessando Mutações e Ações\n\nAo acessar mutações e ações, você pode simplesmente fornecer as funções `commit` e `dispatch` dentro do gatilho (ou _hook_) `setup`.\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      // acessa uma mutação\n      increment: () => store.commit('increment'),\n\n      // acessa uma ação\n      asyncIncrement: () => store.dispatch('asyncIncrement')\n    }\n  }\n}\n```\n\n## Exemplos\n\nConfira o [exemplo da API de Composição](https://github.com/vuejs/vuex/tree/4.0/examples/composition) para ver exemplos de aplicações que utilizam Vuex e a API de Composição (ou _Composition_ API) do Vue.\n"
  },
  {
    "path": "docs/ptbr/guide/forms.md",
    "content": "# Manipulação de Formulários\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKRgEC9\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nAo usar o Vuex no modo estrito, pode ser um pouco complicado usar `v-model` em um pedaço do estado que pertence ao Vuex:\n\n``` html\n<input v-model=\"obj.message\">\n```\n\nAssumindo que `obj` é um dado computado que retorna um Objeto do _store_, o `v-model` aqui tentará alterar diretamente o `obj.message` quando o usuário digitar alguma coisa. No modo estrito, isso resultará em um erro porque a mutação não é executada dentro de uma função explícita manipuladora de mutação do Vuex.\n\n\nO \"modo Vuex\" de lidar com isso é vinculando o valor do(s) `<input>`'s e chamar uma ação no evento _input_ ou _change_:\n\n``` html\n<input :value=\"message\" @input=\"updateMessage\">\n```\n\n``` js\n// ...\ncomputed: {\n  ...mapState({\n    message: state => state.obj.message\n  })\n},\nmethods: {\n  updateMessage (e) {\n    this.$store.commit('updateMessage', e.target.value)\n  }\n}\n```\n\nE aqui está a função manipuladora de mutação:\n\n``` js\n// ...\nmutations: {\n  updateMessage (state, message) {\n    state.obj.message = message\n  }\n}\n```\n\n## Dados Computados Bidirecionais (Two-way)\n\nÉ certo que o código acima é um pouco mais verboso do que o `v-model` + estado local, e também perdemos alguns dos recursos úteis do `v-model`. Uma abordagem alternativa é usar um dado computado bidirecional com um _setter_:\n\n``` html\n<input v-model=\"message\">\n```\n\n``` js\n// ...\ncomputed: {\n  message: {\n    get () {\n      return this.$store.state.obj.message\n    },\n    set (value) {\n      this.$store.commit('updateMessage', value)\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/ptbr/guide/getters.md",
    "content": "# Getters\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c2Be7TB\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nÀs vezes, talvez precisemos calcular o estado derivado com base no estado do _store_, por exemplo, filtrar através de uma lista de itens e contá-los:\n\n``` js\ncomputed: {\n  doneTodosCount () {\n    return this.$store.state.todos.filter(todo => todo.done).length\n  }\n}\n```\n\nSe mais do que um componente precisa fazer uso disso, temos que duplicar a função, ou extraí-lo em um auxiliar compartilhado e importá-lo em vários lugares - ambos são menos do que o ideal.\n\nO Vuex nos permite definir _getters_ no _store_. Você pode pensar neles como dados computados para os _stores_. Como os dados computados, o resultado de um _getter_ é armazenado em _cache_ com base em suas dependências e só será reavaliado quando algumas de suas dependências forem alteradas.\n\nOs _getters_ receberão o estado como 1º argumento:\n\n``` js\nconst store = createStore({\n  state: {\n    todos: [\n      { id: 1, text: '...', done: true },\n      { id: 2, text: '...', done: false }\n    ]\n  },\n  getters: {\n    doneTodos (state) {\n      return state.todos.filter(todo => todo.done)\n    }\n  }\n})\n```\n\n## Acesso Estilo-Propriedade\n\nOs _getters_ serão expostos no objeto `store.getters` e você acessa valores como propriedades:\n\n``` js\nstore.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]\n```\n\nOs _getters_ também recebem outros _getters_ como o 2º argumento:\n\n``` js\ngetters: {\n  // ...\n  doneTodosCount (state, getters) {\n    return getters.doneTodos.length\n  }\n}\n```\n\n``` js\nstore.getters.doneTodosCount // -> 1\n```\n\nAgora podemos usar facilmente isso dentro de qualquer componente:\n\n``` js\ncomputed: {\n  doneTodosCount () {\n    return this.$store.getters.doneTodosCount\n  }\n}\n```\n\nObserve que os _getters_ acessados ​​como propriedades são armazenados em _cache_ como parte do sistema de reatividade do Vue.\n\n## Acesso Estilo-Método\n\nVocê também pode passar argumentos para os _getters_ retornando uma função. Isso é particularmente útil quando você deseja consultar um _Array_ no _store_:\n\n```js\ngetters: {\n  // ...\n  getTodoById: (state) => (id) => {\n    return state.todos.find(todo => todo.id === id)\n  }\n}\n```\n\n``` js\nstore.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }\n```\n\nObserve que os _getters_ acessados ​​via métodos serão executados toda vez que você os chamar, e o resultado não será armazenado em _cache_.\n\n## O Auxiliar `mapGetters`\n\nO auxiliar _mapGetters_ simplesmente mapeia os _getters_ do _store_ para os dados computados locais:\n\n``` js\nimport { mapGetters } from 'vuex'\n\nexport default {\n  // ...\n  computed: {\n    // mistura os getters nos dados computatos com o operador spread\n    ...mapGetters([\n      'doneTodosCount',\n      'anotherGetter',\n      // ...\n    ])\n  }\n}\n```\n\nSe você deseja mapear um _getter_ com um nome diferente, use um objeto:\n\n``` js\n...mapGetters({\n  // mapeia `this.doneCount` para `this.$store.getters.doneTodosCount`\n  doneCount: 'doneTodosCount'\n})\n```\n"
  },
  {
    "path": "docs/ptbr/guide/hot-reload.md",
    "content": "# Hot Reloading (Recarregamento Rápido)\n\nO Vuex suporta _hot-reloading_ de mutações, módulos, ações e _getters_ durante o desenvolvimento, utilizando o _webpack_ [Hot Module Replacement API](https://webpack.js.org/guides/hot-module-replacement/). Você também pode usá-lo no Browserify com o _plugin_ [browserify-hmr](https://github.com/AgentME/browserify-hmr/).\n\nPara mutações e módulos, você precisa usar o método da API `store.hotUpdate()`:\n\n``` js\n// store.js\nimport { createStore } from 'vuex'\nimport mutations from './mutations'\nimport moduleA from './modules/a'\n\nconst state = { ... }\n\nconst store = createStore({\n  state,\n  mutations,\n  modules: {\n    a: moduleA\n  }\n})\n\nif (module.hot) {\n  // aceita ações e mutações como 'hot modules'\n  module.hot.accept(['./mutations', './modules/a'], () => {\n    // requer os módulos atualizados\n    // tem que adicionar .default aqui devido à saída do módulo babel 6\n    const newMutations = require('./mutations').default\n    const newModuleA = require('./modules/a').default\n    // troca nas novas ações e mutações\n    store.hotUpdate({\n      mutations: newMutations,\n      modules: {\n        a: newModuleA\n      }\n    })\n  })\n}\n```\n\nConfira o [counter-hot example](https://github.com/vuejs/vuex/tree/main/examples/counter-hot) para brincar com o _hot-reload_.\n\n## Módulo dinâmico de hot reloading\n\nSe você usa exclusivamente módulos, você pode usar `require.context` para carregar e recarregar todos os módulos dinamicamente.\n\n```js\n// store.js\nimport { createStore } from 'vuex'\n\n// Carrega todos os módulos.\nfunction loadModules() {\n  const context = require.context(\"./modules\", false, /([a-z_]+)\\.js$/i)\n\n  const modules = context\n    .keys()\n    .map((key) => ({ key, name: key.match(/([a-z_]+)\\.js$/i)[1] }))\n    .reduce(\n      (modules, { key, name }) => ({\n        ...modules,\n        [name]: context(key).default\n      }),\n      {}\n    )\n\n  return { context, modules }\n}\n\nconst { context, modules } = loadModules()\n\nconst store = createStore({\n  modules\n})\n\nif (module.hot) {\n  // Hot reload sempre que qualquer módulo for alterado.\n  module.hot.accept(context.id, () => {\n    const { modules } = loadModules()\n\n    store.hotUpdate({\n      modules\n    })\n  })\n}\n```\n"
  },
  {
    "path": "docs/ptbr/guide/index.md",
    "content": "# Começando\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cMPa2Uk\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nNo centro de cada aplicação Vuex existe o **_store_**. Um \"_store_\" é basicamente um contêiner que mantém o **estado** da sua aplicação. Há duas coisas que tornam um _store_ Vuex diferente de um objeto global simples:\n\n1. Os _stores_ Vuex são reativos. Quando os componentes do Vue obtêm o estado dele, eles atualizarão de forma reativa e eficiente se o estado do _store_ mudar.\n\n2. Você não pode alterar diretamente os estados do _store_. A única maneira de mudar o estado de um _store_ é explicitamente **confirmando (ou fazendo _commit_ de) mutações**. Isso garante que cada mudança de estado deixe um registro rastreável, e permite ferramentas que nos ajudem a entender melhor nossas aplicações.\n\n## Um Store Bem Simples\n\n:::tip NOTE\nVamos usar a sintaxe ES2015 para exemplos de código para o resto da documentação. Se você ainda não aprendeu como usá-la, [veja aqui](https://babeljs.io/docs/learn-es2015/)!\n:::\n\nApós [instalar](../installation.md)  o Vuex, vamos criar um _store_. É bem simples - basta fornecer um objeto de estado inicial, e algumas mutações:\n\n```js\nimport { createApp } from 'vue'\nimport { createStore } from 'vuex'\n\n// Cria uma nova instância do store.\nconst store = createStore({\n  state () {\n    return {\n      count: 1\n    }\n  }\n})\n\nconst app = createApp({ /* seu componente raiz */ })\n\n// Instale a instância do store como um plugin\napp.use(store)\n```\n\nAgora, você pode acessar o objeto de estado como `store.state` e acionar uma mudança de estado com o método `store.commit`:\n\n```js\nstore.commit('increment')\n\nconsole.log(store.state.count) // -> 1\n```\n\nEm um componente Vue, você pode acessar o _store_ como `this.$store`. Agora podemos confirmar (ou fazer _commit_ de) uma mutação usando um método de componente:\n\n```js\nmethods: {\n  increment() {\n    this.$store.commit('increment')\n    console.log(this.$store.state.count)\n  }\n}\n```\n\nNovamente, a razão pela qual estamos confirmando (ou fazendo _commit_ de) uma mutação em vez de mudar `store.state.count` diretamente, é porque queremos rastreá-la explicitamente. Esta convenção simples torna sua intenção mais explícita, para que você possa raciocinar melhor sobre as mudanças de estado em sua aplicação ao ler o código. Além disso, isso nos dá a oportunidade de implementar ferramentas que podem registrar cada mutação, capturar momentos do estado ou mesmo realizar depuração viajando pelo histórico de estado (_time travel_).\n\nUsar o estado do _store_ em um componente simplesmente envolve o retorno do estado dentro de um dado computado, porque o estado do _store_ é reativo. Acionar alterações simplesmente significa confirmar (ou fazer _commit_ de) mutações nos métodos dos componentes.\n\nA seguir, discutiremos cada conceito básico em detalhes muito mais sutis, começando com [Estado](state.md).\n"
  },
  {
    "path": "docs/ptbr/guide/migrating-to-4-0-from-3-x.md",
    "content": "# Migrando para versão 4.0 da versão 3.x\n\nQuase todas as APIs do Vuex 4 permaneceram inalteradas desde o Vuex 3. No entanto, ainda existem algumas mudanças importantes que você deve corrigir.\n\n- [Alterações Importantes](#alteracoes-importantes)\n  - [Processo de instalação](#processo-de-instalacao)\n  - [Suporte ao TypeScript](#suporte-ao-typescript)\n  - [Os pacotes agora estão alinhados com Vue 3](#os-pacotes-agora-estao-alinhados-com-vue-3)\n  - [A função \"createLogger\" é exportada do módulo principal](#a-funcao-createlogger-e-exportada-do-modulo-principal)\n- [Novas Características](#novas-caracteristicas)\n  - [Nova função de composição \"useStore\"](#nova-funcao-de-composicao-usestore)\n\n## Alterações Importantes\n\n### Processo de instalação\n\nPara alinhar com o novo processo de inicialização do Vue 3, o processo de instalação do Vuex mudou. Para criar um novo _store_, os usuários agora são incentivados a usar a função createStore recém-introduzida.\n\n```js\nimport { createStore } from 'vuex'\n\nexport const store = createStore({\n  state () {\n    return {\n      count: 1\n    }\n  }\n})\n```\n\nPara instalar Vuex em uma instância Vue, passe o `store` em vez do Vuex.\n\n```js\nimport { createApp } from 'vue'\nimport { store } from './store'\nimport App from './App.vue'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n```\n\n:::tip NOTE\nEmbora esta não seja tecnicamente uma alteração importante, você ainda pode usar a sintaxe `new Store(...)`, recomendamos esta abordagem para alinhar com Vue 3 e Vue Router Next.\n:::\n\n### Suporte ao TypeScript\n\nVuex 4 remove suas tipagens globais para `this.$store` dentro de um componente Vue para resolver essa [issue #994](https://github.com/vuejs/vuex/issues/994). Quando usado com TypeScript, você deve declarar seu próprio _module_ _augmentation_.\n\nColoque o seguinte código em seu projeto para permitir que `this.$store` seja tipado corretamente:\n\n```ts\n// vuex-shim.d.ts\n\nimport { ComponentCustomProperties } from 'vue'\nimport { Store } from 'vuex'\n\ndeclare module 'vue' {\n  // Declare seus próprios estados do store\n  interface State {\n    count: number\n  }\n\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\nVocê pode aprender mais na seção [Suporte ao TypeScript](./typescript-support).\n\n### Os pacotes agora estão alinhados com Vue 3\n\nOs seguintes pacotes são gerados para se alinhar aos pacotes Vue 3:\n\n- `vuex.global(.prod).js`\n  - Para uso direto com `<script src=\"...\">` no navegador. Expõe o Vuex global.\n  - A distribuição (ou _build_) global é construída como IIFE, e não UMD, e destina-se apenas ao uso direto com `<script src=\"...\">`.\n  - Contém branches chumbadas no código (ou _hard-coded_) de prod/dev e a compilação de prod é pré-minificada. Use os arquivos `.prod.js` para produção.\n- `vuex.esm-browser(.prod).js`\n  - Para uso com importações de módulo ES nativo (incluindo navegadores de suporte de módulo via `<script type=\"module\">`.\n- `vuex.esm-bundler.js`\n  - Para uso com empacotadores como `webpack`, `rollup` e `parcel`.\n  - Deixa os branches de prod/dev com os guardas de tipo `process.env.NODE_ENV` (deve ser substituído pelo empacotador).\n  - Não envia distribuições (ou _builds_) minificados (para ser feito junto com o resto do código após o empacotamento).\n- `vuex.cjs.js`\n  - Para uso em renderização do lado do servidor (_server-side_ _rendering_) no Node.js com `require()`.\n\n### A função `createLogger` é exportada do módulo principal\n\nNo Vuex 3, a função `createLogger` foi exportada de `vuex/dist/logger`, mas agora está incluída no pacote principal. A função deve ser importada diretamente do pacote `vuex`.\n\n```js\nimport { createLogger } from 'vuex'\n```\n\n## Novas Características\n\n### Nova função de composição `useStore`\n\nVuex 4 apresenta uma nova API para interagir com o _store_ na API de composição (ou _Composition_ API). Você pode usar a função de composição `useStore` para recuperar o _store_ dentro do gatilho (ou _hook_) `setup` do componente.\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n  }\n}\n```\n\nVocê pode aprender mais na seção [API de Composição](./composition-api).\n"
  },
  {
    "path": "docs/ptbr/guide/modules.md",
    "content": "# Módulos\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKK4psq\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nDevido ao uso de uma única árvore de estado, todos os estados da nossa aplicação estão contidos dentro de um grande objeto. No entanto, à medida que nossa aplicação cresce em escala, o _store_ pode ficar realmente inchado.\n\nPara ajudar com isso, o Vuex nos permite dividir nosso _store_ em **módulos**. Cada módulo pode conter seu próprio estado, mutações, ações, _getters_ e até módulos aninhados - o padrão se repete em todo o fluxo abaixo:\n\n```js\nconst moduleA = {\n  state: () => ({ ... }),\n  mutations: { ... },\n  actions: { ... },\n  getters: { ... }\n}\n\nconst moduleB = {\n  state: () => ({ ... }),\n  mutations: { ... },\n  actions: { ... }\n}\n\nconst store = createStore({\n  modules: {\n    a: moduleA,\n    b: moduleB\n  }\n})\n\nstore.state.a // -> `moduleA`'s state\nstore.state.b // -> `moduleB`'s state\n```\n\n## Estado Local do Módulo\n\nDentro das mutações e _getters_ de um módulo, o 1º argumento recebido será **o estado local do módulo**.\n\n```js\nconst moduleA = {\n  state: () => ({\n    count: 0\n  }),\n  mutations: {\n    increment (state) {\n      // `state` é o estado local do módulo\n      state.count++\n    }\n  },\n  getters: {\n    doubleCount (state) {\n      return state.count * 2\n    }\n  }\n}\n```\n\nDa mesma forma, dentro das ações do módulo, `context.state` irá expor o estado local, e o estado raiz será exposto como `context.rootState`:\n\n```js\nconst moduleA = {\n  // ...\n  actions: {\n    incrementIfOddOnRootSum ({ state, commit, rootState }) {\n      if ((state.count + rootState.count) % 2 === 1) {\n        commit('increment')\n      }\n    }\n  }\n}\n```\n\nAlém disso, dentro do módulo _getters_, o estado raiz será exibido como seu 3º argumento:\n\n```js\nconst moduleA = {\n  // ...\n  getters: {\n    sumWithRootCount (state, getters, rootState) {\n      return state.count + rootState.count\n    }\n  }\n}\n```\n\n## Namespacing\n\nPor padrão, ações, mutações e _getters_ dentro dos módulos ainda são registrados sob o **_namespace_ global** - isso permite que vários módulos reajam ao mesmo tipo de ação/mutação.\n\nSe você quer que seus módulos sejam mais independentes ou reutilizáveis, você pode usá-los com _namespaces_ através do `namespaced: true`. Quando o módulo é registrado, todos os _getters_, ações e mutações terão automaticamente o _namespace_ com base no caminho no qual o módulo está registrado. Por exemplo:\n\n```js\nconst store = createStore({\n  modules: {\n    account: {\n      namespaced: true,\n\n      // recursos do módulo\n      state: () => ({ ... }), // o estado do módulo já está aninhado e não é afetado pela opção namespace\n      getters: {\n        isAdmin () { ... } // -> getters['account/isAdmin']\n      },\n      actions: {\n        login () { ... } // -> dispatch('account/login')\n      },\n      mutations: {\n        login () { ... } // -> commit('account/login')\n      },\n\n      // módulos aninhados\n      modules: {\n        // herda o namespace do módulo pai\n        myPage: {\n          state: () => ({ ... }),\n          getters: {\n            profile () { ... } // -> getters['account/profile']\n          }\n        },\n\n        // aninhar ainda mais o namespace\n        posts: {\n          namespaced: true,\n\n          state: () => ({ ... }),\n          getters: {\n            popular () { ... } // -> getters['account/posts/popular']\n          }\n        }\n      }\n    }\n  }\n})\n```\n\nOs _getters_ e as ações com _namespace_ receberão `getters`, `dispatch` e `commit` localizados. Em outras palavras, você pode usar os recursos do módulo sem escrever prefixo no mesmo módulo. Alternar entre com _namespace_ ou não, não afeta o código dentro do módulo.\n\n### Acessando Recursos Globais em Módulos com Namespaces\n\nSe você quiser usar estado global e _getters_, `rootState` e `rootGetters` são passados como o 3º e 4º argumentos para funções _getter_, e também expostos como propriedades no objeto `context` passado para funções de ação.\n\nPara despachar ações ou confirmar (ou fazer um _commit_ de) mutações no _namespace_ global, passe `{root: true}` como o 3º argumento para `dispatch` e `commit`.\n\n```js\nmodules: {\n  foo: {\n    namespaced: true,\n\n    getters: {\n      // `getters` está localizado nos getters deste módulo\n      // você pode usar rootGetters como 4º argumento de getters\n      someGetter (state, getters, rootState, rootGetters) {\n        getters.someOtherGetter // -> 'foo/someOtherGetter'\n        rootGetters.someOtherGetter // -> 'someOtherGetter'\n        rootGetters['bar/someOtherGetter'] // -> 'bar/someOtherGetter'\n      },\n      someOtherGetter: state => { ... }\n    },\n\n    actions: {\n      // dispatch e commit também estão localizados para este módulo\n      // eles aceitarão a opção `root` para o dispatch/commit raiz\n      someAction ({ dispatch, commit, getters, rootGetters }) {\n        getters.someGetter // -> 'foo/someGetter'\n        rootGetters.someGetter // -> 'someGetter'\n        rootGetters['bar/someGetter'] // -> 'bar/someGetter'\n\n        dispatch('someOtherAction') // -> 'foo/someOtherAction'\n        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'\n\n        commit('someMutation') // -> 'foo/someMutation'\n        commit('someMutation', null, { root: true }) // -> 'someMutation'\n      },\n      someOtherAction (ctx, payload) { ... }\n    }\n  }\n}\n```\n\n### Registrar Ação Global em Módulos com Namespaces\n\nSe você quiser registrar ações globais em módulos com _namespaces_, você pode marcá-lo com `root: true` e colocar a definição de ação na função `handler`. Por exemplo:\n\n```js\n{\n  actions: {\n    someOtherAction ({dispatch}) {\n      dispatch('someAction')\n    }\n  },\n  modules: {\n    foo: {\n      namespaced: true,\n\n      actions: {\n        someAction: {\n          root: true,\n          handler (namespacedContext, payload) { ... } // -> 'someAction'\n        }\n      }\n    }\n  }\n}\n```\n\n### Vinculando Métodos Auxiliares com Namespace\n\nAo vincular um módulo com _namespace_ aos componentes com os auxiliares `mapState`, `mapGetters`, `mapActions` e `mapMutations`, ele pode ficar um pouco verboso:\n\n```js\ncomputed: {\n  ...mapState({\n    a: state => state.some.nested.module.a,\n    b: state => state.some.nested.module.b\n  }),\n  ...mapGetters([\n    'some/nested/module/someGetter', // -> this['some/nested/module/someGetter']\n    'some/nested/module/someOtherGetter', // -> this['some/nested/module/someOtherGetter']\n  ])\n},\nmethods: {\n  ...mapActions([\n    'some/nested/module/foo', // -> this['some/nested/module/foo']()\n    'some/nested/module/bar' // -> this['some/nested/module/bar']()\n  ])\n}\n```\n\nNesses casos, você pode passar a _String_ do _namespace_ do módulo como o 1º argumento para os métodos auxiliares, de modo que todas as ligações sejam feitas usando esse módulo como o contexto. O acima pode ser simplificado para:\n\n```js\ncomputed: {\n  ...mapState('some/nested/module', {\n    a: state => state.a,\n    b: state => state.b\n  }),\n  ...mapGetters('some/nested/module', [\n    'someGetter', // -> this.someGetter\n    'someOtherGetter', // -> this.someOtherGetter\n  ])\n},\nmethods: {\n  ...mapActions('some/nested/module', [\n    'foo', // -> this.foo()\n    'bar' // -> this.bar()\n  ])\n}\n```\n\nAlém disso, você pode criar métodos auxiliares com _namespace_ usando `createNamespacedHelpers`. Ele retorna um objeto com novos métodos auxiliares dos componentes vinculados ao valor do _namespace_ fornecido:\n\n```js\nimport { createNamespacedHelpers } from 'vuex'\n\nconst { mapState, mapActions } = createNamespacedHelpers('some/nested/module')\n\nexport default {\n  computed: {\n    // procura em `some/nested/module`\n    ...mapState({\n      a: state => state.a,\n      b: state => state.b\n    })\n  },\n  methods: {\n    // procura em `some/nested/module`\n    ...mapActions([\n      'foo',\n      'bar'\n    ])\n  }\n}\n```\n\n### Advertência para Desenvolvedores de Plug-ins\n\nVocê pode se preocupar com _namespacing_ imprevisível para seus módulos ao criar um [plugin] (plugins.md) que fornece os módulos e permite que os usuários os adicionem a um _store_ Vuex. Seus módulos também terão _namespaces_ se os usuários do _plugin_ adicionarem seus módulos em um módulo com _namespace_. Para se adaptar a essa situação, pode ser necessário receber um valor de _namespace_ por meio das opções do seu _plugin_:\n\n```js\n// obtem valor do namespace via opção do plugin\n// e retorna a função plugin do Vuex\nexport function createPlugin (options = {}) {\n  return function (store) {\n    // adiciona namespace aos tipos de módulos do plugin\n    const namespace = options.namespace || ''\n    store.dispatch(namespace + 'pluginAction')\n  }\n}\n```\n\n## Registro de Módulo Dinâmico\n\nVocê pode registrar um módulo **após** o _store_ ser criado com o método `store.registerModule`:\n\n```js\nimport { createStore } from 'vuex'\n\nconst store = createStore({ /* options */ })\n\n// registra um módulo `myModule`\nstore.registerModule('myModule', {\n  // ...\n})\n\n// registra um módulo aninhado `nested/myModule`\nstore.registerModule(['nested', 'myModule'], {\n  // ...\n})\n```\n\nOs estados do módulo serão expostos como `store.state.myModule` e `store.state.nested.myModule`.\n\nO registro de módulo dinâmico possibilita que outros _plugins_ Vue aproveitem também o Vuex para gerenciamento de estado, anexando um módulo ao _store_ da aplicação. Por exemplo, a biblioteca [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) integra o vue-router com o vuex gerenciando o estado da rota da aplicação em um módulo conectado dinamicamente.\n\nVocê também pode remover um módulo dinamicamente registrado com o `store.unregisterModule(moduleName)`. Note que você não pode remover módulos estáticos (declarados na criação do _store_) com este método.\n\nObserve que você pode verificar se o módulo já está registrado no _store_ ou não através do método `store.hasModule (moduleName)`.\n\n### Preservando o estado\n\nÉ bem provável que você queira preservar o estado anterior ao registrar um novo módulo, como preservar o estado de uma aplicação Renderizada no Lado do Servidor (_Server_ _Side_ _Rendered_). Você pode fazer isso com a opção `preserveState`:`store.registerModule('a', module, {preserveState: true})`\n\nQuando você define `preserveState: true`, o módulo é registrado, as ações, mutações e _getters_ são incluídos no _store_, mas o estado não. É assumido que estado da sua _store_ já contém um estado para aquele módulo e você não quer sobrescrevê-lo.\n\n## Reutilização do Módulo\n\nÀs vezes, podemos precisar criar várias instâncias de um módulo, por exemplo:\n\n- Criando múltiplos _stores_ que usam o mesmo módulo (e.g. Para [evitar Singletons com informações do estado no SSR](https://ssr.vuejs.org/en/structure.html#avoid-stateful-singletons) quando a opção `runInNewContext` é `false` ou `'_once_'`);\n- Registrar o mesmo módulo várias vezes no mesmo _store_.\n\nSe usarmos um objeto simples para declarar o estado do módulo, esse objeto de estado será compartilhado por referência e causará poluição entre estados de _store_/módulo quando ele sofrer uma mutação.\n\nEste é exatamente o mesmo problema com `data` dentro dos componentes Vue. Então, a solução também é a mesma - use uma função para declarar o estado do módulo (suportado em 2.3.0+):\n\n```js\nconst MyReusableModule = {\n  state: () => ({\n    foo: 'bar'\n  }),\n  // mutations, actions, getters...\n}\n```\n"
  },
  {
    "path": "docs/ptbr/guide/mutations.md",
    "content": "# Mutações\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/ckMZp4HN\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nA única maneira de realmente mudar de estado em um _store_ Vuex é por confirmar (ou fazer _commit_ de) uma mutação. As mutações do Vuex são muito semelhantes aos eventos: cada mutação tem uma _String_ **_type_** e um **_handler_**. Na função manipuladora (ou _handler_) é onde realizamos modificações de estado reais e ele receberá o estado como o 1º argumento:\n\n\n```js\nconst store = createStore({\n  state: {\n    count: 1\n  },\n  mutations: {\n    increment (state) {\n      // muda o estado\n      state.count++\n    }\n  }\n})\n```\n\nVocê não pode chamar diretamente uma função manipuladora de mutação. Pense nisso mais como registro de evento: \"Quando uma mutação com o _type_ `increment` é acionada, chame este _handler_.\" Para invocar uma função manipuladora de mutação (_handler_), você precisa chamar `store.commit` com seu tipo (_type_):\n\n```js\nstore.commit('increment')\n```\n\n## Confirmação (ou Commit) com Payload\n\nVocê pode passar um argumento adicional para o `store.commit`, que é chamado de **_payload_** para a mutação:\n\n```js\n// ...\nmutations: {\n  increment (state, n) {\n    state.count += n\n  }\n}\n```\n\n```js\nstore.commit('increment', 10)\n```\n\nNa maioria dos casos, o _payload_ deve ser um objeto para que possa conter vários campos, e a mutação gravada também será mais descritiva:\n\n```js\n// ...\nmutations: {\n  increment (state, payload) {\n    state.count += payload.amount\n  }\n}\n```\n\n```js\nstore.commit('increment', {\n  amount: 10\n})\n```\n\n## Confirmação (ou Commit) Estilo-Objeto\n\nUma maneira alternativa de confirmar (ou fazer um _commit_ de) uma mutação é usando diretamente um objeto que tenha uma propriedade `type`:\n\n```js\nstore.commit({\n  type: 'increment',\n  amount: 10\n})\n```\n\nAo usar a Confirmação Estilo-Objeto, o objeto inteiro será passado como o _payload_ para os manipuladores de mutação, portanto, a função manipuladora permanecerá a mesma:\n\n```js\nmutations: {\n  increment (state, payload) {\n    state.count += payload.amount\n  }\n}\n```\n\n## Usando Constantes para Declarar os Tipos de Mutação\n\nÉ um padrão comumente visto usar constantes para declarar tipos de mutação em várias implementações do Flux. Isso permite que o código aproveite as ferramentas como os _linters_, e colocar todas as constantes em um único arquivo permite que seus colaboradores tenham uma visão geral das mutações possíveis em toda a aplicação:\n\n```js\n// mutation-types.js\nexport const SOME_MUTATION = 'SOME_MUTATION'\n```\n\n```js\n// store.js\nimport { createStore } from 'vuex'\nimport { SOME_MUTATION } from './mutation-types'\n\nconst store = createStore({\n  state: { ... },\n  mutations: {\n    // podemos usar o recurso de nome do dado computado do ES2015\n    // para usar uma constante como o nome da função\n    [SOME_MUTATION] (state) {\n      // muda o estado\n    }\n  }\n})\n```\n\nSe usar constantes é em grande parte uma preferência - pode ser útil em grandes projetos com muitos desenvolvedores, mas é totalmente opcional se você não gostar deles.\n\n## Mutações Devem Ser Síncronas\n\nUma regra importante a lembrar é que **as funções manipuladoras de mutação devem ser síncronas**. Por quê? Considere o seguinte exemplo:\n\n```js\nmutations: {\n  someMutation (state) {\n    api.callAsyncMethod(() => {\n      state.count++\n    })\n  }\n}\n```\n\nAgora imagine que estamos depurando a aplicação e observando os logs de mutação do _devtool_. Para cada mutação registrada, o _devtool_ precisará capturar os momentos \"antes\" e \"depois\" do estado. No entanto, o _callback_ assíncrono dentro da mutação de exemplo acima torna isso impossível: o _callback_ ainda não é chamado quando a mutação é confirmada (ou o _commit_ da mutação é feito) e não há como o _devtool_ saber quando o _callback_ será realmente chamado - qualquer mutação de estado executada no _callback_ é essencialmente impossível de rastrear!\n\n## Confirmando (ou fazendo Commits de) Mutações em Componentes\n\nVocê pode confirmar (ou fazer _commit_ de) mutações em componentes com `this.$store.commit('xxx')`, ou use o método auxiliar `mapMutations` que mapeia métodos de componentes para chamadas `store.commit` (requer injeção do _store_ raiz):\n\n```js\nimport { mapMutations } from 'vuex'\n\nexport default {\n  // ...\n  methods: {\n    ...mapMutations([\n      'increment', // mapeia `this.increment()` para `this.$store.commit('increment')`\n\n      // `mapMutations` also supports payloads:\n      'incrementBy' // mapeia `this.incrementBy(amount)` para`this.$store.commit('incrementBy', amount)`\n    ]),\n    ...mapMutations({\n      add: 'increment' // mapeia `this.add()` para`this.$store.commit('increment')`\n    })\n  }\n}\n```\n\n## Vamos as Ações\n\nA assincronicidade combinada com mutação de estado pode tornar seu programa muito difícil de entender. Por exemplo, quando você chama dois métodos com retornos de _callbacks_ assíncronos que alteram o estado, como saber quando eles são chamados e qual retorno de _callback_ foi chamado primeiro? É exatamente por isso que queremos separar os dois conceitos. No Vuex, **mutações são transações síncronas**:\n\n```js\nstore.commit('increment')\n// qualquer mudança de estado que a mutação \"increment\" pode causar\n// deve ser feito neste momento.\n```\n\nPara lidar com operações assíncronas, vamos apresentar [Ações](actions.md).\n"
  },
  {
    "path": "docs/ptbr/guide/plugins.md",
    "content": "# Plugins\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cvp8ZkCR\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nOs _stores_ do Vuex aceitam a opção _plugins_ que expõe gatilhos (ou _hooks_) para cada mutação. Um _plugin_ Vuex é simplesmente uma função que recebe um _store_ como seu único argumento:\n\n```js\nconst myPlugin = (store) => {\n  // chamado quando o store é inicializado\n  store.subscribe((mutation, state) => {\n    // chamada após cada mutação.\n    // A mutação vem no formato de `{ type, payload }`.\n  })\n}\n```\n\nE pode ser usada assim:\n\n```js\nconst store = createStore({\n  // ...\n  plugins: [myPlugin]\n})\n```\n\n## Confirmando (ou fazendo _commit_ de) Mutações Dentro de Plugins\n\n_Plugins_ não tem permissão para alterar o estado diretamente - similar aos seus componentes, eles podem apenas acionar mudanças confirmando (ou fazendo o _commit_ de) mutações.\n\nPor confirmar (ou fazer _commit_ de) mutações, um _plugin_ pode ser usado para sincronizar uma fonte de dados ao _store_. Por exemplo, para sincronizar uma fonte de dados _websocket_ ao _store_ (isso é só um exemplo inventado, na realidade a função _createPlugin_ pode receber parâmetros adicionais para tarefas mais complexas):\n\n```js\nexport default function createWebSocketPlugin (socket) {\n  return (store) => {\n    socket.on('data', data => {\n      store.commit('receiveData', data)\n    })\n    store.subscribe(mutation => {\n      if (mutation.type === 'UPDATE_DATA') {\n        socket.emit('update', mutation.payload)\n      }\n    })\n  }\n}\n```\n\n```js\nconst plugin = createWebSocketPlugin(socket)\n\nconst store = createStore({\n  state,\n  mutations,\n  plugins: [plugin]\n})\n```\n\n## Capturando os Momentos do Estado\n\nÀs vezes, um _plugin_ pode querer receber \"momentos\" do estado, e também comparar o estado pós-mutação com o estado de pré-mutação. Para conseguir isso, você precisará realizar uma cópia-profunda do objeto de estado:\n\n```js\nconst myPluginWithSnapshot = (store) => {\n  let prevState = _.cloneDeep(store.state)\n  store.subscribe((mutation, state) => {\n    let nextState = _.cloneDeep(state)\n\n    // compara `prevState` e `nextState`...\n\n    // salva o estado para a próxima mutação\n    prevState = nextState\n  })\n}\n```\n\n**_Plugins_ que capturam momentos do estado devem ser usados apenas durante o desenvolvimento.** Quando usamos _webpack_ ou _Browserify_, podemos construir nossas próprias ferramentas de distribuição (ou nossos próprios _builds_) que lidam com isso para nós:\n\n```js\nconst store = createStore({\n  // ...\n  plugins: process.env.NODE_ENV !== 'production'\n    ? [myPluginWithSnapshot]\n    : []\n})\n```\n\nO _plugin_ vai ser usado por padrão. Para produção, você vai precisar do [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) para webpack ou [envify](https://github.com/hughsk/envify) para Browserify para converter o valor do `process.env.NODE_ENV !== 'production'` para `false` na distribuição (ou _build_) final.\n\n## Plugin de Log Integrado\n\nVuex vem com um _plugin_ de _log_ para casos comuns de depuração:\n\n```js\nimport { createLogger } from 'vuex'\n\nconst store = createStore({\n  plugins: [createLogger()]\n})\n```\n\nA função `createLogger` tem algumas opções:\n\n```js\nconst logger = createLogger({\n  collapsed: false, // expande automaticamente mutações registradas no log\n  filter (mutation, stateBefore, stateAfter) {\n    // retorna `true` se uma mutação deve ser registrada no log\n    // `mutation` é um `{ type, payload }`\n    return mutation.type !== \"aBlocklistedMutation\"\n  },\n  actionFilter (action, state) {\n    // o mesmo que `filter`, mas para ações\n    // `action` é um `{ type, payload }`\n    return action.type !== \"aBlocklistedAction\"\n  },\n  transformer (state) {\n    // transforma o estado antes de regitrá-lo no log.\n    // por exemplo, retorna apenas uma sub-árvore específica\n    return state.subTree\n  },\n  mutationTransformer (mutation) {\n    // mutações são registradas no log no formato de  `{ type, payload }`\n    // mas podemos formatá-las como quisermos.\n    return mutation.type\n  },\n  actionTransformer (action) {\n    // O mesmo que mutationTransformer mas para ações\n    return action.type\n  },\n  logActions: true, // Log de Ações\n  logMutations: true, // Log de mutações\n  logger: console, // implementação da API `console`, valor padrão `console`\n})\n```\n\nO arquivo de _log_ também pode ser incluído diretamente via _tag_ `<script>`, e vai expor a função `createVuexLogger` globalmente.\n\nPerceba que o _plugin_ de _log_ captura momentos do estado, então use-o apenas durante o desenvolvimento.\n"
  },
  {
    "path": "docs/ptbr/guide/state.md",
    "content": "# Estado\n\n## Árvore Única de Estado\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cWw3Zhb\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nVuex usa uma **única árvore de estado** - ou seja, este único objeto contém todo o estado da sua aplicação e serve como \"fonte única da verdade\". Isso também significa que normalmente você terá apenas uma _store_ para cada aplicação. Uma única árvore de estado facilita a localização de uma parte específica do estado e nos permite capiturar facilmente momentos do estado atual da aplicação para fins de depuração.\n\nA árvore única de estado não entra em conflito com a modularidade - em capítulos posteriores, discutiremos como dividir seu estado e mutações em sub-módulos.\n\nOs dados que você armazena no Vuex seguem as mesmas regras que o `data` em uma instância do Vue, ou seja, o objeto de estado deve ser simples. **Veja também:** [Vue#data](https://v3.vuejs.org/api/options-data.html#data-2).\n\n## Obtendo o Estado Vuex nos Componentes Vue\n\nEntão, como exibimos o estado dentro do _store_ em nossos componentes Vue? Como os _stores_ Vuex são reativos, a maneira mais simples de \"recuperar\" o estado dele é simplesmente retornar algum estado do _store_ de dentro de um [dado computado](https://vuejs.org/guide/computed.html):\n\n```js\n// vamos criar um componente de Contador\nconst Counter = {\n  template: `<div>{{ count }}</div>`,\n  computed: {\n    count () {\n      return store.state.count\n    }\n  }\n}\n```\n\nSempre que o `store.state.count` mudar, fará com que o dado computado seja reavaliado e ative as atualizações de DOM associadas.\n\nNo entanto, esse padrão faz com que o componente dependa do _singleton_ do _store_ global. Ao usar um sistema de módulo, ele precisa importar o _store_ em todos os componentes que usam o estado do _store_ e também requer dados fictícios (ou _mocking_) ao testar o componente.\n\nO Vuex \"injeta\" o _store_ em todos os componentes filhos do componente raiz através do sistema de _plugins_ do Vue e estará disponível neles como `this.$store`. Vamos atualizar nossa implementação do `Counter`:\n\n```js\nconst Counter = {\n  template: `<div>{{ count }}</div>`,\n  computed: {\n    count () {\n      return this.$store.state.count\n    }\n  }\n}\n```\n\n## O Método Auxiliar `mapState`\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c8Pz7BSK\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nQuando um componente precisa usar várias propriedades ou _getters_ de estado do _store_, declarar todas esses dados computados pode ser repetitivo e verboso. Para lidar com isso, podemos fazer uso do método auxiliar `mapState` que gera funções _getter_ computadas para nós, economizando algumas linhas de código:\n\n```js\n// em builds completos, os métodos auxiliares são expostos como Vuex.mapState\nimport { mapState } from 'vuex'\n\nexport default {\n  // ...\n  computed: mapState({\n    // As arrow functions (ou funções de seta) podem tornar o código muito sucinto!\n    count: state => state.count,\n\n    // passar o valor da String 'count' é o mesmo que `state => state.count`\n    countAlias: 'count',\n\n    // para acessar o estado local com `this`, uma função normal deve ser usada\n    countPlusLocalState (state) {\n      return state.count + this.localCount\n    }\n  })\n}\n```\n\nTambém podemos passar um _Array_ de _Strings_ para `mapState` quando o nome de um dado computado mapeado é o mesmo que um nome de árvore secundária do estado.\n\n```js\ncomputed: mapState([\n  // mapeia this.count para store.state.count\n  'count'\n])\n```\n\n## Objeto Spread Operator\n\nObserve que `mapState` retorna um objeto. Como usá-lo em combinação com outros dados computados locais? Normalmente, teríamos que usar um utilitário para fundir vários objetos em um para que possamos passar o objeto final para `computed`. No entanto, com o [objeto spread operator](https://github.com/tc39/proposal-object-rest-spread), podemos simplificar muito a sintaxe:\n\n```js\ncomputed: {\n  localComputed () { /* ... */ },\n  // mistura isso no objeto externo com o objeto spread operator\n  ...mapState({\n    // ...\n  })\n}\n```\n\n## Componentes Ainda Podem Ter Um Estado Local\n\nUsar Vuex não significa que você deve colocar **todo** o estado no Vuex. Embora colocar mais estado no Vuex torna suas mutações de estado mais explícitas e depuráveis, às vezes também pode tornar o código mais verboso e indireto. Se uma parte do estado pertencer estritamente a um único componente, não haverá problema em deixá-lo apenas como um estado local. Você deve pesar os prós e contras e tomar decisões que atendam às necessidades de desenvolvimento da sua aplicação.\n"
  },
  {
    "path": "docs/ptbr/guide/strict.md",
    "content": "# Strict Mode\n\nPara habilitar o modo estrito, simplesmente passe `strict: true` ao criar um _store_ Vuex:\n\n```js\nconst store = createStore({\n  // ...\n  strict: true\n})\n```\n\nEm modo estrito, sempre que o estado do Vuex é mudado fora das funções manipuladoras de mutação, um erro será lançado. Isso garante que todas as mutações do estado possam ser explicitamente rastreadas por ferramentas de depuração.\n\n## Desenvolvimento vs. Produção\n\n**Não habilite o modo estrito ao fazer um _deploy_ para a produção!** O modo estrito executa um observador profundo síncrono na árvore de estados para detectar mutações inapropriadas e pode ser bastante caro quando você faz grande quantidade de mutações no estado. Certifique-se de desligá-lo em produção para evitar o custo de desempenho.\n\nSemelhante aos plugins, podemos deixar as ferramentas de compilação lidar com isso:\n\n```js\nconst store = createStore({\n  // ...\n  strict: process.env.NODE_ENV !== 'production'\n})\n```\n"
  },
  {
    "path": "docs/ptbr/guide/structure.md",
    "content": "# Estrutura da Aplicação\n\nO Vuex não restringe realmente como você estrutura seu código. Em vez disso, ele impõe um conjunto de princípios de alto nível:\n\n1. O estado do nível da aplicação é centralizado no _store_.\n\n2. A única maneira de mudar o estado é confirmando (ou fazendo _commit_ das) **mutações**, que são transações síncronas.\n\n3. A lógica assíncrona deve ser encapsulada e pode ser composta com **ações**.\n\nEnquanto você seguir estas regras, depende de você como estruturar seu projeto. Se o arquivo do seu _store_ for muito grande, basta começar a dividir as ações, mutações e _getters_ em arquivos separados.\n\nPara qualquer aplicação mais complexa, provavelmente precisaremos aproveitar os módulos. Aqui está um exemplo de estrutura de projeto:\n\n```bash\n├── index.html\n├── main.js\n├── api\n│   └── ... # abstrações para fazer requisições a API\n├── components\n│   ├── App.vue\n│   └── ...\n└── store\n    ├── index.js          # onde montamos os módulos e exportamos o store\n    ├── actions.js        # ações raiz\n    ├── mutations.js      # mutações raiz\n    └── modules\n        ├── cart.js       # módulo cart\n        └── products.js   # módulo products\n```\n\nComo referência, confira o [Exemplo do Carrinho de Compras](https://github.com/vuejs/vuex/tree/4.0/examples/classic/shopping-cart).\n"
  },
  {
    "path": "docs/ptbr/guide/testing.md",
    "content": "# Testando\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cPGkpJhq\" target=\"_blank\" rel=\"noopener noreferrer\">Tente esta lição no Scrimba</a></div>\n\nAs partes principais que queremos testar unitáriamente no Vuex são mutações e ações.\n\n## Testando Mutações\n\nAs mutações são muito simples de testar, porque são apenas funções que dependem completamente de seus argumentos. Um truque é que se você estiver usando módulos ES2015 e colocar suas mutações dentro do arquivo `store.js`, além da exportação padrão, você também deve exportar as mutações como uma exportação nomeada:\n\n```js\nconst state = { ... }\n\n// exporta `mutações` como uma exportação nomeada\nexport const mutations = { ... }\n\nexport default createStore({\n  state,\n  mutations\n})\n```\n\nExemplo de teste de uma mutação usando _Mocha_ + _Chai_ (você pode usar qualquer biblioteca de _framework_/_assertion_ que desejar):\n\n```js\n// mutations.js\nexport const mutations = {\n  increment: state => state.count++\n}\n```\n\n```js\n// mutations.spec.js\nimport { expect } from 'chai'\nimport { mutations } from './store'\n\n// desestrutura `mutações` atribuidas\nconst { increment } = mutations\n\ndescribe('mutations', () => {\n  it('INCREMENT', () => {\n    // estado mockado (ou simulado)\n    const state = { count: 0 }\n    // aplica a mutação\n    increment(state)\n    // afirma o resultado\n    expect(state.count).to.equal(1)\n  })\n})\n```\n\n## Testando Ações\n\nAs ações podem ser um pouco mais complicadas porque podem chamar as APIs externas. Ao testar ações, geralmente precisamos fazer algum nível de _mocking_ - por exemplo, podemos abistrair as chamadas da API em um serviço e simular (ou mockar (_mock_)) esse serviço dentro de nossos testes. A fim de simular facilmente as dependências, podemos usar o _webpack_ e [inject-loader](https://github.com/plasticine/inject-loader) para empacotar (ou criar um _bundle_ dos) nossos arquivos de teste.\n\nExemplo de teste de uma ação assíncrona:\n\n```js\n// actions.js\nimport shop from '../api/shop'\n\nexport const getAllProducts = ({ commit }) => {\n  commit('REQUEST_PRODUCTS')\n  shop.getProducts(products => {\n    commit('RECEIVE_PRODUCTS', products)\n  })\n}\n```\n\n```js\n// actions.spec.js\n\n// use a sintaxe 'require' para inline loaders.\n// com inject-loader, isso retorna um factory de módulos\n// que nos permite injetar dependências mockadas (ou simuladas).\nimport { expect } from 'chai'\nconst actionsInjector = require('inject-loader!./actions')\n\n// cria o módulo com nossos mocks\nconst actions = actionsInjector({\n  '../api/shop': {\n    getProducts (cb) {\n      setTimeout(() => {\n        cb([ /* resposta simulada */ ])\n      }, 100)\n    }\n  }\n})\n\n// método auxiliar para teste de ação com mutações esperadas\nconst testAction = (action, payload, state, expectedMutations, done) => {\n  let count = 0\n\n  // confirmação simulada (ou mock commit)\n  const commit = (type, payload) => {\n    const mutation = expectedMutations[count]\n\n    try {\n      expect(type).to.equal(mutation.type)\n      expect(payload).to.deep.equal(mutation.payload)\n    } catch (error) {\n      done(error)\n    }\n\n    count++\n    if (count >= expectedMutations.length) {\n      done()\n    }\n  }\n\n  // chame a ação com store mockado (ou simulado) e argumentos\n  action({ commit, state }, payload)\n\n  // verifica se nenhuma mutação deveria ter sido despachada\n  if (expectedMutations.length === 0) {\n    expect(count).to.equal(0)\n    done()\n  }\n}\n\ndescribe('actions', () => {\n  it('getAllProducts', done => {\n    testAction(actions.getAllProducts, null, {}, [\n      { type: 'REQUEST_PRODUCTS' },\n      { type: 'RECEIVE_PRODUCTS', payload: { /* resposta simulada */ } }\n    ], done)\n  })\n})\n```\n\nSe você tem _spies_ disponíveis em seu ambiente de teste (por exemplo via [Sinon.JS](http://sinonjs.org/)), você pode usá-los em vez do método auxiliar `testAction`:\n\n```js\ndescribe('actions', () => {\n  it('getAllProducts', () => {\n    const commit = sinon.spy()\n    const state = {}\n\n    actions.getAllProducts({ commit, state })\n\n    expect(commit.args).to.deep.equal([\n      ['REQUEST_PRODUCTS'],\n      ['RECEIVE_PRODUCTS', { /* resposta simulada */ }]\n    ])\n  })\n})\n```\n\n## Testando Getters\n\nSe seus _getters_ tiverem um código complexo, vale a pena testá-los. Os _Getters_ também são muito simples de testar pelo mesmo motivo que as mutações.\n\nExemplo testando um _getter_:\n\n```js\n// getters.js\nexport const getters = {\n  filteredProducts (state, { filterCategory }) {\n    return state.products.filter(product => {\n      return product.category === filterCategory\n    })\n  }\n}\n```\n\n```js\n// getters.spec.js\nimport { expect } from 'chai'\nimport { getters } from './getters'\n\ndescribe('getters', () => {\n  it('filteredProducts', () => {\n    // estado mockado (ou simulado)\n    const state = {\n      products: [\n        { id: 1, title: 'Apple', category: 'fruit' },\n        { id: 2, title: 'Orange', category: 'fruit' },\n        { id: 3, title: 'Carrot', category: 'vegetable' }\n      ]\n    }\n    // getter mockado (ou simulado)\n    const filterCategory = 'fruit'\n\n    // obtem o resultado do getter\n    const result = getters.filteredProducts(state, { filterCategory })\n\n    // afirma o resultado\n    expect(result).to.deep.equal([\n      { id: 1, title: 'Apple', category: 'fruit' },\n      { id: 2, title: 'Orange', category: 'fruit' }\n    ])\n  })\n})\n```\n\n## Executando Testes\n\nSe suas mutações e ações estiverem escritas corretamente, os testes não devem ter dependência direta das APIs do navegador após uma simulação apropriada. Assim, você pode simplesmente empacotar (ou criar um _bundle_) dos testes com o _webpack_ e executá-lo diretamente no _Node_. Alternativamente, você pode usar `mocha-loader` ou _Karma_ + `karma-webpack` para executar os testes em navegadores reais.\n\n### Executando no Node\n\nCrie a seguinte configuração de _webpack_ (juntamente com [`.babelrc`](https://babeljs.io/docs/usage/babelrc/)):\n\n```js\n// webpack.config.js\nmodule.exports = {\n  entry: './test.js',\n  output: {\n    path: __dirname,\n    filename: 'test-bundle.js'\n  },\n  module: {\n    loaders: [\n      {\n        test: /\\.js$/,\n        loader: 'babel-loader',\n        exclude: /node_modules/\n      }\n    ]\n  }\n}\n```\n\nEntão:\n\n``` bash\nwebpack\nmocha test-bundle.js\n```\n\n### Executando no Navegador\n\n1. Instale o `mocha-loader`.\n2. Mude o `entry` da configuração do _webpack_ acima para `'mocha-loader!babel-loader!./test.js'`.\n3. Inicie o `webpack-dev-server` usando a configuração.\n4. Vá para `localhost:8080/webpack-dev-server/test-bundle`.\n\n### Executando no Navegador com Karma + karma-webpack\n\nConsulte a instalação na [documentação do vue-loader](https://vue-loader.vuejs.org/pt_BR/workflow/testing.html).\n"
  },
  {
    "path": "docs/ptbr/guide/typescript-support.md",
    "content": "# Suporte ao TypeScript\n\nO Vuex fornece suas tipagens para que você possa usar o TypeScript para escrever uma definição do _store_. Você não precisa de nenhuma configuração especial do TypeScript para Vuex. Por favor siga a [configuração básica do TypeScript no Vue](https://v3.vuejs.org/guide/typescript-support.html) para configurar seu projeto.\n\nNo entanto, se você estiver escrevendo seus componentes Vue em TypeScript, há algumas etapas a seguir que exigem que você forneça a tipagem correta para um _store_.\n\n## Tipando a propriedade `$store` no Componente Vue\n\nO Vuex não fornece tipagens para a propriedade `this.$store` _out_ _of_ _the_ _box_. Quando usado com TypeScript, você deve declarar seu próprio _module_ _augmentation_.\n\nPara fazer isso, declare tipagens personalizadas para o `ComponentCustomProperties` do Vue adicionando um arquivo de declaração na pasta do seu projeto:\n\n```ts\n// vuex.d.ts\nimport { ComponentCustomProperties } from 'vue'\nimport { Store } from 'vuex'\n\ndeclare module 'vue' {\n  // declare seus próprios estados do store\n  interface State {\n    count: number\n  }\n\n  // fornece tipagem para `this.$store`\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\n## Tipando a Função de Composição `useStore`\n\nQuando você está escrevendo seu componente Vue na API de Composição (ou _Composition_ API), provavelmente desejará que `useStore` retorne o _store_ tipado. Para que `useStore` retorne corretamente o _store_ tipado, você deve:\n\n1. Defina o `InjectionKey` tipado.\n2. Forneça o `InjectionKey` tipado ao instalar um _store_ na aplicação Vue.\n3. Passe o `InjectionKey` tipado para o método `useStore`.\n\nVamos abordar isso passo a passo. Primeiro, defina a chave usando a interface `InjectionKey` do Vue junto com sua própria definição de tipo do _store_:\n\n```ts\n// store.ts\nimport { InjectionKey } from 'vue'\nimport { createStore, Store } from 'vuex'\n\n// defina suas tipagens para o estado do store\nexport interface State {\n  count: number\n}\n\n// defina o injection key\nexport const key: InjectionKey<Store<State>> = Symbol()\n\nexport const store = createStore<State>({\n  state: {\n    count: 0\n  }\n})\n```\n\nEm seguida, passe o _injection_ _key_ definido ao instalar o _store_ para a aplicação Vue:\n\n```ts\n// main.ts\nimport { createApp } from 'vue'\nimport { store, key } from './store'\n\nconst app = createApp({ ... })\n\n// passe o injection key\napp.use(store, key)\n\napp.mount('#app')\n```\n\nFinalmente, você pode passar a chave para o método `useStore` para recuperar o _store_ tipado.\n\n```ts\n// in a vue component\nimport { useStore } from 'vuex'\nimport { key } from './store'\n\nexport default {\n  setup () {\n    const store = useStore(key)\n\n    store.state.count // tipado como number\n  }\n}\n```\n\nPor baixo dos panos, o Vuex instala o _store_ para a aplicação Vue usando o [Provide/Inject](https://v3.vuejs.org/api/composition-api.html#provide-inject) do Vue, característica que é a razão pela qual o _injection_ _key_ é um fator importante.\n\n### Simplificando o uso do `useStore`\n\nTer que importar `InjectionKey` e passá-lo para `useStore` em todos os lugares em que é usado pode rapidamente se tornar uma tarefa repetitiva. Para simplificar as coisas, você pode definir sua própria função combinável (ou _composable_ _function_) para recuperar um _store_ tipado:\n\n```ts\n// store.ts\nimport { InjectionKey } from 'vue'\nimport { createStore, useStore as baseUseStore, Store } from 'vuex'\n\nexport interface State {\n  count: number\n}\n\nexport const key: InjectionKey<Store<State>> = Symbol()\n\nexport const store = createStore<State>({\n  state: {\n    count: 0\n  }\n})\n\n// defina sua própria função de composição `useStore`\nexport function useStore () {\n  return baseUseStore(key)\n}\n```\n\nAgora, ao importar sua própria função combinável (ou _composable_ _function_), você pode recuperar o _store_ tipado **sem** ter que fornecer o _injection_ _key_ e ela está tipada:\n\n```ts\n// em um componente vue\nimport { useStore } from './store'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    store.state.count // tipado como number\n  }\n}\n```\n"
  },
  {
    "path": "docs/ptbr/index.md",
    "content": "# O que é Vuex?\n\n::: tip NOTE\nEsta documentação é para o Vuex 4, que funciona com Vue 3. Se você está procurando a documentação para o Vuex 3, que funciona com Vue 2, [por favor, confira aqui](https://vuex.vuejs.org/ptbr/).\n:::\n\nO Vuex é um **padrão de gerenciamento de estado + biblioteca** para aplicações Vue.js. Ele serve como um _store_ centralizado para todos os componentes em uma aplicação, com regras garantindo que o estado só possa ser mutado de forma previsível.\n\n## O que é um \"Padrão de Gerenciamento do Estado\"?\n\nVamos começar com uma aplicação simples em Vue, um contador:\n\n```js\nconst Counter = {\n  // state\n  data () {\n    return {\n      count: 0\n    }\n  },\n  // view\n  template: `\n    <div>{{ count }}</div>\n  `,\n  // actions\n  methods: {\n    increment () {\n      this.count++\n    }\n  }\n}\n\ncreateApp(Counter).mount('#app')\n```\n\nÉ uma aplicação independente com as seguintes partes:\n\n- O **estado** (_state_), que é a fonte da verdade que direciona nossa aplicação;\n- A **_view_**, que é apenas um mapeamento declarativo do **estado**;\n- As **ações** (_actions_), que são as possíveis maneiras pelas quais o estado pode mudar em reação às interações dos usuários da **_view_**.\n\nEsta é uma representação simples do conceito de \"fluxo de dados unidirecional\" (_one-way_):\n\n<p style=\"text-align: center; margin: 2em\">\n  <img style=\"width:100%; max-width:450px;\" src=\"/flow.png\">\n</p>\n\nNo entanto, a simplicidade é rapidamente descartada quando temos **vários componentes que compartilham um estado comum**:\n\n- Múltiplas _views_ que podem depender do mesmo pedaço de estado.\n- Ações de diferentes _views_ que podem precisar alterar o mesmo pedaço de estado.\n\nPara o problema um, passar tudo via propriedades (_props_) pode ser entediante para componentes profundamente aninhados e simplesmente não funciona para componentes irmãos. Para o problema dois, muitas vezes nos encontramos recorrendo a soluções como buscar referências diretas de instância pai / filho ou tentar mudar e sincronizar várias cópias do estado por meio de eventos. Ambos os padrões são frágeis e levam rapidamente a códigos impossíveis de manter.\n\nEntão, por que não extraímos o estado compartilhado dos componentes, e o gerenciamos em um _singleton_ global? Com isso, nossa árvore de componentes se torna uma grande \"_view_\", e qualquer componente pode acessar o estado ou acionar ações, não importando onde elas estejam na árvore!\n\nAlém disso, ao definir e separar os conceitos envolvidos no gerenciamento do estado e aplicar regras que mantêm a independência entre as _views_ e os estados, damos ao nosso código mais estrutura e capacidade de manutenção.\n\nEsta é a ideia básica por trás do Vuex, inspirado no [Flux](https://facebook.github.io/flux/docs/overview), [Redux](http://redux.js.org/) e [The Elm Architecture](https://guide.elm-lang.org/architecture/). Ao contrário dos outros padrões, o Vuex também é uma implementação da biblioteca adaptada especificamente para o Vue.js aproveitar as vantagens de seu sistema de reatividade granular para atualizações eficientes.\n\nSe você quiser aprender Vuex de uma forma interativa, você pode conferir esse [curso de Vuex no Scrimba](https://scrimba.com/g/gvuex), que oferece uma mistura de _screencast_ e _playground_ de código em que você pode pausar e brincar com o código a qualquer momento.\n\n![vuex](/vuex.png)\n\n## Quando usar o Vuex?\n\nEmbora o Vuex nos ajude a lidar com o gerenciamento de estado compartilhado, ele também vem com o custo de mais conceitos e códigos repetitivos. É uma escolha de prós e contras entre produtividade de curto e longo prazo\n\nSe você nunca construiu um SPA em grande escala e for direto para o Vuex, ele pode parecer verboso e desanimador. Isso é perfeitamente normal - se a sua aplicação é simples, você provavelmente ficará bem sem o Vuex. Um simples [store pattern](https://v3.vuejs.org/guide/state-management.html#simple-state-management-from-scratch) pode ser tudo que você precisa. Mas, se você está criando um SPA de médio a grande porte, é provável que tenha encontrado situações que fazem você pensar em como lidar melhor com o estado fora de seus componentes Vue, e o Vuex será naturalmente o próximo passo para você. Há uma boa citação de Dan Abramov, o autor do Redux:\n\n> As bibliotecas Flux são como óculos: você saberá quando precisar delas.\n"
  },
  {
    "path": "docs/ptbr/installation.md",
    "content": "# Instalação\n\n## Download Direto / CDN\n\n[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) fornece os links de CDN baseados em NPM. O link acima sempre apontará para a última versão do NPM. Você também pode usar uma versão/tag específica por meio de URLs como `https://unpkg.com/vuex@4.0.0/dist/vuex.global.js`.\n<!--/email_off-->\n\nInclua o `vuex` após o Vue e ele se instalará automaticamente:\n\n```html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vuex.js\"></script>\n```\n\n## NPM\n\n```bash\nnpm install vuex@next --save\n```\n\n## Yarn\n\n```bash\nyarn add vuex@next --save\n```\n\n## Dev Build\n\nVocê terá que clonar diretamente do GitHub e fazer a distribuição (_build_) do `vuex` se\nquiser usar a compilação mais recente do dev.\n\n```bash\ngit clone https://github.com/vuejs/vuex.git node_modules/vuex\ncd node_modules/vuex\nyarn\nyarn build\n```\n"
  },
  {
    "path": "docs/public/_redirects",
    "content": "# redirect old urls to root\n\n/en/api.html  /api/\n/en/intro.html /en/guide/\n/en/* /guide/:splat\n\n/ptbr/api.html  /api/\n/ptbr/intro.html /ptbr/guide/\n/ptbr/* /guide/:splat\n\n/zh-cn/api.html  /zh/api/\n/zh-cn/intro.html /zh/guide/\n/zh-cn/* /zh/guide/:splat\n\n/ja/api.html  /ja/api/\n/ja/intro.html /ja/guide/\n/ja/* /ja/guide/:splat\n\n/ru/api.html  /ru/api/\n/ru/intro.html /ru/guide/\n/ru/* /ru/guide/:splat\n\n/kr/api.html  /kr/api/\n/kr/intro.html /kr/guide/\n/kr/* /kr/guide/:splat\n"
  },
  {
    "path": "docs/zh/api/index.md",
    "content": "---\nsidebar: auto\n---\n\n# API 参考\n\n## Store\n\n### createStore\n\n- `createStore<S>(options: StoreOptions<S>): Store<S>`\n\n  创建一个 store 实例。\n\n  ```js\n  import { createStore } from 'vuex'\n\n  const store = createStore({ ...options })\n  ```\n\n## Store 构造器选项\n\n### state\n\n- 类型: `Object | Function`\n\n  Vuex store 实例的根 state 对象。[详细介绍](../guide/state.md)\n\n  如果你传入返回一个对象的函数，其返回的对象会被用作根 state。这在你想要重用 state 对象，尤其是对于重用 module 来说非常有用。[详细介绍](../guide/modules.md#模块重用)\n\n### mutations\n\n- 类型: `{ [type: string]: Function }`\n\n  在 store 上注册 mutation，处理函数总是接受 `state` 作为第一个参数（如果定义在模块中，则为模块的局部状态），`payload` 作为第二个参数（可选）。\n\n  [详细介绍](../guide/mutations.md)\n\n### actions\n\n- 类型: `{ [type: string]: Function }`\n\n  在 store 上注册 action。处理函数总是接受 `context` 作为第一个参数，`context` 对象包含以下属性：\n\n  ``` js\n  {\n    state,      // 等同于 `store.state`，若在模块中则为局部状态\n    rootState,  // 等同于 `store.state`，只存在于模块中\n    commit,     // 等同于 `store.commit`\n    dispatch,   // 等同于 `store.dispatch`\n    getters,    // 等同于 `store.getters`\n    rootGetters // 等同于 `store.getters`，只存在于模块中\n  }\n  ```\n\n  同时如果有第二个参数 `payload` 的话也能够接收。\n\n  [详细介绍](../guide/actions.md)\n\n### getters\n\n- 类型: `{ [key: string]: Function }`\n\n在 store 上注册 getter，getter 方法接受以下参数：\n\n  ```\n  state,     // 如果在模块中定义则为模块的局部状态\n  getters    // 等同于 store.getters\n  ```\n\n  当定义在一个模块里时会特别一些：\n\n  ```\n  state,       // 如果在模块中定义则为模块的局部状态\n  getters,     // 当前模块的局部 getters\n  rootState,   // 全局 state\n  rootGetters  // 所有 getters\n  ```\n\n  注册的 getter 暴露为 `store.getters`。\n\n  [详细介绍](../guide/getters.md)\n\n### modules\n\n- 类型: `Object`\n\n  包含了子模块的对象，会被合并到 store，大概长这样：\n\n  ```js\n  {\n    key: {\n      state,\n      namespaced?,\n      mutations?,\n      actions?,\n      getters?,\n      modules?\n    },\n    ...\n  }\n  ```\n\n  与根模块的选项一样，每个模块也包含 `state` 和 `mutations` 选项。模块的状态使用 key 关联到 store 的根状态。模块的 mutation 和 getter 只会接收 module 的局部状态作为第一个参数，而不是根状态，并且模块 action 的 `context.state` 同样指向局部状态。\n\n  [详细介绍](../guide/modules.md)\n\n### plugins\n\n- 类型: `Array<Function>`\n\n  一个数组，包含应用在 store 上的插件方法。这些插件直接接收 store 作为唯一参数，可以监听 mutation（用于外部地数据持久化、记录或调试）或者提交 mutation （用于内部数据，例如 websocket 或 某些观察者）\n\n  [详细介绍](../guide/plugins.md)\n\n### strict\n\n- 类型: `boolean`\n- 默认值: `false`\n\n  使 Vuex store 进入严格模式，在严格模式下，任何 mutation 处理函数以外修改 Vuex state 都会抛出错误。\n\n  [详细介绍](../guide/strict.md)\n\n### devtools\n\n- 类型：`boolean`\n\n  为某个特定的 Vuex 实例打开或关闭 devtools。对于传入 `false` 的实例来说 Vuex store 不会订阅到 devtools 插件。对于一个页面中有多个 store 的情况非常有用。\n\n  ```js\n  {\n    devtools: false\n  }\n  ```\n\n## Store 实例属性\n\n### state\n\n- 类型: `Object`\n\n  根状态，只读。\n\n### getters\n\n- 类型: `Object`\n\n  暴露出注册的 getter，只读。\n\n## Store 实例方法\n\n### commit\n\n-  `commit(type: string, payload?: any, options?: Object)`\n-  `commit(mutation: Object, options?: Object)`\n\n  提交 mutation。`options` 里可以有 `root: true`，它允许在[命名空间模块](../guide/modules.md#命名空间)里提交根的 mutation。[详细介绍](../guide/mutations.md)\n\n### dispatch\n\n-  `dispatch(type: string, payload?: any, options?: Object): Promise<any>`\n-  `dispatch(action: Object, options?: Object): Promise<any>`\n\n  分发 action。`options` 里可以有 `root: true`，它允许在[命名空间模块](../guide/modules.md#命名空间)里分发根的 action。返回一个解析所有被触发的 action 处理器的 Promise。[详细介绍](../guide/actions.md)\n\n### replaceState\n\n- `replaceState(state: Object)`\n\n  替换 store 的根状态，仅用状态合并或时光旅行调试。\n\n### watch\n\n-  `watch(fn: Function, callback: Function, options?: Object): Function`\n\n  响应式地侦听 `fn` 的返回值，当值改变时调用回调函数。`fn` 接收 store 的 state 作为第一个参数，其 getter 作为第二个参数。最后接收一个可选的对象参数表示 Vue 的 [`vm.$watch`](https://cn.vuejs.org/v2/api/#vm-watch) 方法的参数。\n\n  要停止侦听，调用此方法返回的函数即可停止侦听。\n\n### subscribe\n\n-  `subscribe(handler: Function, options?: Object): Function`\n\n  订阅 store 的 mutation。`handler` 会在每个 mutation 完成后调用，接收 mutation 和经过 mutation 后的状态作为参数：\n\n  ```js\n  const unsubscribe = store.subscribe((mutation, state) => {\n    console.log(mutation.type)\n    console.log(mutation.payload)\n  })\n\n  // 你可以调用 unsubscribe 来停止订阅。\n  unsubscribe()\n  ```\n\n  默认情况下，新的处理函数会被添加到其链的尾端，因此它会在其它之前已经被添加了的处理函数之后执行。这一行为可以通过向 `options` 添加 `prepend: true` 来覆写，即把处理函数添加到其链的最开始。\n\n  ```js\n  store.subscribe(handler, { prepend: true })\n  ```\n \n `subscribe` 方法将返回一个 `unsubscribe` 函数，当不再需要订阅时应该调用该函数。例如，你可能会订阅一个 Vuex 模块，当你取消注册该模块时取消订阅。或者你可能从一个 Vue 组件内部调用 `subscribe`，然后不久就会销毁该组件。在这些情况下，你应该记得手动取消订阅。\n\n  通常用于插件。[详细介绍](../guide/plugins.md)\n\n### subscribeAction\n\n-  `subscribeAction(handler: Function, options?: Object): Function`\n\n  订阅 store 的 action。`handler` 会在每个 action 分发的时候调用并接收 action 描述和当前的 store 的 state 这两个参数。\n  `subscribe` 方法将返回一个 `unsubscribe` 函数，当不再需要订阅时，应调用该函数。例如，当取消注册一个 Vuex 模块或销毁一个 Vue 组件之前。\n\n  ```js\n  const unsubscribe = store.subscribeAction((action, state) => {\n    console.log(action.type)\n    console.log(action.payload)\n  })\n\n  // 你可以调用 unsubscribe 来停止订阅。\n  unsubscribe()\n  ```\n\n  默认情况下，新的处理函数会被添加到其链的尾端，因此它会在其它之前已经被添加了的处理函数之后执行。这一行为可以通过向 `options` 添加 `prepend: true` 来覆写，即把处理函数添加到其链的最开始。\n\n  ```js\n  store.subscribeAction(handler, { prepend: true })\n  ```\n\n  `subscribeAction` 方法将返回一个 `unsubscribe` 函数，当不再需要订阅时，应该调用该函数。例如，你可能会订阅一个 Vuex 模块，并在取消注册该模块时取消订阅。或者你可能从 Vue 组件内部调用`subscribeAction`，然后不久就会销毁该组件。在这些情况下，你应该记得手动取消订阅。\n\n  `subscribeAction` 也可以指定订阅处理函数的被调用时机应该在一个 action 分发*之前*还是*之后* (默认行为是*之前*)：\n\n  ```js\n  store.subscribeAction({\n    before: (action, state) => {\n      console.log(`before action ${action.type}`)\n    },\n    after: (action, state) => {\n      console.log(`after action ${action.type}`)\n    }\n  })\n  ```\n\n  `subscribeAction` 也可以指定一个 `error` 处理函数以捕获分发 action 的时候被抛出的错误。该函数会从第三个参数接收到一个 `error` 对象。\n\n  ```js\n  store.subscribeAction({\n    error: (action, state, error) => {\n      console.log(`error action ${action.type}`)\n      console.error(error)\n    }\n  })\n  ```\n\n  该 `subscribeAction` 方法常用于插件。[详细介绍](../guide/plugins.md)\n\n### registerModule\n\n-  `registerModule(path: string | Array<string>, module: Module, options?: Object)`\n\n  注册一个动态模块。[详细介绍](../guide/modules.md#模块动态注册)\n\n  `options` 可以包含 `preserveState: true` 以允许保留之前的 state。用于服务端渲染。\n\n### unregisterModule\n\n-  `unregisterModule(path: string | Array<string>)`\n\n  卸载一个动态模块。[详细介绍](../guide/modules.md#模块动态注册)\n\n### hasModule\n\n- `hasModule(path: string | Array<string>): boolean`\n\n  检查该模块的名字是否已经被注册。[详细介绍](../guide/modules.md#模块动态注册)\n\n### hotUpdate\n\n-  `hotUpdate(newOptions: Object)`\n\n  热替换新的 action 和 mutation。[详细介绍](../guide/hot-reload.md)\n\n## 组件绑定的辅助函数\n\n### mapState\n\n-  `mapState(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  为组件创建计算属性以返回 Vuex store 中的状态。[详细介绍](../guide/state.md#mapstate-辅助函数)\n\n  第一个参数是可选的，可以是一个命名空间字符串。[详细介绍](../guide/modules.md#带命名空间的绑定函数)\n\n  对象形式的第二个参数的成员可以是一个函数。`function(state: any)`\n\n### mapGetters\n\n-  `mapGetters(namespace?: string, map: Array<string> | Object<string>): Object`\n\n  为组件创建计算属性以返回 getter 的返回值。[详细介绍](../guide/getters.md#mapgetters-辅助函数)\n\n  第一个参数是可选的，可以是一个命名空间字符串。[详细介绍](../guide/modules.md#带命名空间的绑定函数)\n\n### mapActions\n\n-  `mapActions(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  创建组件方法分发 action。[详细介绍](../guide/actions.md#在组件中分发-action)\n\n  第一个参数是可选的，可以是一个命名空间字符串。[详细介绍](../guide/modules.md#带命名空间的绑定函数)\n\n  对象形式的第二个参数的成员可以是一个函数。`function(dispatch: function, ...args: any[])`\n\n### mapMutations\n\n-  `mapMutations(namespace?: string, map: Array<string> | Object<string | function>): Object`\n\n  创建组件方法提交 mutation。[详细介绍](../guide/mutations.md#在组件中提交-mutation)\n\n  第一个参数是可选的，可以是一个命名空间字符串。[详细介绍](../guide/modules.md#带命名空间的绑定函数)\n\n  对象形式的第二个参数的成员可以是一个函数。`function(commit: function, ...args: any[])`\n\n### createNamespacedHelpers\n\n- `createNamespacedHelpers(namespace: string): Object`\n\n  创建基于命名空间的组件绑定辅助函数。其返回一个包含 `mapState`、`mapGetters`、`mapActions` 和 `mapMutations` 的对象。它们都已经绑定在了给定的命名空间上。[详细介绍](../guide/modules.md#带命名空间的绑定函数)\n\n## 组合式函数\n\n### useStore\n\n- `useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;`\n\n  在 `setup` 钩子函数中调用该方法可以获取注入的 store。当使用组合式 API 时，可以通过调用该方法检索 store。\n\n  ```js\n  import { useStore } from 'vuex'\n\n  export default {\n    setup () {\n      const store = useStore()\n    }\n  }\n  ```\n\n  TypeScript 用户可以使用 injection key 来检索已经定义了类型的 store。为了使其工作，在将 store 实例安装到 Vue 应用中时，必须定义 injection key 并将其与 store 一起传递给 Vue 应用。\n\n  首先，使用 Vue 的 `InjectionKey` 接口声明一个 injection key。\n\n  ```ts\n  // store.ts\n  import { InjectionKey } from 'vue'\n  import { createStore, Store } from 'vuex'\n\n  export interface State {\n    count: number\n  }\n\n  export const key: InjectionKey<Store<State>> = Symbol()\n\n  export const store = createStore<State>({\n    state: {\n      count: 0\n    }\n  })\n  ```\n\n  然后，将定义好的 key 作为第二个参数传递给 `app.use` 方法。\n\n  ```ts\n  // main.ts\n  import { createApp } from 'vue'\n  import { store, key } from './store'\n\n  const app = createApp({ ... })\n\n  app.use(store, key)\n\n  app.mount('#app')\n  ```\n\n  最后，将 key 传递给 `useStore` 方法以获取指定类型的 store 实例。\n\n  ```ts\n  // 在 vue 组件内\n  import { useStore } from 'vuex'\n  import { key } from './store'\n\n  export default {\n    setup () {\n      const store = useStore(key)\n\n      store.state.count // 类型为 number\n    }\n  }\n  ```\n"
  },
  {
    "path": "docs/zh/guide/actions.md",
    "content": "# Action\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c6ggR3cG\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\nAction 类似于 mutation，不同在于：\n\n- Action 提交的是 mutation，而不是直接变更状态。\n- Action 可以包含任意异步操作。\n\n让我们来注册一个简单的 action：\n\n``` js\nconst store = createStore({\n  state: {\n    count: 0\n  },\n  mutations: {\n    increment (state) {\n      state.count++\n    }\n  },\n  actions: {\n    increment (context) {\n      context.commit('increment')\n    }\n  }\n})\n```\n\nAction 函数接受一个与 store 实例具有相同方法和属性的 context 对象，因此你可以调用 `context.commit` 提交一个 mutation，或者通过 `context.state` 和 `context.getters` 来获取 state 和 getters。当我们在之后介绍到 [Modules](modules.md) 时，你就知道 context 对象为什么不是 store 实例本身了。\n\n实践中，我们会经常用到 ES2015 的[参数解构](https://github.com/lukehoban/es6features#destructuring)来简化代码（特别是我们需要调用 `commit` 很多次的时候）：\n\n``` js\nactions: {\n  increment ({ commit }) {\n    commit('increment')\n  }\n}\n```\n\n## 分发 Action\n\nAction 通过 `store.dispatch` 方法触发：\n\n``` js\nstore.dispatch('increment')\n```\n\n乍一眼看上去感觉多此一举，我们直接分发 mutation 岂不更方便？实际上并非如此，还记得 **mutation 必须同步执行**这个限制么？Action 就不受约束！我们可以在 action 内部执行**异步**操作：\n\n``` js\nactions: {\n  incrementAsync ({ commit }) {\n    setTimeout(() => {\n      commit('increment')\n    }, 1000)\n  }\n}\n```\n\nActions 支持同样的载荷方式和对象方式进行分发：\n\n``` js\n// 以载荷形式分发\nstore.dispatch('incrementAsync', {\n  amount: 10\n})\n\n// 以对象形式分发\nstore.dispatch({\n  type: 'incrementAsync',\n  amount: 10\n})\n```\n\n来看一个更加实际的购物车示例，涉及到**调用异步 API** 和**分发多重 mutation**：\n\n``` js\nactions: {\n  checkout ({ commit, state }, products) {\n    // 把当前购物车的物品备份起来\n    const savedCartItems = [...state.cart.added]\n    // 发出结账请求\n    // 然后乐观地清空购物车\n    commit(types.CHECKOUT_REQUEST)\n    // 购物 API 接受一个成功回调和一个失败回调\n    shop.buyProducts(\n      products,\n      // 成功操作\n      () => commit(types.CHECKOUT_SUCCESS),\n      // 失败操作\n      () => commit(types.CHECKOUT_FAILURE, savedCartItems)\n    )\n  }\n}\n```\n\n注意我们正在进行一系列的异步操作，并且通过提交 mutation 来记录 action 产生的副作用（即状态变更）。\n\n## 在组件中分发 Action\n\n你在组件中使用 `this.$store.dispatch('xxx')` 分发 action，或者使用 `mapActions` 辅助函数将组件的 methods 映射为 `store.dispatch` 调用（需要先在根节点注入 `store`）：\n\n``` js\nimport { mapActions } from 'vuex'\n\nexport default {\n  // ...\n  methods: {\n    ...mapActions([\n      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`\n\n      // `mapActions` 也支持载荷：\n      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`\n    ]),\n    ...mapActions({\n      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`\n    })\n  }\n}\n```\n\n## 组合 Action\n\nAction 通常是异步的，那么如何知道 action 什么时候结束呢？更重要的是，我们如何才能组合多个 action，以处理更加复杂的异步流程？\n\n首先，你需要明白 `store.dispatch` 可以处理被触发的 action 的处理函数返回的 Promise，并且 `store.dispatch` 仍旧返回 Promise：\n\n``` js\nactions: {\n  actionA ({ commit }) {\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        commit('someMutation')\n        resolve()\n      }, 1000)\n    })\n  }\n}\n```\n\n现在你可以：\n\n``` js\nstore.dispatch('actionA').then(() => {\n  // ...\n})\n```\n\n在另外一个 action 中也可以：\n\n``` js\nactions: {\n  // ...\n  actionB ({ dispatch, commit }) {\n    return dispatch('actionA').then(() => {\n      commit('someOtherMutation')\n    })\n  }\n}\n```\n\n最后，如果我们利用 [async / await](https://tc39.github.io/ecmascript-asyncawait/)，我们可以如下组合 action：\n\n``` js\n// 假设 getData() 和 getOtherData() 返回的是 Promise\n\nactions: {\n  async actionA ({ commit }) {\n    commit('gotData', await getData())\n  },\n  async actionB ({ dispatch, commit }) {\n    await dispatch('actionA') // 等待 actionA 完成\n    commit('gotOtherData', await getOtherData())\n  }\n}\n```\n\n> 一个 `store.dispatch` 在不同模块中可以触发多个 action 函数。在这种情况下，只有当所有触发函数完成后，返回的 Promise 才会执行。\n"
  },
  {
    "path": "docs/zh/guide/composition-api.md",
    "content": "# 组合式API\n\n可以通过调用 `useStore` 函数，来在 `setup` 钩子函数中访问 store。这与在组件中使用选项式 API 访问 `this.$store` 是等效的。\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n  }\n}\n```\n\n## 访问 State 和 Getter\n\n为了访问 state 和 getter，需要创建 `computed` 引用以保留响应性，这与在选项式 API 中创建计算属性等效。\n\n```js\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      // 在 computed 函数中访问 state\n      count: computed(() => store.state.count),\n\n      // 在 computed 函数中访问 getter\n      double: computed(() => store.getters.double)\n    }\n  }\n}\n```\n\n## 访问 Mutation 和 Action\n\n要使用 mutation 和 action 时，只需要在 `setup` 钩子函数中调用 `commit` 和 `dispatch` 函数。\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      // 使用 mutation\n      increment: () => store.commit('increment'),\n\n      // 使用 action\n      asyncIncrement: () => store.dispatch('asyncIncrement')\n    }\n  }\n}\n```\n\n## 示例\n\n查看[组合式 API 案例](https://github.com/vuejs/vuex/tree/4.0/examples/composition)，以便了解使用 Vuex 和 Vue 的组合式 API 的应用案例。\n"
  },
  {
    "path": "docs/zh/guide/forms.md",
    "content": "# 表单处理\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKRgEC9\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\n当在严格模式中使用 Vuex 时，在属于 Vuex 的 state 上使用 `v-model` 会比较棘手：\n\n``` html\n<input v-model=\"obj.message\">\n```\n\n假设这里的 `obj` 是在计算属性中返回的一个属于 Vuex store 的对象，在用户输入时，`v-model` 会试图直接修改 `obj.message`。在严格模式中，由于这个修改不是在 mutation 函数中执行的, 这里会抛出一个错误。\n\n用“Vuex 的思维”去解决这个问题的方法是：给 `<input>` 中绑定 value，然后侦听 `input` 或者 `change` 事件，在事件回调中调用一个方法:\n\n``` html\n<input :value=\"message\" @input=\"updateMessage\">\n```\n\n``` js\n// ...\ncomputed: {\n  ...mapState({\n    message: state => state.obj.message\n  })\n},\nmethods: {\n  updateMessage (e) {\n    this.$store.commit('updateMessage', e.target.value)\n  }\n}\n```\n\n下面是 mutation 函数：\n\n``` js\n// ...\nmutations: {\n  updateMessage (state, message) {\n    state.obj.message = message\n  }\n}\n```\n\n## 双向绑定的计算属性\n\n必须承认，这样做比简单地使用“`v-model` + 局部状态”要啰嗦得多，并且也损失了一些 `v-model` 中很有用的特性。另一个方法是使用带有 setter 的双向绑定计算属性：\n\n``` html\n<input v-model=\"message\">\n```\n\n``` js\n// ...\ncomputed: {\n  message: {\n    get () {\n      return this.$store.state.obj.message\n    },\n    set (value) {\n      this.$store.commit('updateMessage', value)\n    }\n  }\n}\n```\n"
  },
  {
    "path": "docs/zh/guide/getters.md",
    "content": "# Getter\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c2Be7TB\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\n有时候我们需要从 store 中的 state 中派生出一些状态，例如对列表进行过滤并计数：\n\n``` js\ncomputed: {\n  doneTodosCount () {\n    return this.$store.state.todos.filter(todo => todo.done).length\n  }\n}\n```\n\n如果有多个组件需要用到此属性，我们要么复制这个函数，或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。\n\nVuex 允许我们在 store 中定义“getter”（可以认为是 store 的计算属性）。\n\n::: warning 注意\n从 Vue 3.0 开始，getter 的结果不再像计算属性一样会被缓存起来。这是一个已知的问题，将会在 3.1 版本中修复。详情请看 [PR #1878](https://github.com/vuejs/vuex/pull/1883)。\n:::\n\nGetter 接受 state 作为其第一个参数：\n\n``` js\nconst store = createStore({\n  state: {\n    todos: [\n      { id: 1, text: '...', done: true },\n      { id: 2, text: '...', done: false }\n    ]\n  },\n  getters: {\n    doneTodos (state) {\n      return state.todos.filter(todo => todo.done)\n    }\n  }\n})\n```\n\n## 通过属性访问\n\nGetter 会暴露为 `store.getters` 对象，你可以以属性的形式访问这些值：\n\n``` js\nstore.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]\n```\n\nGetter 也可以接受其他 getter 作为第二个参数：\n\n``` js\ngetters: {\n  // ...\n  doneTodosCount (state, getters) {\n    return getters.doneTodos.length\n  }\n}\n```\n\n``` js\nstore.getters.doneTodosCount // -> 1\n```\n\n我们可以很容易地在任何组件中使用它：\n\n``` js\ncomputed: {\n  doneTodosCount () {\n    return this.$store.getters.doneTodosCount\n  }\n}\n```\n\n注意，getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。\n\n## 通过方法访问\n\n你也可以通过让 getter 返回一个函数，来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。\n\n```js\ngetters: {\n  // ...\n  getTodoById: (state) => (id) => {\n    return state.todos.find(todo => todo.id === id)\n  }\n}\n```\n\n``` js\nstore.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }\n```\n\n注意，getter 在通过方法访问时，每次都会去进行调用，而不会缓存结果。\n\n## `mapGetters` 辅助函数\n\n`mapGetters` 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性：\n\n``` js\nimport { mapGetters } from 'vuex'\n\nexport default {\n  // ...\n  computed: {\n  // 使用对象展开运算符将 getter 混入 computed 对象中\n    ...mapGetters([\n      'doneTodosCount',\n      'anotherGetter',\n      // ...\n    ])\n  }\n}\n```\n\n如果你想将一个 getter 属性另取一个名字，使用对象形式：\n\n``` js\n...mapGetters({\n  // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`\n  doneCount: 'doneTodosCount'\n})\n```\n"
  },
  {
    "path": "docs/zh/guide/hot-reload.md",
    "content": "# 热重载\n\n使用 webpack 的 [Hot Module Replacement API](https://webpack.js.org/guides/hot-module-replacement/)，Vuex 支持在开发过程中热重载 mutation、module、action 和 getter。你也可以在 Browserify 中使用 [browserify-hmr](https://github.com/AgentME/browserify-hmr/) 插件。\n\n对于 mutation 和模块，你需要使用 `store.hotUpdate()` 方法：\n\n``` js\n// store.js\nimport { createStore } from 'vuex'\nimport mutations from './mutations'\nimport moduleA from './modules/a'\n\nconst state = { ... }\n\nconst store = createStore({\n  state,\n  mutations,\n  modules: {\n    a: moduleA\n  }\n})\n\nif (module.hot) {\n  // 使 action 和 mutation 成为可热重载模块\n  module.hot.accept(['./mutations', './modules/a'], () => {\n    // 获取更新后的模块\n    // 因为 babel 6 的模块编译格式问题，这里需要加上 `.default`\n    const newMutations = require('./mutations').default\n    const newModuleA = require('./modules/a').default\n    // 加载新模块\n    store.hotUpdate({\n      mutations: newMutations,\n      modules: {\n        a: newModuleA\n      }\n    })\n  })\n}\n```\n\n参考热重载示例 [counter-hot](https://github.com/vuejs/vuex/tree/main/examples/counter-hot)。\n\n## 动态模块热重载\n\n如果你仅使用模块，你可以使用 `require.context` 来动态地加载或热重载所有的模块。\n\n```js\n// store.js\nimport { createStore } from 'vuex'\n\n// 加载所有模块。\nfunction loadModules() {\n  const context = require.context(\"./modules\", false, /([a-z_]+)\\.js$/i)\n\n  const modules = context\n    .keys()\n    .map((key) => ({ key, name: key.match(/([a-z_]+)\\.js$/i)[1] }))\n    .reduce(\n      (modules, { key, name }) => ({\n        ...modules,\n        [name]: context(key).default\n      }),\n      {}\n    )\n\n  return { context, modules }\n}\n\nconst { context, modules } = loadModules()\n\nconst store = new createStore({\n  modules\n})\n\nif (module.hot) {\n  // 在任何模块发生改变时进行热重载。\n  module.hot.accept(context.id, () => {\n    const { modules } = loadModules()\n\n    store.hotUpdate({\n      modules\n    })\n  })\n}\n```\n"
  },
  {
    "path": "docs/zh/guide/index.md",
    "content": "# 开始\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cMPa2Uk\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\n每一个 Vuex 应用的核心就是 store（仓库）。“store”基本上就是一个容器，它包含着你的应用中大部分的**状态 (state)**。Vuex 和单纯的全局对象有以下两点不同：\n\n1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候，若 store 中的状态发生变化，那么相应的组件也会相应地得到高效更新。\n\n2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地**提交 (commit) mutation**。这样使得我们可以方便地跟踪每一个状态的变化，从而让我们能够实现一些工具帮助我们更好地了解我们的应用。\n\n## 最简单的 Store\n\n:::tip 提示\n我们将在后续的文档示例代码中使用 ES2015 语法。如果你还没能掌握 ES2015，[你得抓紧了](https://babeljs.io/docs/learn-es2015/)！\n:::\n\n[安装](../installation.md) Vuex 之后，让我们来创建一个 store。创建过程直截了当——仅需要提供一个初始 state 对象和一些 mutation：\n\n``` js\nimport { createApp } from 'vue'\nimport { createStore } from 'vuex'\n\n// 创建一个新的 store 实例\nconst store = createStore({\n  state () {\n    return {\n      count: 0\n    }\n  },\n  mutations: {\n    increment (state) {\n      state.count++\n    }\n  }\n})\n\nconst app = createApp({ /* 根组件 */ })\n\n// 将 store 实例作为插件安装\napp.use(store)\n```\n\n现在，你可以通过 `store.state` 来获取状态对象，并通过 `store.commit` 方法触发状态变更：\n\n``` js\nstore.commit('increment')\n\nconsole.log(store.state.count) // -> 1\n```\n\n在 Vue 组件中， 可以通过 `this.$store` 访问store实例。现在我们可以从组件的方法提交一个变更：\n\n``` js\nmethods: {\n  increment() {\n    this.$store.commit('increment')\n    console.log(this.$store.state.count)\n  }\n}\n```\n\n再次强调，我们通过提交 mutation 的方式，而非直接改变 `store.state.count`，是因为我们想要更明确地追踪到状态的变化。这个简单的约定能够让你的意图更加明显，这样你在阅读代码的时候能更容易地解读应用内部的状态改变。此外，这样也让我们有机会去实现一些能记录每次状态改变，保存状态快照的调试工具。有了它，我们甚至可以实现如时间穿梭般的调试体验。\n\n由于 store 中的状态是响应式的，在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的 methods 中提交 mutation。\n\n接下来，我们将会更深入地探讨一些核心概念。让我们先从 [State](state.md) 概念开始。\n"
  },
  {
    "path": "docs/zh/guide/migrating-to-4-0-from-3-x.md",
    "content": "# 从 3.x 迁移到 4.0\n\n几乎所有的 Vuex 4 API 都与 Vuex 3 保持不变。但是，仍有一些非兼容性变更需要注意。\n\n- [非兼容性变更](#非兼容性变更)\n  - [安装过程](#安装过程)\n  - [TypeScript 支持](#TypeScript-支持)\n  - [打包产物已经与 Vue 3 配套](#打包产物已经与-Vue-3-配套)\n  - [“createLogger”函数从核心模块导出](#“createLogger”函数从核心模块导出)\n- [新特性](#新特性)\n  - [全新的“useStore”组合式函数](#全新的“usestore”组合式函数)\n\n## 非兼容性变更\n\n### 安装过程\n\n为了与 Vue 3 初始化过程保持一致，Vuex 的安装方式已经改变了。用户现在应该使用新引入的 `createStore` 方法来创建 store 实例。\n\n```js\nimport { createStore } from 'vuex'\n\nexport const store = createStore({\n  state () {\n    return {\n      count: 1\n    }\n  }\n})\n```\n\n要将 Vuex 安装到 Vue 实例中，需要用 `store` 替代之前的 Vuex 传递给 `use` 方法。\n\n```js\nimport { createApp } from 'vue'\nimport { store } from './store'\nimport App from './App.vue'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n```\n\n:::tip 提示\n从技术上讲这并不是一个非兼容性变更，仍然可以使用 `new Store(...)` 语法，但是建议使用上述方式以保持与 Vue 3 和 Vue Router Next 的一致。\n:::\n\n### TypeScript 支持\n\n为了修复 [issue #994](https://github.com/vuejs/vuex/issues/994)，Vuex 4 删除了 `this.$store` 在 Vue 组件中的全局类型声明。当使用 TypeScript 时，必须声明自己的[模块补充(module augmentation)](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)。\n\n将下面的代码放到项目中，以允许 `this.$store` 能被正确的类型化：\n\n```ts\n// vuex-shim.d.ts\n\nimport { ComponentCustomProperties } from 'vue'\nimport { Store } from 'vuex'\n\ndeclare module 'vue' {\n  // 声明自己的 store state\n  interface State {\n    count: number\n  }\n\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\n在 [TypeScript 支持](./typescript-support)章节可以了解到更多。\n\n### 打包产物已经与 Vue 3 配套\n\n下面的打包产物分别与 Vue 3 的打包产物配套：\n\n- `vuex.global(.prod).js`\n  - 通过`<script src=\"...\">` 标签直接用在浏览器中，将 Vuex 暴露为全局变量。\n  - 全局构建为 IIFE ， 而不是 UMD ，并且只能与 `<script src=\"...\">` 一起使用。\n  - 包含硬编码的 prod/dev 分支，并且生产环境版本已经压缩过。生产环境请使用 `.prod.js` 文件。\n- `vuex.esm-browser(.prod).js`\n  - 用于通过原生 ES 模块导入使用(在浏览器中通过 `<script type=\"module\">` 标签使用)。\n- `vuex.esm-bundler.js`\n  - 用于与 `webpack`， `rollup`， `parcel` 等构建工具一起使用。\n  - 通过 `process.env.NODE_ENV` 环境变量决定应该运行在生产环境还是开发环境（必须由构建工具替换）。\n  - 不提供压缩后的构建版本(与打包后的其他代码一起压缩)\n- `vuex.cjs.js`\n  - 通过 `require` 在 Node.js 服务端渲染使用。\n\n### “createLogger”函数从核心模块导出\n\n在 Vuex 3 中，`createLogger` 方法从 `vuex/dist/logger` 文件中导出，但是现在该方法已经包含在核心包中了，应该直接从 `vuex` 包中引入。\n\n```js\nimport { createLogger } from 'vuex'\n```\n\n## 新特性\n\n### 全新的“useStore”组合式函数\n\nVuex 4 引入了一个新的 API 用于在组合式 API 中与 store 进行交互。可以在组件的 `setup` 钩子函数中使用 `useStore` 组合式函数来检索 store。\n\n```js\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n  }\n}\n```\n\n在[组合式 API](./composition-api) 章节可以了解到更多。\n"
  },
  {
    "path": "docs/zh/guide/modules.md",
    "content": "# Module\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cqKK4psq\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\n由于使用单一状态树，应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时，store 对象就有可能变得相当臃肿。\n\n为了解决以上问题，Vuex 允许我们将 store 分割成**模块（module）**。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割：\n\n``` js\nconst moduleA = {\n  state: () => ({ ... }),\n  mutations: { ... },\n  actions: { ... },\n  getters: { ... }\n}\n\nconst moduleB = {\n  state: () => ({ ... }),\n  mutations: { ... },\n  actions: { ... }\n}\n\nconst store = createStore({\n  modules: {\n    a: moduleA,\n    b: moduleB\n  }\n})\n\nstore.state.a // -> moduleA 的状态\nstore.state.b // -> moduleB 的状态\n```\n\n## 模块的局部状态\n\n对于模块内部的 mutation 和 getter，接收的第一个参数是**模块的局部状态对象**。\n\n``` js\nconst moduleA = {\n  state: () => ({\n    count: 0\n  }),\n  mutations: {\n    increment (state) {\n      // 这里的 `state` 对象是模块的局部状态\n      state.count++\n    }\n  },\n  getters: {\n    doubleCount (state) {\n      return state.count * 2\n    }\n  }\n}\n```\n\n同样，对于模块内部的 action，局部状态通过 `context.state` 暴露出来，根节点状态则为 `context.rootState`：\n\n``` js\nconst moduleA = {\n  // ...\n  actions: {\n    incrementIfOddOnRootSum ({ state, commit, rootState }) {\n      if ((state.count + rootState.count) % 2 === 1) {\n        commit('increment')\n      }\n    }\n  }\n}\n```\n\n对于模块内部的 getter，根节点状态会作为第三个参数暴露出来：\n\n``` js\nconst moduleA = {\n  // ...\n  getters: {\n    sumWithRootCount (state, getters, rootState) {\n      return state.count + rootState.count\n    }\n  }\n}\n```\n\n## 命名空间\n\n默认情况下，模块内部的 action 和 mutation 仍然是注册在**全局命名空间**的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间，但是目前这并非出于功能上的目的（仅仅是维持现状来避免非兼容性变更）。必须注意，不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。\n\n如果希望你的模块具有更高的封装度和复用性，你可以通过添加 `namespaced: true` 的方式使其成为带命名空间的模块。当模块被注册后，它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如：\n\n``` js\nconst store = createStore({\n  modules: {\n    account: {\n      namespaced: true,\n\n      // 模块内容（module assets）\n      state: () => ({ ... }), // 模块内的状态已经是嵌套的了，使用 `namespaced` 属性不会对其产生影响\n      getters: {\n        isAdmin () { ... } // -> getters['account/isAdmin']\n      },\n      actions: {\n        login () { ... } // -> dispatch('account/login')\n      },\n      mutations: {\n        login () { ... } // -> commit('account/login')\n      },\n\n      // 嵌套模块\n      modules: {\n        // 继承父模块的命名空间\n        myPage: {\n          state: () => ({ ... }),\n          getters: {\n            profile () { ... } // -> getters['account/profile']\n          }\n        },\n\n        // 进一步嵌套命名空间\n        posts: {\n          namespaced: true,\n\n          state: () => ({ ... }),\n          getters: {\n            popular () { ... } // -> getters['account/posts/popular']\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n启用了命名空间的 getter 和 action 会收到局部化的 `getter`，`dispatch` 和 `commit`。换言之，你在使用模块内容（module assets）时不需要在同一模块内额外添加空间名前缀。更改 `namespaced` 属性后不需要修改模块内的代码。\n\n### 在带命名空间的模块内访问全局内容（Global Assets）\n\n如果你希望使用全局 state 和 getter，`rootState` 和 `rootGetters` 会作为第三和第四参数传入 getter，也会通过 `context` 对象的属性传入 action。\n\n若需要在全局命名空间内分发 action 或提交 mutation，将 `{ root: true }` 作为第三参数传给 `dispatch` 或 `commit` 即可。\n\n``` js\nmodules: {\n  foo: {\n    namespaced: true,\n\n    getters: {\n      // 在这个模块的 getter 中，`getters` 被局部化了\n      // 你可以使用 getter 的第四个参数来调用 `rootGetters`\n      someGetter (state, getters, rootState, rootGetters) {\n        getters.someOtherGetter // -> 'foo/someOtherGetter'\n        rootGetters.someOtherGetter // -> 'someOtherGetter'\n        rootGetters['bar/someOtherGetter'] // -> 'bar/someOtherGetter'\n      },\n      someOtherGetter: state => { ... }\n    },\n\n    actions: {\n      // 在这个模块中， dispatch 和 commit 也被局部化了\n      // 他们可以接受 `root` 属性以访问根 dispatch 或 commit\n      someAction ({ dispatch, commit, getters, rootGetters }) {\n        getters.someGetter // -> 'foo/someGetter'\n        rootGetters.someGetter // -> 'someGetter'\n        rootGetters['bar/someGetter'] // -> 'bar/someGetter'\n\n        dispatch('someOtherAction') // -> 'foo/someOtherAction'\n        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'\n\n        commit('someMutation') // -> 'foo/someMutation'\n        commit('someMutation', null, { root: true }) // -> 'someMutation'\n      },\n      someOtherAction (ctx, payload) { ... }\n    }\n  }\n}\n```\n\n### 在带命名空间的模块注册全局 action\n\n若需要在带命名空间的模块注册全局 action，你可添加 `root: true`，并将这个 action 的定义放在函数 `handler` 中。例如：\n\n``` js\n{\n  actions: {\n    someOtherAction ({dispatch}) {\n      dispatch('someAction')\n    }\n  },\n  modules: {\n    foo: {\n      namespaced: true,\n\n      actions: {\n        someAction: {\n          root: true,\n          handler (namespacedContext, payload) { ... } // -> 'someAction'\n        }\n      }\n    }\n  }\n}\n```\n\n### 带命名空间的绑定函数\n\n当使用 `mapState`、`mapGetters`、`mapActions` 和 `mapMutations` 这些函数来绑定带命名空间的模块时，写起来可能比较繁琐：\n\n``` js\ncomputed: {\n  ...mapState({\n    a: state => state.some.nested.module.a,\n    b: state => state.some.nested.module.b\n  }),\n  ...mapGetters([\n    'some/nested/module/someGetter', // -> this['some/nested/module/someGetter']\n    'some/nested/module/someOtherGetter', // -> this['some/nested/module/someOtherGetter']\n  ])\n},\nmethods: {\n  ...mapActions([\n    'some/nested/module/foo', // -> this['some/nested/module/foo']()\n    'some/nested/module/bar' // -> this['some/nested/module/bar']()\n  ])\n}\n```\n\n对于这种情况，你可以将模块的空间名称字符串作为第一个参数传递给上述函数，这样所有绑定都会自动将该模块作为上下文。于是上面的例子可以简化为：\n\n``` js\ncomputed: {\n  ...mapState('some/nested/module', {\n    a: state => state.a,\n    b: state => state.b\n  }),\n  ...mapGetters('some/nested/module', [\n    'someGetter', // -> this.someGetter\n    'someOtherGetter', // -> this.someOtherGetter\n  ])\n},\nmethods: {\n  ...mapActions('some/nested/module', [\n    'foo', // -> this.foo()\n    'bar' // -> this.bar()\n  ])\n}\n```\n\n而且，你可以通过使用 `createNamespacedHelpers` 创建基于某个命名空间辅助函数。它返回一个对象，对象里有新的绑定在给定命名空间值上的组件绑定辅助函数：\n\n``` js\nimport { createNamespacedHelpers } from 'vuex'\n\nconst { mapState, mapActions } = createNamespacedHelpers('some/nested/module')\n\nexport default {\n  computed: {\n    // 在 `some/nested/module` 中查找\n    ...mapState({\n      a: state => state.a,\n      b: state => state.b\n    })\n  },\n  methods: {\n    // 在 `some/nested/module` 中查找\n    ...mapActions([\n      'foo',\n      'bar'\n    ])\n  }\n}\n```\n\n### 给插件开发者的注意事项\n\n如果你开发的[插件（Plugin）](plugins.md)提供了模块并允许用户将其添加到 Vuex store，可能需要考虑模块的空间名称问题。对于这种情况，你可以通过插件的参数对象来允许用户指定空间名称：\n\n``` js\n// 通过插件的参数对象得到空间名称\n// 然后返回 Vuex 插件函数\nexport function createPlugin (options = {}) {\n  return function (store) {\n    // 把空间名字添加到插件模块的类型（type）中去\n    const namespace = options.namespace || ''\n    store.dispatch(namespace + 'pluginAction')\n  }\n}\n```\n\n## 模块动态注册\n\n在 store 创建**之后**，你可以使用 `store.registerModule` 方法注册模块：\n\n``` js\nimport { createStore } from 'vuex'\n\nconst store = createStore({ /* 选项 */ })\n\n// 注册模块 `myModule`\nstore.registerModule('myModule', {\n  // ...\n})\n\n// 注册嵌套模块 `nested/myModule`\nstore.registerModule(['nested', 'myModule'], {\n  // ...\n})\n```\n\n之后就可以通过 `store.state.myModule` 和 `store.state.nested.myModule` 访问模块的状态。\n\n模块动态注册功能使得其他 Vue 插件可以通过在 store 中附加新模块的方式来使用 Vuex 管理状态。例如，[`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) 插件就是通过动态注册模块将 Vue Router 和 Vuex 结合在一起，实现应用的路由状态管理。\n\n你也可以使用 `store.unregisterModule(moduleName)` 来动态卸载模块。注意，你不能使用此方法卸载静态模块（即创建 store 时声明的模块）。\n\n注意，你可以通过 `store.hasModule(moduleName)` 方法检查该模块是否已经被注册到 store。需要记住的是，嵌套模块应该以数组形式传递给 `registerModule` 和 `hasModule`，而不是以路径字符串的形式传递给 module。\n\n### 保留 state\n\n在注册一个新 module 时，你很有可能想保留过去的 state，例如从一个服务端渲染的应用保留 state。你可以通过 `preserveState` 选项将其归档：`store.registerModule('a', module, { preserveState: true })`。\n\n当你设置 `preserveState: true` 时，该模块会被注册，action、mutation 和 getter 会被添加到 store 中，但是 state 不会。这里假设 store 的 state 已经包含了这个 module 的 state 并且你不希望将其覆写。\n\n## 模块重用\n\n有时我们可能需要创建一个模块的多个实例，例如：\n\n- 创建多个 store，他们公用同一个模块 (例如当 `runInNewContext` 选项是 `false` 或 `'once'` 时，为了[在服务端渲染中避免有状态的单例](https://ssr.vuejs.org/en/structure.html#avoid-stateful-singletons))\n- 在一个 store 中多次注册同一个模块\n\n如果我们使用一个纯对象来声明模块的状态，那么这个状态对象会通过引用被共享，导致状态对象被修改时 store 或模块间数据互相污染的问题。\n\n实际上这和 Vue 组件内的 `data` 是同样的问题。因此解决办法也是相同的——使用一个函数来声明模块状态（仅 2.3.0+ 支持）：\n\n``` js\nconst MyReusableModule = {\n  state: () => ({\n    foo: 'bar'\n  }),\n  // mutation、action 和 getter 等等...\n}\n```\n"
  },
  {
    "path": "docs/zh/guide/mutations.md",
    "content": "# Mutation\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/ckMZp4HN\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\n更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件：每个 mutation 都有一个字符串的**事件类型 (type)**和一个**回调函数 (handler)**。这个回调函数就是我们实际进行状态更改的地方，并且它会接受 state 作为第一个参数：\n\n``` js\nconst store = createStore({\n  state: {\n    count: 1\n  },\n  mutations: {\n    increment (state) {\n      // 变更状态\n      state.count++\n    }\n  }\n})\n```\n\n你不能直接调用一个 mutation 处理函数。这个选项更像是事件注册：“当触发一个类型为 `increment` 的 mutation 时，调用此函数。”要唤醒一个 mutation 处理函数，你需要以相应的 type 调用 **store.commit** 方法：\n\n``` js\nstore.commit('increment')\n```\n\n## 提交载荷（Payload）\n\n你可以向 `store.commit` 传入额外的参数，即 mutation 的**载荷（payload）**：\n\n``` js\n// ...\nmutations: {\n  increment (state, n) {\n    state.count += n\n  }\n}\n```\n\n``` js\nstore.commit('increment', 10)\n```\n\n在大多数情况下，载荷应该是一个对象，这样可以包含多个字段并且记录的 mutation 会更易读：\n\n``` js\n// ...\nmutations: {\n  increment (state, payload) {\n    state.count += payload.amount\n  }\n}\n```\n\n``` js\nstore.commit('increment', {\n  amount: 10\n})\n```\n\n## 对象风格的提交方式\n\n提交 mutation 的另一种方式是直接使用包含 `type` 属性的对象：\n\n``` js\nstore.commit({\n  type: 'increment',\n  amount: 10\n})\n```\n\n当使用对象风格的提交方式，整个对象都作为载荷传给 mutation 函数，因此处理函数保持不变：\n\n``` js\nmutations: {\n  increment (state, payload) {\n    state.count += payload.amount\n  }\n}\n```\n\n## 使用常量替代 Mutation 事件类型\n\n使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用，同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然：\n\n``` js\n// mutation-types.js\nexport const SOME_MUTATION = 'SOME_MUTATION'\n```\n\n``` js\n// store.js\nimport { createStore } from 'vuex'\nimport { SOME_MUTATION } from './mutation-types'\n\nconst store = createStore({\n  state: { ... },\n  mutations: {\n    // 我们可以使用 ES2015 风格的计算属性命名功能\n    // 来使用一个常量作为函数名\n    [SOME_MUTATION] (state) {\n      // 修改 state\n    }\n  }\n})\n```\n\n用不用常量取决于你——在需要多人协作的大型项目中，这会很有帮助。但如果你不喜欢，你完全可以不这样做。\n\n## Mutation 必须是同步函数\n\n一条重要的原则就是要记住 **mutation 必须是同步函数**。为什么？请参考下面的例子：\n\n``` js\nmutations: {\n  someMutation (state) {\n    api.callAsyncMethod(() => {\n      state.count++\n    })\n  }\n}\n```\n\n现在想象，我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录，devtools 都需要捕捉到前一状态和后一状态的快照。然而，在上面的例子中 mutation 中的异步函数中的回调让这不可能完成：因为当 mutation 触发的时候，回调函数还没有被调用，devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。\n\n## 在组件中提交 Mutation\n\n你可以在组件中使用 `this.$store.commit('xxx')` 提交 mutation，或者使用 `mapMutations` 辅助函数将组件中的 methods 映射为 `store.commit` 调用（需要在根节点注入 `store`）。\n\n``` js\nimport { mapMutations } from 'vuex'\n\nexport default {\n  // ...\n  methods: {\n    ...mapMutations([\n      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`\n\n      // `mapMutations` 也支持载荷：\n      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`\n    ]),\n    ...mapMutations({\n      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`\n    })\n  }\n}\n```\n\n## 下一步：Action\n\n在 mutation 中混合异步调用会导致你的程序很难调试。例如，当你调用了两个包含异步回调的 mutation 来改变状态，你怎么知道什么时候回调和哪个先回调呢？这就是为什么我们要区分这两个概念。在 Vuex 中，**mutation 都是同步事务**：\n\n``` js\nstore.commit('increment')\n// 任何由 \"increment\" 导致的状态变更都应该在此刻完成。\n```\n\n为了处理异步操作，让我们来看一看 [Action](actions.md)。\n"
  },
  {
    "path": "docs/zh/guide/plugins.md",
    "content": "# 插件\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cvp8ZkCR\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\nVuex 的 store 接受 `plugins` 选项，这个选项暴露出每次 mutation 的钩子。Vuex 插件就是一个函数，它接收 store 作为唯一参数：\n\n``` js\nconst myPlugin = (store) => {\n  // 当 store 初始化后调用\n  store.subscribe((mutation, state) => {\n    // 每次 mutation 之后调用\n    // mutation 的格式为 { type, payload }\n  })\n}\n```\n\n然后像这样使用：\n\n``` js\nconst store = createStore({\n  // ...\n  plugins: [myPlugin]\n})\n```\n\n## 在插件内提交 Mutation\n\n在插件中不允许直接修改状态——类似于组件，只能通过提交 mutation 来触发变化。\n\n通过提交 mutation，插件可以用来同步数据源到 store。例如，同步 websocket 数据源到 store（下面是个大概例子，实际上 `createWebSocketPlugin` 方法可以有更多选项来完成复杂任务）：\n\n``` js\nexport default function createWebSocketPlugin (socket) {\n  return (store) => {\n    socket.on('data', data => {\n      store.commit('receiveData', data)\n    })\n    store.subscribe(mutation => {\n      if (mutation.type === 'UPDATE_DATA') {\n        socket.emit('update', mutation.payload)\n      }\n    })\n  }\n}\n```\n\n``` js\nconst plugin = createWebSocketPlugin(socket)\n\nconst store = createStore({\n  state,\n  mutations,\n  plugins: [plugin]\n})\n```\n\n## 生成 State 快照\n\n有时候插件需要获得状态的“快照”，比较改变的前后状态。想要实现这项功能，你需要对状态对象进行深拷贝：\n\n``` js\nconst myPluginWithSnapshot = (store) => {\n  let prevState = _.cloneDeep(store.state)\n  store.subscribe((mutation, state) => {\n    let nextState = _.cloneDeep(state)\n\n    // 比较 prevState 和 nextState...\n\n    // 保存状态，用于下一次 mutation\n    prevState = nextState\n  })\n}\n```\n\n**生成状态快照的插件应该只在开发阶段使用**，使用 webpack 或 Browserify，让构建工具帮我们处理：\n\n``` js\nconst store = createStore({\n  // ...\n  plugins: process.env.NODE_ENV !== 'production'\n    ? [myPluginWithSnapshot]\n    : []\n})\n```\n\n上面插件会默认启用。在发布阶段，你需要使用 webpack 的 [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) 或者是 Browserify 的 [envify](https://github.com/hughsk/envify) 使 `process.env.NODE_ENV !== 'production'` 为 `false`。\n\n## 内置 Logger 插件\n\nVuex 自带一个日志插件用于一般的调试:\n\n``` js\nimport { createLogger } from 'vuex'\n\nconst store = createStore({\n  plugins: [createLogger()]\n})\n```\n\n`createLogger` 函数有几个配置项：\n\n``` js\nconst logger = createLogger({\n  collapsed: false, // 自动展开记录的 mutation\n  filter (mutation, stateBefore, stateAfter) {\n    // 若 mutation 需要被记录，就让它返回 true 即可\n    // 顺便，`mutation` 是个 { type, payload } 对象\n    return mutation.type !== \"aBlocklistedMutation\"\n  },\n  actionFilter (action, state) {\n    // 和 `filter` 一样，但是是针对 action 的\n    // `action` 的格式是 `{ type, payload }`\n    return action.type !== \"aBlocklistedAction\"\n  },\n  transformer (state) {\n    // 在开始记录之前转换状态\n    // 例如，只返回指定的子树\n    return state.subTree\n  },\n  mutationTransformer (mutation) {\n    // mutation 按照 { type, payload } 格式记录\n    // 我们可以按任意方式格式化\n    return mutation.type\n  },\n  actionTransformer (action) {\n    // 和 `mutationTransformer` 一样，但是是针对 action 的\n    return action.type\n  },\n  logActions: true, // 记录 action 日志\n  logMutations: true, // 记录 mutation 日志\n  logger: console, // 自定义 console 实现，默认为 `console`\n})\n```\n\n日志插件还可以直接通过 `<script>` 标签引入，它会提供全局方法 `createVuexLogger`。\n\n要注意，logger 插件会生成状态快照，所以仅在开发环境使用。\n"
  },
  {
    "path": "docs/zh/guide/state.md",
    "content": "# State\n\n## 单一状态树\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cWw3Zhb\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\nVuex 使用**单一状态树**——是的，用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 ([SSOT](https://en.wikipedia.org/wiki/Single_source_of_truth))”而存在。这也意味着，每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段，在调试的过程中也能轻易地取得整个当前应用状态的快照。\n\n单状态树和模块化并不冲突——在后面的章节里我们会讨论如何将状态和状态变更事件分布到各个子模块中。\n\n存储在 Vuex 中的数据和 Vue 实例中的 `data` 遵循相同的规则，例如状态对象必须是纯粹 (plain) 的。**参考：**[Vue#data](https://v3.cn.vuejs.org/api/options-data.html#data-2)。\n\n## 在 Vue 组件中获得 Vuex 状态\n\n那么我们如何在 Vue 组件中展示状态呢？由于 Vuex 的状态存储是响应式的，从 store 实例中读取状态最简单的方法就是在[计算属性](https://cn.vuejs.org/guide/computed.html)中返回某个状态：\n\n``` js\n// 创建一个 Counter 组件\nconst Counter = {\n  template: `<div>{{ count }}</div>`,\n  computed: {\n    count () {\n      return store.state.count\n    }\n  }\n}\n```\n\n每当 `store.state.count` 变化的时候, 都会重新求取计算属性，并且触发更新相关联的 DOM。\n\n然而，这种模式导致组件依赖全局状态单例。在模块化的构建系统中，在每个需要使用 state 的组件中需要频繁地导入，并且在测试组件时需要模拟状态。\n\nVuex 通过 Vue 的插件系统将 store 实例从根组件中“注入”到所有的子组件里。且子组件能通过 `this.$store` 访问到。让我们更新下 `Counter` 的实现：\n\n``` js\nconst Counter = {\n  template: `<div>{{ count }}</div>`,\n  computed: {\n    count () {\n      return this.$store.state.count\n    }\n  }\n}\n```\n\n## `mapState` 辅助函数\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/c8Pz7BSK\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\n当一个组件需要获取多个状态的时候，将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题，我们可以使用 `mapState` 辅助函数帮助我们生成计算属性，让你少按几次键：\n\n``` js\n// 在单独构建的版本中辅助函数为 Vuex.mapState\nimport { mapState } from 'vuex'\n\nexport default {\n  // ...\n  computed: mapState({\n    // 箭头函数可使代码更简练\n    count: state => state.count,\n\n    // 传字符串参数 'count' 等同于 `state => state.count`\n    countAlias: 'count',\n\n    // 为了能够使用 `this` 获取局部状态，必须使用常规函数\n    countPlusLocalState (state) {\n      return state.count + this.localCount\n    }\n  })\n}\n```\n\n当映射的计算属性的名称与 state 的子节点名称相同时，我们也可以给 `mapState` 传一个字符串数组。\n\n``` js\ncomputed: mapState([\n  // 映射 this.count 为 store.state.count\n  'count'\n])\n```\n\n## 对象展开运算符\n\n`mapState` 函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢？通常，我们需要使用一个工具函数将多个对象合并为一个，以使我们可以将最终对象传给 `computed` 属性。但是自从有了[对象展开运算符](https://github.com/tc39/proposal-object-rest-spread)，我们可以极大地简化写法：\n\n``` js\ncomputed: {\n  localComputed () { /* ... */ },\n  // 使用对象展开运算符将此对象混入到外部对象中\n  ...mapState({\n    // ...\n  })\n}\n```\n\n## 组件仍然保有局部状态\n\n使用 Vuex 并不意味着你需要将**所有的**状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试，但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件，最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。\n"
  },
  {
    "path": "docs/zh/guide/strict.md",
    "content": "# 严格模式\n\n开启严格模式，仅需在创建 store 的时候传入 `strict: true`：\n\n``` js\nconst store = createStore({\n  // ...\n  strict: true\n})\n```\n\n在严格模式下，无论何时发生了状态变更且不是由 mutation 函数引起的，将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。\n\n## 开发环境与发布环境\n\n**不要在发布环境下启用严格模式**！严格模式会深度监测状态树来检测不合规的状态变更——请确保在发布环境下关闭严格模式，以避免性能损失。\n\n类似于插件，我们可以让构建工具来处理这种情况：\n\n``` js\nconst store = createStore({\n  // ...\n  strict: process.env.NODE_ENV !== 'production'\n})\n```\n"
  },
  {
    "path": "docs/zh/guide/structure.md",
    "content": "# 项目结构\n\nVuex 并不限制你的代码结构。但是，它规定了一些需要遵守的规则：\n\n1. 应用层级的状态应该集中到单个 store 对象中。\n\n2. 提交 **mutation** 是更改状态的唯一方法，并且这个过程是同步的。\n\n3. 异步逻辑都应该封装到 **action** 里面。\n\n只要你遵守以上规则，如何组织代码随你便。如果你的 store 文件太大，只需将 action、mutation 和 getter 分割到单独的文件。\n\n对于大型应用，我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例：\n\n\n``` bash\n├── index.html\n├── main.js\n├── api\n│   └── ... # 抽取出API请求\n├── components\n│   ├── App.vue\n│   └── ...\n└── store\n    ├── index.js          # 我们组装模块并导出 store 的地方\n    ├── actions.js        # 根级别的 action\n    ├── mutations.js      # 根级别的 mutation\n    └── modules\n        ├── cart.js       # 购物车模块\n        └── products.js   # 产品模块\n```\n\n请参考[购物车示例](https://github.com/vuejs/vuex/tree/4.0/examples/classic/shopping-cart)。\n"
  },
  {
    "path": "docs/zh/guide/testing.md",
    "content": "# 测试\n\n<div class=\"scrimba\"><a href=\"https://scrimba.com/p/pnyzgAP/cPGkpJhq\" target=\"_blank\" rel=\"noopener noreferrer\">在 Scrimba 上尝试这节课</a></div>\n\n我们主要想针对 Vuex 中的 mutation 和 action 进行单元测试。\n\n## 测试 Mutation\n\nMutation 很容易被测试，因为它们仅仅是一些完全依赖参数的函数。这里有一个小技巧，如果你使用了 ES2015 模块，且将 mutation 定义在了 `store.js` 文件中，那么除了模块的默认导出外，你还应该将 mutation 进行命名导出：\n\n``` js\nconst state = { ... }\n\n// `mutations` 作为命名输出对象\nexport const mutations = { ... }\n\nexport default createStore({\n  state,\n  mutations\n})\n```\n\n下面是用 Mocha + Chai 测试一个 mutation 的例子（实际上你可以用任何你喜欢的测试框架）：\n\n``` js\n// mutations.js\nexport const mutations = {\n  increment: state => state.count++\n}\n```\n\n``` js\n// mutations.spec.js\nimport { expect } from 'chai'\nimport { mutations } from './store'\n\n// 解构 `mutations`\nconst { increment } = mutations\n\ndescribe('mutations', () => {\n  it('INCREMENT', () => {\n    // 模拟状态\n    const state = { count: 0 }\n    // 应用 mutation\n    increment(state)\n    // 断言结果\n    expect(state.count).to.equal(1)\n  })\n})\n```\n\n## 测试 Action\n\nAction 应对起来略微棘手，因为它们可能需要调用外部的 API。当测试 action 的时候，我们需要增加一个 mocking 服务层——例如，我们可以把 API 调用抽象成服务，然后在测试文件中用 mock 服务回应 API 调用。为了便于解决 mock 依赖，可以用 webpack 和 [inject-loader](https://github.com/plasticine/inject-loader) 打包测试文件。\n\n下面是一个测试异步 action 的例子：\n\n``` js\n// actions.js\nimport shop from '../api/shop'\n\nexport const getAllProducts = ({ commit }) => {\n  commit('REQUEST_PRODUCTS')\n  shop.getProducts(products => {\n    commit('RECEIVE_PRODUCTS', products)\n  })\n}\n```\n\n``` js\n// actions.spec.js\n\n// 使用 require 语法处理内联 loaders。\n// inject-loader 返回一个允许我们注入 mock 依赖的模块工厂\nimport { expect } from 'chai'\nconst actionsInjector = require('inject-loader!./actions')\n\n// 使用 mocks 创建模块\nconst actions = actionsInjector({\n  '../api/shop': {\n    getProducts (cb) {\n      setTimeout(() => {\n        cb([ /* mocked response */ ])\n      }, 100)\n    }\n  }\n})\n\n// 用指定的 mutations 测试 action 的辅助函数\nconst testAction = (action, args, state, expectedMutations, done) => {\n  let count = 0\n\n  // 模拟提交\n  const commit = (type, payload) => {\n    const mutation = expectedMutations[count]\n\n    try {\n      expect(mutation.type).to.equal(type)\n      expect(mutation.payload).to.deep.equal(payload)\n    } catch (error) {\n      done(error)\n    }\n\n    count++\n    if (count >= expectedMutations.length) {\n      done()\n    }\n  }\n\n  // 用模拟的 store 和参数调用 action\n  action({ commit, state }, ...args)\n\n  // 检查是否没有 mutation 被 dispatch\n  if (expectedMutations.length === 0) {\n    expect(count).to.equal(0)\n    done()\n  }\n}\n\ndescribe('actions', () => {\n  it('getAllProducts', done => {\n    testAction(actions.getAllProducts, null, {}, [\n      { type: 'REQUEST_PRODUCTS' },\n      { type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } }\n    ], done)\n  })\n})\n```\n\n如果在测试环境下有可用的 spy (比如通过 [Sinon.JS](http://sinonjs.org/))，你可以使用它们替换辅助函数 `testAction`：\n\n``` js\ndescribe('actions', () => {\n  it('getAllProducts', () => {\n    const commit = sinon.spy()\n    const state = {}\n\n    actions.getAllProducts({ commit, state })\n\n    expect(commit.args).to.deep.equal([\n      ['REQUEST_PRODUCTS'],\n      ['RECEIVE_PRODUCTS', { /* mocked response */ }]\n    ])\n  })\n})\n```\n\n## 测试 Getter\n\n如果你的 getter 包含很复杂的计算过程，很有必要测试它们。Getter 的测试与 mutation 一样直截了当。\n\n测试一个 getter 的示例：\n\n``` js\n// getters.js\nexport const getters = {\n  filteredProducts (state, { filterCategory }) {\n    return state.products.filter(product => {\n      return product.category === filterCategory\n    })\n  }\n}\n```\n\n``` js\n// getters.spec.js\nimport { expect } from 'chai'\nimport { getters } from './getters'\n\ndescribe('getters', () => {\n  it('filteredProducts', () => {\n    // 模拟状态\n    const state = {\n      products: [\n        { id: 1, title: 'Apple', category: 'fruit' },\n        { id: 2, title: 'Orange', category: 'fruit' },\n        { id: 3, title: 'Carrot', category: 'vegetable' }\n      ]\n    }\n    // 模拟 getter\n    const filterCategory = 'fruit'\n\n    // 获取 getter 的结果\n    const result = getters.filteredProducts(state, { filterCategory })\n\n    // 断言结果\n    expect(result).to.deep.equal([\n      { id: 1, title: 'Apple', category: 'fruit' },\n      { id: 2, title: 'Orange', category: 'fruit' }\n    ])\n  })\n})\n```\n\n## 执行测试\n\n如果你的 mutation 和 action 编写正确，经过合理地 mocking 处理之后这些测试应该不依赖任何浏览器 API，因此你可以直接用 webpack 打包这些测试文件然后在 Node 中执行。换种方式，你也可以用 `mocha-loader` 或 Karma + `karma-webpack` 在真实浏览器环境中进行测试。\n\n### 在 Node 中执行测试\n\n创建以下 webpack 配置（配置好 [`.babelrc`](https://babeljs.io/docs/usage/babelrc/)）:\n\n``` js\n// webpack.config.js\nmodule.exports = {\n  entry: './test.js',\n  output: {\n    path: __dirname,\n    filename: 'test-bundle.js'\n  },\n  module: {\n    loaders: [\n      {\n        test: /\\.js$/,\n        loader: 'babel-loader',\n        exclude: /node_modules/\n      }\n    ]\n  }\n}\n```\n\n然后：\n\n``` bash\nwebpack\nmocha test-bundle.js\n```\n\n### 在浏览器中测试\n\n1. 安装 `mocha-loader`。\n2. 把上述 webpack 配置中的 `entry` 改成 `'mocha-loader!babel-loader!./test.js'`。\n3. 用以上配置启动 `webpack-dev-server`。\n4. 访问 `localhost:8080/webpack-dev-server/test-bundle`。\n\n### 使用 Karma + karma-webpack 在浏览器中执行测试\n\n详见 [Vue Loader 的文档](https://vuejs.github.io/vue-loader/workflow/testing.html)。\n"
  },
  {
    "path": "docs/zh/guide/typescript-support.md",
    "content": "# TypeScript 支持\n\nVuex 提供了类型声明，因此可以使用 TypeScript 定义 store，并且不需要任何特殊的 TypeScript 配置。请遵循 [Vue 的基本 TypeScript 配置](https://v3.cn.vuejs.org/guide/typescript-support.html)来配置项目。\n\n但是，如果你使用 TypeScript 来编写 Vue 组件，则需要遵循一些步骤才能正确地为 store 提供类型声明。\n\n## Vue 组件中 `$store` 属性的类型声明\n\nVuex 没有为 `this.$store` 属性提供开箱即用的类型声明。如果你要使用 TypeScript，首先需要声明自定义的[模块补充(module augmentation)](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)。\n\n为此，需要在项目文件夹中添加一个声明文件来声明 Vue 的自定义类型 `ComponentCustomProperties` ：\n\n```ts\n// vuex.d.ts\nimport { Store } from 'vuex'\n\ndeclare module 'vue' {\n  // 声明自己的 store state\n  interface State {\n    count: number\n  }\n\n  // 为 `this.$store` 提供类型声明\n  interface ComponentCustomProperties {\n    $store: Store<State>\n  }\n}\n```\n\n## `useStore` 组合式函数类型声明\n\n当使用组合式 API 编写 Vue 组件时，您可能希望 `useStore` 返回类型化的 store。为了 `useStore` 能正确返回类型化的 store，必须执行以下步骤：\n\n1. 定义类型化的 `InjectionKey`。\n2. 将 store 安装到 Vue 应用时提供类型化的 `InjectionKey` 。\n3. 将类型化的 `InjectionKey` 传给 `useStore` 方法。\n\n让我们逐步解决这个问题。首先，使用 Vue 的 `InjectionKey` 接口和自己的 store 类型定义来定义 key ：\n\n```ts\n// store.ts\nimport { InjectionKey } from 'vue'\nimport { createStore, Store } from 'vuex'\n\n// 为 store state 声明类型\nexport interface State {\n  count: number\n}\n\n// 定义 injection key\nexport const key: InjectionKey<Store<State>> = Symbol()\n\nexport const store = createStore<State>({\n  state: {\n    count: 0\n  }\n})\n```\n\n然后，将 store 安装到 Vue 应用时传入定义好的 injection key。\n\n```ts\n// main.ts\nimport { createApp } from 'vue'\nimport { store, key } from './store'\n\nconst app = createApp({ ... })\n\n// 传入 injection key\napp.use(store, key)\n\napp.mount('#app')\n```\n\n最后，将上述 injection key 传入 `useStore` 方法可以获取类型化的 store。\n\n```ts\n// vue 组件\nimport { useStore } from 'vuex'\nimport { key } from './store'\n\nexport default {\n  setup () {\n    const store = useStore(key)\n\n    store.state.count // 类型为 number\n  }\n}\n```\n\n本质上，Vuex 将store 安装到 Vue 应用中使用了 Vue 的 [Provide/Inject](https://v3.cn.vuejs.org/api/composition-api.html#provide-inject) 特性，这就是 injection key 是很重要的因素的原因。\n\n### 简化 `useStore` 用法\n\n引入 `InjectionKey` 并将其传入 `useStore` 使用过的任何地方，很快就会成为一项重复性的工作。为了简化问题，可以定义自己的组合式函数来检索类型化的 store ：\n\n```ts\n// store.ts\nimport { InjectionKey } from 'vue'\nimport { createStore, useStore as baseUseStore, Store } from 'vuex'\n\nexport interface State {\n  count: number\n}\n\nexport const key: InjectionKey<Store<State>> = Symbol()\n\nexport const store = createStore<State>({\n  state: {\n    count: 0\n  }\n})\n\n// 定义自己的 `useStore` 组合式函数\nexport function useStore () {\n  return baseUseStore(key)\n}\n```\n\n现在，通过引入自定义的组合式函数，不用提供 injection key 和类型声明就可以直接得到类型化的 store：\n\n```ts\n// vue 组件\nimport { useStore } from './store'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    store.state.count // 类型为 number\n  }\n}\n```\n"
  },
  {
    "path": "docs/zh/index.md",
    "content": "# Vuex 是什么？\n\n::: tip 提示\n这是与 Vue 3 匹配的 Vuex 4 的文档。如果您在找与 Vue 2 匹配的 Vuex 3 的文档，[请在这里查看](https://v3.vuex.vuejs.org/zh/)。\n:::\n\nVuex 是一个专为 Vue.js 应用程序开发的**状态管理模式 + 库**。它采用集中式存储管理应用的所有组件的状态，并以相应的规则保证状态以一种可预测的方式发生变化。\n\n## 什么是“状态管理模式”？\n\n让我们从一个简单的 Vue 计数应用开始：\n\n``` js\nconst Counter = {\n  // 状态\n  data () {\n    return {\n      count: 0\n    }\n  },\n  // 视图\n  template: `\n    <div>{{ count }}</div>\n  `,\n  // 操作\n  methods: {\n    increment () {\n      this.count++\n    }\n  }\n}\n\ncreateApp(Counter).mount('#app')\n```\n\n这个状态自管理应用包含以下几个部分：\n\n- **状态**，驱动应用的数据源；\n- **视图**，以声明方式将**状态**映射到视图；\n- **操作**，响应在**视图**上的用户输入导致的状态变化。\n\n以下是一个表示“单向数据流”理念的简单示意：\n\n<p style=\"text-align: center; margin: 2em;\">\n  <img style=\"width: 100%; max-width: 450px;\" src=\"/flow.png\">\n</p>\n\n但是，当我们的应用遇到**多个组件共享状态**时，单向数据流的简洁性很容易被破坏：\n\n- 多个视图依赖于同一状态。\n- 来自不同视图的行为需要变更同一状态。\n\n对于问题一，传参的方法对于多层嵌套的组件将会非常繁琐，并且对于兄弟组件间的状态传递无能为力。对于问题二，我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱，通常会导致无法维护的代码。\n\n因此，我们为什么不把组件的共享状态抽取出来，以一个全局单例模式管理呢？在这种模式下，我们的组件树构成了一个巨大的“视图”，不管在树的哪个位置，任何组件都能获取状态或者触发行为！\n\n通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性，我们的代码将会变得更结构化且易维护。\n\n这就是 Vuex 背后的基本思想，借鉴了 [Flux](https://facebook.github.io/flux/docs/overview)、[Redux](http://redux.js.org/) 和 [The Elm Architecture](https://guide.elm-lang.org/architecture/)。与其他模式不同的是，Vuex 是专门为 Vue.js 设计的状态管理库，以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。\n\n如果你想交互式地学习 Vuex，可以看这个 [Scrimba 上的 Vuex 课程](https://scrimba.com/g/gvuex)，它将录屏和代码试验场混合在了一起，你可以随时暂停并尝试。\n\n![vuex](/vuex.png)\n\n## 什么情况下我应该使用 Vuex？\n\nVuex 可以帮助我们管理共享状态，并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。\n\n如果您不打算开发大型单页应用，使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单，您最好不要使用 Vuex。一个简单的 [store 模式](https://v3.cn.vuejs.org/guide/state-management.html#从零打造简单状态管理)就足够您所需了。但是，如果您需要构建一个中大型单页应用，您很可能会考虑如何更好地在组件外部管理状态，Vuex 将会成为自然而然的选择。引用 Redux 的作者 Dan Abramov 的话说就是：\n\n> Flux 架构就像眼镜：您自会知道什么时候需要它。\n"
  },
  {
    "path": "docs/zh/installation.md",
    "content": "# 安装\n\n## 直接下载 / CDN 引用\n\n[https://unpkg.com/vuex@4](https://unpkg.com/vuex@4)\n\n<!--email_off-->\n[Unpkg.com](https://unpkg.com) 提供了基于 npm 的 CDN 链接。以上的链接会一直指向 npm 上发布的最新版本。您也可以通过 `https://unpkg.com/vuex@4.0.0/dist/vuex.global.js` 这样的方式指定特定的版本。\n<!--/email_off-->\n\n在 Vue 之后引入 `vuex` 会进行自动安装：\n\n``` html\n<script src=\"/path/to/vue.js\"></script>\n<script src=\"/path/to/vuex.js\"></script>\n```\n\n## npm\n\n``` bash\nnpm install vuex@next --save\n```\n\n## Yarn\n\n``` bash\nyarn add vuex@next --save\n```\n\n## 自己构建\n\n如果需要使用 dev 分支下的最新版本，您可以直接从 GitHub 上克隆代码并自己构建。\n\n``` bash\ngit clone https://github.com/vuejs/vuex.git node_modules/vuex\ncd node_modules/vuex\nyarn\nyarn build\n```\n"
  },
  {
    "path": "examples/classic/chat/api/index.js",
    "content": "const data = require('./mock-data')\nconst LATENCY = 16\n\nexport function getAllMessages (cb) {\n  setTimeout(() => {\n    cb(data)\n  }, LATENCY)\n}\n\nexport function createMessage ({ text, thread }, cb) {\n  const timestamp = Date.now()\n  const id = 'm_' + timestamp\n  const message = {\n    id,\n    text,\n    timestamp,\n    threadID: thread.id,\n    threadName: thread.name,\n    authorName: 'Evan'\n  }\n  setTimeout(function () {\n    cb(message)\n  }, LATENCY)\n}\n"
  },
  {
    "path": "examples/classic/chat/api/mock-data.js",
    "content": "module.exports = [\n  {\n    id: 'm_1',\n    threadID: 't_1',\n    threadName: 'Jing and Bill',\n    authorName: 'Bill',\n    text: 'Hey Jing, want to give a Flux talk at ForwardJS?',\n    timestamp: Date.now() - 99999\n  },\n  {\n    id: 'm_2',\n    threadID: 't_1',\n    threadName: 'Jing and Bill',\n    authorName: 'Bill',\n    text: 'Seems like a pretty cool conference.',\n    timestamp: Date.now() - 89999\n  },\n  {\n    id: 'm_3',\n    threadID: 't_1',\n    threadName: 'Jing and Bill',\n    authorName: 'Jing',\n    text: 'Sounds good.  Will they be serving dessert?',\n    timestamp: Date.now() - 79999\n  },\n  {\n    id: 'm_4',\n    threadID: 't_2',\n    threadName: 'Dave and Bill',\n    authorName: 'Bill',\n    text: 'Hey Dave, want to get a beer after the conference?',\n    timestamp: Date.now() - 69999\n  },\n  {\n    id: 'm_5',\n    threadID: 't_2',\n    threadName: 'Dave and Bill',\n    authorName: 'Dave',\n    text: 'Totally!  Meet you at the hotel bar.',\n    timestamp: Date.now() - 59999\n  },\n  {\n    id: 'm_6',\n    threadID: 't_3',\n    threadName: 'Functional Heads',\n    authorName: 'Bill',\n    text: 'Hey Brian, are you going to be talking about functional stuff?',\n    timestamp: Date.now() - 49999\n  },\n  {\n    id: 'm_7',\n    threadID: 't_3',\n    threadName: 'Bill and Brian',\n    authorName: 'Brian',\n    text: 'At ForwardJS?  Yeah, of course.  See you there!',\n    timestamp: Date.now() - 39999\n  }\n]\n"
  },
  {
    "path": "examples/classic/chat/app.js",
    "content": "import { createApp } from 'vue'\nimport App from './components/App.vue'\nimport store from './store'\nimport { getAllMessages } from './store/actions'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n\ngetAllMessages(store)\n"
  },
  {
    "path": "examples/classic/chat/components/App.vue",
    "content": "<style src=\"../css/chat.css\"></style>\n\n<template>\n  <div class=\"chatapp\">\n    <thread-section></thread-section>\n    <message-section></message-section>\n  </div>\n</template>\n\n<script>\nimport ThreadSection from './ThreadSection.vue'\nimport MessageSection from './MessageSection.vue'\n\nexport default {\n  name: 'App',\n  components: {\n    ThreadSection,\n    MessageSection\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/classic/chat/components/Message.vue",
    "content": "<template>\n  <li class=\"message-list-item\">\n    <h5 class=\"message-author-name\">{{ message.authorName }}</h5>\n    <div class=\"message-time\">\n      {{ time(message.timestamp) }}\n    </div>\n    <div class=\"message-text\">{{ message.text }}</div>\n  </li>\n</template>\n\n<script>\nexport default {\n  name: 'Message',\n  props: {\n    message: Object\n  },\n  methods: {\n    time (value) {\n      return new Date(value).toLocaleTimeString()\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/classic/chat/components/MessageSection.vue",
    "content": "<template>\n  <div class=\"message-section\">\n    <h3 class=\"message-thread-heading\">{{ thread.name }}</h3>\n    <ul class=\"message-list\" ref=\"list\">\n      <message\n        v-for=\"message in messages\"\n        :key=\"message.id\"\n        :message=\"message\">\n      </message>\n    </ul>\n    <textarea\n      class=\"message-composer\"\n      v-model=\"text\"\n      @keyup.enter=\"sendMessage\"></textarea>\n  </div>\n</template>\n\n<script>\nimport Message from './Message.vue'\nimport { mapActions, mapGetters } from 'vuex'\n\nexport default {\n  name: 'MessageSection',\n  components: { Message },\n  data () {\n    return {\n      text: ''\n    }\n  },\n  computed: mapGetters({\n    thread: 'currentThread',\n    messages: 'sortedMessages'\n  }),\n  watch: {\n    'thread.lastMessage': function () {\n      this.$nextTick(() => {\n        const ul = this.$refs.list\n        ul.scrollTop = ul.scrollHeight\n      })\n    }\n  },\n  methods: mapActions({\n    sendMessage (dispatch) {\n      const { text, thread } = this\n      if (text.trim()) {\n        dispatch('sendMessage', {\n          text,\n          thread\n        })\n        this.text = ''\n      }\n    }\n  })\n}\n</script>\n"
  },
  {
    "path": "examples/classic/chat/components/Thread.vue",
    "content": "<template>\n  <li\n    class=\"thread-list-item\"\n    :class=\"{ active }\"\n    @click=\"$emit('switch-thread', thread.id)\">\n    <h5 class=\"thread-name\">{{ thread.name }}</h5>\n    <div class=\"thread-time\">\n      {{ time(thread.lastMessage.timestamp) }}\n    </div>\n    <div class=\"thread-last-message\">\n      {{ thread.lastMessage.text }}\n    </div>\n  </li>\n</template>\n\n<script>\nexport default {\n  name: 'Thread',\n  props: {\n    thread: Object,\n    active: Boolean\n  },\n  methods: {\n    time (value) {\n      return new Date(value).toLocaleTimeString()\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/classic/chat/components/ThreadSection.vue",
    "content": "<template>\n  <div class=\"thread-section\">\n    <div class=\"thread-count\">\n      <span v-show=\"unreadCount\">\n        Unread threads: {{ unreadCount }}\n      </span>\n    </div>\n    <ul class=\"thread-list\">\n      <thread\n        v-for=\"thread in threads\"\n        :key=\"thread.id\"\n        :thread=\"thread\"\n        :active=\"thread.id === currentThread.id\"\n        @switch-thread=\"switchThread\">\n      </thread>\n    </ul>\n  </div>\n</template>\n\n<script>\nimport Thread from './Thread.vue'\nimport { mapActions, mapGetters } from 'vuex'\n\nexport default {\n  name: 'ThreadSection',\n  components: { Thread },\n  computed: mapGetters(['threads', 'currentThread', 'unreadCount']),\n  methods: mapActions(['switchThread'])\n}\n</script>\n"
  },
  {
    "path": "examples/classic/chat/css/chat.css",
    "content": "/**\n * This file is provided by Facebook for testing and evaluation purposes\n * only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN\n * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n.chatapp {\n  font-family: 'Muli', 'Helvetica Neue', helvetica, arial;\n  max-width: 760px;\n  margin: 20px auto;\n  overflow: hidden;\n}\n\n.message-list, .thread-list {\n  border: 1px solid #ccf;\n  font-size: 16px;\n  height: 400px;\n  margin: 0;\n  overflow-y: auto;\n  padding: 0;\n}\n\n.message-section {\n  float: right;\n  width: 65%;\n}\n\n.thread-section {\n  float: left;\n  width: 32.5%;\n}\n\n.message-thread-heading,\n.thread-count {\n  height: 40px;\n  margin: 0;\n}\n\n.message-list-item, .thread-list-item {\n  list-style: none;\n  padding: 12px 14px 14px;\n}\n\n.thread-list-item {\n  border-bottom: 1px solid #ccc;\n  cursor: pointer;\n}\n\n.thread-list:hover .thread-list-item:hover {\n  background-color: #f8f8ff;\n}\n\n.thread-list:hover .thread-list-item {\n  background-color: #fff;\n}\n\n.thread-list-item.active,\n.thread-list:hover .thread-list-item.active,\n.thread-list:hover .thread-list-item.active:hover {\n  background-color: #efefff;\n  cursor: default;\n}\n\n.message-author-name,\n.thread-name {\n  color: #66c;\n  float: left;\n  font-size: 13px;\n  margin: 0;\n}\n\n.message-time, .thread-time {\n  color: #aad;\n  float: right;\n  font-size: 12px;\n}\n\n.message-text, .thread-last-message {\n  clear: both;\n  font-size: 14px;\n  padding-top: 10px;\n}\n\n.message-composer {\n  box-sizing: border-box;\n  font-family: inherit;\n  font-size: 14px;\n  height: 5em;\n  width: 100%;\n  margin: 20px 0 0;\n  padding: 10px;\n}\n"
  },
  {
    "path": "examples/classic/chat/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex chat example</title>\n    <link href=\"http://fonts.googleapis.com/css?family=Muli\" rel=\"stylesheet\" type=\"text/css\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/classic/chat.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/classic/chat/store/actions.js",
    "content": "import * as api from '../api'\n\nexport const getAllMessages = ({ commit }) => {\n  api.getAllMessages(messages => {\n    commit('receiveAll', messages)\n  })\n}\n\nexport const sendMessage = ({ commit }, payload) => {\n  api.createMessage(payload, message => {\n    commit('receiveMessage', message)\n  })\n}\n\nexport const switchThread = ({ commit }, payload) => {\n  commit('switchThread', payload)\n}\n"
  },
  {
    "path": "examples/classic/chat/store/getters.js",
    "content": "export const threads = state => state.threads\n\nexport const currentThread = state => {\n  return state.currentThreadID\n    ? state.threads[state.currentThreadID]\n    : {}\n}\n\nexport const currentMessages = state => {\n  const thread = currentThread(state)\n  return thread.messages\n    ? thread.messages.map(id => state.messages[id])\n    : []\n}\n\nexport const unreadCount = ({ threads }) => {\n  return Object.keys(threads).reduce((count, id) => {\n    return threads[id].lastMessage.isRead ? count : count + 1\n  }, 0)\n}\n\nexport const sortedMessages = (state, getters) => {\n  const messages = getters.currentMessages\n  return messages.slice().sort((a, b) => a.timestamp - b.timestamp)\n}\n"
  },
  {
    "path": "examples/classic/chat/store/index.js",
    "content": "import { createStore, createLogger } from 'vuex'\nimport * as getters from './getters'\nimport * as actions from './actions'\nimport mutations from './mutations'\n\nconst state = {\n  currentThreadID: null,\n  threads: {\n    /*\n    id: {\n      id,\n      name,\n      messages: [...ids],\n      lastMessage\n    }\n    */\n  },\n  messages: {\n    /*\n    id: {\n      id,\n      threadId,\n      threadName,\n      authorName,\n      text,\n      timestamp,\n      isRead\n    }\n    */\n  }\n}\n\nexport default createStore({\n  state,\n  getters,\n  actions,\n  mutations,\n  plugins: process.env.NODE_ENV !== 'production'\n    ? [createLogger()]\n    : []\n})\n"
  },
  {
    "path": "examples/classic/chat/store/mutations.js",
    "content": "export default {\n  receiveAll (state, messages) {\n    let latestMessage\n    messages.forEach(message => {\n      // create new thread if the thread doesn't exist\n      if (!state.threads[message.threadID]) {\n        createThread(state, message.threadID, message.threadName)\n      }\n      // mark the latest message\n      if (!latestMessage || message.timestamp > latestMessage.timestamp) {\n        latestMessage = message\n      }\n      // add message\n      addMessage(state, message)\n    })\n    // set initial thread to the one with the latest message\n    setCurrentThread(state, latestMessage.threadID)\n  },\n\n  receiveMessage (state, message) {\n    addMessage(state, message)\n  },\n\n  switchThread (state, id) {\n    setCurrentThread(state, id)\n  }\n}\n\nfunction createThread (state, id, name) {\n  state.threads = {\n    ...state.threads,\n    [id]: {\n      id,\n      name,\n      messages: [],\n      lastMessage: null\n    }\n  }\n}\n\nfunction addMessage (state, message) {\n  // add a `isRead` field before adding the message\n  message.isRead = message.threadID === state.currentThreadID\n  // add it to the thread it belongs to\n  const thread = state.threads[message.threadID]\n  if (!thread.messages.some(id => id === message.id)) {\n    thread.messages.push(message.id)\n    thread.lastMessage = message\n  }\n  // add it to the messages map\n  state.messages = {\n    ...state.messages,\n    [message.id]: message\n  }\n}\n\nfunction setCurrentThread (state, id) {\n  state.currentThreadID = id\n  if (!state.threads[id]) {\n    debugger\n  }\n  // mark thread as read\n  state.threads[id].lastMessage.isRead = true\n}\n"
  },
  {
    "path": "examples/classic/counter/Counter.vue",
    "content": "<template>\n  <div id=\"app\">\n    Clicked: {{ $store.state.count }} times, count is {{ evenOrOdd }}.\n    <button @click=\"increment\">+</button>\n    <button @click=\"decrement\">-</button>\n    <button @click=\"incrementIfOdd\">Increment if odd</button>\n    <button @click=\"incrementAsync\">Increment async</button>\n  </div>\n</template>\n\n<script>\nimport { mapGetters, mapActions } from 'vuex'\n\nexport default {\n  computed: mapGetters([\n    'evenOrOdd'\n  ]),\n  methods: mapActions([\n    'increment',\n    'decrement',\n    'incrementIfOdd',\n    'incrementAsync'\n  ])\n}\n</script>\n"
  },
  {
    "path": "examples/classic/counter/app.js",
    "content": "import { createApp } from 'vue'\nimport Counter from './Counter.vue'\nimport store from './store'\n\nconst app = createApp(Counter)\n\napp.use(store)\n\napp.mount('#app')\n"
  },
  {
    "path": "examples/classic/counter/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex counter example</title>\n    <link rel=\"stylesheet\" href=\"/global.css\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/classic/counter.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/classic/counter/store.js",
    "content": "import { createStore } from 'vuex'\n\n// root state object.\n// each Vuex instance is just a single state tree.\nconst state = {\n  count: 0\n}\n\n// mutations are operations that actually mutate the state.\n// each mutation handler gets the entire state tree as the\n// first argument, followed by additional payload arguments.\n// mutations must be synchronous and can be recorded by plugins\n// for debugging purposes.\nconst mutations = {\n  increment (state) {\n    state.count++\n  },\n  decrement (state) {\n    state.count--\n  }\n}\n\n// actions are functions that cause side effects and can involve\n// asynchronous operations.\nconst actions = {\n  increment: ({ commit }) => commit('increment'),\n  decrement: ({ commit }) => commit('decrement'),\n  incrementIfOdd ({ commit, state }) {\n    if ((state.count + 1) % 2 === 0) {\n      commit('increment')\n    }\n  },\n  incrementAsync ({ commit }) {\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        commit('increment')\n        resolve()\n      }, 1000)\n    })\n  }\n}\n\n// getters are functions.\nconst getters = {\n  evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'\n}\n\n// A Vuex instance is created by combining the state, mutations, actions,\n// and getters.\nexport default createStore({\n  state,\n  getters,\n  actions,\n  mutations\n})\n"
  },
  {
    "path": "examples/classic/counter-hot/CounterControls.vue",
    "content": "<template>\n  <div>\n    Value: {{ count }}\n    <button @click=\"increment\">+</button>\n    <button @click=\"decrement\">-</button>\n    <button @click=\"incrementIfOdd\">Increment if odd</button>\n    <button @click=\"incrementAsync\">Increment async</button>\n    <div>\n      <div>Recent History (last 5 entries): {{ recentHistory }}</div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { mapGetters, mapActions } from 'vuex'\n\nexport default {\n  computed: mapGetters([\n    'count',\n    'recentHistory'\n  ]),\n  methods: mapActions([\n    'increment',\n    'decrement',\n    'incrementIfOdd',\n    'incrementAsync'\n  ])\n}\n</script>\n"
  },
  {
    "path": "examples/classic/counter-hot/app.js",
    "content": "import { createApp } from 'vue'\nimport store from './store'\nimport CounterControls from './CounterControls.vue'\n\nconst app = createApp(CounterControls)\n\napp.use(store)\n\napp.mount('#app')\n"
  },
  {
    "path": "examples/classic/counter-hot/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex counter example</title>\n    <link rel=\"stylesheet\" href=\"/global.css\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/classic/counter-hot.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/classic/counter-hot/store/actions.js",
    "content": "export const increment = ({ commit }) => {\n  commit('increment')\n}\nexport const decrement = ({ commit }) => {\n  commit('decrement')\n}\n\nexport const incrementIfOdd = ({ commit, state }) => {\n  if ((state.count + 1) % 2 === 0) {\n    commit('increment')\n  }\n}\n\nexport const incrementAsync = ({ commit }) => {\n  setTimeout(() => {\n    commit('increment')\n  }, 1000)\n}\n"
  },
  {
    "path": "examples/classic/counter-hot/store/getters.js",
    "content": "export const count = state => state.count\n\nexport const recentHistory = state => {\n  return state.history\n    .slice(-5)\n    .join(', ')\n}\n"
  },
  {
    "path": "examples/classic/counter-hot/store/index.js",
    "content": "import { createStore } from 'vuex'\nimport * as getters from './getters'\nimport * as actions from './actions'\nimport * as mutations from './mutations'\n\nconst state = {\n  count: 0,\n  history: []\n}\n\nconst store = createStore({\n  state,\n  getters,\n  actions,\n  mutations\n})\n\nif (module.hot) {\n  module.hot.accept([\n    './getters',\n    './actions',\n    './mutations'\n  ], () => {\n    store.hotUpdate({\n      getters: require('./getters'),\n      actions: require('./actions'),\n      mutations: require('./mutations')\n    })\n  })\n}\n\nexport default store\n"
  },
  {
    "path": "examples/classic/counter-hot/store/mutations.js",
    "content": "export const increment = state => {\n  state.count++\n  state.history.push('increment')\n}\n\nexport const decrement = state => {\n  state.count--\n  state.history.push('decrement')\n}\n"
  },
  {
    "path": "examples/classic/shopping-cart/api/shop.js",
    "content": "/**\n * Mocking client-server processing\n */\nconst _products = [\n  { 'id': 1, 'title': 'iPad 4 Mini', 'price': 500.01, 'inventory': 2 },\n  { 'id': 2, 'title': 'H&M T-Shirt White', 'price': 10.99, 'inventory': 10 },\n  { 'id': 3, 'title': 'Charli XCX - Sucker CD', 'price': 19.99, 'inventory': 5 }\n]\n\nexport default {\n  async getProducts () {\n    await wait(100)\n    return _products\n  },\n\n  async buyProducts (products) {\n    await wait(100)\n    if (\n      // simulate random checkout failure.\n      (Math.random() > 0.5 || navigator.webdriver)\n    ) {\n      return\n    } else {\n      throw new Error('Checkout error')\n    }\n  }\n}\n\nfunction wait (ms) {\n  return new Promise(resolve => {\n    setTimeout(resolve, ms)\n  })\n}\n"
  },
  {
    "path": "examples/classic/shopping-cart/app.js",
    "content": "import { createApp } from 'vue'\nimport App from './components/App.vue'\nimport store from './store'\nimport { currency } from './currency'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n"
  },
  {
    "path": "examples/classic/shopping-cart/components/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <h1>Shopping Cart Example</h1>\n    <hr>\n    <h2>Products</h2>\n    <ProductList/>\n    <hr>\n    <ShoppingCart/>\n  </div>\n</template>\n\n<script>\nimport ProductList from './ProductList.vue'\nimport ShoppingCart from './ShoppingCart.vue'\n\nexport default {\n  components: { ProductList, ShoppingCart }\n}\n</script>\n"
  },
  {
    "path": "examples/classic/shopping-cart/components/ProductList.vue",
    "content": "<template>\n  <ul>\n    <li\n      v-for=\"product in products\"\n      :key=\"product.id\">\n      {{ product.title }} - {{ currency(product.price) }}\n      <br>\n      <button\n        :disabled=\"!product.inventory\"\n        @click=\"addProductToCart(product)\">\n        Add to cart\n      </button>\n    </li>\n  </ul>\n</template>\n\n<script>\nimport { mapState, mapActions } from 'vuex'\nimport { currency } from '../currency'\n\nexport default {\n  computed: mapState({\n    products: state => state.products.all\n  }),\n  methods: {\n    ...mapActions('cart', [\n      'addProductToCart'\n    ]),\n    currency\n  },\n  created () {\n    this.$store.dispatch('products/getAllProducts')\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/classic/shopping-cart/components/ShoppingCart.vue",
    "content": "<template>\n  <div class=\"cart\">\n    <h2>Your Cart</h2>\n    <p v-show=\"!products.length\">\n      <i>Please add some products to cart.</i>\n    </p>\n    <ul>\n      <li v-for=\"product in products\" :key=\"product.id\">\n        {{ product.title }} - {{ currency(product.price) }} x {{ product.quantity }}\n      </li>\n    </ul>\n    <p>Total: {{ currency(total) }}</p>\n    <p><button :disabled=\"!products.length\" @click=\"checkout(products)\">Checkout</button></p>\n    <p v-show=\"checkoutStatus\">Checkout {{ checkoutStatus }}.</p>\n  </div>\n</template>\n\n<script>\nimport { mapGetters, mapState } from 'vuex'\nimport { currency } from '../currency'\n\nexport default {\n  computed: {\n    ...mapState({\n      checkoutStatus: state => state.cart.checkoutStatus\n    }),\n    ...mapGetters('cart', {\n      products: 'cartProducts',\n      total: 'cartTotalPrice'\n    })\n  },\n  methods: {\n    currency,\n    checkout (products) {\n      this.$store.dispatch('cart/checkout', products)\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/classic/shopping-cart/currency.js",
    "content": "const digitsRE = /(\\d{3})(?=\\d)/g\n\nexport function currency (value, currency, decimals) {\n  value = parseFloat(value)\n  if (!isFinite(value) || (!value && value !== 0)) return ''\n  currency = currency != null ? currency : '$'\n  decimals = decimals != null ? decimals : 2\n  var stringified = Math.abs(value).toFixed(decimals)\n  var _int = decimals\n    ? stringified.slice(0, -1 - decimals)\n    : stringified\n  var i = _int.length % 3\n  var head = i > 0\n    ? (_int.slice(0, i) + (_int.length > 3 ? ',' : ''))\n    : ''\n  var _float = decimals\n    ? stringified.slice(-1 - decimals)\n    : ''\n  var sign = value < 0 ? '-' : ''\n  return sign + currency + head +\n    _int.slice(i).replace(digitsRE, '$1,') +\n    _float\n}\n"
  },
  {
    "path": "examples/classic/shopping-cart/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex shopping cart example</title>\n    <link rel=\"stylesheet\" href=\"/global.css\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/classic/shopping-cart.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/classic/shopping-cart/store/index.js",
    "content": "import { createStore, createLogger } from 'vuex'\nimport cart from './modules/cart'\nimport products from './modules/products'\n\nconst debug = process.env.NODE_ENV !== 'production'\n\nexport default createStore({\n  modules: {\n    cart,\n    products\n  },\n  strict: debug,\n  plugins: debug ? [createLogger()] : []\n})\n"
  },
  {
    "path": "examples/classic/shopping-cart/store/modules/cart.js",
    "content": "import shop from '../../api/shop'\nimport nested from './nested'\n\n// initial state\n// shape: [{ id, quantity }]\nconst state = () => ({\n  items: [],\n  checkoutStatus: null\n})\n\n// getters\nconst getters = {\n  cartProducts: (state, getters, rootState) => {\n    return state.items.map(({ id, quantity }) => {\n      const product = rootState.products.all.find(product => product.id === id)\n      return {\n        id: product.id,\n        title: product.title,\n        price: product.price,\n        quantity\n      }\n    })\n  },\n\n  cartTotalPrice: (state, getters) => {\n    return getters.cartProducts.reduce((total, product) => {\n      return total + product.price * product.quantity\n    }, 0)\n  }\n}\n\n// actions\nconst actions = {\n  async checkout ({ commit, state }, products) {\n    const savedCartItems = [...state.items]\n    commit('setCheckoutStatus', null)\n    // empty cart\n    commit('setCartItems', { items: [] })\n    try {\n      await shop.buyProducts(products)\n      commit('setCheckoutStatus', 'successful')\n    } catch (e) {\n      console.error(e)\n      commit('setCheckoutStatus', 'failed')\n      // rollback to the cart saved before sending the request\n      commit('setCartItems', { items: savedCartItems })\n    }\n  },\n\n  addProductToCart ({ state, commit }, product) {\n    commit('setCheckoutStatus', null)\n    if (product.inventory > 0) {\n      const cartItem = state.items.find(item => item.id === product.id)\n      if (!cartItem) {\n        commit('pushProductToCart', { id: product.id })\n      } else {\n        commit('incrementItemQuantity', cartItem)\n      }\n      // remove 1 item from stock\n      commit('products/decrementProductInventory', { id: product.id }, { root: true })\n    }\n  }\n}\n\n// mutations\nconst mutations = {\n  pushProductToCart (state, { id }) {\n    state.items.push({\n      id,\n      quantity: 1\n    })\n  },\n\n  incrementItemQuantity (state, { id }) {\n    const cartItem = state.items.find(item => item.id === id)\n    cartItem.quantity++\n  },\n\n  setCartItems (state, { items }) {\n    state.items = items\n  },\n\n  setCheckoutStatus (state, status) {\n    state.checkoutStatus = status\n  }\n}\n\nexport default {\n  namespaced: true,\n  state,\n  getters,\n  actions,\n  mutations,\n  modules: {\n    nested\n  }\n}\n"
  },
  {
    "path": "examples/classic/shopping-cart/store/modules/nested.js",
    "content": "export default {\n  namespaced: true,\n  state: () => ({\n    foo: 'bar'\n  }),\n  getters: {\n    twoBars: state => state.foo.repeat(2)\n  }\n}\n"
  },
  {
    "path": "examples/classic/shopping-cart/store/modules/products.js",
    "content": "import shop from '../../api/shop'\n\n// initial state\nconst state = () => ({\n  all: []\n})\n\n// getters\nconst getters = {}\n\n// actions\nconst actions = {\n  async getAllProducts ({ commit }) {\n    const products = await shop.getProducts()\n    commit('setProducts', products)\n  }\n}\n\n// mutations\nconst mutations = {\n  setProducts (state, products) {\n    state.all = products\n  },\n\n  decrementProductInventory (state, { id }) {\n    const product = state.all.find(product => product.id === id)\n    product.inventory--\n  }\n}\n\nexport default {\n  namespaced: true,\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "examples/classic/todomvc/app.js",
    "content": "import { createApp } from 'vue'\nimport store from './store'\nimport App from './components/App.vue'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n"
  },
  {
    "path": "examples/classic/todomvc/components/App.vue",
    "content": "<style src=\"todomvc-app-css/index.css\"></style>\n\n<template>\n  <section class=\"todoapp\">\n    <!-- header -->\n    <header class=\"header\">\n      <h1>todos</h1>\n      <input class=\"new-todo\"\n        autofocus\n        autocomplete=\"off\"\n        placeholder=\"What needs to be done?\"\n        @keyup.enter=\"addTodo\">\n    </header>\n    <!-- main section -->\n    <section class=\"main\" v-show=\"todos.length\">\n      <input class=\"toggle-all\" id=\"toggle-all\"\n        type=\"checkbox\"\n        :checked=\"allChecked\"\n        @change=\"toggleAll(!allChecked)\">\n      <label for=\"toggle-all\"></label>\n      <ul class=\"todo-list\">\n        <TodoItem\n          v-for=\"(todo, index) in filteredTodos\"\n          :key=\"index\"\n          :todo=\"todo\"\n        />\n      </ul>\n    </section>\n    <!-- footer -->\n    <footer class=\"footer\" v-show=\"todos.length\">\n      <span class=\"todo-count\">\n        <strong>{{ remaining }}</strong>\n        {{ pluralize(remaining, 'item') }} left\n      </span>\n      <ul class=\"filters\">\n        <li v-for=\"(val, key) in filters\">\n          <a :href=\"'#/' + key\"\n            :class=\"{ selected: visibility === key }\"\n            @click=\"visibility = key\">{{ capitalize(key) }}</a>\n        </li>\n      </ul>\n      <button class=\"clear-completed\"\n        v-show=\"todos.length > remaining\"\n        @click=\"clearCompleted\">\n        Clear completed\n      </button>\n    </footer>\n  </section>\n</template>\n\n<script>\nimport { mapActions } from 'vuex'\nimport TodoItem from './TodoItem.vue'\n\nconst filters = {\n  all: todos => todos,\n  active: todos => todos.filter(todo => !todo.done),\n  completed: todos => todos.filter(todo => todo.done)\n}\n\nexport default {\n  components: { TodoItem },\n  data () {\n    return {\n      visibility: 'all',\n      filters: filters\n    }\n  },\n  computed: {\n    todos () {\n      return this.$store.state.todos\n    },\n    allChecked () {\n      return this.todos.every(todo => todo.done)\n    },\n    filteredTodos () {\n      return filters[this.visibility](this.todos)\n    },\n    remaining () {\n      return this.todos.filter(todo => !todo.done).length\n    }\n  },\n  methods: {\n    ...mapActions([\n      'toggleAll',\n      'clearCompleted'\n    ]),\n    addTodo (e) {\n      const text = e.target.value\n      if (text.trim()) {\n        this.$store.dispatch('addTodo', text)\n      }\n      e.target.value = ''\n    },\n    pluralize (n, w) {\n      return n === 1 ? w : (w + 's')\n    },\n    capitalize (s) {\n      return s.charAt(0).toUpperCase() + s.slice(1)\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/classic/todomvc/components/TodoItem.vue",
    "content": "<template>\n  <li class=\"todo\" :class=\"{ completed: todo.done, editing }\">\n    <div class=\"view\">\n      <input class=\"toggle\"\n        type=\"checkbox\"\n        :checked=\"todo.done\"\n        @change=\"toggleTodo(todo)\">\n      <label v-text=\"todo.text\" @dblclick=\"editing = true\"></label>\n      <button class=\"destroy\" @click=\"removeTodo(todo)\"></button>\n    </div>\n    <input class=\"edit\"\n      v-show=\"editing\"\n      :value=\"todo.text\"\n      ref=\"input\"\n      @keyup.enter=\"doneEdit\"\n      @keyup.esc=\"cancelEdit\"\n      @blur=\"doneEdit\">\n  </li>\n</template>\n\n<script>\nimport { nextTick } from 'vue'\nimport { mapActions } from 'vuex'\n\nexport default {\n  name: 'Todo',\n  props: ['todo'],\n  data () {\n    return {\n      editing: false\n    }\n  },\n  directives: {\n    focus (el, { value }, { context }) {\n      if (value) {\n        context.$nextTick(() => {\n          el.focus()\n        })\n      }\n    }\n  },\n  watch: {\n    editing (v) {\n      v && nextTick(() => { this.$refs.input.focus() })\n    }\n  },\n  methods: {\n    ...mapActions([\n      'editTodo',\n      'toggleTodo',\n      'removeTodo'\n    ]),\n    doneEdit (e) {\n      const value = e.target.value.trim()\n      const { todo } = this\n      if (!value) {\n        this.removeTodo(todo)\n      } else if (this.editing) {\n        this.editTodo({\n          todo,\n          value\n        })\n        this.editing = false\n      }\n    },\n    cancelEdit (e) {\n      e.target.value = this.todo.text\n      this.editing = false\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/classic/todomvc/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex todomvc example</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/classic/todomvc.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/classic/todomvc/store/actions.js",
    "content": "export default {\n  addTodo ({ commit }, text) {\n    commit('addTodo', {\n      text,\n      done: false\n    })\n  },\n\n  removeTodo ({ commit }, todo) {\n    commit('removeTodo', todo)\n  },\n\n  toggleTodo ({ commit }, todo) {\n    commit('editTodo', { todo, done: !todo.done })\n  },\n\n  editTodo ({ commit }, { todo, value }) {\n    commit('editTodo', { todo, text: value })\n  },\n\n  toggleAll ({ state, commit }, done) {\n    state.todos.forEach((todo) => {\n      commit('editTodo', { todo, done })\n    })\n  },\n\n  clearCompleted ({ state, commit }) {\n    state.todos.filter(todo => todo.done)\n      .forEach(todo => {\n        commit('removeTodo', todo)\n      })\n  }\n}\n"
  },
  {
    "path": "examples/classic/todomvc/store/index.js",
    "content": "import { createStore } from 'vuex'\nimport { mutations, STORAGE_KEY } from './mutations'\nimport actions from './actions'\nimport plugins from './plugins'\n\nexport default createStore({\n  state: {\n    todos: JSON.parse(window.localStorage.getItem(STORAGE_KEY) || '[]')\n  },\n  actions,\n  mutations,\n  plugins\n})\n"
  },
  {
    "path": "examples/classic/todomvc/store/mutations.js",
    "content": "export const STORAGE_KEY = 'todos-vuejs'\n\n// for testing\nif (navigator.webdriver) {\n  window.localStorage.clear()\n}\n\nexport const mutations = {\n  addTodo (state, todo) {\n    state.todos.push(todo)\n  },\n\n  removeTodo (state, todo) {\n    state.todos.splice(state.todos.indexOf(todo), 1)\n  },\n\n  editTodo (state, { todo, text = todo.text, done = todo.done }) {\n    const index = state.todos.indexOf(todo)\n\n    state.todos.splice(index, 1, {\n      ...todo,\n      text,\n      done\n    })\n  }\n}\n"
  },
  {
    "path": "examples/classic/todomvc/store/plugins.js",
    "content": "import { createLogger } from 'vuex'\nimport { STORAGE_KEY } from './mutations'\n\nconst localStoragePlugin = store => {\n  store.subscribe((mutation, { todos }) => {\n    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))\n  })\n}\n\nexport default process.env.NODE_ENV !== 'production'\n  ? [createLogger(), localStoragePlugin]\n  : [localStoragePlugin]\n"
  },
  {
    "path": "examples/composition/chat/api/index.js",
    "content": "const data = require('./mock-data')\nconst LATENCY = 16\n\nexport function getAllMessages (cb) {\n  setTimeout(() => {\n    cb(data)\n  }, LATENCY)\n}\n\nexport function createMessage ({ text, thread }, cb) {\n  const timestamp = Date.now()\n  const id = 'm_' + timestamp\n  const message = {\n    id,\n    text,\n    timestamp,\n    threadID: thread.id,\n    threadName: thread.name,\n    authorName: 'Evan'\n  }\n  setTimeout(function () {\n    cb(message)\n  }, LATENCY)\n}\n"
  },
  {
    "path": "examples/composition/chat/api/mock-data.js",
    "content": "module.exports = [\n  {\n    id: 'm_1',\n    threadID: 't_1',\n    threadName: 'Jing and Bill',\n    authorName: 'Bill',\n    text: 'Hey Jing, want to give a Flux talk at ForwardJS?',\n    timestamp: Date.now() - 99999\n  },\n  {\n    id: 'm_2',\n    threadID: 't_1',\n    threadName: 'Jing and Bill',\n    authorName: 'Bill',\n    text: 'Seems like a pretty cool conference.',\n    timestamp: Date.now() - 89999\n  },\n  {\n    id: 'm_3',\n    threadID: 't_1',\n    threadName: 'Jing and Bill',\n    authorName: 'Jing',\n    text: 'Sounds good.  Will they be serving dessert?',\n    timestamp: Date.now() - 79999\n  },\n  {\n    id: 'm_4',\n    threadID: 't_2',\n    threadName: 'Dave and Bill',\n    authorName: 'Bill',\n    text: 'Hey Dave, want to get a beer after the conference?',\n    timestamp: Date.now() - 69999\n  },\n  {\n    id: 'm_5',\n    threadID: 't_2',\n    threadName: 'Dave and Bill',\n    authorName: 'Dave',\n    text: 'Totally!  Meet you at the hotel bar.',\n    timestamp: Date.now() - 59999\n  },\n  {\n    id: 'm_6',\n    threadID: 't_3',\n    threadName: 'Functional Heads',\n    authorName: 'Bill',\n    text: 'Hey Brian, are you going to be talking about functional stuff?',\n    timestamp: Date.now() - 49999\n  },\n  {\n    id: 'm_7',\n    threadID: 't_3',\n    threadName: 'Bill and Brian',\n    authorName: 'Brian',\n    text: 'At ForwardJS?  Yeah, of course.  See you there!',\n    timestamp: Date.now() - 39999\n  }\n]\n"
  },
  {
    "path": "examples/composition/chat/app.js",
    "content": "import { createApp } from 'vue'\nimport App from './components/App.vue'\nimport store from './store'\nimport { getAllMessages } from './store/actions'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n\ngetAllMessages(store)\n"
  },
  {
    "path": "examples/composition/chat/components/App.vue",
    "content": "<style src=\"../css/chat.css\"></style>\n\n<template>\n  <div class=\"chatapp\">\n    <thread-section></thread-section>\n    <message-section></message-section>\n  </div>\n</template>\n\n<script>\nimport ThreadSection from './ThreadSection.vue'\nimport MessageSection from './MessageSection.vue'\n\nexport default {\n  name: 'App',\n  components: {\n    ThreadSection,\n    MessageSection\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/chat/components/Message.vue",
    "content": "<template>\n  <li class=\"message-list-item\">\n    <h5 class=\"message-author-name\">{{ message.authorName }}</h5>\n    <div class=\"message-time\">\n      {{ time(message.timestamp) }}\n    </div>\n    <div class=\"message-text\">{{ message.text }}</div>\n  </li>\n</template>\n\n<script>\nexport default {\n  name: 'Message',\n  props: {\n    message: Object\n  },\n  setup () {\n    return {\n      time: value => new Date(value).toLocaleTimeString()\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/chat/components/MessageSection.vue",
    "content": "<template>\n  <div class=\"message-section\">\n    <h3 class=\"message-thread-heading\">{{ thread.name }}</h3>\n    <ul class=\"message-list\" ref=\"list\">\n      <message\n        v-for=\"message in messages\"\n        :key=\"message.id\"\n        :message=\"message\">\n      </message>\n    </ul>\n    <textarea\n      class=\"message-composer\"\n      v-model=\"text\"\n      @keyup.enter=\"sendMessage\"></textarea>\n  </div>\n</template>\n\n<script>\nimport { ref, computed, watch, nextTick } from 'vue'\nimport { useStore } from 'vuex'\nimport Message from './Message.vue'\n\nexport default {\n  name: 'MessageSection',\n  components: { Message },\n  setup () {\n    const list = ref(null)\n\n    const store = useStore()\n\n    const text = ref('')\n\n    const thread = computed(() => store.getters.currentThread)\n    const messages = computed(() => store.getters.sortedMessages)\n\n    watch(() => thread.value.lastMessage, () => {\n      nextTick(() => {\n        const ul = list.value\n        ul.scrollTop = ul.scrollHeight\n      })\n    })\n\n    function sendMessage () {\n      const trimedText = text.value.trim()\n      if (trimedText) {\n        store.dispatch('sendMessage', {\n          text: trimedText,\n          thread: thread.value\n        })\n        this.text = ''\n      }\n    }\n\n    return {\n      list,\n      text,\n      thread,\n      messages,\n      sendMessage\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/chat/components/Thread.vue",
    "content": "<template>\n  <li\n    class=\"thread-list-item\"\n    :class=\"{ active }\"\n    @click=\"$emit('switch-thread', thread.id)\">\n    <h5 class=\"thread-name\">{{ thread.name }}</h5>\n    <div class=\"thread-time\">\n      {{ time(thread.lastMessage.timestamp) }}\n    </div>\n    <div class=\"thread-last-message\">\n      {{ thread.lastMessage.text }}\n    </div>\n  </li>\n</template>\n\n<script>\nexport default {\n  name: 'Thread',\n  props: {\n    thread: Object,\n    active: Boolean\n  },\n  setup () {\n    return {\n      time: value => new Date(value).toLocaleTimeString()\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/chat/components/ThreadSection.vue",
    "content": "<template>\n  <div class=\"thread-section\">\n    <div class=\"thread-count\">\n      <span v-show=\"unreadCount\">\n        Unread threads: {{ unreadCount }}\n      </span>\n    </div>\n    <ul class=\"thread-list\">\n      <thread\n        v-for=\"thread in threads\"\n        :key=\"thread.id\"\n        :thread=\"thread\"\n        :active=\"thread.id === currentThread.id\"\n        @switch-thread=\"switchThread\">\n      </thread>\n    </ul>\n  </div>\n</template>\n\n<script>\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\nimport Thread from './Thread.vue'\n\nexport default {\n  name: 'ThreadSection',\n  components: { Thread },\n  setup () {\n    const store = useStore()\n\n    return {\n      threads: computed(() => store.getters.threads),\n      currentThread: computed(() => store.getters.currentThread),\n      unreadCount: computed(() => store.getters.unreadCount),\n      switchThread: (id) => store.dispatch('switchThread', id)\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/chat/css/chat.css",
    "content": "/**\n * This file is provided by Facebook for testing and evaluation purposes\n * only. Facebook reserves all rights not expressly granted.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN\n * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n.chatapp {\n  font-family: 'Muli', 'Helvetica Neue', helvetica, arial;\n  max-width: 760px;\n  margin: 20px auto;\n  overflow: hidden;\n}\n\n.message-list, .thread-list {\n  border: 1px solid #ccf;\n  font-size: 16px;\n  height: 400px;\n  margin: 0;\n  overflow-y: auto;\n  padding: 0;\n}\n\n.message-section {\n  float: right;\n  width: 65%;\n}\n\n.thread-section {\n  float: left;\n  width: 32.5%;\n}\n\n.message-thread-heading,\n.thread-count {\n  height: 40px;\n  margin: 0;\n}\n\n.message-list-item, .thread-list-item {\n  list-style: none;\n  padding: 12px 14px 14px;\n}\n\n.thread-list-item {\n  border-bottom: 1px solid #ccc;\n  cursor: pointer;\n}\n\n.thread-list:hover .thread-list-item:hover {\n  background-color: #f8f8ff;\n}\n\n.thread-list:hover .thread-list-item {\n  background-color: #fff;\n}\n\n.thread-list-item.active,\n.thread-list:hover .thread-list-item.active,\n.thread-list:hover .thread-list-item.active:hover {\n  background-color: #efefff;\n  cursor: default;\n}\n\n.message-author-name,\n.thread-name {\n  color: #66c;\n  float: left;\n  font-size: 13px;\n  margin: 0;\n}\n\n.message-time, .thread-time {\n  color: #aad;\n  float: right;\n  font-size: 12px;\n}\n\n.message-text, .thread-last-message {\n  clear: both;\n  font-size: 14px;\n  padding-top: 10px;\n}\n\n.message-composer {\n  box-sizing: border-box;\n  font-family: inherit;\n  font-size: 14px;\n  height: 5em;\n  width: 100%;\n  margin: 20px 0 0;\n  padding: 10px;\n}\n"
  },
  {
    "path": "examples/composition/chat/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex chat example</title>\n    <link href=\"http://fonts.googleapis.com/css?family=Muli\" rel=\"stylesheet\" type=\"text/css\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/composition/chat.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/composition/chat/store/actions.js",
    "content": "import * as api from '../api'\n\nexport const getAllMessages = ({ commit }) => {\n  api.getAllMessages(messages => {\n    commit('receiveAll', messages)\n  })\n}\n\nexport const sendMessage = ({ commit }, payload) => {\n  api.createMessage(payload, message => {\n    commit('receiveMessage', message)\n  })\n}\n\nexport const switchThread = ({ commit }, payload) => {\n  commit('switchThread', payload)\n}\n"
  },
  {
    "path": "examples/composition/chat/store/getters.js",
    "content": "export const threads = state => state.threads\n\nexport const currentThread = state => {\n  return state.currentThreadID\n    ? state.threads[state.currentThreadID]\n    : {}\n}\n\nexport const currentMessages = state => {\n  const thread = currentThread(state)\n  return thread.messages\n    ? thread.messages.map(id => state.messages[id])\n    : []\n}\n\nexport const unreadCount = ({ threads }) => {\n  return Object.keys(threads).reduce((count, id) => {\n    return threads[id].lastMessage.isRead ? count : count + 1\n  }, 0)\n}\n\nexport const sortedMessages = (state, getters) => {\n  const messages = getters.currentMessages\n  return messages.slice().sort((a, b) => a.timestamp - b.timestamp)\n}\n"
  },
  {
    "path": "examples/composition/chat/store/index.js",
    "content": "import { createStore, createLogger } from 'vuex'\nimport * as getters from './getters'\nimport * as actions from './actions'\nimport mutations from './mutations'\n\nconst state = {\n  currentThreadID: null,\n  threads: {\n    /*\n    id: {\n      id,\n      name,\n      messages: [...ids],\n      lastMessage\n    }\n    */\n  },\n  messages: {\n    /*\n    id: {\n      id,\n      threadId,\n      threadName,\n      authorName,\n      text,\n      timestamp,\n      isRead\n    }\n    */\n  }\n}\n\nexport default createStore({\n  state,\n  getters,\n  actions,\n  mutations,\n  plugins: process.env.NODE_ENV !== 'production'\n    ? [createLogger()]\n    : []\n})\n"
  },
  {
    "path": "examples/composition/chat/store/mutations.js",
    "content": "export default {\n  receiveAll (state, messages) {\n    let latestMessage\n    messages.forEach(message => {\n      // create new thread if the thread doesn't exist\n      if (!state.threads[message.threadID]) {\n        createThread(state, message.threadID, message.threadName)\n      }\n      // mark the latest message\n      if (!latestMessage || message.timestamp > latestMessage.timestamp) {\n        latestMessage = message\n      }\n      // add message\n      addMessage(state, message)\n    })\n    // set initial thread to the one with the latest message\n    setCurrentThread(state, latestMessage.threadID)\n  },\n\n  receiveMessage (state, message) {\n    addMessage(state, message)\n  },\n\n  switchThread (state, id) {\n    setCurrentThread(state, id)\n  }\n}\n\nfunction createThread (state, id, name) {\n  state.threads = {\n    ...state.threads,\n    [id]: {\n      id,\n      name,\n      messages: [],\n      lastMessage: null\n    }\n  }\n}\n\nfunction addMessage (state, message) {\n  // add a `isRead` field before adding the message\n  message.isRead = message.threadID === state.currentThreadID\n  // add it to the thread it belongs to\n  const thread = state.threads[message.threadID]\n  if (!thread.messages.some(id => id === message.id)) {\n    thread.messages.push(message.id)\n    thread.lastMessage = message\n  }\n  // add it to the messages map\n  state.messages = {\n    ...state.messages,\n    [message.id]: message\n  }\n}\n\nfunction setCurrentThread (state, id) {\n  state.currentThreadID = id\n  if (!state.threads[id]) {\n    debugger\n  }\n  // mark thread as read\n  state.threads[id].lastMessage.isRead = true\n}\n"
  },
  {
    "path": "examples/composition/counter/Counter.vue",
    "content": "<template>\n  <div id=\"app\">\n    Clicked: {{ count }} times, count is {{ evenOrOdd }}.\n    <button @click=\"increment\">+</button>\n    <button @click=\"decrement\">-</button>\n    <button @click=\"incrementIfOdd\">Increment if odd</button>\n    <button @click=\"incrementAsync\">Increment async</button>\n  </div>\n</template>\n\n<script>\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      count: computed(() => store.state.count),\n      evenOrOdd: computed(() => store.getters.evenOrOdd),\n      increment: () => store.dispatch('increment'),\n      decrement: () => store.dispatch('decrement'),\n      incrementIfOdd: () => store.dispatch('incrementIfOdd'),\n      incrementAsync: () => store.dispatch('incrementAsync')\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/counter/app.js",
    "content": "import { createApp } from 'vue'\nimport Counter from './Counter.vue'\nimport store from './store'\n\nconst app = createApp(Counter)\n\napp.use(store)\n\napp.mount('#app')\n"
  },
  {
    "path": "examples/composition/counter/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex counter example</title>\n    <link rel=\"stylesheet\" href=\"/global.css\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/composition/counter.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/composition/counter/store.js",
    "content": "import { createStore } from 'vuex'\n\n// root state object.\n// each Vuex instance is just a single state tree.\nconst state = {\n  count: 0\n}\n\n// mutations are operations that actually mutate the state.\n// each mutation handler gets the entire state tree as the\n// first argument, followed by additional payload arguments.\n// mutations must be synchronous and can be recorded by plugins\n// for debugging purposes.\nconst mutations = {\n  increment (state) {\n    state.count++\n  },\n  decrement (state) {\n    state.count--\n  }\n}\n\n// actions are functions that cause side effects and can involve\n// asynchronous operations.\nconst actions = {\n  increment: ({ commit }) => commit('increment'),\n  decrement: ({ commit }) => commit('decrement'),\n  incrementIfOdd ({ commit, state }) {\n    if ((state.count + 1) % 2 === 0) {\n      commit('increment')\n    }\n  },\n  incrementAsync ({ commit }) {\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        commit('increment')\n        resolve()\n      }, 1000)\n    })\n  }\n}\n\n// getters are functions.\nconst getters = {\n  evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'\n}\n\n// A Vuex instance is created by combining the state, mutations, actions,\n// and getters.\nexport default createStore({\n  state,\n  getters,\n  actions,\n  mutations\n})\n"
  },
  {
    "path": "examples/composition/counter-hot/CounterControls.vue",
    "content": "<template>\n  <div>\n    Value: {{ count }}\n    <button @click=\"increment\">+</button>\n    <button @click=\"decrement\">-</button>\n    <button @click=\"incrementIfOdd\">Increment if odd</button>\n    <button @click=\"incrementAsync\">Increment async</button>\n    <div>\n      <div>Recent History (last 5 entries): {{ recentHistory }}</div>\n    </div>\n  </div>\n</template>\n\n<script>\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    return {\n      count: computed(() => store.getters.count),\n      recentHistory: computed(() => store.getters.recentHistory),\n      increment: () => store.dispatch('increment'),\n      decrement: () => store.dispatch('decrement'),\n      incrementIfOdd: () => store.dispatch('incrementIfOdd'),\n      incrementAsync: () => store.dispatch('incrementAsync')\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/counter-hot/app.js",
    "content": "import { createApp } from 'vue'\nimport store from './store'\nimport CounterControls from './CounterControls.vue'\n\nconst app = createApp(CounterControls)\n\napp.use(store)\n\napp.mount('#app')\n"
  },
  {
    "path": "examples/composition/counter-hot/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex counter example</title>\n    <link rel=\"stylesheet\" href=\"/global.css\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/composition/counter-hot.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/composition/counter-hot/store/actions.js",
    "content": "export const increment = ({ commit }) => {\n  commit('increment')\n}\nexport const decrement = ({ commit }) => {\n  commit('decrement')\n}\n\nexport const incrementIfOdd = ({ commit, state }) => {\n  if ((state.count + 1) % 2 === 0) {\n    commit('increment')\n  }\n}\n\nexport const incrementAsync = ({ commit }) => {\n  setTimeout(() => {\n    commit('increment')\n  }, 1000)\n}\n"
  },
  {
    "path": "examples/composition/counter-hot/store/getters.js",
    "content": "export const count = state => state.count\n\nexport const t = (state) => {\n  return state.test\n}\n\nconst limit = 5\n\nexport const recentHistory = state => {\n  const end = state.history.length\n  const begin = end - limit < 0 ? 0 : end - limit\n  return state.history\n    .slice(begin, end)\n    .join(', ')\n}\n"
  },
  {
    "path": "examples/composition/counter-hot/store/index.js",
    "content": "import { createStore } from 'vuex'\nimport * as getters from './getters'\nimport * as actions from './actions'\nimport * as mutations from './mutations'\n\nconst state = {\n  test: 0,\n  count: 0,\n  history: []\n}\n\nconst store = createStore({\n  state,\n  getters,\n  actions,\n  mutations\n})\n\nif (module.hot) {\n  module.hot.accept([\n    './getters',\n    './actions',\n    './mutations'\n  ], () => {\n    store.hotUpdate({\n      getters: require('./getters'),\n      actions: require('./actions'),\n      mutations: require('./mutations')\n    })\n  })\n}\n\nexport default store\n"
  },
  {
    "path": "examples/composition/counter-hot/store/mutations.js",
    "content": "export const increment = state => {\n  state.count++\n  state.history.push('increment')\n}\n\nexport const decrement = state => {\n  state.count--\n  state.history.push('decrement')\n}\n"
  },
  {
    "path": "examples/composition/shopping-cart/api/shop.js",
    "content": "/**\n * Mocking client-server processing\n */\nconst _products = [\n  { 'id': 1, 'title': 'iPad 4 Mini', 'price': 500.01, 'inventory': 2 },\n  { 'id': 2, 'title': 'H&M T-Shirt White', 'price': 10.99, 'inventory': 10 },\n  { 'id': 3, 'title': 'Charli XCX - Sucker CD', 'price': 19.99, 'inventory': 5 }\n]\n\nexport default {\n  getProducts (cb) {\n    setTimeout(() => cb(_products), 100)\n  },\n\n  buyProducts (products, cb, errorCb) {\n    setTimeout(() => {\n      // simulate random checkout failure.\n      (Math.random() > 0.5 || navigator.webdriver)\n        ? cb()\n        : errorCb()\n    }, 100)\n  }\n}\n"
  },
  {
    "path": "examples/composition/shopping-cart/app.js",
    "content": "import { createApp } from 'vue'\nimport App from './components/App.vue'\nimport store from './store'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n"
  },
  {
    "path": "examples/composition/shopping-cart/components/App.vue",
    "content": "<template>\n  <div id=\"app\">\n    <h1>Shopping Cart Example</h1>\n    <hr>\n    <h2>Products</h2>\n    <ProductList/>\n    <hr>\n    <ShoppingCart/>\n  </div>\n</template>\n\n<script>\nimport ProductList from './ProductList.vue'\nimport ShoppingCart from './ShoppingCart.vue'\n\nexport default {\n  components: { ProductList, ShoppingCart }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/shopping-cart/components/ProductList.vue",
    "content": "<template>\n  <ul>\n    <li\n      v-for=\"product in products\"\n      :key=\"product.id\">\n      {{ product.title }} - {{ currency(product.price) }}\n      <br>\n      <button\n        :disabled=\"!product.inventory\"\n        @click=\"addProductToCart(product)\">\n        Add to cart\n      </button>\n    </li>\n  </ul>\n</template>\n\n<script>\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\nimport { currency } from '../currency'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    const products = computed(() => store.state.products.all)\n\n    const addProductToCart = (product) => store.dispatch('cart/addProductToCart', product)\n\n    store.dispatch('products/getAllProducts')\n\n    return {\n      products,\n      addProductToCart,\n      currency\n    }\n  }\n  // computed: mapState({\n  //   products: state => state.products.all\n  // }),\n  // methods: mapActions('cart', [\n  //   'addProductToCart'\n  // ]),\n  // created () {\n  //   this.$store.dispatch('products/getAllProducts')\n  // }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/shopping-cart/components/ShoppingCart.vue",
    "content": "<template>\n  <div class=\"cart\">\n    <h2>Your Cart</h2>\n    <p v-show=\"!products.length\">\n      <i>Please add some products to cart.</i>\n    </p>\n    <ul>\n      <li v-for=\"product in products\" :key=\"product.id\">\n        {{ product.title }} - {{ currency(product.price) }} x {{ product.quantity }}\n      </li>\n    </ul>\n    <p>Total: {{ currency(total) }}</p>\n    <p><button :disabled=\"!products.length\" @click=\"checkout(products)\">Checkout</button></p>\n    <p v-show=\"checkoutStatus\">Checkout {{ checkoutStatus }}.</p>\n  </div>\n</template>\n\n<script>\nimport { computed } from 'vue'\nimport { useStore } from 'vuex'\nimport { currency } from '../currency'\n\nexport default {\n  setup () {\n    const store = useStore()\n\n    const checkoutStatus = computed(() => store.state.cart.checkoutStatus)\n    const products = computed(() => store.getters['cart/cartProducts'])\n    const total = computed(() => store.getters['cart/cartTotalPrice'])\n\n    const checkout = (products) => store.dispatch('cart/checkout', products)\n\n    return {\n      currency,\n      checkoutStatus,\n      products,\n      total,\n      checkout\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/shopping-cart/currency.js",
    "content": "const digitsRE = /(\\d{3})(?=\\d)/g\n\nexport function currency (value, currency, decimals) {\n  value = parseFloat(value)\n  if (!isFinite(value) || (!value && value !== 0)) return ''\n  currency = currency != null ? currency : '$'\n  decimals = decimals != null ? decimals : 2\n  var stringified = Math.abs(value).toFixed(decimals)\n  var _int = decimals\n    ? stringified.slice(0, -1 - decimals)\n    : stringified\n  var i = _int.length % 3\n  var head = i > 0\n    ? (_int.slice(0, i) + (_int.length > 3 ? ',' : ''))\n    : ''\n  var _float = decimals\n    ? stringified.slice(-1 - decimals)\n    : ''\n  var sign = value < 0 ? '-' : ''\n  return sign + currency + head +\n    _int.slice(i).replace(digitsRE, '$1,') +\n    _float\n}\n"
  },
  {
    "path": "examples/composition/shopping-cart/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex shopping cart example</title>\n    <link rel=\"stylesheet\" href=\"/global.css\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/composition/shopping-cart.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/composition/shopping-cart/store/index.js",
    "content": "import { createStore, createLogger } from 'vuex'\nimport cart from './modules/cart'\nimport products from './modules/products'\n\nconst debug = process.env.NODE_ENV !== 'production'\n\nexport default createStore({\n  modules: {\n    cart,\n    products\n  },\n  strict: debug,\n  plugins: debug ? [createLogger()] : []\n})\n"
  },
  {
    "path": "examples/composition/shopping-cart/store/modules/cart.js",
    "content": "import shop from '../../api/shop'\n\n// initial state\n// shape: [{ id, quantity }]\nconst state = {\n  items: [],\n  checkoutStatus: null\n}\n\n// getters\nconst getters = {\n  cartProducts: (state, getters, rootState) => {\n    return state.items.map(({ id, quantity }) => {\n      const product = rootState.products.all.find(product => product.id === id)\n      return {\n        id: product.id,\n        title: product.title,\n        price: product.price,\n        quantity\n      }\n    })\n  },\n\n  cartTotalPrice: (state, getters) => {\n    return getters.cartProducts.reduce((total, product) => {\n      return total + product.price * product.quantity\n    }, 0)\n  }\n}\n\n// actions\nconst actions = {\n  checkout ({ commit, state }, products) {\n    const savedCartItems = [...state.items]\n    commit('setCheckoutStatus', null)\n    // empty cart\n    commit('setCartItems', { items: [] })\n    shop.buyProducts(\n      products,\n      () => commit('setCheckoutStatus', 'successful'),\n      () => {\n        commit('setCheckoutStatus', 'failed')\n        // rollback to the cart saved before sending the request\n        commit('setCartItems', { items: savedCartItems })\n      }\n    )\n  },\n\n  addProductToCart ({ state, commit }, product) {\n    commit('setCheckoutStatus', null)\n    if (product.inventory > 0) {\n      const cartItem = state.items.find(item => item.id === product.id)\n      if (!cartItem) {\n        commit('pushProductToCart', { id: product.id })\n      } else {\n        commit('incrementItemQuantity', cartItem)\n      }\n      // remove 1 item from stock\n      commit('products/decrementProductInventory', { id: product.id }, { root: true })\n    }\n  }\n}\n\n// mutations\nconst mutations = {\n  pushProductToCart (state, { id }) {\n    state.items.push({\n      id,\n      quantity: 1\n    })\n  },\n\n  incrementItemQuantity (state, { id }) {\n    const cartItem = state.items.find(item => item.id === id)\n    cartItem.quantity++\n  },\n\n  setCartItems (state, { items }) {\n    state.items = items\n  },\n\n  setCheckoutStatus (state, status) {\n    state.checkoutStatus = status\n  }\n}\n\nexport default {\n  namespaced: true,\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "examples/composition/shopping-cart/store/modules/products.js",
    "content": "import shop from '../../api/shop'\n\n// initial state\nconst state = {\n  all: []\n}\n\n// getters\nconst getters = {}\n\n// actions\nconst actions = {\n  getAllProducts ({ commit }) {\n    shop.getProducts(products => {\n      commit('setProducts', products)\n    })\n  }\n}\n\n// mutations\nconst mutations = {\n  setProducts (state, products) {\n    state.all = products\n  },\n\n  decrementProductInventory (state, { id }) {\n    const product = state.all.find(product => product.id === id)\n    product.inventory--\n  }\n}\n\nexport default {\n  namespaced: true,\n  state,\n  getters,\n  actions,\n  mutations\n}\n"
  },
  {
    "path": "examples/composition/todomvc/app.js",
    "content": "import { createApp } from 'vue'\nimport store from './store'\nimport App from './components/App.vue'\n\nconst app = createApp(App)\n\napp.use(store)\n\napp.mount('#app')\n"
  },
  {
    "path": "examples/composition/todomvc/components/App.vue",
    "content": "<style src=\"todomvc-app-css/index.css\"></style>\n\n<template>\n  <section class=\"todoapp\">\n    <!-- header -->\n    <header class=\"header\">\n      <h1>todos</h1>\n      <input class=\"new-todo\"\n        autofocus\n        autocomplete=\"off\"\n        placeholder=\"What needs to be done?\"\n        @keyup.enter=\"addTodo\">\n    </header>\n    <!-- main section -->\n    <section class=\"main\" v-show=\"todos.length\">\n      <input class=\"toggle-all\" id=\"toggle-all\"\n        type=\"checkbox\"\n        :checked=\"allChecked\"\n        @change=\"toggleAll(!allChecked)\">\n      <label for=\"toggle-all\"></label>\n      <ul class=\"todo-list\">\n        <TodoItem\n          v-for=\"(todo, index) in filteredTodos\"\n          :key=\"index\"\n          :todo=\"todo\"\n        />\n      </ul>\n    </section>\n    <!-- footer -->\n    <footer class=\"footer\" v-show=\"todos.length\">\n      <span class=\"todo-count\">\n        <strong>{{ remaining }}</strong>\n        {{ pluralize(remaining, 'item') }} left\n      </span>\n      <ul class=\"filters\">\n        <li v-for=\"(val, key) in filters\">\n          <a :href=\"'#/' + key\"\n            :class=\"{ selected: visibility === key }\"\n            @click=\"visibility = key\">{{ capitalize(key) }}</a>\n        </li>\n      </ul>\n      <button class=\"clear-completed\"\n        v-show=\"todos.length > remaining\"\n        @click=\"clearCompleted\">\n        Clear completed\n      </button>\n    </footer>\n  </section>\n</template>\n\n<script>\nimport { ref, computed } from 'vue'\nimport { useStore } from 'vuex'\nimport TodoItem from './TodoItem.vue'\n\nconst filters = {\n  all: todos => todos,\n  active: todos => todos.filter(todo => !todo.done),\n  completed: todos => todos.filter(todo => todo.done)\n}\n\nexport default {\n  components: { TodoItem },\n  setup () {\n    const visibility = ref('all')\n\n    const store = useStore()\n\n    const todos = computed(() => store.state.todos)\n    const allChecked = computed(() => todos.value.every(todo => todo.done))\n    const filteredTodos = computed(() => filters[visibility.value](todos.value))\n    const remaining = computed(() => todos.value.filter(todo => !todo.done).length)\n\n    const toggleAll = (done) => store.dispatch('toggleAll', done)\n    const clearCompleted = () => store.dispatch('clearCompleted')\n\n    function addTodo (e) {\n      const text = e.target.value\n      if (text.trim()) {\n        store.dispatch('addTodo', text)\n      }\n      e.target.value = ''\n    }\n\n    const pluralize = (n, w) => n === 1 ? w : (w + 's')\n    const capitalize = s => s.charAt(0).toUpperCase() + s.slice(1)\n\n    return {\n      visibility,\n      filters,\n      todos,\n      allChecked,\n      filteredTodos,\n      remaining,\n      addTodo,\n      clearCompleted,\n      toggleAll,\n      pluralize,\n      capitalize\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/todomvc/components/TodoItem.vue",
    "content": "<template>\n  <li class=\"todo\" :class=\"{ completed: todo.done, editing }\">\n    <div class=\"view\">\n      <input class=\"toggle\"\n        type=\"checkbox\"\n        :checked=\"todo.done\"\n        @change=\"toggleTodo(todo)\">\n      <label v-text=\"todo.text\" @dblclick=\"editing = true\"></label>\n      <button class=\"destroy\" @click=\"removeTodo(todo)\"></button>\n    </div>\n    <input class=\"edit\"\n      v-show=\"editing\"\n      :value=\"todo.text\"\n      ref=\"input\"\n      @keyup.enter=\"doneEdit\"\n      @keyup.esc=\"cancelEdit\"\n      @blur=\"doneEdit\">\n  </li>\n</template>\n\n<script>\nimport { ref, watch, nextTick } from 'vue'\nimport { useStore } from 'vuex'\n\nexport default {\n  name: 'Todo',\n  props: ['todo'],\n  setup (props) {\n    const input = ref(null)\n\n    const editing = ref(false)\n\n    watch(editing, (v) => {\n      v && nextTick(() => { input.value.focus() })\n    })\n\n    const store = useStore()\n\n    const editTodo = (todo, value) => store.dispatch('editTodo', { todo, value })\n    const toggleTodo = (todo) => store.dispatch('toggleTodo', todo)\n    const removeTodo = (todo) => store.dispatch('removeTodo', todo)\n\n    function doneEdit (e) {\n      const value = e.target.value.trim()\n      if (!value) {\n        removeTodo(props.todo)\n      } else if (editing.value) {\n        editTodo(props.todo, value)\n      }\n      editing.value = false\n    }\n\n    function cancelEdit (e) {\n      e.target.value = props.todo.text\n      editing.value = false\n    }\n\n    return {\n      input,\n      editing,\n      toggleTodo,\n      doneEdit,\n      cancelEdit,\n      removeTodo\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "examples/composition/todomvc/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>vuex todomvc example</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"/__build__/shared.js\"></script>\n    <script src=\"/__build__/composition/todomvc.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/composition/todomvc/store/actions.js",
    "content": "export default {\n  addTodo ({ commit }, text) {\n    commit('addTodo', {\n      text,\n      done: false\n    })\n  },\n\n  removeTodo ({ commit }, todo) {\n    commit('removeTodo', todo)\n  },\n\n  toggleTodo ({ commit }, todo) {\n    commit('editTodo', { todo, done: !todo.done })\n  },\n\n  editTodo ({ commit }, { todo, value }) {\n    commit('editTodo', { todo, text: value })\n  },\n\n  toggleAll ({ state, commit }, done) {\n    state.todos.forEach((todo) => {\n      commit('editTodo', { todo, done })\n    })\n  },\n\n  clearCompleted ({ state, commit }) {\n    state.todos.filter(todo => todo.done)\n      .forEach(todo => {\n        commit('removeTodo', todo)\n      })\n  }\n}\n"
  },
  {
    "path": "examples/composition/todomvc/store/index.js",
    "content": "import { createStore } from 'vuex'\nimport { mutations, STORAGE_KEY } from './mutations'\nimport actions from './actions'\nimport plugins from './plugins'\n\nexport default createStore({\n  state: {\n    todos: JSON.parse(window.localStorage.getItem(STORAGE_KEY) || '[]')\n  },\n  actions,\n  mutations,\n  plugins\n})\n"
  },
  {
    "path": "examples/composition/todomvc/store/mutations.js",
    "content": "export const STORAGE_KEY = 'todos-vuejs'\n\n// for testing\nif (navigator.webdriver) {\n  window.localStorage.clear()\n}\n\nexport const mutations = {\n  addTodo (state, todo) {\n    state.todos.push(todo)\n  },\n\n  removeTodo (state, todo) {\n    state.todos.splice(state.todos.indexOf(todo), 1)\n  },\n\n  editTodo (state, { todo, text = todo.text, done = todo.done }) {\n    const index = state.todos.indexOf(todo)\n\n    state.todos.splice(index, 1, {\n      ...todo,\n      text,\n      done\n    })\n  }\n}\n"
  },
  {
    "path": "examples/composition/todomvc/store/plugins.js",
    "content": "import { createLogger } from 'vuex'\nimport { STORAGE_KEY } from './mutations'\n\nconst localStoragePlugin = store => {\n  store.subscribe((mutation, { todos }) => {\n    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(todos))\n  })\n}\n\nexport default process.env.NODE_ENV !== 'production'\n  ? [createLogger(), localStoragePlugin]\n  : [localStoragePlugin]\n"
  },
  {
    "path": "examples/global.css",
    "content": "html, body {\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n  color: #2c3e50;\n}\n\nul {\n  line-height: 1.5em;\n  padding-left: 1.5em;\n}\n\na {\n  color: #7f8c8d;\n  text-decoration: none;\n}\n\na:hover {\n  color: #4fc08d;\n}\n"
  },
  {
    "path": "examples/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Vuex Examples</title>\n    <link rel=\"stylesheet\" href=\"/global.css\">\n  </head>\n  <body style=\"padding: 0 20px\">\n    <h1>Vuex Examples</h1>\n\n    <h2>Classic API</h2>\n\n    <ul>\n      <li><a href=\"classic/counter\">Counter</a></li>\n      <li><a href=\"classic/counter-hot\">Counter with Hot Reload</a></li>\n      <li><a href=\"classic/shopping-cart\">Shopping Cart</a></li>\n      <li><a href=\"classic/todomvc\">TodoMVC</a></li>\n      <li><a href=\"classic/chat\">FluxChat</a></li>\n    </ul>\n\n    <h2>Composition API</h2>\n\n    <ul>\n      <li><a href=\"composition/counter\">Counter</a></li>\n      <li><a href=\"composition/counter-hot\">Counter with Hot Reload</a></li>\n      <li><a href=\"composition/shopping-cart\">Shopping Cart</a></li>\n      <li><a href=\"composition/todomvc\">TodoMVC</a></li>\n      <li><a href=\"composition/chat\">FluxChat</a></li>\n    </ul>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/server.js",
    "content": "const express = require('express')\nconst webpack = require('webpack')\nconst webpackDevMiddleware = require('webpack-dev-middleware')\nconst webpackHotMiddleware = require('webpack-hot-middleware')\nconst WebpackConfig = require('./webpack.config')\n\nconst app = express()\nconst compiler = webpack(WebpackConfig)\n\napp.use(webpackDevMiddleware(compiler, {\n  publicPath: '/__build__/',\n  stats: {\n    colors: true,\n    chunks: false\n  }\n}))\n\napp.use(webpackHotMiddleware(compiler))\n\napp.use(express.static(__dirname))\n\napp.use((req, res, next) => {\n  res.redirect('/')\n})\n\nconst port = process.env.PORT || 8080\nmodule.exports = app.listen(port, () => {\n  console.log(`Server listening on http://localhost:${port}, Ctrl+C to stop`)\n})\n"
  },
  {
    "path": "examples/webpack.config.js",
    "content": "const fs = require('fs')\nconst path = require('path')\nconst webpack = require('webpack')\nconst { VueLoaderPlugin } = require('vue-loader')\n\nfunction buildEntry (dirname) {\n  const lookupDir = path.join(__dirname, dirname)\n\n  return fs.readdirSync(lookupDir).reduce((entries, dir) => {\n    const fullDir = path.join(lookupDir, dir)\n    const entry = path.join(fullDir, 'app.js')\n    if (fs.statSync(fullDir).isDirectory() && fs.existsSync(entry)) {\n      entries[`${dirname}/${dir}`] = ['webpack-hot-middleware/client', entry]\n    }\n\n    return entries\n  }, {})\n}\n\nmodule.exports = {\n  mode: 'development',\n\n  entry: {\n    ...buildEntry('classic'),\n    ...buildEntry('composition')\n  },\n\n  output: {\n    path: path.join(__dirname, '__build__'),\n    filename: '[name].js',\n    chunkFilename: '[id].chunk.js',\n    publicPath: '/__build__/'\n  },\n\n  module: {\n    rules: [\n      { test: /\\.js$/, exclude: /node_modules/, use: ['babel-loader'] },\n      { test: /\\.vue$/, use: ['vue-loader'] },\n      { test: /\\.css$/, use: ['vue-style-loader', 'css-loader'] }\n    ]\n  },\n\n  resolve: {\n    alias: {\n      vuex: path.resolve(__dirname, '../src/index.js')\n    }\n  },\n\n  optimization: {\n    splitChunks: {\n      cacheGroups: {\n        vendors: {\n          name: 'shared',\n          filename: 'shared.js',\n          chunks: 'initial'\n        }\n      }\n    }\n  },\n\n  plugins: [\n    new VueLoaderPlugin(),\n    new webpack.HotModuleReplacementPlugin(),\n    new webpack.NoEmitOnErrorsPlugin(),\n    new webpack.DefinePlugin({\n      __DEV__: JSON.stringify(true),\n      'process.env': {\n        NODE_ENV: JSON.stringify(process.env.NODE_ENV)\n      }\n    })\n  ]\n}\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  rootDir: __dirname,\n  testEnvironment: 'jsdom',\n  globals: {\n    __DEV__: true\n  },\n  moduleNameMapper: {\n    '^@/(.*)$': '<rootDir>/src/$1',\n    '^test/(.*)$': '<rootDir>/test/$1'\n  },\n  testMatch: ['<rootDir>/test/**/*.spec.js'],\n  testPathIgnorePatterns: ['/node_modules/'],\n  setupFilesAfterEnv: ['./test/setup.js'],\n  transform: {\n    '^.+\\\\.js$': '<rootDir>/node_modules/babel-jest'\n  },\n  coverageDirectory: 'coverage',\n  coverageReporters: ['json', 'lcov', 'text-summary', 'clover'],\n  collectCoverageFrom: [\n    'src/**/*.js',\n    '!src/index.cjs.js'\n  ]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"vuex\",\n  \"version\": \"4.1.0\",\n  \"description\": \"state management for Vue.js\",\n  \"main\": \"dist/vuex.cjs.js\",\n  \"exports\": {\n    \".\": {\n      \"module\": \"./dist/vuex.esm-bundler.js\",\n      \"require\": \"./dist/vuex.cjs.js\",\n      \"import\": \"./dist/vuex.mjs\"\n    },\n    \"./*\": \"./*\",\n    \"./\": \"./\"\n  },\n  \"module\": \"dist/vuex.esm-bundler.js\",\n  \"browser\": \"dist/vuex.esm-browser.js\",\n  \"unpkg\": \"dist/vuex.global.js\",\n  \"jsdelivr\": \"dist/vuex.global.js\",\n  \"typings\": \"types/index.d.ts\",\n  \"sideEffects\": false,\n  \"files\": [\n    \"dist\",\n    \"types/index.d.ts\",\n    \"types/helpers.d.ts\",\n    \"types/logger.d.ts\",\n    \"types/vue.d.ts\"\n  ],\n  \"scripts\": {\n    \"dev\": \"node examples/server.js\",\n    \"build\": \"node scripts/build.js\",\n    \"lint\": \"eslint src test\",\n    \"test\": \"npm run lint && npm run build && npm run test:types && npm run test:unit && npm run test:ssr && npm run test:e2e && npm run test:esm\",\n    \"test:unit\": \"jest --testPathIgnorePatterns test/e2e\",\n    \"test:e2e\": \"start-server-and-test dev http://localhost:8080 \\\"jest --testPathIgnorePatterns test/unit\\\"\",\n    \"test:ssr\": \"cross-env VUE_ENV=server jest --testPathIgnorePatterns test/e2e\",\n    \"test:types\": \"tsc -p types/test\",\n    \"test:esm\": \"node test/esm/esm-test.js\",\n    \"coverage\": \"jest --testPathIgnorePatterns test/e2e --coverage\",\n    \"changelog\": \"conventional-changelog -p angular -i CHANGELOG.md -s\",\n    \"release\": \"node scripts/release.js\",\n    \"docs\": \"vitepress dev docs\",\n    \"docs:build\": \"vitepress build docs\",\n    \"docs:serve\": \"yarn docs:build && vitepress serve docs\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/vuejs/vuex.git\"\n  },\n  \"author\": \"Evan You\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/vuejs/vuex/issues\"\n  },\n  \"homepage\": \"https://github.com/vuejs/vuex#readme\",\n  \"peerDependencies\": {\n    \"vue\": \"^3.2.0\"\n  },\n  \"dependencies\": {\n    \"@vue/devtools-api\": \"^6.4.4\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.19.3\",\n    \"@babel/preset-env\": \"^7.19.4\",\n    \"@rollup/plugin-buble\": \"^1.0.0\",\n    \"@rollup/plugin-commonjs\": \"^13.0.0\",\n    \"@rollup/plugin-node-resolve\": \"^15.0.0\",\n    \"@rollup/plugin-replace\": \"^5.0.0\",\n    \"@types/node\": \"^18.11.0\",\n    \"babel-jest\": \"^29.2.0\",\n    \"babel-loader\": \"^8.2.5\",\n    \"brotli\": \"^1.3.3\",\n    \"chalk\": \"^4.1.1\",\n    \"conventional-changelog-cli\": \"^2.2.2\",\n    \"cross-env\": \"^7.0.3\",\n    \"css-loader\": \"^2.1.0\",\n    \"enquirer\": \"^2.3.6\",\n    \"eslint\": \"^7.32.0\",\n    \"eslint-plugin-vue-libs\": \"^4.0.0\",\n    \"execa\": \"^5.0.0\",\n    \"express\": \"^4.18.2\",\n    \"fs-extra\": \"^10.1.0\",\n    \"jest\": \"^29.2.0\",\n    \"jest-environment-jsdom\": \"^29.2.0\",\n    \"puppeteer\": \"^19.0.0\",\n    \"regenerator-runtime\": \"^0.13.5\",\n    \"rollup\": \"^2.79.1\",\n    \"rollup-plugin-terser\": \"^7.0.2\",\n    \"semver\": \"^7.3.5\",\n    \"start-server-and-test\": \"^1.12.3\",\n    \"todomvc-app-css\": \"^2.4.1\",\n    \"typescript\": \"^4.8.4\",\n    \"vitepress\": \"^0.20.0\",\n    \"vue\": \"^3.2.41\",\n    \"vue-loader\": \"^17.0.0\",\n    \"vue-style-loader\": \"^4.1.3\",\n    \"webpack\": \"^4.43.0\",\n    \"webpack-dev-middleware\": \"^3.7.2\",\n    \"webpack-hot-middleware\": \"^2.25.0\"\n  }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import buble from '@rollup/plugin-buble'\nimport replace from '@rollup/plugin-replace'\nimport resolve from '@rollup/plugin-node-resolve'\nimport commonjs from '@rollup/plugin-commonjs'\nimport { terser } from 'rollup-plugin-terser'\nimport pkg from './package.json'\n\nconst banner = `/*!\n * vuex v${pkg.version}\n * (c) ${new Date().getFullYear()} Evan You\n * @license MIT\n */`\n\nconst configs = [\n  {\n    input: 'src/index.js',\n    file: 'dist/vuex.esm-browser.js',\n    format: 'es',\n    browser: true,\n    env: 'development'\n  },\n  {\n    input: 'src/index.js',\n    file: 'dist/vuex.esm-browser.prod.js',\n    format: 'es',\n    browser: true,\n    env: 'production'\n  },\n  {\n    input: 'src/index.js',\n    file: 'dist/vuex.esm-bundler.js',\n    format: 'es',\n    env: 'development'\n  },\n  {\n    input: 'src/index.cjs.js',\n    file: 'dist/vuex.global.js',\n    format: 'iife',\n    env: 'development'\n  },\n  {\n    input: 'src/index.cjs.js',\n    file: 'dist/vuex.global.prod.js',\n    format: 'iife',\n    minify: true,\n    env: 'production'\n  },\n  {\n    input: 'src/index.cjs.js',\n    file: 'dist/vuex.cjs.js',\n    format: 'cjs',\n    env: 'development'\n  }\n]\n\nfunction createEntries() {\n  return configs.map((c) => createEntry(c))\n}\n\nfunction createEntry(config) {\n  const isGlobalBuild = config.format === 'iife'\n  const isBundlerBuild = config.format !== 'iife' && !config.browser\n  const isBundlerESMBuild = config.format === 'es' && !config.browser\n\n  const c = {\n    external: ['vue'],\n    input: config.input,\n    plugins: [],\n    output: {\n      banner,\n      file: config.file,\n      format: config.format,\n      exports: 'auto',\n      globals: {\n        vue: 'Vue'\n      }\n    },\n    onwarn: (msg, warn) => {\n      if (!/Circular/.test(msg)) {\n        warn(msg)\n      }\n    }\n  }\n\n  if (isGlobalBuild) {\n    c.output.name = c.output.name || 'Vuex'\n  }\n\n  if (!isGlobalBuild) {\n    c.external.push('@vue/devtools-api')\n  }\n\n  c.plugins.push(\n    replace({\n      preventAssignment: true,\n      __VERSION__: pkg.version,\n      __DEV__: isBundlerBuild\n        ? `(process.env.NODE_ENV !== 'production')`\n        : config.env !== 'production',\n      __VUE_PROD_DEVTOOLS__: isBundlerESMBuild\n        ? '__VUE_PROD_DEVTOOLS__'\n        : 'false'\n    })\n  )\n\n  if (config.transpile !== false) {\n    c.plugins.push(\n      buble({\n        transforms: { asyncAwait: false, forOf: false }\n      })\n    )\n  }\n\n  c.plugins.push(resolve())\n  c.plugins.push(commonjs())\n\n  if (config.minify) {\n    c.plugins.push(terser({ module: config.format === 'es' }))\n  }\n\n  return c\n}\n\nexport default createEntries()\n"
  },
  {
    "path": "scripts/build.js",
    "content": "const fs = require('fs-extra')\nconst chalk = require('chalk')\nconst execa = require('execa')\nconst { gzipSync } = require('zlib')\nconst { compress } = require('brotli')\n\nconst files = [\n  'dist/vuex.esm-browser.js',\n  'dist/vuex.esm-browser.prod.js',\n  'dist/vuex.esm-bundler.js',\n  'dist/vuex.global.js',\n  'dist/vuex.global.prod.js',\n  'dist/vuex.cjs.js'\n]\n\nasync function run() {\n  await Promise.all([build(), copy()])\n  checkAllSizes()\n}\n\nasync function build() {\n  await execa('rollup', ['-c', 'rollup.config.js'], { stdio: 'inherit' })\n}\n\nasync function copy() {\n   await fs.copy('src/index.mjs', 'dist/vuex.mjs')\n }\n\nfunction checkAllSizes() {\n  console.log()\n  files.map((f) => checkSize(f))\n  console.log()\n}\n\nfunction checkSize(file) {\n  const f = fs.readFileSync(file)\n  const minSize = (f.length / 1024).toFixed(2) + 'kb'\n  const gzipped = gzipSync(f)\n  const gzippedSize = (gzipped.length / 1024).toFixed(2) + 'kb'\n  const compressed = compress(f)\n  const compressedSize = (compressed.length / 1024).toFixed(2) + 'kb'\n  console.log(\n    `${chalk.gray(\n      chalk.bold(file)\n    )} size:${minSize} / gzip:${gzippedSize} / brotli:${compressedSize}`\n  )\n}\n\nrun()\n"
  },
  {
    "path": "scripts/release.js",
    "content": "const fs = require('fs')\nconst path = require('path')\nconst chalk = require('chalk')\nconst semver = require('semver')\nconst { prompt } = require('enquirer')\nconst execa = require('execa')\nconst currentVersion = require('../package.json').version\n\nconst versionIncrements = [\n  'patch',\n  'minor',\n  'major'\n]\n\nconst tags = [\n  'latest',\n  'next'\n]\n\nconst inc = (i) => semver.inc(currentVersion, i)\nconst bin = (name) => path.resolve(__dirname, `../node_modules/.bin/${name}`)\nconst run = (bin, args, opts = {}) => execa(bin, args, { stdio: 'inherit', ...opts })\nconst step = (msg) => console.log(chalk.cyan(msg))\n\nasync function main() {\n  let targetVersion\n\n  const { release } = await prompt({\n    type: 'select',\n    name: 'release',\n    message: 'Select release type',\n    choices: versionIncrements.map(i => `${i} (${inc(i)})`).concat(['custom'])\n  })\n\n  if (release === 'custom') {\n    targetVersion = (await prompt({\n      type: 'input',\n      name: 'version',\n      message: 'Input custom version',\n      initial: currentVersion\n    })).version\n  } else {\n    targetVersion = release.match(/\\((.*)\\)/)[1]\n  }\n\n  if (!semver.valid(targetVersion)) {\n    throw new Error(`Invalid target version: ${targetVersion}`)\n  }\n\n  const { tag } = await prompt({\n    type: 'select',\n    name: 'tag',\n    message: 'Select tag type',\n    choices: tags\n  })\n\n  const { yes: tagOk } = await prompt({\n    type: 'confirm',\n    name: 'yes',\n    message: `Releasing v${targetVersion} with the \"${tag}\" tag. Confirm?`\n  })\n\n  if (!tagOk) {\n    return\n  }\n\n  // Run tests before release.\n  step('\\nRunning tests...')\n  await run('yarn', ['test'])\n\n  // Update the package version.\n  step('\\nUpdating the package version...')\n  updatePackage(targetVersion)\n\n  // Build the package.\n  step('\\nBuilding the package...')\n  await run('yarn', ['build'])\n\n  // Generate the changelog.\n  step('\\nGenerating the changelog...')\n  await run('yarn', ['changelog'])\n\n  const { yes: changelogOk } = await prompt({\n    type: 'confirm',\n    name: 'yes',\n    message: `Changelog generated. Does it look good?`\n  })\n\n  if (!changelogOk) {\n    return\n  }\n\n  // Commit changes to the Git.\n  step('\\nCommitting changes...')\n  await run('git', ['add', '-A'])\n  await run('git', ['commit', '-m', `release: v${targetVersion}`])\n\n  // Publish the package.\n  step('\\nPublishing the package...')\n  await run ('yarn', [\n    'publish', '--tag', tag, '--new-version', targetVersion, '--no-commit-hooks',\n    '--no-git-tag-version'\n  ])\n\n  // Push to GitHub.\n  step('\\nPushing to GitHub...')\n  await run('git', ['tag', `v${targetVersion}`])\n  await run('git', ['push', 'origin', `refs/tags/v${targetVersion}`])\n  await run('git', ['push'])\n}\n\nfunction updatePackage(version) {\n  const pkgPath = path.resolve(path.resolve(__dirname, '..'), 'package.json')\n  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n\n  pkg.version = version\n\n  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\\n')\n}\n\nmain().catch((err) => console.error(err))\n"
  },
  {
    "path": "src/helpers.js",
    "content": "import { isObject } from './util'\n\n/**\n * Reduce the code which written in Vue.js for getting the state.\n * @param {String} [namespace] - Module's namespace\n * @param {Object|Array} states # Object's item can be a function which accept state and getters for param, you can do something for state and getters in it.\n * @param {Object}\n */\nexport const mapState = normalizeNamespace((namespace, states) => {\n  const res = {}\n  if (__DEV__ && !isValidMap(states)) {\n    console.error('[vuex] mapState: mapper parameter must be either an Array or an Object')\n  }\n  normalizeMap(states).forEach(({ key, val }) => {\n    res[key] = function mappedState () {\n      let state = this.$store.state\n      let getters = this.$store.getters\n      if (namespace) {\n        const module = getModuleByNamespace(this.$store, 'mapState', namespace)\n        if (!module) {\n          return\n        }\n        state = module.context.state\n        getters = module.context.getters\n      }\n      return typeof val === 'function'\n        ? val.call(this, state, getters)\n        : state[val]\n    }\n    // mark vuex getter for devtools\n    res[key].vuex = true\n  })\n  return res\n})\n\n/**\n * Reduce the code which written in Vue.js for committing the mutation\n * @param {String} [namespace] - Module's namespace\n * @param {Object|Array} mutations # Object's item can be a function which accept `commit` function as the first param, it can accept another params. You can commit mutation and do any other things in this function. specially, You need to pass anthor params from the mapped function.\n * @return {Object}\n */\nexport const mapMutations = normalizeNamespace((namespace, mutations) => {\n  const res = {}\n  if (__DEV__ && !isValidMap(mutations)) {\n    console.error('[vuex] mapMutations: mapper parameter must be either an Array or an Object')\n  }\n  normalizeMap(mutations).forEach(({ key, val }) => {\n    res[key] = function mappedMutation (...args) {\n      // Get the commit method from store\n      let commit = this.$store.commit\n      if (namespace) {\n        const module = getModuleByNamespace(this.$store, 'mapMutations', namespace)\n        if (!module) {\n          return\n        }\n        commit = module.context.commit\n      }\n      return typeof val === 'function'\n        ? val.apply(this, [commit].concat(args))\n        : commit.apply(this.$store, [val].concat(args))\n    }\n  })\n  return res\n})\n\n/**\n * Reduce the code which written in Vue.js for getting the getters\n * @param {String} [namespace] - Module's namespace\n * @param {Object|Array} getters\n * @return {Object}\n */\nexport const mapGetters = normalizeNamespace((namespace, getters) => {\n  const res = {}\n  if (__DEV__ && !isValidMap(getters)) {\n    console.error('[vuex] mapGetters: mapper parameter must be either an Array or an Object')\n  }\n  normalizeMap(getters).forEach(({ key, val }) => {\n    // The namespace has been mutated by normalizeNamespace\n    val = namespace + val\n    res[key] = function mappedGetter () {\n      if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {\n        return\n      }\n      if (__DEV__ && !(val in this.$store.getters)) {\n        console.error(`[vuex] unknown getter: ${val}`)\n        return\n      }\n      return this.$store.getters[val]\n    }\n    // mark vuex getter for devtools\n    res[key].vuex = true\n  })\n  return res\n})\n\n/**\n * Reduce the code which written in Vue.js for dispatch the action\n * @param {String} [namespace] - Module's namespace\n * @param {Object|Array} actions # Object's item can be a function which accept `dispatch` function as the first param, it can accept anthor params. You can dispatch action and do any other things in this function. specially, You need to pass anthor params from the mapped function.\n * @return {Object}\n */\nexport const mapActions = normalizeNamespace((namespace, actions) => {\n  const res = {}\n  if (__DEV__ && !isValidMap(actions)) {\n    console.error('[vuex] mapActions: mapper parameter must be either an Array or an Object')\n  }\n  normalizeMap(actions).forEach(({ key, val }) => {\n    res[key] = function mappedAction (...args) {\n      // get dispatch function from store\n      let dispatch = this.$store.dispatch\n      if (namespace) {\n        const module = getModuleByNamespace(this.$store, 'mapActions', namespace)\n        if (!module) {\n          return\n        }\n        dispatch = module.context.dispatch\n      }\n      return typeof val === 'function'\n        ? val.apply(this, [dispatch].concat(args))\n        : dispatch.apply(this.$store, [val].concat(args))\n    }\n  })\n  return res\n})\n\n/**\n * Rebinding namespace param for mapXXX function in special scoped, and return them by simple object\n * @param {String} namespace\n * @return {Object}\n */\nexport const createNamespacedHelpers = (namespace) => ({\n  mapState: mapState.bind(null, namespace),\n  mapGetters: mapGetters.bind(null, namespace),\n  mapMutations: mapMutations.bind(null, namespace),\n  mapActions: mapActions.bind(null, namespace)\n})\n\n/**\n * Normalize the map\n * normalizeMap([1, 2, 3]) => [ { key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 } ]\n * normalizeMap({a: 1, b: 2, c: 3}) => [ { key: 'a', val: 1 }, { key: 'b', val: 2 }, { key: 'c', val: 3 } ]\n * @param {Array|Object} map\n * @return {Object}\n */\nfunction normalizeMap (map) {\n  if (!isValidMap(map)) {\n    return []\n  }\n  return Array.isArray(map)\n    ? map.map(key => ({ key, val: key }))\n    : Object.keys(map).map(key => ({ key, val: map[key] }))\n}\n\n/**\n * Validate whether given map is valid or not\n * @param {*} map\n * @return {Boolean}\n */\nfunction isValidMap (map) {\n  return Array.isArray(map) || isObject(map)\n}\n\n/**\n * Return a function expect two param contains namespace and map. it will normalize the namespace and then the param's function will handle the new namespace and the map.\n * @param {Function} fn\n * @return {Function}\n */\nfunction normalizeNamespace (fn) {\n  return (namespace, map) => {\n    if (typeof namespace !== 'string') {\n      map = namespace\n      namespace = ''\n    } else if (namespace.charAt(namespace.length - 1) !== '/') {\n      namespace += '/'\n    }\n    return fn(namespace, map)\n  }\n}\n\n/**\n * Search a special module from store by namespace. if module not exist, print error message.\n * @param {Object} store\n * @param {String} helper\n * @param {String} namespace\n * @return {Object}\n */\nfunction getModuleByNamespace (store, helper, namespace) {\n  const module = store._modulesNamespaceMap[namespace]\n  if (__DEV__ && !module) {\n    console.error(`[vuex] module namespace not found in ${helper}(): ${namespace}`)\n  }\n  return module\n}\n"
  },
  {
    "path": "src/index.cjs.js",
    "content": "import { Store, createStore } from './store'\nimport { storeKey, useStore } from './injectKey'\nimport { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from './helpers'\nimport { createLogger } from './plugins/logger'\n\nexport default {\n  version: '__VERSION__',\n  Store,\n  storeKey,\n  createStore,\n  useStore,\n  mapState,\n  mapMutations,\n  mapGetters,\n  mapActions,\n  createNamespacedHelpers,\n  createLogger\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import { Store, createStore } from './store'\nimport { storeKey, useStore } from './injectKey'\nimport { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from './helpers'\nimport { createLogger } from './plugins/logger'\n\nexport default {\n  version: '__VERSION__',\n  Store,\n  storeKey,\n  createStore,\n  useStore,\n  mapState,\n  mapMutations,\n  mapGetters,\n  mapActions,\n  createNamespacedHelpers,\n  createLogger\n}\n\nexport {\n  Store,\n  storeKey,\n  createStore,\n  useStore,\n  mapState,\n  mapMutations,\n  mapGetters,\n  mapActions,\n  createNamespacedHelpers,\n  createLogger\n}\n"
  },
  {
    "path": "src/index.mjs",
    "content": "import Vuex from '../dist/vuex.cjs.js'\n\nconst {\n  version,\n  Store,\n  storeKey,\n  createStore,\n  install,\n  useStore,\n  mapState,\n  mapMutations,\n  mapGetters,\n  mapActions,\n  createNamespacedHelpers,\n  createLogger\n} = Vuex\n\nexport {\n  Vuex as default,\n  version,\n  Store,\n  storeKey,\n  createStore,\n  install,\n  useStore,\n  mapState,\n  mapMutations,\n  mapGetters,\n  mapActions,\n  createNamespacedHelpers,\n  createLogger\n}\n"
  },
  {
    "path": "src/injectKey.js",
    "content": "import { inject } from 'vue'\n\nexport const storeKey = 'store'\n\nexport function useStore (key = null) {\n  return inject(key !== null ? key : storeKey)\n}\n"
  },
  {
    "path": "src/module/module-collection.js",
    "content": "import Module from './module'\nimport { assert, forEachValue } from '../util'\n\nexport default class ModuleCollection {\n  constructor (rawRootModule) {\n    // register root module (Vuex.Store options)\n    this.register([], rawRootModule, false)\n  }\n\n  get (path) {\n    return path.reduce((module, key) => {\n      return module.getChild(key)\n    }, this.root)\n  }\n\n  getNamespace (path) {\n    let module = this.root\n    return path.reduce((namespace, key) => {\n      module = module.getChild(key)\n      return namespace + (module.namespaced ? key + '/' : '')\n    }, '')\n  }\n\n  update (rawRootModule) {\n    update([], this.root, rawRootModule)\n  }\n\n  register (path, rawModule, runtime = true) {\n    if (__DEV__) {\n      assertRawModule(path, rawModule)\n    }\n\n    const newModule = new Module(rawModule, runtime)\n    if (path.length === 0) {\n      this.root = newModule\n    } else {\n      const parent = this.get(path.slice(0, -1))\n      parent.addChild(path[path.length - 1], newModule)\n    }\n\n    // register nested modules\n    if (rawModule.modules) {\n      forEachValue(rawModule.modules, (rawChildModule, key) => {\n        this.register(path.concat(key), rawChildModule, runtime)\n      })\n    }\n  }\n\n  unregister (path) {\n    const parent = this.get(path.slice(0, -1))\n    const key = path[path.length - 1]\n    const child = parent.getChild(key)\n\n    if (!child) {\n      if (__DEV__) {\n        console.warn(\n          `[vuex] trying to unregister module '${key}', which is ` +\n          `not registered`\n        )\n      }\n      return\n    }\n\n    if (!child.runtime) {\n      return\n    }\n\n    parent.removeChild(key)\n  }\n\n  isRegistered (path) {\n    const parent = this.get(path.slice(0, -1))\n    const key = path[path.length - 1]\n\n    if (parent) {\n      return parent.hasChild(key)\n    }\n\n    return false\n  }\n}\n\nfunction update (path, targetModule, newModule) {\n  if (__DEV__) {\n    assertRawModule(path, newModule)\n  }\n\n  // update target module\n  targetModule.update(newModule)\n\n  // update nested modules\n  if (newModule.modules) {\n    for (const key in newModule.modules) {\n      if (!targetModule.getChild(key)) {\n        if (__DEV__) {\n          console.warn(\n            `[vuex] trying to add a new module '${key}' on hot reloading, ` +\n            'manual reload is needed'\n          )\n        }\n        return\n      }\n      update(\n        path.concat(key),\n        targetModule.getChild(key),\n        newModule.modules[key]\n      )\n    }\n  }\n}\n\nconst functionAssert = {\n  assert: value => typeof value === 'function',\n  expected: 'function'\n}\n\nconst objectAssert = {\n  assert: value => typeof value === 'function' ||\n    (typeof value === 'object' && typeof value.handler === 'function'),\n  expected: 'function or object with \"handler\" function'\n}\n\nconst assertTypes = {\n  getters: functionAssert,\n  mutations: functionAssert,\n  actions: objectAssert\n}\n\nfunction assertRawModule (path, rawModule) {\n  Object.keys(assertTypes).forEach(key => {\n    if (!rawModule[key]) return\n\n    const assertOptions = assertTypes[key]\n\n    forEachValue(rawModule[key], (value, type) => {\n      assert(\n        assertOptions.assert(value),\n        makeAssertionMessage(path, key, type, value, assertOptions.expected)\n      )\n    })\n  })\n}\n\nfunction makeAssertionMessage (path, key, type, value, expected) {\n  let buf = `${key} should be ${expected} but \"${key}.${type}\"`\n  if (path.length > 0) {\n    buf += ` in module \"${path.join('.')}\"`\n  }\n  buf += ` is ${JSON.stringify(value)}.`\n  return buf\n}\n"
  },
  {
    "path": "src/module/module.js",
    "content": "import { forEachValue } from '../util'\n\n// Base data struct for store's module, package with some attribute and method\nexport default class Module {\n  constructor (rawModule, runtime) {\n    this.runtime = runtime\n    // Store some children item\n    this._children = Object.create(null)\n    // Store the origin module object which passed by programmer\n    this._rawModule = rawModule\n    const rawState = rawModule.state\n\n    // Store the origin module's state\n    this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}\n  }\n\n  get namespaced () {\n    return !!this._rawModule.namespaced\n  }\n\n  addChild (key, module) {\n    this._children[key] = module\n  }\n\n  removeChild (key) {\n    delete this._children[key]\n  }\n\n  getChild (key) {\n    return this._children[key]\n  }\n\n  hasChild (key) {\n    return key in this._children\n  }\n\n  update (rawModule) {\n    this._rawModule.namespaced = rawModule.namespaced\n    if (rawModule.actions) {\n      this._rawModule.actions = rawModule.actions\n    }\n    if (rawModule.mutations) {\n      this._rawModule.mutations = rawModule.mutations\n    }\n    if (rawModule.getters) {\n      this._rawModule.getters = rawModule.getters\n    }\n  }\n\n  forEachChild (fn) {\n    forEachValue(this._children, fn)\n  }\n\n  forEachGetter (fn) {\n    if (this._rawModule.getters) {\n      forEachValue(this._rawModule.getters, fn)\n    }\n  }\n\n  forEachAction (fn) {\n    if (this._rawModule.actions) {\n      forEachValue(this._rawModule.actions, fn)\n    }\n  }\n\n  forEachMutation (fn) {\n    if (this._rawModule.mutations) {\n      forEachValue(this._rawModule.mutations, fn)\n    }\n  }\n}\n"
  },
  {
    "path": "src/plugins/devtool.js",
    "content": "import { setupDevtoolsPlugin } from '@vue/devtools-api'\nimport { makeLocalGetters } from '../store-util'\n\nconst LABEL_VUEX_BINDINGS = 'vuex bindings'\nconst MUTATIONS_LAYER_ID = 'vuex:mutations'\nconst ACTIONS_LAYER_ID = 'vuex:actions'\nconst INSPECTOR_ID = 'vuex'\n\nlet actionId = 0\n\nexport function addDevtools (app, store) {\n  setupDevtoolsPlugin(\n    {\n      id: 'org.vuejs.vuex',\n      app,\n      label: 'Vuex',\n      homepage: 'https://next.vuex.vuejs.org/',\n      logo: 'https://vuejs.org/images/icons/favicon-96x96.png',\n      packageName: 'vuex',\n      componentStateTypes: [LABEL_VUEX_BINDINGS]\n    },\n    (api) => {\n      api.addTimelineLayer({\n        id: MUTATIONS_LAYER_ID,\n        label: 'Vuex Mutations',\n        color: COLOR_LIME_500\n      })\n\n      api.addTimelineLayer({\n        id: ACTIONS_LAYER_ID,\n        label: 'Vuex Actions',\n        color: COLOR_LIME_500\n      })\n\n      api.addInspector({\n        id: INSPECTOR_ID,\n        label: 'Vuex',\n        icon: 'storage',\n        treeFilterPlaceholder: 'Filter stores...'\n      })\n\n      api.on.getInspectorTree((payload) => {\n        if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {\n          if (payload.filter) {\n            const nodes = []\n            flattenStoreForInspectorTree(nodes, store._modules.root, payload.filter, '')\n            payload.rootNodes = nodes\n          } else {\n            payload.rootNodes = [\n              formatStoreForInspectorTree(store._modules.root, '')\n            ]\n          }\n        }\n      })\n\n      api.on.getInspectorState((payload) => {\n        if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {\n          const modulePath = payload.nodeId\n          makeLocalGetters(store, modulePath)\n          payload.state = formatStoreForInspectorState(\n            getStoreModule(store._modules, modulePath),\n            modulePath === 'root' ? store.getters : store._makeLocalGettersCache,\n            modulePath\n          )\n        }\n      })\n\n      api.on.editInspectorState((payload) => {\n        if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {\n          const modulePath = payload.nodeId\n          let path = payload.path\n          if (modulePath !== 'root') {\n            path = [...modulePath.split('/').filter(Boolean), ...path]\n          }\n          store._withCommit(() => {\n            payload.set(store._state.data, path, payload.state.value)\n          })\n        }\n      })\n\n      store.subscribe((mutation, state) => {\n        const data = {}\n\n        if (mutation.payload) {\n          data.payload = mutation.payload\n        }\n\n        data.state = state\n\n        api.notifyComponentUpdate()\n        api.sendInspectorTree(INSPECTOR_ID)\n        api.sendInspectorState(INSPECTOR_ID)\n\n        api.addTimelineEvent({\n          layerId: MUTATIONS_LAYER_ID,\n          event: {\n            time: Date.now(),\n            title: mutation.type,\n            data\n          }\n        })\n      })\n\n      store.subscribeAction({\n        before: (action, state) => {\n          const data = {}\n          if (action.payload) {\n            data.payload = action.payload\n          }\n          action._id = actionId++\n          action._time = Date.now()\n          data.state = state\n\n          api.addTimelineEvent({\n            layerId: ACTIONS_LAYER_ID,\n            event: {\n              time: action._time,\n              title: action.type,\n              groupId: action._id,\n              subtitle: 'start',\n              data\n            }\n          })\n        },\n        after: (action, state) => {\n          const data = {}\n          const duration = Date.now() - action._time\n          data.duration = {\n            _custom: {\n              type: 'duration',\n              display: `${duration}ms`,\n              tooltip: 'Action duration',\n              value: duration\n            }\n          }\n          if (action.payload) {\n            data.payload = action.payload\n          }\n          data.state = state\n\n          api.addTimelineEvent({\n            layerId: ACTIONS_LAYER_ID,\n            event: {\n              time: Date.now(),\n              title: action.type,\n              groupId: action._id,\n              subtitle: 'end',\n              data\n            }\n          })\n        }\n      })\n    }\n  )\n}\n\n// extracted from tailwind palette\nconst COLOR_LIME_500 = 0x84cc16\nconst COLOR_DARK = 0x666666\nconst COLOR_WHITE = 0xffffff\n\nconst TAG_NAMESPACED = {\n  label: 'namespaced',\n  textColor: COLOR_WHITE,\n  backgroundColor: COLOR_DARK\n}\n\n/**\n * @param {string} path\n */\nfunction extractNameFromPath (path) {\n  return path && path !== 'root' ? path.split('/').slice(-2, -1)[0] : 'Root'\n}\n\n/**\n * @param {*} module\n * @return {import('@vue/devtools-api').CustomInspectorNode}\n */\nfunction formatStoreForInspectorTree (module, path) {\n  return {\n    id: path || 'root',\n    // all modules end with a `/`, we want the last segment only\n    // cart/ -> cart\n    // nested/cart/ -> cart\n    label: extractNameFromPath(path),\n    tags: module.namespaced ? [TAG_NAMESPACED] : [],\n    children: Object.keys(module._children).map((moduleName) =>\n      formatStoreForInspectorTree(\n        module._children[moduleName],\n        path + moduleName + '/'\n      )\n    )\n  }\n}\n\n/**\n * @param {import('@vue/devtools-api').CustomInspectorNode[]} result\n * @param {*} module\n * @param {string} filter\n * @param {string} path\n */\nfunction flattenStoreForInspectorTree (result, module, filter, path) {\n  if (path.includes(filter)) {\n    result.push({\n      id: path || 'root',\n      label: path.endsWith('/') ? path.slice(0, path.length - 1) : path || 'Root',\n      tags: module.namespaced ? [TAG_NAMESPACED] : []\n    })\n  }\n  Object.keys(module._children).forEach(moduleName => {\n    flattenStoreForInspectorTree(result, module._children[moduleName], filter, path + moduleName + '/')\n  })\n}\n\n/**\n * @param {*} module\n * @return {import('@vue/devtools-api').CustomInspectorState}\n */\nfunction formatStoreForInspectorState (module, getters, path) {\n  getters = path === 'root' ? getters : getters[path]\n  const gettersKeys = Object.keys(getters)\n  const storeState = {\n    state: Object.keys(module.state).map((key) => ({\n      key,\n      editable: true,\n      value: module.state[key]\n    }))\n  }\n\n  if (gettersKeys.length) {\n    const tree = transformPathsToObjectTree(getters)\n    storeState.getters = Object.keys(tree).map((key) => ({\n      key: key.endsWith('/') ? extractNameFromPath(key) : key,\n      editable: false,\n      value: canThrow(() => tree[key])\n    }))\n  }\n\n  return storeState\n}\n\nfunction transformPathsToObjectTree (getters) {\n  const result = {}\n  Object.keys(getters).forEach(key => {\n    const path = key.split('/')\n    if (path.length > 1) {\n      let target = result\n      const leafKey = path.pop()\n      path.forEach((p) => {\n        if (!target[p]) {\n          target[p] = {\n            _custom: {\n              value: {},\n              display: p,\n              tooltip: 'Module',\n              abstract: true\n            }\n          }\n        }\n        target = target[p]._custom.value\n      })\n      target[leafKey] = canThrow(() => getters[key])\n    } else {\n      result[key] = canThrow(() => getters[key])\n    }\n  })\n  return result\n}\n\nfunction getStoreModule (moduleMap, path) {\n  const names = path.split('/').filter((n) => n)\n  return names.reduce(\n    (module, moduleName, i) => {\n      const child = module[moduleName]\n      if (!child) {\n        throw new Error(`Missing module \"${moduleName}\" for path \"${path}\".`)\n      }\n      return i === names.length - 1 ? child : child._children\n    },\n    path === 'root' ? moduleMap : moduleMap.root._children\n  )\n}\n\nfunction canThrow (cb) {\n  try {\n    return cb()\n  } catch (e) {\n    return e\n  }\n}\n"
  },
  {
    "path": "src/plugins/logger.js",
    "content": "// Credits: borrowed code from fcomb/redux-logger\n\nimport { deepCopy } from '../util'\n\nexport function createLogger ({\n  collapsed = true,\n  filter = (mutation, stateBefore, stateAfter) => true,\n  transformer = state => state,\n  mutationTransformer = mut => mut,\n  actionFilter = (action, state) => true,\n  actionTransformer = act => act,\n  logMutations = true,\n  logActions = true,\n  logger = console\n} = {}) {\n  return store => {\n    let prevState = deepCopy(store.state)\n\n    if (typeof logger === 'undefined') {\n      return\n    }\n\n    if (logMutations) {\n      store.subscribe((mutation, state) => {\n        const nextState = deepCopy(state)\n\n        if (filter(mutation, prevState, nextState)) {\n          const formattedTime = getFormattedTime()\n          const formattedMutation = mutationTransformer(mutation)\n          const message = `mutation ${mutation.type}${formattedTime}`\n\n          startMessage(logger, message, collapsed)\n          logger.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState))\n          logger.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation)\n          logger.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState))\n          endMessage(logger)\n        }\n\n        prevState = nextState\n      })\n    }\n\n    if (logActions) {\n      store.subscribeAction((action, state) => {\n        if (actionFilter(action, state)) {\n          const formattedTime = getFormattedTime()\n          const formattedAction = actionTransformer(action)\n          const message = `action ${action.type}${formattedTime}`\n\n          startMessage(logger, message, collapsed)\n          logger.log('%c action', 'color: #03A9F4; font-weight: bold', formattedAction)\n          endMessage(logger)\n        }\n      })\n    }\n  }\n}\n\nfunction startMessage (logger, message, collapsed) {\n  const startMessage = collapsed\n    ? logger.groupCollapsed\n    : logger.group\n\n  // render\n  try {\n    startMessage.call(logger, message)\n  } catch (e) {\n    logger.log(message)\n  }\n}\n\nfunction endMessage (logger) {\n  try {\n    logger.groupEnd()\n  } catch (e) {\n    logger.log('—— log end ——')\n  }\n}\n\nfunction getFormattedTime () {\n  const time = new Date()\n  return ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`\n}\n\nfunction repeat (str, times) {\n  return (new Array(times + 1)).join(str)\n}\n\nfunction pad (num, maxLength) {\n  return repeat('0', maxLength - num.toString().length) + num\n}\n"
  },
  {
    "path": "src/store-util.js",
    "content": "import { reactive, computed, watch, effectScope } from 'vue'\nimport { forEachValue, isObject, isPromise, assert, partial } from './util'\n\nexport function genericSubscribe (fn, subs, options) {\n  if (subs.indexOf(fn) < 0) {\n    options && options.prepend\n      ? subs.unshift(fn)\n      : subs.push(fn)\n  }\n  return () => {\n    const i = subs.indexOf(fn)\n    if (i > -1) {\n      subs.splice(i, 1)\n    }\n  }\n}\n\nexport function resetStore (store, hot) {\n  store._actions = Object.create(null)\n  store._mutations = Object.create(null)\n  store._wrappedGetters = Object.create(null)\n  store._modulesNamespaceMap = Object.create(null)\n  const state = store.state\n  // init all modules\n  installModule(store, state, [], store._modules.root, true)\n  // reset state\n  resetStoreState(store, state, hot)\n}\n\nexport function resetStoreState (store, state, hot) {\n  const oldState = store._state\n  const oldScope = store._scope\n\n  // bind store public getters\n  store.getters = {}\n  // reset local getters cache\n  store._makeLocalGettersCache = Object.create(null)\n  const wrappedGetters = store._wrappedGetters\n  const computedObj = {}\n  const computedCache = {}\n\n  // create a new effect scope and create computed object inside it to avoid\n  // getters (computed) getting destroyed on component unmount.\n  const scope = effectScope(true)\n\n  scope.run(() => {\n    forEachValue(wrappedGetters, (fn, key) => {\n      // use computed to leverage its lazy-caching mechanism\n      // direct inline function use will lead to closure preserving oldState.\n      // using partial to return function with only arguments preserved in closure environment.\n      computedObj[key] = partial(fn, store)\n      computedCache[key] = computed(() => computedObj[key]())\n      Object.defineProperty(store.getters, key, {\n        get: () => computedCache[key].value,\n        enumerable: true // for local getters\n      })\n    })\n  })\n\n  store._state = reactive({\n    data: state\n  })\n\n  // register the newly created effect scope to the store so that we can\n  // dispose the effects when this method runs again in the future.\n  store._scope = scope\n\n  // enable strict mode for new state\n  if (store.strict) {\n    enableStrictMode(store)\n  }\n\n  if (oldState) {\n    if (hot) {\n      // dispatch changes in all subscribed watchers\n      // to force getter re-evaluation for hot reloading.\n      store._withCommit(() => {\n        oldState.data = null\n      })\n    }\n  }\n\n  // dispose previously registered effect scope if there is one.\n  if (oldScope) {\n    oldScope.stop()\n  }\n}\n\nexport function installModule (store, rootState, path, module, hot) {\n  const isRoot = !path.length\n  const namespace = store._modules.getNamespace(path)\n\n  // register in namespace map\n  if (module.namespaced) {\n    if (store._modulesNamespaceMap[namespace] && __DEV__) {\n      console.error(`[vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')}`)\n    }\n    store._modulesNamespaceMap[namespace] = module\n  }\n\n  // set state\n  if (!isRoot && !hot) {\n    const parentState = getNestedState(rootState, path.slice(0, -1))\n    const moduleName = path[path.length - 1]\n    store._withCommit(() => {\n      if (__DEV__) {\n        if (moduleName in parentState) {\n          console.warn(\n            `[vuex] state field \"${moduleName}\" was overridden by a module with the same name at \"${path.join('.')}\"`\n          )\n        }\n      }\n      parentState[moduleName] = module.state\n    })\n  }\n\n  const local = module.context = makeLocalContext(store, namespace, path)\n\n  module.forEachMutation((mutation, key) => {\n    const namespacedType = namespace + key\n    registerMutation(store, namespacedType, mutation, local)\n  })\n\n  module.forEachAction((action, key) => {\n    const type = action.root ? key : namespace + key\n    const handler = action.handler || action\n    registerAction(store, type, handler, local)\n  })\n\n  module.forEachGetter((getter, key) => {\n    const namespacedType = namespace + key\n    registerGetter(store, namespacedType, getter, local)\n  })\n\n  module.forEachChild((child, key) => {\n    installModule(store, rootState, path.concat(key), child, hot)\n  })\n}\n\n/**\n * make localized dispatch, commit, getters and state\n * if there is no namespace, just use root ones\n */\nfunction makeLocalContext (store, namespace, path) {\n  const noNamespace = namespace === ''\n\n  const local = {\n    dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => {\n      const args = unifyObjectStyle(_type, _payload, _options)\n      const { payload, options } = args\n      let { type } = args\n\n      if (!options || !options.root) {\n        type = namespace + type\n        if (__DEV__ && !store._actions[type]) {\n          console.error(`[vuex] unknown local action type: ${args.type}, global type: ${type}`)\n          return\n        }\n      }\n\n      return store.dispatch(type, payload)\n    },\n\n    commit: noNamespace ? store.commit : (_type, _payload, _options) => {\n      const args = unifyObjectStyle(_type, _payload, _options)\n      const { payload, options } = args\n      let { type } = args\n\n      if (!options || !options.root) {\n        type = namespace + type\n        if (__DEV__ && !store._mutations[type]) {\n          console.error(`[vuex] unknown local mutation type: ${args.type}, global type: ${type}`)\n          return\n        }\n      }\n\n      store.commit(type, payload, options)\n    }\n  }\n\n  // getters and state object must be gotten lazily\n  // because they will be changed by state update\n  Object.defineProperties(local, {\n    getters: {\n      get: noNamespace\n        ? () => store.getters\n        : () => makeLocalGetters(store, namespace)\n    },\n    state: {\n      get: () => getNestedState(store.state, path)\n    }\n  })\n\n  return local\n}\n\nexport function makeLocalGetters (store, namespace) {\n  if (!store._makeLocalGettersCache[namespace]) {\n    const gettersProxy = {}\n    const splitPos = namespace.length\n    Object.keys(store.getters).forEach(type => {\n      // skip if the target getter is not match this namespace\n      if (type.slice(0, splitPos) !== namespace) return\n\n      // extract local getter type\n      const localType = type.slice(splitPos)\n\n      // Add a port to the getters proxy.\n      // Define as getter property because\n      // we do not want to evaluate the getters in this time.\n      Object.defineProperty(gettersProxy, localType, {\n        get: () => store.getters[type],\n        enumerable: true\n      })\n    })\n    store._makeLocalGettersCache[namespace] = gettersProxy\n  }\n\n  return store._makeLocalGettersCache[namespace]\n}\n\nfunction registerMutation (store, type, handler, local) {\n  const entry = store._mutations[type] || (store._mutations[type] = [])\n  entry.push(function wrappedMutationHandler (payload) {\n    handler.call(store, local.state, payload)\n  })\n}\n\nfunction registerAction (store, type, handler, local) {\n  const entry = store._actions[type] || (store._actions[type] = [])\n  entry.push(function wrappedActionHandler (payload) {\n    let res = handler.call(store, {\n      dispatch: local.dispatch,\n      commit: local.commit,\n      getters: local.getters,\n      state: local.state,\n      rootGetters: store.getters,\n      rootState: store.state\n    }, payload)\n    if (!isPromise(res)) {\n      res = Promise.resolve(res)\n    }\n    if (store._devtoolHook) {\n      return res.catch(err => {\n        store._devtoolHook.emit('vuex:error', err)\n        throw err\n      })\n    } else {\n      return res\n    }\n  })\n}\n\nfunction registerGetter (store, type, rawGetter, local) {\n  if (store._wrappedGetters[type]) {\n    if (__DEV__) {\n      console.error(`[vuex] duplicate getter key: ${type}`)\n    }\n    return\n  }\n  store._wrappedGetters[type] = function wrappedGetter (store) {\n    return rawGetter(\n      local.state, // local state\n      local.getters, // local getters\n      store.state, // root state\n      store.getters // root getters\n    )\n  }\n}\n\nfunction enableStrictMode (store) {\n  watch(() => store._state.data, () => {\n    if (__DEV__) {\n      assert(store._committing, `do not mutate vuex store state outside mutation handlers.`)\n    }\n  }, { deep: true, flush: 'sync' })\n}\n\nexport function getNestedState (state, path) {\n  return path.reduce((state, key) => state[key], state)\n}\n\nexport function unifyObjectStyle (type, payload, options) {\n  if (isObject(type) && type.type) {\n    options = payload\n    payload = type\n    type = type.type\n  }\n\n  if (__DEV__) {\n    assert(typeof type === 'string', `expects string as the type, but found ${typeof type}.`)\n  }\n\n  return { type, payload, options }\n}\n"
  },
  {
    "path": "src/store.js",
    "content": "import { watch } from 'vue'\nimport { storeKey } from './injectKey'\nimport { addDevtools } from './plugins/devtool'\nimport ModuleCollection from './module/module-collection'\nimport { assert } from './util'\nimport {\n  genericSubscribe,\n  getNestedState,\n  installModule,\n  resetStore,\n  resetStoreState,\n  unifyObjectStyle\n} from './store-util'\n\nexport function createStore (options) {\n  return new Store(options)\n}\n\nexport class Store {\n  constructor (options = {}) {\n    if (__DEV__) {\n      assert(typeof Promise !== 'undefined', `vuex requires a Promise polyfill in this browser.`)\n      assert(this instanceof Store, `store must be called with the new operator.`)\n    }\n\n    const {\n      plugins = [],\n      strict = false,\n      devtools\n    } = options\n\n    // store internal state\n    this._committing = false\n    this._actions = Object.create(null)\n    this._actionSubscribers = []\n    this._mutations = Object.create(null)\n    this._wrappedGetters = Object.create(null)\n    this._modules = new ModuleCollection(options)\n    this._modulesNamespaceMap = Object.create(null)\n    this._subscribers = []\n    this._makeLocalGettersCache = Object.create(null)\n\n    // EffectScope instance. when registering new getters, we wrap them inside\n    // EffectScope so that getters (computed) would not be destroyed on\n    // component unmount.\n    this._scope = null\n\n    this._devtools = devtools\n\n    // bind commit and dispatch to self\n    const store = this\n    const { dispatch, commit } = this\n    this.dispatch = function boundDispatch (type, payload) {\n      return dispatch.call(store, type, payload)\n    }\n    this.commit = function boundCommit (type, payload, options) {\n      return commit.call(store, type, payload, options)\n    }\n\n    // strict mode\n    this.strict = strict\n\n    const state = this._modules.root.state\n\n    // init root module.\n    // this also recursively registers all sub-modules\n    // and collects all module getters inside this._wrappedGetters\n    installModule(this, state, [], this._modules.root)\n\n    // initialize the store state, which is responsible for the reactivity\n    // (also registers _wrappedGetters as computed properties)\n    resetStoreState(this, state)\n\n    // apply plugins\n    plugins.forEach(plugin => plugin(this))\n  }\n\n  install (app, injectKey) {\n    app.provide(injectKey || storeKey, this)\n    app.config.globalProperties.$store = this\n\n    const useDevtools = this._devtools !== undefined\n      ? this._devtools\n      : __DEV__ || __VUE_PROD_DEVTOOLS__\n\n    if (useDevtools) {\n      addDevtools(app, this)\n    }\n  }\n\n  get state () {\n    return this._state.data\n  }\n\n  set state (v) {\n    if (__DEV__) {\n      assert(false, `use store.replaceState() to explicit replace store state.`)\n    }\n  }\n\n  commit (_type, _payload, _options) {\n    // check object-style commit\n    const {\n      type,\n      payload,\n      options\n    } = unifyObjectStyle(_type, _payload, _options)\n\n    const mutation = { type, payload }\n    const entry = this._mutations[type]\n    if (!entry) {\n      if (__DEV__) {\n        console.error(`[vuex] unknown mutation type: ${type}`)\n      }\n      return\n    }\n    this._withCommit(() => {\n      entry.forEach(function commitIterator (handler) {\n        handler(payload)\n      })\n    })\n\n    this._subscribers\n      .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe\n      .forEach(sub => sub(mutation, this.state))\n\n    if (\n      __DEV__ &&\n      options && options.silent\n    ) {\n      console.warn(\n        `[vuex] mutation type: ${type}. Silent option has been removed. ` +\n        'Use the filter functionality in the vue-devtools'\n      )\n    }\n  }\n\n  dispatch (_type, _payload) {\n    // check object-style dispatch\n    const {\n      type,\n      payload\n    } = unifyObjectStyle(_type, _payload)\n\n    const action = { type, payload }\n    const entry = this._actions[type]\n    if (!entry) {\n      if (__DEV__) {\n        console.error(`[vuex] unknown action type: ${type}`)\n      }\n      return\n    }\n\n    try {\n      this._actionSubscribers\n        .slice() // shallow copy to prevent iterator invalidation if subscriber synchronously calls unsubscribe\n        .filter(sub => sub.before)\n        .forEach(sub => sub.before(action, this.state))\n    } catch (e) {\n      if (__DEV__) {\n        console.warn(`[vuex] error in before action subscribers: `)\n        console.error(e)\n      }\n    }\n\n    const result = entry.length > 1\n      ? Promise.all(entry.map(handler => handler(payload)))\n      : entry[0](payload)\n\n    return new Promise((resolve, reject) => {\n      result.then(res => {\n        try {\n          this._actionSubscribers\n            .filter(sub => sub.after)\n            .forEach(sub => sub.after(action, this.state))\n        } catch (e) {\n          if (__DEV__) {\n            console.warn(`[vuex] error in after action subscribers: `)\n            console.error(e)\n          }\n        }\n        resolve(res)\n      }, error => {\n        try {\n          this._actionSubscribers\n            .filter(sub => sub.error)\n            .forEach(sub => sub.error(action, this.state, error))\n        } catch (e) {\n          if (__DEV__) {\n            console.warn(`[vuex] error in error action subscribers: `)\n            console.error(e)\n          }\n        }\n        reject(error)\n      })\n    })\n  }\n\n  subscribe (fn, options) {\n    return genericSubscribe(fn, this._subscribers, options)\n  }\n\n  subscribeAction (fn, options) {\n    const subs = typeof fn === 'function' ? { before: fn } : fn\n    return genericSubscribe(subs, this._actionSubscribers, options)\n  }\n\n  watch (getter, cb, options) {\n    if (__DEV__) {\n      assert(typeof getter === 'function', `store.watch only accepts a function.`)\n    }\n    return watch(() => getter(this.state, this.getters), cb, Object.assign({}, options))\n  }\n\n  replaceState (state) {\n    this._withCommit(() => {\n      this._state.data = state\n    })\n  }\n\n  registerModule (path, rawModule, options = {}) {\n    if (typeof path === 'string') path = [path]\n\n    if (__DEV__) {\n      assert(Array.isArray(path), `module path must be a string or an Array.`)\n      assert(path.length > 0, 'cannot register the root module by using registerModule.')\n    }\n\n    this._modules.register(path, rawModule)\n    installModule(this, this.state, path, this._modules.get(path), options.preserveState)\n    // reset store to update getters...\n    resetStoreState(this, this.state)\n  }\n\n  unregisterModule (path) {\n    if (typeof path === 'string') path = [path]\n\n    if (__DEV__) {\n      assert(Array.isArray(path), `module path must be a string or an Array.`)\n    }\n\n    this._modules.unregister(path)\n    this._withCommit(() => {\n      const parentState = getNestedState(this.state, path.slice(0, -1))\n      delete parentState[path[path.length - 1]]\n    })\n    resetStore(this)\n  }\n\n  hasModule (path) {\n    if (typeof path === 'string') path = [path]\n\n    if (__DEV__) {\n      assert(Array.isArray(path), `module path must be a string or an Array.`)\n    }\n\n    return this._modules.isRegistered(path)\n  }\n\n  hotUpdate (newOptions) {\n    this._modules.update(newOptions)\n    resetStore(this, true)\n  }\n\n  _withCommit (fn) {\n    const committing = this._committing\n    this._committing = true\n    fn()\n    this._committing = committing\n  }\n}\n"
  },
  {
    "path": "src/util.js",
    "content": "/**\n * Get the first item that pass the test\n * by second argument function\n *\n * @param {Array} list\n * @param {Function} f\n * @return {*}\n */\nexport function find (list, f) {\n  return list.filter(f)[0]\n}\n\n/**\n * Deep copy the given object considering circular structure.\n * This function caches all nested objects and its copies.\n * If it detects circular structure, use cached copy to avoid infinite loop.\n *\n * @param {*} obj\n * @param {Array<Object>} cache\n * @return {*}\n */\nexport function deepCopy (obj, cache = []) {\n  // just return if obj is immutable value\n  if (obj === null || typeof obj !== 'object') {\n    return obj\n  }\n\n  // if obj is hit, it is in circular structure\n  const hit = find(cache, c => c.original === obj)\n  if (hit) {\n    return hit.copy\n  }\n\n  const copy = Array.isArray(obj) ? [] : {}\n  // put the copy into cache at first\n  // because we want to refer it in recursive deepCopy\n  cache.push({\n    original: obj,\n    copy\n  })\n\n  Object.keys(obj).forEach(key => {\n    copy[key] = deepCopy(obj[key], cache)\n  })\n\n  return copy\n}\n\n/**\n * forEach for object\n */\nexport function forEachValue (obj, fn) {\n  Object.keys(obj).forEach(key => fn(obj[key], key))\n}\n\nexport function isObject (obj) {\n  return obj !== null && typeof obj === 'object'\n}\n\nexport function isPromise (val) {\n  return val && typeof val.then === 'function'\n}\n\nexport function assert (condition, msg) {\n  if (!condition) throw new Error(`[vuex] ${msg}`)\n}\n\nexport function partial (fn, arg) {\n  return function () {\n    return fn(arg)\n  }\n}\n"
  },
  {
    "path": "test/.eslintrc.json",
    "content": "{\n  \"env\": {\n    \"jest\": true\n  }\n}\n"
  },
  {
    "path": "test/e2e/cart.spec.js",
    "content": "import { setupPuppeteer, E2E_TIMEOUT } from 'test/helpers'\n\ndescribe('e2e/cart', () => {\n  const { page, text, count, click, sleep } = setupPuppeteer()\n\n  async function testCart (url) {\n    await page().goto(url)\n\n    await sleep(120) // api simulation\n\n    expect(await count('li')).toBe(3)\n    expect(await count('.cart button[disabled]')).toBe(1)\n    expect(await text('li:nth-child(1)')).toContain('iPad 4 Mini')\n    expect(await text('.cart')).toContain('Please add some products to cart')\n    expect(await text('.cart')).toContain('Total: $0.00')\n\n    await click('li:nth-child(1) button')\n    expect(await text('.cart')).toContain('iPad 4 Mini - $500.01 x 1')\n    expect(await text('.cart')).toContain('Total: $500.01')\n\n    await click('li:nth-child(1) button')\n    expect(await text('.cart')).toContain('iPad 4 Mini - $500.01 x 2')\n    expect(await text('.cart')).toContain('Total: $1,000.02')\n    expect(await count('li:nth-child(1) button[disabled]')).toBe(1)\n\n    await click('li:nth-child(2) button')\n    expect(await text('.cart')).toContain('H&M T-Shirt White - $10.99 x 1')\n    expect(await text('.cart')).toContain('Total: $1,011.01')\n\n    await click('.cart button')\n    await sleep(200)\n    expect(await text('.cart')).toContain('Please add some products to cart')\n    expect(await text('.cart')).toContain('Total: $0.00')\n    expect(await text('.cart')).toContain('Checkout successful')\n    expect(await count('.cart button[disabled]')).toBe(1)\n  }\n\n  test('classic', async () => {\n    await testCart('http://localhost:8080/classic/shopping-cart/')\n  }, E2E_TIMEOUT)\n\n  test('composition', async () => {\n    await testCart('http://localhost:8080/composition/shopping-cart/')\n  }, E2E_TIMEOUT)\n})\n"
  },
  {
    "path": "test/e2e/chat.spec.js",
    "content": "import { setupPuppeteer, E2E_TIMEOUT } from 'test/helpers'\n\ndescribe('e2e/chat', () => {\n  const { page, text, count, click, enterValue, sleep } = setupPuppeteer()\n\n  async function testChat (url) {\n    await page().goto(url)\n\n    expect(await text('.thread-count')).toContain('Unread threads: 2')\n    expect(await count('.thread-list-item')).toBe(3)\n    expect(await text('.thread-list-item.active')).toContain('Functional Heads')\n    expect(await text('.message-thread-heading')).toContain('Functional Heads')\n    expect(await count('.message-list-item')).toBe(2)\n    expect(await text('.message-list-item:nth-child(1) .message-author-name')).toContain('Bill')\n    expect(await text('.message-list-item:nth-child(1) .message-text')).toContain('Hey Brian')\n\n    await enterValue('.message-composer', 'hi')\n    await sleep(50) // fake api\n    expect(await count('.message-list-item')).toBe(3)\n    expect(await text('.message-list-item:nth-child(3)')).toContain('hi')\n\n    await click('.thread-list-item:nth-child(2)')\n    expect(await text('.thread-list-item.active')).toContain('Dave and Bill')\n    expect(await text('.message-thread-heading')).toContain('Dave and Bill')\n    expect(await count('.message-list-item')).toBe(2)\n    expect(await text('.message-list-item:nth-child(1) .message-author-name')).toContain('Bill')\n    expect(await text('.message-list-item:nth-child(1) .message-text')).toContain('Hey Dave')\n\n    await enterValue('.message-composer', 'hi')\n    await sleep(50) // fake api\n    expect(await count('.message-list-item')).toBe(3)\n    expect(await text('.message-list-item:nth-child(3)')).toContain('hi')\n  }\n\n  test('classic', async () => {\n    await testChat('http://localhost:8080/classic/chat/')\n  }, E2E_TIMEOUT)\n\n  test('composition', async () => {\n    await testChat('http://localhost:8080/composition/chat/')\n  }, E2E_TIMEOUT)\n})\n"
  },
  {
    "path": "test/e2e/counter.spec.js",
    "content": "import { setupPuppeteer, E2E_TIMEOUT } from 'test/helpers'\n\ndescribe('e2e/counter', () => {\n  const { page, text, click, sleep } = setupPuppeteer()\n\n  async function testCounter (url) {\n    await page().goto(url)\n    expect(await text('#app')).toContain('Clicked: 0 times')\n\n    await click('button:nth-child(1)')\n    expect(await text('#app')).toContain('Clicked: 1 times')\n\n    await click('button:nth-child(2)')\n    expect(await text('#app')).toContain('Clicked: 0 times')\n\n    await click('button:nth-child(3)')\n    expect(await text('#app')).toContain('Clicked: 0 times')\n\n    await click('button:nth-child(1)')\n    expect(await text('#app')).toContain('Clicked: 1 times')\n\n    await click('button:nth-child(3)')\n    expect(await text('#app')).toContain('Clicked: 2 times')\n\n    await click('button:nth-child(4)')\n    expect(await text('#app')).toContain('Clicked: 2 times')\n    await sleep(1000)\n    expect(await text('#app')).toContain('Clicked: 3 times')\n  }\n\n  test('classic', async () => {\n    await testCounter('http://localhost:8080/classic/counter/')\n  }, E2E_TIMEOUT)\n\n  test('composition', async () => {\n    await testCounter('http://localhost:8080/composition/counter/')\n  }, E2E_TIMEOUT)\n})\n"
  },
  {
    "path": "test/e2e/todomvc.spec.js",
    "content": "import { setupPuppeteer, E2E_TIMEOUT } from 'test/helpers'\n\ndescribe('e2e/todomvc', () => {\n  const {\n    page,\n    isVisible,\n    isChecked,\n    isFocused,\n    text,\n    value,\n    count,\n    hasClass,\n    hover,\n    click,\n    keyUp,\n    setValue,\n    enterValue,\n    clearValue\n  } = setupPuppeteer()\n\n  async function testTodoMVC (url) {\n    await page().goto(url)\n\n    expect(await isVisible('.main')).toBe(false)\n    expect(await isVisible('.footer')).toBe(false)\n    expect(await count('.filters .selected')).toBe(1)\n\n    await enterValue('.new-todo', 'test')\n    expect(await count('.todo')).toBe(1)\n    expect(await isVisible('.todo .edit')).toBe(false)\n    expect(await text('.todo label')).toContain('test')\n    expect(await text('.todo-count strong')).toContain('1')\n    expect(await isChecked('.todo .toggle')).toBe(false)\n    expect(await isVisible('.main')).toBe(true)\n    expect(await isVisible('.footer')).toBe(true)\n    expect(await isVisible('.clear-completed')).toBe(false)\n    expect(await value('.new-todo')).toBe('')\n\n    await enterValue('.new-todo', 'test2')\n    expect(await count('.todo')).toBe(2)\n    expect(await text('.todo:nth-child(2) label')).toContain('test2')\n    expect(await text('.todo-count strong')).toContain('2')\n\n    // toggle\n    await click('.todo .toggle')\n    expect(await count('.todo.completed')).toBe(1)\n    expect(await hasClass('.todo:nth-child(1)', 'completed')).toBe(true)\n    expect(await text('.todo-count strong')).toContain('1')\n    expect(await isVisible('.clear-completed')).toBe(true)\n\n    await enterValue('.new-todo', 'test3')\n    expect(await count('.todo')).toBe(3)\n    expect(await text('.todo:nth-child(3) label')).toContain('test3')\n    expect(await text('.todo-count strong')).toContain('2')\n\n    await enterValue('.new-todo', 'test4')\n    await enterValue('.new-todo', 'test5')\n    expect(await count('.todo')).toBe(5)\n    expect(await text('.todo-count strong')).toContain('4')\n\n    // toggle more\n    await click('.todo:nth-child(4) .toggle')\n    await click('.todo:nth-child(5) .toggle')\n    expect(await count('.todo.completed')).toBe(3)\n    expect(await text('.todo-count strong')).toContain('2')\n\n    // remove\n    await hover('.todo:nth-child(1)')\n    await click('.todo:nth-child(1) .destroy')\n    expect(await count('.todo')).toBe(4)\n    expect(await count('.todo.completed')).toBe(2)\n    expect(await text('.todo-count strong')).toContain('2')\n\n    await hover('.todo:nth-child(2)')\n    await click('.todo:nth-child(2) .destroy')\n    expect(await count('.todo')).toBe(3)\n    expect(await count('.todo.completed')).toBe(2)\n    expect(await text('.todo-count strong')).toContain('1')\n\n    // remove all\n    await click('.clear-completed')\n    expect(await count('.todo')).toBe(1)\n    expect(await text('.todo label')).toContain('test2')\n    expect(await count('.todo.completed')).toBe(0)\n    expect(await text('.todo-count strong')).toBe('1')\n    expect(await isVisible('.clear-completed')).toBe(false)\n\n    // prepare to test filters\n    await enterValue('.new-todo', 'test')\n    await enterValue('.new-todo', 'test')\n    await click('.todo:nth-child(2) .toggle')\n    await click('.todo:nth-child(3) .toggle')\n\n    // active filter\n    await click('.filters li:nth-child(2) a')\n    expect(await count('.todo')).toBe(1)\n    expect(await count('.todo.completed')).toBe(0)\n\n    // add item with filter active\n    await enterValue('.new-todo', 'test')\n    expect(await count('.todo', 2)).toBe(2)\n\n    // complted filter\n    await click('.filters li:nth-child(3) a')\n    expect(await count('.todo')).toBe(2)\n    expect(await count('.todo.completed')).toBe(2)\n\n    // toggling with filter active\n    await click('.todo .toggle')\n    expect(await count('.todo')).toBe(1)\n    await click('.filters li:nth-child(2) a')\n    expect(await count('.todo')).toBe(3)\n    await click('.todo .toggle')\n    expect(await count('.todo')).toBe(2)\n\n    // editing triggered by blur\n    await click('.filters li:nth-child(1) a')\n    await click('.todo:nth-child(1) label', { clickCount: 2 })\n    expect(await count('.todo.editing')).toBe(1)\n    expect(await isFocused('.todo:nth-child(1) .edit')).toBe(true)\n    await clearValue('.todo:nth-child(1) .edit')\n    await setValue('.todo:nth-child(1) .edit', 'edited!')\n    await click('.todo-count') // blur\n    expect(await count('.todo.editing')).toBe(0)\n    expect(await text('.todo:nth-child(1) label')).toBe('edited!')\n\n    // editing triggered by enter\n    await click('.todo label', { clickCount: 2 })\n    await clearValue('.todo:nth-child(1) .edit')\n    await enterValue('.todo:nth-child(1) .edit', 'edited again!')\n    expect(await count('.todo.editing')).toBe(0)\n    expect(await text('.todo:nth-child(1) label')).toBe('edited again!')\n\n    // cancel\n    await click('.todo label', { clickCount: 2 })\n    await clearValue('.todo:nth-child(1) .edit')\n    await setValue('.todo:nth-child(1) .edit', 'edited!')\n    await keyUp('Escape')\n    expect(await count('.todo.editing')).toBe(0)\n    expect(await text('.todo:nth-child(1) label')).toBe('edited again!')\n\n    // empty value should remove\n    await click('.todo label', { clickCount: 2 })\n    await clearValue('.todo:nth-child(1) .edit')\n    await enterValue('.todo:nth-child(1) .edit', ' ')\n    expect(await count('.todo')).toBe(3)\n\n    // toggle all\n    await click('label[for=\"toggle-all\"]')\n    expect(await count('.todo.completed')).toBe(3)\n    await click('label[for=\"toggle-all\"]')\n    expect(await count('.todo:not(.completed)')).toBe(3)\n  }\n\n  test('classic', async () => {\n    await testTodoMVC('http://localhost:8080/classic/todomvc/')\n  }, E2E_TIMEOUT)\n\n  test('composition', async () => {\n    await testTodoMVC('http://localhost:8080/composition/todomvc/')\n  }, E2E_TIMEOUT)\n})\n"
  },
  {
    "path": "test/esm/esm-import.mjs",
    "content": "import assert from 'assert'\n\nimport { createRequire } from 'module'\n\nimport Vuex, {\n  Store,\n  install,\n  version,\n  mapState,\n  mapMutations,\n  mapGetters,\n  mapActions,\n  createNamespacedHelpers,\n  createLogger\n} from 'vuex'\n\nconst require = createRequire(import.meta.url)\n\nconst cjs = require('vuex')\n\nassert.equal(Vuex, cjs)\nassert.equal(Store, cjs.Store)\nassert.equal(install, cjs.install)\nassert.equal(version, cjs.version)\nassert.equal(mapState, cjs.mapState)\nassert.equal(mapMutations, cjs.mapMutations)\nassert.equal(mapGetters, cjs.mapGetters)\nassert.equal(mapActions, cjs.mapActions)\nassert.equal(createNamespacedHelpers, cjs.createNamespacedHelpers)\nassert.equal(createLogger, cjs.createLogger)\n"
  },
  {
    "path": "test/esm/esm-test.js",
    "content": "// only test esm entry points on Node.14 or higher\nconst [major] = process.versions.node.split('.')\n\nif (+major >= 14) {\n  (async function () {\n    await import('./esm-import.mjs')\n  })().catch(console.error)\n}\n"
  },
  {
    "path": "test/helpers.js",
    "content": "import { createApp } from 'vue'\nimport puppeteer from 'puppeteer'\n\nexport function mount (store, component) {\n  const el = createElement()\n\n  component.render = component.render || (() => {})\n\n  const app = createApp(component)\n\n  app.use(store)\n\n  return app.mount(el)\n}\n\nfunction createElement () {\n  const el = document.createElement('div')\n\n  document.body.appendChild(el)\n\n  return el\n}\n\nexport const E2E_TIMEOUT = 30 * 1000\n\nconst puppeteerOptions = process.env.CI\n  ? { args: ['--no-sandbox', '--disable-setuid-sandbox'] }\n  : {}\n\nexport function setupPuppeteer () {\n  let browser\n  let page\n\n  beforeEach(async () => {\n    browser = await puppeteer.launch(puppeteerOptions)\n    page = await browser.newPage()\n\n    page.on('console', (e) => {\n      if (e.type() === 'error') {\n        const err = e.args()[0]\n        console.error(\n          `Error from Puppeteer-loaded page:\\n`,\n          err._remoteObject.description\n        )\n      }\n    })\n  })\n\n  afterEach(async () => {\n    await browser.close()\n  })\n\n  async function click (selector, options) {\n    await page.click(selector, options)\n  }\n\n  async function hover (selector) {\n    await page.hover(selector)\n  }\n\n  async function keyUp (key) {\n    await page.keyboard.up(key)\n  }\n\n  async function count (selector) {\n    return (await page.$$(selector)).length\n  }\n\n  async function text (selector) {\n    return await page.$eval(selector, (node) => node.textContent)\n  }\n\n  async function value (selector) {\n    return await page.$eval(selector, (node) => node.value)\n  }\n\n  async function html (selector) {\n    return await page.$eval(selector, (node) => node.innerHTML)\n  }\n\n  async function classList (selector) {\n    return await page.$eval(selector, (node) => {\n      const list = []\n      for (const index in node.classList) {\n        list.push(node.classList[index])\n      }\n      return list\n    })\n  }\n\n  async function hasClass (selector, name) {\n    return (await classList(selector)).find(c => c === name) !== undefined\n  }\n\n  async function isVisible (selector) {\n    const display = await page.$eval(selector, (node) => {\n      return window.getComputedStyle(node).display\n    })\n    return display !== 'none'\n  }\n\n  async function isChecked (selector) {\n    return await page.$eval(selector, (node) => node.checked)\n  }\n\n  async function isFocused (selector) {\n    return await page.$eval(selector, (node) => node === document.activeElement)\n  }\n\n  async function setValue (selector, value) {\n    const el = (await page.$(selector))\n    await el.evaluate((node) => { node.value = '' })\n    await el.type(value)\n  }\n\n  async function enterValue (selector, value) {\n    const el = (await page.$(selector))\n    await el.evaluate((node) => { node.value = '' })\n    await el.type(value)\n    await el.press('Enter')\n  }\n\n  async function clearValue (selector) {\n    return await page.$eval(selector, (node) => { node.value = '' })\n  }\n\n  async function sleep (ms = 0) {\n    return new Promise((resolve) => {\n      setTimeout(resolve, ms)\n    })\n  }\n\n  return {\n    page: () => page,\n    click,\n    hover,\n    keyUp,\n    count,\n    text,\n    value,\n    html,\n    classList,\n    hasClass,\n    isVisible,\n    isChecked,\n    isFocused,\n    setValue,\n    enterValue,\n    clearValue,\n    sleep\n  }\n}\n"
  },
  {
    "path": "test/setup.js",
    "content": "import 'regenerator-runtime/runtime'\n"
  },
  {
    "path": "test/unit/helpers.spec.js",
    "content": "import { mount } from 'test/helpers'\nimport Vuex, { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from '@/index'\n\ndescribe('Helpers', () => {\n  it('mapState (array)', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      }\n    })\n    const vm = mount(store, {\n      computed: mapState(['a'])\n    })\n    expect(vm.a).toBe(1)\n    store.state.a++\n    expect(vm.a).toBe(2)\n  })\n\n  it('mapState (object)', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      getters: {\n        b: () => 2\n      }\n    })\n    const vm = mount(store, {\n      computed: mapState({\n        a: (state, getters) => {\n          return state.a + getters.b\n        }\n      })\n    })\n    expect(vm.a).toBe(3)\n    store.state.a++\n    expect(vm.a).toBe(4)\n  })\n\n  it('mapState (with namespace)', () => {\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { a: 1 },\n          getters: {\n            b: state => state.a + 1\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      computed: mapState('foo', {\n        a: (state, getters) => {\n          return state.a + getters.b\n        }\n      })\n    })\n    expect(vm.a).toBe(3)\n    store.state.foo.a++\n    expect(vm.a).toBe(5)\n    store.replaceState({\n      foo: { a: 3 }\n    })\n    expect(vm.a).toBe(7)\n  })\n\n  // #708\n  it('mapState (with namespace and a nested module)', () => {\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { a: 1 },\n          modules: {\n            bar: {\n              state: { b: 2 }\n            }\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      computed: mapState('foo', {\n        value: state => state\n      })\n    })\n    expect(vm.value.a).toBe(1)\n    expect(vm.value.bar.b).toBe(2)\n    expect(vm.value.b).toBeUndefined()\n  })\n\n  it('mapState (with undefined states)', () => {\n    jest.spyOn(console, 'error').mockImplementation()\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { a: 1 }\n        }\n      }\n    })\n    const vm = mount(store, {\n      computed: mapState('foo')\n    })\n    expect(vm.a).toBeUndefined()\n    expect(console.error).toHaveBeenCalledWith('[vuex] mapState: mapper parameter must be either an Array or an Object')\n  })\n\n  it('mapMutations (array)', () => {\n    const store = new Vuex.Store({\n      state: { count: 0 },\n      mutations: {\n        inc: state => state.count++,\n        dec: state => state.count--\n      }\n    })\n    const vm = mount(store, {\n      methods: mapMutations(['inc', 'dec'])\n    })\n    vm.inc()\n    expect(store.state.count).toBe(1)\n    vm.dec()\n    expect(store.state.count).toBe(0)\n  })\n\n  it('mapMutations (object)', () => {\n    const store = new Vuex.Store({\n      state: { count: 0 },\n      mutations: {\n        inc: state => state.count++,\n        dec: state => state.count--\n      }\n    })\n    const vm = mount(store, {\n      methods: mapMutations({\n        plus: 'inc',\n        minus: 'dec'\n      })\n    })\n    vm.plus()\n    expect(store.state.count).toBe(1)\n    vm.minus()\n    expect(store.state.count).toBe(0)\n  })\n\n  it('mapMutations (function)', () => {\n    const store = new Vuex.Store({\n      state: { count: 0 },\n      mutations: {\n        inc (state, amount) {\n          state.count += amount\n        }\n      }\n    })\n    const vm = mount(store, {\n      methods: mapMutations({\n        plus (commit, amount) {\n          commit('inc', amount + 1)\n        }\n      })\n    })\n    vm.plus(42)\n    expect(store.state.count).toBe(43)\n  })\n\n  it('mapMutations (with namespace)', () => {\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { count: 0 },\n          mutations: {\n            inc: state => state.count++,\n            dec: state => state.count--\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      methods: mapMutations('foo', {\n        plus: 'inc',\n        minus: 'dec'\n      })\n    })\n    vm.plus()\n    expect(store.state.foo.count).toBe(1)\n    vm.minus()\n    expect(store.state.foo.count).toBe(0)\n  })\n\n  it('mapMutations (function with namepsace)', () => {\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { count: 0 },\n          mutations: {\n            inc (state, amount) {\n              state.count += amount\n            }\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      methods: mapMutations('foo', {\n        plus (commit, amount) {\n          commit('inc', amount + 1)\n        }\n      })\n    })\n    vm.plus(42)\n    expect(store.state.foo.count).toBe(43)\n  })\n\n  it('mapMutations (with undefined mutations)', () => {\n    jest.spyOn(console, 'error').mockImplementation()\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { count: 0 },\n          mutations: {\n            inc: state => state.count++,\n            dec: state => state.count--\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      methods: mapMutations('foo')\n    })\n    expect(vm.inc).toBeUndefined()\n    expect(vm.dec).toBeUndefined()\n    expect(console.error).toHaveBeenCalledWith('[vuex] mapMutations: mapper parameter must be either an Array or an Object')\n  })\n\n  it('mapGetters (array)', () => {\n    const store = new Vuex.Store({\n      state: { count: 0 },\n      mutations: {\n        inc: state => state.count++,\n        dec: state => state.count--\n      },\n      getters: {\n        hasAny: ({ count }) => count > 0,\n        negative: ({ count }) => count < 0\n      }\n    })\n    const vm = mount(store, {\n      computed: mapGetters(['hasAny', 'negative'])\n    })\n    expect(vm.hasAny).toBe(false)\n    expect(vm.negative).toBe(false)\n    store.commit('inc')\n    expect(vm.hasAny).toBe(true)\n    expect(vm.negative).toBe(false)\n    store.commit('dec')\n    store.commit('dec')\n    expect(vm.hasAny).toBe(false)\n    expect(vm.negative).toBe(true)\n  })\n\n  it('mapGetters (object)', () => {\n    const store = new Vuex.Store({\n      state: { count: 0 },\n      mutations: {\n        inc: state => state.count++,\n        dec: state => state.count--\n      },\n      getters: {\n        hasAny: ({ count }) => count > 0,\n        negative: ({ count }) => count < 0\n      }\n    })\n    const vm = mount(store, {\n      computed: mapGetters({\n        a: 'hasAny',\n        b: 'negative'\n      })\n    })\n    expect(vm.a).toBe(false)\n    expect(vm.b).toBe(false)\n    store.commit('inc')\n    expect(vm.a).toBe(true)\n    expect(vm.b).toBe(false)\n    store.commit('dec')\n    store.commit('dec')\n    expect(vm.a).toBe(false)\n    expect(vm.b).toBe(true)\n  })\n\n  it('mapGetters (with namespace)', () => {\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { count: 0 },\n          mutations: {\n            inc: state => state.count++,\n            dec: state => state.count--\n          },\n          getters: {\n            hasAny: ({ count }) => count > 0,\n            negative: ({ count }) => count < 0\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      computed: mapGetters('foo', {\n        a: 'hasAny',\n        b: 'negative'\n      })\n    })\n    expect(vm.a).toBe(false)\n    expect(vm.b).toBe(false)\n    store.commit('foo/inc')\n    expect(vm.a).toBe(true)\n    expect(vm.b).toBe(false)\n    store.commit('foo/dec')\n    store.commit('foo/dec')\n    expect(vm.a).toBe(false)\n    expect(vm.b).toBe(true)\n  })\n\n  it('mapGetters (with namespace and nested module)', () => {\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          modules: {\n            bar: {\n              namespaced: true,\n              state: { count: 0 },\n              mutations: {\n                inc: state => state.count++,\n                dec: state => state.count--\n              },\n              getters: {\n                hasAny: ({ count }) => count > 0,\n                negative: ({ count }) => count < 0\n              }\n            },\n            cat: {\n              state: { count: 9 },\n              getters: {\n                count: ({ count }) => count\n              }\n            }\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      computed: {\n        ...mapGetters('foo/bar', [\n          'hasAny',\n          'negative'\n        ]),\n        ...mapGetters('foo', [\n          'count'\n        ])\n      }\n    })\n    expect(vm.hasAny).toBe(false)\n    expect(vm.negative).toBe(false)\n    store.commit('foo/bar/inc')\n    expect(vm.hasAny).toBe(true)\n    expect(vm.negative).toBe(false)\n    store.commit('foo/bar/dec')\n    store.commit('foo/bar/dec')\n    expect(vm.hasAny).toBe(false)\n    expect(vm.negative).toBe(true)\n\n    expect(vm.count).toBe(9)\n  })\n\n  it('mapGetters (with undefined getters)', () => {\n    jest.spyOn(console, 'error').mockImplementation()\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { count: 0 },\n          mutations: {\n            inc: state => state.count++,\n            dec: state => state.count--\n          },\n          getters: {\n            hasAny: ({ count }) => count > 0,\n            negative: ({ count }) => count < 0\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      computed: mapGetters('foo')\n    })\n    expect(vm.a).toBeUndefined()\n    expect(vm.b).toBeUndefined()\n    expect(console.error).toHaveBeenCalledWith('[vuex] mapGetters: mapper parameter must be either an Array or an Object')\n  })\n\n  it('mapActions (array)', () => {\n    const a = jest.fn()\n    const b = jest.fn()\n    const store = new Vuex.Store({\n      actions: {\n        a,\n        b\n      }\n    })\n    const vm = mount(store, {\n      methods: mapActions(['a', 'b'])\n    })\n    vm.a()\n    expect(a).toHaveBeenCalled()\n    expect(b).not.toHaveBeenCalled()\n    vm.b()\n    expect(b).toHaveBeenCalled()\n  })\n\n  it('mapActions (object)', () => {\n    const a = jest.fn()\n    const b = jest.fn()\n    const store = new Vuex.Store({\n      actions: {\n        a,\n        b\n      }\n    })\n    const vm = mount(store, {\n      methods: mapActions({\n        foo: 'a',\n        bar: 'b'\n      })\n    })\n    vm.foo()\n    expect(a).toHaveBeenCalled()\n    expect(b).not.toHaveBeenCalled()\n    vm.bar()\n    expect(b).toHaveBeenCalled()\n  })\n\n  it('mapActions (function)', () => {\n    const a = jest.fn()\n    const store = new Vuex.Store({\n      actions: { a }\n    })\n    const vm = mount(store, {\n      methods: mapActions({\n        foo (dispatch, arg) {\n          dispatch('a', arg + 'bar')\n        }\n      })\n    })\n    vm.foo('foo')\n    expect(a.mock.calls[0][1]).toBe('foobar')\n  })\n\n  it('mapActions (with namespace)', () => {\n    const a = jest.fn()\n    const b = jest.fn()\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          actions: {\n            a,\n            b\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      methods: mapActions('foo/', {\n        foo: 'a',\n        bar: 'b'\n      })\n    })\n    vm.foo()\n    expect(a).toHaveBeenCalled()\n    expect(b).not.toHaveBeenCalled()\n    vm.bar()\n    expect(b).toHaveBeenCalled()\n  })\n\n  it('mapActions (function with namespace)', () => {\n    const a = jest.fn()\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          actions: { a }\n        }\n      }\n    })\n    const vm = mount(store, {\n      methods: mapActions('foo/', {\n        foo (dispatch, arg) {\n          dispatch('a', arg + 'bar')\n        }\n      })\n    })\n    vm.foo('foo')\n    expect(a.mock.calls[0][1]).toBe('foobar')\n  })\n\n  it('mapActions (with undefined actions)', () => {\n    jest.spyOn(console, 'error').mockImplementation()\n    const a = jest.fn()\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          actions: {\n            a\n          }\n        }\n      }\n    })\n    const vm = mount(store, {\n      methods: mapActions('foo/')\n    })\n    expect(vm.a).toBeUndefined()\n    expect(a).not.toHaveBeenCalled()\n    expect(console.error).toHaveBeenCalledWith('[vuex] mapActions: mapper parameter must be either an Array or an Object')\n  })\n\n  it('createNamespacedHelpers', () => {\n    const actionA = jest.fn()\n    const actionB = jest.fn()\n    const store = new Vuex.Store({\n      modules: {\n        foo: {\n          namespaced: true,\n          state: { count: 0 },\n          getters: {\n            isEven: state => state.count % 2 === 0\n          },\n          mutations: {\n            inc: state => state.count++,\n            dec: state => state.count--\n          },\n          actions: {\n            actionA,\n            actionB\n          }\n        }\n      }\n    })\n    const {\n      mapState,\n      mapGetters,\n      mapMutations,\n      mapActions\n    } = createNamespacedHelpers('foo/')\n    const vm = mount(store, {\n      computed: {\n        ...mapState(['count']),\n        ...mapGetters(['isEven'])\n      },\n      methods: {\n        ...mapMutations(['inc', 'dec']),\n        ...mapActions(['actionA', 'actionB'])\n      }\n    })\n    expect(vm.count).toBe(0)\n    expect(vm.isEven).toBe(true)\n    store.state.foo.count++\n    expect(vm.count).toBe(1)\n    expect(vm.isEven).toBe(false)\n    vm.inc()\n    expect(store.state.foo.count).toBe(2)\n    expect(store.getters['foo/isEven']).toBe(true)\n    vm.dec()\n    expect(store.state.foo.count).toBe(1)\n    expect(store.getters['foo/isEven']).toBe(false)\n    vm.actionA()\n    expect(actionA).toHaveBeenCalled()\n    expect(actionB).not.toHaveBeenCalled()\n    vm.actionB()\n    expect(actionB).toHaveBeenCalled()\n  })\n})\n"
  },
  {
    "path": "test/unit/hot-reload.spec.js",
    "content": "import { nextTick } from 'vue'\nimport { mount } from 'test/helpers'\nimport Vuex from '@/index'\n\nconst TEST = 'TEST'\nconst isSSR = process.env.VUE_ENV === 'server'\n\ndescribe('Hot Reload', () => {\n  it('mutations', function () {\n    const mutations = {\n      [TEST] (state, n) {\n        state.a += n\n      }\n    }\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations,\n      modules: {\n        nested: {\n          state: { a: 2 },\n          mutations,\n          modules: {\n            one: {\n              state: { a: 3 },\n              mutations\n            },\n            nested: {\n              modules: {\n                two: {\n                  state: { a: 4 },\n                  mutations\n                },\n                three: {\n                  state: { a: 5 },\n                  mutations\n                }\n              }\n            }\n          }\n        },\n        four: {\n          state: { a: 6 },\n          mutations\n        }\n      }\n    })\n    store.commit(TEST, 1)\n    expect(store.state.a).toBe(2)\n    expect(store.state.nested.a).toBe(3)\n    expect(store.state.nested.one.a).toBe(4)\n    expect(store.state.nested.nested.two.a).toBe(5)\n    expect(store.state.nested.nested.three.a).toBe(6)\n    expect(store.state.four.a).toBe(7)\n\n    // hot reload only root mutations\n    store.hotUpdate({\n      mutations: {\n        [TEST] (state, n) {\n          state.a = n\n        }\n      }\n    })\n    store.commit(TEST, 1)\n    expect(store.state.a).toBe(1) // only root mutation updated\n    expect(store.state.nested.a).toBe(4)\n    expect(store.state.nested.one.a).toBe(5)\n    expect(store.state.nested.nested.two.a).toBe(6)\n    expect(store.state.nested.nested.three.a).toBe(7)\n    expect(store.state.four.a).toBe(8)\n\n    // hot reload modules\n    store.hotUpdate({\n      modules: {\n        nested: {\n          state: { a: 234 },\n          mutations,\n          modules: {\n            one: {\n              state: { a: 345 },\n              mutations\n            },\n            nested: {\n              modules: {\n                two: {\n                  state: { a: 456 },\n                  mutations\n                },\n                three: {\n                  state: { a: 567 },\n                  mutations\n                }\n              }\n            }\n          }\n        },\n        four: {\n          state: { a: 678 },\n          mutations\n        }\n      }\n    })\n    store.commit(TEST, 2)\n    expect(store.state.a).toBe(2)\n    expect(store.state.nested.a).toBe(6) // should not reload initial state\n    expect(store.state.nested.one.a).toBe(7) // should not reload initial state\n    expect(store.state.nested.nested.two.a).toBe(8) // should not reload initial state\n    expect(store.state.nested.nested.three.a).toBe(9) // should not reload initial state\n    expect(store.state.four.a).toBe(10) // should not reload initial state\n\n    // hot reload all\n    store.hotUpdate({\n      mutations: {\n        [TEST] (state, n) {\n          state.a -= n\n        }\n      },\n      modules: {\n        nested: {\n          state: { a: 234 },\n          mutations: {\n            [TEST] (state, n) {\n              state.a += n\n            }\n          },\n          modules: {\n            one: {\n              state: { a: 345 },\n              mutations: {\n                [TEST] (state, n) {\n                  state.a += n\n                }\n              }\n            },\n            nested: {\n              modules: {\n                two: {\n                  state: { a: 456 },\n                  mutations: {\n                    [TEST] (state, n) {\n                      state.a += n\n                    }\n                  }\n                },\n                three: {\n                  state: { a: 567 },\n                  mutations: {\n                    [TEST] (state, n) {\n                      state.a -= n\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        four: {\n          state: { a: 678 },\n          mutations: {\n            [TEST] (state, n) {\n              state.a -= n\n            }\n          }\n        }\n      }\n    })\n    store.commit(TEST, 3)\n    expect(store.state.a).toBe(-1)\n    expect(store.state.nested.a).toBe(9)\n    expect(store.state.nested.one.a).toBe(10)\n    expect(store.state.nested.nested.two.a).toBe(11)\n    expect(store.state.nested.nested.three.a).toBe(6)\n    expect(store.state.four.a).toBe(7)\n  })\n\n  it('actions', () => {\n    const store = new Vuex.Store({\n      state: {\n        list: []\n      },\n      mutations: {\n        [TEST] (state, n) {\n          state.list.push(n)\n        }\n      },\n      actions: {\n        [TEST] ({ commit }) {\n          commit(TEST, 1)\n        }\n      },\n      modules: {\n        a: {\n          actions: {\n            [TEST] ({ commit }) {\n              commit(TEST, 2)\n            }\n          }\n        }\n      }\n    })\n    store.dispatch(TEST)\n    expect(store.state.list.join()).toBe('1,2')\n\n    // update root\n    store.hotUpdate({\n      actions: {\n        [TEST] ({ commit }) {\n          commit(TEST, 3)\n        }\n      }\n    })\n    store.dispatch(TEST)\n    expect(store.state.list.join()).toBe('1,2,3,2')\n\n    // update modules\n    store.hotUpdate({\n      actions: {\n        [TEST] ({ commit }) {\n          commit(TEST, 4)\n        }\n      },\n      modules: {\n        a: {\n          actions: {\n            [TEST] ({ commit }) {\n              commit(TEST, 5)\n            }\n          }\n        }\n      }\n    })\n    store.dispatch(TEST)\n    expect(store.state.list.join()).toBe('1,2,3,2,4,5')\n  })\n\n  it('getters', done => {\n    const store = new Vuex.Store({\n      state: {\n        count: 0\n      },\n      mutations: {\n        inc: state => state.count++\n      },\n      getters: {\n        count: state => state.count\n      },\n      actions: {\n        check ({ getters }, value) {\n          expect(getters.count).toBe(value)\n        }\n      }\n    })\n\n    const spy = jest.fn()\n\n    const vm = mount(store, {\n      computed: {\n        a: () => store.getters.count\n      },\n      watch: {\n        a: spy\n      }\n    })\n\n    expect(vm.a).toBe(0)\n    store.dispatch('check', 0)\n\n    store.commit('inc')\n\n    expect(vm.a).toBe(1)\n    store.dispatch('check', 1)\n\n    // update getters\n    store.hotUpdate({\n      getters: {\n        count: state => state.count * 10\n      }\n    })\n\n    expect(vm.a).toBe(10)\n    store.dispatch('check', 10)\n\n    if (isSSR) {\n      done()\n    } else {\n      nextTick(() => {\n        expect(spy).toHaveBeenCalled()\n        done()\n      })\n    }\n  })\n\n  it('provide warning if a new module is given', () => {\n    const store = new Vuex.Store({})\n\n    jest.spyOn(console, 'warn').mockImplementation()\n\n    store.hotUpdate({\n      modules: {\n        test: {\n          state: {\n            count: 0\n          }\n        }\n      }\n    })\n\n    expect(console.warn).toHaveBeenCalledWith(\n      '[vuex] trying to add a new module \\'test\\' on hot reloading, ' +\n      'manual reload is needed'\n    )\n  })\n\n  it('update namespace', () => {\n    // prevent to print notification of unknown action/mutation\n    jest.spyOn(console, 'error').mockImplementation()\n\n    const actionSpy = jest.fn()\n    const mutationSpy = jest.fn()\n\n    const store = new Vuex.Store({\n      modules: {\n        a: {\n          namespaced: true,\n          state: { value: 1 },\n          getters: { foo: state => state.value },\n          actions: { foo: actionSpy },\n          mutations: { foo: mutationSpy }\n        }\n      }\n    })\n\n    expect(store.state.a.value).toBe(1)\n    expect(store.getters['a/foo']).toBe(1)\n    store.dispatch('a/foo')\n    expect(actionSpy).toHaveBeenCalledTimes(1)\n    store.commit('a/foo')\n    expect(actionSpy).toHaveBeenCalledTimes(1)\n\n    store.hotUpdate({\n      modules: {\n        a: {\n          namespaced: false\n        }\n      }\n    })\n\n    expect(store.state.a.value).toBe(1)\n    expect(store.getters['a/foo']).toBe(undefined) // removed\n    expect(store.getters['foo']).toBe(1) // renamed\n\n    // should not be called\n    store.dispatch('a/foo')\n    expect(actionSpy).toHaveBeenCalledTimes(1)\n\n    // should be called\n    store.dispatch('foo')\n    expect(actionSpy).toHaveBeenCalledTimes(2)\n\n    // should not be called\n    store.commit('a/foo')\n    expect(mutationSpy).toHaveBeenCalledTimes(1)\n\n    // should be called\n    store.commit('foo')\n    expect(mutationSpy).toHaveBeenCalledTimes(2)\n  })\n})\n"
  },
  {
    "path": "test/unit/module/module-collection.spec.js",
    "content": "import ModuleCollection from '@/module/module-collection'\n\ndescribe('ModuleCollection', () => {\n  it('get', () => {\n    const collection = new ModuleCollection({\n      state: { value: 1 },\n      modules: {\n        a: {\n          state: { value: 2 }\n        },\n        b: {\n          state: { value: 3 },\n          modules: {\n            c: {\n              state: { value: 4 }\n            }\n          }\n        }\n      }\n    })\n    expect(collection.get([]).state.value).toBe(1)\n    expect(collection.get(['a']).state.value).toBe(2)\n    expect(collection.get(['b']).state.value).toBe(3)\n    expect(collection.get(['b', 'c']).state.value).toBe(4)\n  })\n\n  it('getNamespace', () => {\n    const module = (namespaced, children) => {\n      return {\n        namespaced,\n        modules: children\n      }\n    }\n    const collection = new ModuleCollection({\n      namespace: 'ignore/', // root module namespace should be ignored\n      modules: {\n        a: module(true, {\n          b: module(false, {\n            c: module(true)\n          }),\n          d: module(true)\n        })\n      }\n    })\n    const check = (path, expected) => {\n      const type = 'test'\n      const namespace = collection.getNamespace(path)\n      expect(namespace + type).toBe(expected)\n    }\n    check(['a'], 'a/test')\n    check(['a', 'b'], 'a/test')\n    check(['a', 'b', 'c'], 'a/c/test')\n    check(['a', 'd'], 'a/d/test')\n  })\n\n  it('register', () => {\n    const collection = new ModuleCollection({})\n    collection.register(['a'], {\n      state: { value: 1 }\n    })\n    collection.register(['b'], {\n      state: { value: 2 }\n    })\n    collection.register(['a', 'b'], {\n      state: { value: 3 }\n    })\n\n    expect(collection.get(['a']).state.value).toBe(1)\n    expect(collection.get(['b']).state.value).toBe(2)\n    expect(collection.get(['a', 'b']).state.value).toBe(3)\n  })\n\n  it('unregister', () => {\n    const collection = new ModuleCollection({})\n    collection.register(['a'], {\n      state: { value: true }\n    })\n    expect(collection.get(['a']).state.value).toBe(true)\n\n    collection.unregister(['a'])\n    expect(collection.get(['a'])).toBe(undefined)\n  })\n\n  it('isRegistered', () => {\n    const collection = new ModuleCollection({})\n\n    collection.register(['a'], {\n      state: { value: true }\n    })\n\n    collection.register(['a', 'b'], {\n      state: { value: false }\n    })\n\n    expect(collection.isRegistered(['a'])).toBe(true)\n    expect(collection.isRegistered(['a', 'b'])).toBe(true)\n    expect(collection.isRegistered(['c'])).toBe(false)\n    expect(collection.isRegistered(['c', 'd'])).toBe(false)\n  })\n\n  it('does not unregister initial modules', () => {\n    const collection = new ModuleCollection({\n      modules: {\n        a: {\n          state: { value: true }\n        }\n      }\n    })\n    collection.unregister(['a'])\n    expect(collection.get(['a']).state.value).toBe(true)\n  })\n\n  it('warns when unregistering non existing module', () => {\n    const spy = jest.spyOn(console, 'warn').mockImplementation()\n\n    const collection = new ModuleCollection({})\n    collection.unregister(['a'])\n    expect(spy).toHaveBeenCalled()\n  })\n})\n"
  },
  {
    "path": "test/unit/module/module.spec.js",
    "content": "import Module from '@/module/module'\n\ndescribe('Module', () => {\n  it('get state', () => {\n    const module = new Module({\n      state: {\n        value: true\n      }\n    })\n    expect(module.state).toEqual({ value: true })\n  })\n\n  it('get state: should return object if state option is empty', () => {\n    const module = new Module({})\n    expect(module.state).toEqual({})\n  })\n\n  it('get namespacer: no namespace option', () => {\n    const module = new Module({})\n    expect(module.namespaced).toBe(false)\n  })\n\n  it('get namespacer: namespace option is true', () => {\n    let module = new Module({\n      namespaced: true\n    })\n    expect(module.namespaced).toBe(true)\n\n    module = new Module({\n      namespaced: 100\n    })\n    expect(module.namespaced).toBe(true)\n  })\n\n  it('add child method', () => {\n    const module = new Module({})\n\n    module.addChild('v1', new Module({}))\n    module.addChild('v2', new Module({}))\n    expect(Object.keys(module._children)).toEqual(['v1', 'v2'])\n  })\n\n  it('remove child method', () => {\n    const module = new Module({})\n\n    module.addChild('v1', new Module({}))\n    module.addChild('v2', new Module({}))\n    expect(Object.keys(module._children)).toEqual(['v1', 'v2'])\n    module.removeChild('v2')\n    module.removeChild('abc')\n    expect(Object.keys(module._children)).toEqual(['v1'])\n  })\n\n  it('get child method', () => {\n    const module = new Module({})\n\n    const subModule1 = new Module({ state: { name: 'v1' }})\n    const subModule2 = new Module({ state: { name: 'v2' }})\n    module.addChild('v1', subModule1)\n    module.addChild('v2', subModule2)\n    expect(module.getChild('v2')).toEqual(subModule2)\n    expect(module.getChild('v1')).toEqual(subModule1)\n  })\n\n  it('update method', () => {\n    const originObject = {\n      state: {\n        name: 'vuex',\n        version: '2.x.x'\n      },\n      namespaced: true,\n      actions: {\n        a1: () => {},\n        a2: () => {}\n      },\n      mutations: {\n        m1: () => {},\n        m2: () => {}\n      },\n      getters: {\n        g1: () => {},\n        g2: () => {}\n      }\n    }\n    const newObject = {\n      actions: {\n        a3: () => {},\n        a4: () => {}\n      },\n      mutations: {\n        m3: () => {},\n        m2: () => {}\n      },\n      getters: {\n        g1: () => {}\n      },\n      namespaced: false,\n      state: {\n        name: 'vuex',\n        version: '3.x.x'\n      }\n    }\n    const module = new Module(originObject)\n\n    expect(module._rawModule).toEqual(originObject)\n\n    module.update(newObject)\n    expect(module._rawModule.actions).toEqual(newObject.actions)\n    expect(module._rawModule.mutations).toEqual(newObject.mutations)\n    expect(module._rawModule.getters).toEqual(newObject.getters)\n    expect(module._rawModule.namespaced).toEqual(newObject.namespaced)\n    expect(module._rawModule.state).toEqual(originObject.state)\n  })\n\n  it('forEachChild method', () => {\n    const module = new Module({})\n    const module1 = new Module({})\n    const module2 = new Module({})\n\n    module.addChild('v1', module1)\n    module.addChild('v2', module2)\n\n    const collections = []\n    module.forEachChild((item) => { collections.push(item) })\n    expect(collections.length).toEqual(2)\n    expect(collections).toEqual([module2, module1])\n  })\n\n  it('forEachAction method', () => {\n    const action1 = () => {}\n    const action2 = () => {}\n\n    const module = new Module({\n      actions: {\n        action1, action2\n      }\n    })\n\n    const collections = []\n    module.forEachAction((item) => { collections.push(item) })\n    expect(collections.length).toEqual(2)\n    expect(collections).toEqual([action1, action2])\n  })\n\n  it('forEachGetter method', () => {\n    const getter1 = () => {}\n    const getter2 = () => {}\n\n    const module = new Module({\n      getters: {\n        getter1, getter2\n      }\n    })\n\n    const collections = []\n    module.forEachGetter((item) => { collections.push(item) })\n    expect(collections.length).toEqual(2)\n    expect(collections).toEqual([getter1, getter2])\n  })\n\n  it('forEachMutation method', () => {\n    const mutation1 = () => {}\n    const mutation2 = () => {}\n\n    const module = new Module({\n      mutations: {\n        mutation1, mutation2\n      }\n    })\n\n    const collections = []\n    module.forEachMutation((item) => { collections.push(item) })\n    expect(collections.length).toEqual(2)\n    expect(collections).toEqual([mutation1, mutation2])\n  })\n})\n"
  },
  {
    "path": "test/unit/modules.spec.js",
    "content": "import { h, nextTick } from 'vue'\nimport { mount } from 'test/helpers'\nimport Vuex from '@/index'\n\nconst TEST = 'TEST'\n\ndescribe('Modules', () => {\n  describe('module registration', () => {\n    it('dynamic module registration', () => {\n      const store = new Vuex.Store({\n        strict: true,\n        modules: {\n          foo: {\n            state: { bar: 1 },\n            mutations: { inc: state => state.bar++ },\n            actions: { incFoo: ({ commit }) => commit('inc') },\n            getters: { bar: state => state.bar }\n          }\n        }\n      })\n      expect(() => {\n        store.registerModule('hi', {\n          state: { a: 1 },\n          mutations: { inc: state => state.a++ },\n          actions: { inc: ({ commit }) => commit('inc') },\n          getters: { a: state => state.a }\n        })\n      }).not.toThrow()\n\n      expect(store._mutations.inc.length).toBe(2)\n      expect(store.state.hi.a).toBe(1)\n      expect(store.getters.a).toBe(1)\n\n      // assert initial modules work as expected after dynamic registration\n      expect(store.state.foo.bar).toBe(1)\n      expect(store.getters.bar).toBe(1)\n\n      // test dispatching actions defined in dynamic module\n      store.dispatch('inc')\n      expect(store.state.hi.a).toBe(2)\n      expect(store.getters.a).toBe(2)\n      expect(store.state.foo.bar).toBe(2)\n      expect(store.getters.bar).toBe(2)\n\n      // unregister\n      store.unregisterModule('hi')\n      expect(store.state.hi).toBeUndefined()\n      expect(store.getters.a).toBeUndefined()\n      expect(store._mutations.inc.length).toBe(1)\n      expect(store._actions.inc).toBeUndefined()\n\n      // assert initial modules still work as expected after unregister\n      store.dispatch('incFoo')\n      expect(store.state.foo.bar).toBe(3)\n      expect(store.getters.bar).toBe(3)\n    })\n\n    it('dynamic module registration with namespace inheritance', () => {\n      const store = new Vuex.Store({\n        modules: {\n          a: {\n            namespaced: true\n          }\n        }\n      })\n      const actionSpy = jest.fn()\n      const mutationSpy = jest.fn()\n      store.registerModule(['a', 'b'], {\n        state: { value: 1 },\n        getters: { foo: state => state.value },\n        actions: { foo: actionSpy },\n        mutations: { foo: mutationSpy }\n      })\n\n      expect(store.state.a.b.value).toBe(1)\n      expect(store.getters['a/foo']).toBe(1)\n\n      store.dispatch('a/foo')\n      expect(actionSpy).toHaveBeenCalled()\n\n      store.commit('a/foo')\n      expect(mutationSpy).toHaveBeenCalled()\n    })\n\n    it('dynamic module existance test', () => {\n      const store = new Vuex.Store({})\n\n      store.registerModule('bonjour', {})\n\n      expect(store.hasModule('bonjour')).toBe(true)\n      store.unregisterModule('bonjour')\n      expect(store.hasModule('bonjour')).toBe(false)\n    })\n\n    it('dynamic module existance test with nested modules', () => {\n      const store = new Vuex.Store({})\n\n      store.registerModule('a', {})\n      store.registerModule(['a', 'b'], {})\n\n      expect(store.hasModule(['a'])).toBe(true)\n      expect(store.hasModule(['a', 'b'])).toBe(true)\n      expect(store.hasModule(['c'])).toBe(false)\n      expect(store.hasModule(['c', 'd'])).toBe(false)\n    })\n\n    it('dynamic module registration preserving hydration', () => {\n      const store = new Vuex.Store({})\n      store.replaceState({ a: { foo: 'state' }})\n      const actionSpy = jest.fn()\n      const mutationSpy = jest.fn()\n      store.registerModule('a', {\n        namespaced: true,\n        getters: { foo: state => state.foo },\n        actions: { foo: actionSpy },\n        mutations: { foo: mutationSpy }\n      }, { preserveState: true })\n\n      expect(store.state.a.foo).toBe('state')\n      expect(store.getters['a/foo']).toBe('state')\n\n      store.dispatch('a/foo')\n      expect(actionSpy).toHaveBeenCalled()\n\n      store.commit('a/foo')\n      expect(mutationSpy).toHaveBeenCalled()\n    })\n\n    it('should keep getters when component gets destroyed', async () => {\n      const store = new Vuex.Store()\n\n      const spy = jest.fn()\n\n      const moduleA = {\n        namespaced: true,\n        state: () => ({ value: 1 }),\n        getters: {\n          getState (state) {\n            spy()\n            return state.value\n          }\n        },\n        mutations: {\n          increment: (state) => { state.value++ }\n        }\n      }\n\n      const CompA = {\n        template: `<div />`,\n        created () {\n          this.$store.registerModule('moduleA', moduleA)\n        }\n      }\n\n      const CompB = {\n        template: `<div />`\n      }\n\n      const vm = mount(store, {\n        components: { CompA, CompB },\n        data: () => ({ show: 'a' }),\n        render () {\n          return this.show === 'a' ? h(CompA) : h(CompB)\n        }\n      })\n\n      expect(store.getters['moduleA/getState']).toBe(1)\n      expect(spy).toHaveBeenCalledTimes(1)\n\n      vm.show = 'b'\n      await nextTick()\n\n      store.commit('moduleA/increment')\n\n      expect(store.getters['moduleA/getState']).toBe(2)\n      expect(spy).toHaveBeenCalledTimes(2)\n    })\n  })\n\n  // #524\n  it('should not fire an unrelated watcher', done => {\n    const spy = jest.fn()\n    const store = new Vuex.Store({\n      modules: {\n        a: {\n          state: { value: 1 }\n        },\n        b: {}\n      }\n    })\n\n    store.watch(state => state.a, spy)\n    store.registerModule(['b', 'c'], {\n      state: { value: 2 }\n    })\n    nextTick(() => {\n      expect(spy).not.toHaveBeenCalled()\n      done()\n    })\n  })\n\n  describe('modules usage', () => {\n    it('state as function (multiple module in same store)', () => {\n      const module = {\n        state () {\n          return { a: 0 }\n        },\n        mutations: {\n          [TEST] (state, n) {\n            state.a += n\n          }\n        }\n      }\n\n      const store = new Vuex.Store({\n        modules: {\n          one: module,\n          two: module\n        }\n      })\n\n      expect(store.state.one.a).toBe(0)\n      expect(store.state.two.a).toBe(0)\n\n      store.commit(TEST, 1)\n      expect(store.state.one.a).toBe(1)\n      expect(store.state.two.a).toBe(1)\n    })\n\n    it('state as function (same module in multiple stores)', () => {\n      const module = {\n        state () {\n          return { a: 0 }\n        },\n        mutations: {\n          [TEST] (state, n) {\n            state.a += n\n          }\n        }\n      }\n\n      const storeA = new Vuex.Store({\n        modules: {\n          foo: module\n        }\n      })\n\n      const storeB = new Vuex.Store({\n        modules: {\n          bar: module\n        }\n      })\n\n      expect(storeA.state.foo.a).toBe(0)\n      expect(storeB.state.bar.a).toBe(0)\n\n      storeA.commit(TEST, 1)\n      expect(storeA.state.foo.a).toBe(1)\n      expect(storeB.state.bar.a).toBe(0)\n\n      storeB.commit(TEST, 2)\n      expect(storeA.state.foo.a).toBe(1)\n      expect(storeB.state.bar.a).toBe(2)\n    })\n\n    it('module: mutation', function () {\n      const mutations = {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      }\n      const store = new Vuex.Store({\n        state: {\n          a: 1\n        },\n        mutations,\n        modules: {\n          nested: {\n            state: { a: 2 },\n            mutations,\n            modules: {\n              one: {\n                state: { a: 3 },\n                mutations\n              },\n              nested: {\n                modules: {\n                  two: {\n                    state: { a: 4 },\n                    mutations\n                  },\n                  three: {\n                    state: { a: 5 },\n                    mutations\n                  }\n                }\n              }\n            }\n          },\n          four: {\n            state: { a: 6 },\n            mutations\n          }\n        }\n      })\n      store.commit(TEST, 1)\n      expect(store.state.a).toBe(2)\n      expect(store.state.nested.a).toBe(3)\n      expect(store.state.nested.one.a).toBe(4)\n      expect(store.state.nested.nested.two.a).toBe(5)\n      expect(store.state.nested.nested.three.a).toBe(6)\n      expect(store.state.four.a).toBe(7)\n    })\n\n    it('module: action', function () {\n      let calls = 0\n      const makeAction = n => {\n        return {\n          [TEST] ({ state, rootState }) {\n            calls++\n            expect(state.a).toBe(n)\n            expect(rootState).toBe(store.state)\n          }\n        }\n      }\n      const store = new Vuex.Store({\n        state: {\n          a: 1\n        },\n        actions: makeAction(1),\n        modules: {\n          nested: {\n            state: { a: 2 },\n            actions: makeAction(2),\n            modules: {\n              one: {\n                state: { a: 3 },\n                actions: makeAction(3)\n              },\n              nested: {\n                modules: {\n                  two: {\n                    state: { a: 4 },\n                    actions: makeAction(4)\n                  },\n                  three: {\n                    state: { a: 5 },\n                    actions: makeAction(5)\n                  }\n                }\n              }\n            }\n          },\n          four: {\n            state: { a: 6 },\n            actions: makeAction(6)\n          }\n        }\n      })\n      store.dispatch(TEST)\n      expect(calls).toBe(6)\n    })\n\n    it('module: getters', function () {\n      const makeGetter = n => ({\n        [`getter${n}`]: (state, getters, rootState) => {\n          expect(getters.constant).toBe(0)\n          expect(rootState).toBe(store.state)\n          return state.a\n        }\n      })\n      const store = new Vuex.Store({\n        state: {\n          a: 1\n        },\n        getters: {\n          constant: () => 0,\n          ...makeGetter(1)\n        },\n        modules: {\n          nested: {\n            state: { a: 2 },\n            getters: makeGetter(2),\n            modules: {\n              one: {\n                state: { a: 3 },\n                getters: makeGetter(3)\n              },\n              nested: {\n                modules: {\n                  two: {\n                    state: { a: 4 },\n                    getters: makeGetter(4)\n                  },\n                  three: {\n                    state: { a: 5 },\n                    getters: makeGetter(5)\n                  }\n                }\n              }\n            }\n          },\n          four: {\n            state: { a: 6 },\n            getters: makeGetter(6)\n          }\n        }\n      })\n      ;[1, 2, 3, 4, 5, 6].forEach(n => {\n        expect(store.getters[`getter${n}`]).toBe(n)\n      })\n    })\n\n    it('module: namespace', () => {\n      const actionSpy = jest.fn()\n      const mutationSpy = jest.fn()\n\n      const store = new Vuex.Store({\n        modules: {\n          a: {\n            namespaced: true,\n            state: {\n              a: 1\n            },\n            getters: {\n              b: () => 2\n            },\n            actions: {\n              [TEST]: actionSpy\n            },\n            mutations: {\n              [TEST]: mutationSpy\n            }\n          }\n        }\n      })\n\n      expect(store.state.a.a).toBe(1)\n      expect(store.getters['a/b']).toBe(2)\n      store.dispatch('a/' + TEST)\n      expect(actionSpy).toHaveBeenCalled()\n      store.commit('a/' + TEST)\n      expect(mutationSpy).toHaveBeenCalled()\n    })\n\n    it('module: nested namespace', () => {\n      // mock module generator\n      const actionSpys = []\n      const mutationSpys = []\n      const createModule = (name, namespaced, children) => {\n        const actionSpy = jest.fn()\n        const mutationSpy = jest.fn()\n\n        actionSpys.push(actionSpy)\n        mutationSpys.push(mutationSpy)\n\n        return {\n          namespaced,\n          state: {\n            [name]: true\n          },\n          getters: {\n            [name]: state => state[name]\n          },\n          actions: {\n            [name]: actionSpy\n          },\n          mutations: {\n            [name]: mutationSpy\n          },\n          modules: children\n        }\n      }\n\n      // mock module\n      const modules = {\n        a: createModule('a', true, { // a/a\n          b: createModule('b', false, { // a/b - does not add namespace\n            c: createModule('c', true) // a/c/c\n          }),\n          d: createModule('d', true) // a/d/d\n        })\n      }\n\n      const store = new Vuex.Store({ modules })\n\n      const expectedTypes = [\n        'a/a', 'a/b', 'a/c/c', 'a/d/d'\n      ]\n\n      // getters\n      expectedTypes.forEach(type => {\n        expect(store.getters[type]).toBe(true)\n      })\n\n      // actions\n      expectedTypes.forEach(type => {\n        store.dispatch(type)\n      })\n      actionSpys.forEach(spy => {\n        expect(spy).toHaveBeenCalledTimes(1)\n      })\n\n      // mutations\n      expectedTypes.forEach(type => {\n        store.commit(type)\n      })\n      mutationSpys.forEach(spy => {\n        expect(spy).toHaveBeenCalledTimes(1)\n      })\n    })\n\n    it('module: getters are namespaced in namespaced module', () => {\n      const store = new Vuex.Store({\n        state: { value: 'root' },\n        getters: {\n          foo: state => state.value\n        },\n        modules: {\n          a: {\n            namespaced: true,\n            state: { value: 'module' },\n            getters: {\n              foo: state => state.value,\n              bar: (state, getters) => getters.foo,\n              baz: (state, getters, rootState, rootGetters) => rootGetters.foo\n            }\n          }\n        }\n      })\n\n      expect(store.getters['a/foo']).toBe('module')\n      expect(store.getters['a/bar']).toBe('module')\n      expect(store.getters['a/baz']).toBe('root')\n    })\n\n    it('module: action context is namespaced in namespaced module', done => {\n      const rootActionSpy = jest.fn()\n      const rootMutationSpy = jest.fn()\n      const moduleActionSpy = jest.fn()\n      const moduleMutationSpy = jest.fn()\n\n      const store = new Vuex.Store({\n        state: { value: 'root' },\n        getters: { foo: state => state.value },\n        actions: { foo: rootActionSpy },\n        mutations: { foo: rootMutationSpy },\n        modules: {\n          a: {\n            namespaced: true,\n            state: { value: 'module' },\n            getters: { foo: state => state.value },\n            actions: {\n              foo: moduleActionSpy,\n              test ({ dispatch, commit, getters, rootGetters }) {\n                expect(getters.foo).toBe('module')\n                expect(rootGetters.foo).toBe('root')\n\n                dispatch('foo')\n                expect(moduleActionSpy).toHaveBeenCalledTimes(1)\n                dispatch('foo', null, { root: true })\n                expect(rootActionSpy).toHaveBeenCalledTimes(1)\n\n                commit('foo')\n                expect(moduleMutationSpy).toHaveBeenCalledTimes(1)\n                commit('foo', null, { root: true })\n                expect(rootMutationSpy).toHaveBeenCalledTimes(1)\n\n                done()\n              }\n            },\n            mutations: { foo: moduleMutationSpy }\n          }\n        }\n      })\n\n      store.dispatch('a/test')\n    })\n\n    it('module: use other module that has same namespace', done => {\n      const actionSpy = jest.fn()\n      const mutationSpy = jest.fn()\n\n      const store = new Vuex.Store({\n        modules: {\n          parent: {\n            namespaced: true,\n\n            modules: {\n              a: {\n                state: { value: 'a' },\n                getters: { foo: state => state.value },\n                actions: { foo: actionSpy },\n                mutations: { foo: mutationSpy }\n              },\n\n              b: {\n                state: { value: 'b' },\n                getters: { bar: (state, getters) => getters.foo },\n                actions: {\n                  test ({ dispatch, commit, getters }) {\n                    expect(getters.foo).toBe('a')\n                    expect(getters.bar).toBe('a')\n\n                    dispatch('foo')\n                    expect(actionSpy).toHaveBeenCalled()\n\n                    commit('foo')\n                    expect(mutationSpy).toHaveBeenCalled()\n\n                    done()\n                  }\n                }\n              }\n            }\n          }\n        }\n      })\n\n      store.dispatch('parent/test')\n    })\n\n    it('module: warn when module overrides state', () => {\n      jest.spyOn(console, 'warn').mockImplementation()\n      const store = new Vuex.Store({\n        modules: {\n          foo: {\n            state () {\n              return { value: 1 }\n            },\n            modules: {\n              value: {\n                state: () => 2\n              }\n            }\n          }\n        }\n      })\n      expect(store.state.foo.value).toBe(2)\n      expect(console.warn).toHaveBeenCalledWith(\n        `[vuex] state field \"value\" was overridden by a module with the same name at \"foo.value\"`\n      )\n    })\n\n    it('dispatching multiple actions in different modules', done => {\n      const store = new Vuex.Store({\n        modules: {\n          a: {\n            actions: {\n              [TEST] () {\n                return 1\n              }\n            }\n          },\n          b: {\n            actions: {\n              [TEST] () {\n                return new Promise(r => r(2))\n              }\n            }\n          }\n        }\n      })\n      store.dispatch(TEST).then(res => {\n        expect(res[0]).toBe(1)\n        expect(res[1]).toBe(2)\n        done()\n      })\n    })\n\n    it('root actions dispatched in namespaced modules', done => {\n      const store = new Vuex.Store({\n        modules: {\n          a: {\n            namespaced: true,\n            actions: {\n              [TEST]: {\n                root: true,\n                handler () {\n                  return 1\n                }\n              }\n            }\n          },\n          b: {\n            namespaced: true,\n            actions: {\n              [TEST]: {\n                root: true,\n                handler () {\n                  return new Promise(r => r(2))\n                }\n              }\n            }\n          },\n          c: {\n            namespaced: true,\n            actions: {\n              [TEST]: {\n                handler () {\n                  // Should not be called\n                  return 3\n                }\n              }\n            }\n          },\n          d: {\n            namespaced: true,\n            actions: {\n              [TEST] () {\n                // Should not be called\n                return 4\n              }\n            }\n          }\n        }\n      })\n      store.dispatch(TEST).then(res => {\n        expect(res.length).toBe(2)\n        expect(res[0]).toBe(1)\n        expect(res[1]).toBe(2)\n        done()\n      })\n    })\n\n    it('plugins', function () {\n      let initState\n      const actionSpy = jest.fn()\n      const mutations = []\n      const subscribeActionSpy = jest.fn()\n      const store = new Vuex.Store({\n        state: {\n          a: 1\n        },\n        mutations: {\n          [TEST] (state, n) {\n            state.a += n\n          }\n        },\n        actions: {\n          [TEST]: actionSpy\n        },\n        plugins: [\n          store => {\n            initState = store.state\n            store.subscribe((mut, state) => {\n              expect(state).toBe(state)\n              mutations.push(mut)\n            })\n            store.subscribeAction(subscribeActionSpy)\n          }\n        ]\n      })\n      expect(initState).toBe(store.state)\n      store.commit(TEST, 2)\n      store.dispatch(TEST, 2)\n      expect(mutations.length).toBe(1)\n      expect(mutations[0].type).toBe(TEST)\n      expect(mutations[0].payload).toBe(2)\n      expect(actionSpy).toHaveBeenCalled()\n      expect(subscribeActionSpy).toHaveBeenCalledWith(\n        { type: TEST, payload: 2 },\n        store.state\n      )\n    })\n\n    it('action before/after subscribers', (done) => {\n      const beforeSpy = jest.fn()\n      const afterSpy = jest.fn()\n      const store = new Vuex.Store({\n        actions: {\n          [TEST]: () => Promise.resolve()\n        },\n        plugins: [\n          store => {\n            store.subscribeAction({\n              before: beforeSpy,\n              after: afterSpy\n            })\n          }\n        ]\n      })\n      store.dispatch(TEST, 2)\n      expect(beforeSpy).toHaveBeenCalledWith(\n        { type: TEST, payload: 2 },\n        store.state\n      )\n      expect(afterSpy).not.toHaveBeenCalled()\n      nextTick(() => {\n        expect(afterSpy).toHaveBeenCalledWith(\n          { type: TEST, payload: 2 },\n          store.state\n        )\n        done()\n      })\n    })\n  })\n\n  it('action error subscribers', (done) => {\n    const beforeSpy = jest.fn()\n    const afterSpy = jest.fn()\n    const errorSpy = jest.fn()\n    const error = new Error()\n    const store = new Vuex.Store({\n      actions: {\n        [TEST]: () => Promise.reject(error)\n      },\n      plugins: [\n        store => {\n          store.subscribeAction({\n            before: beforeSpy,\n            after: afterSpy,\n            error: errorSpy\n          })\n        }\n      ]\n    })\n    store.dispatch(TEST, 2).catch(() => {\n      expect(beforeSpy).toHaveBeenCalledWith(\n        { type: TEST, payload: 2 },\n        store.state\n      )\n      expect(afterSpy).not.toHaveBeenCalled()\n      nextTick(() => {\n        expect(afterSpy).not.toHaveBeenCalledWith(\n          { type: TEST, payload: 2 },\n          store.state\n        )\n        expect(errorSpy).toHaveBeenCalledWith(\n          { type: TEST, payload: 2 },\n          store.state,\n          error\n        )\n        done()\n      })\n    })\n  })\n\n  it('asserts a mutation should be a function', () => {\n    expect(() => {\n      new Vuex.Store({\n        mutations: {\n          test: null\n        }\n      })\n    }).toThrowError(\n      /mutations should be function but \"mutations\\.test\" is null/\n    )\n\n    expect(() => {\n      new Vuex.Store({\n        modules: {\n          foo: {\n            modules: {\n              bar: {\n                mutations: {\n                  test: 123\n                }\n              }\n            }\n          }\n        }\n      })\n    }).toThrowError(\n      /mutations should be function but \"mutations\\.test\" in module \"foo\\.bar\" is 123/\n    )\n  })\n\n  it('asserts an action should be a function', () => {\n    expect(() => {\n      new Vuex.Store({\n        actions: {\n          test: 'test'\n        }\n      })\n    }).toThrowError(\n      /actions should be function or object with \"handler\" function but \"actions\\.test\" is \"test\"/\n    )\n\n    expect(() => {\n      new Vuex.Store({\n        modules: {\n          foo: {\n            modules: {\n              bar: {\n                actions: {\n                  test: 'error'\n                }\n              }\n            }\n          }\n        }\n      })\n    }).toThrowError(\n      /actions should be function or object with \"handler\" function but \"actions\\.test\" in module \"foo\\.bar\" is \"error\"/\n    )\n  })\n\n  it('asserts a getter should be a function', () => {\n    expect(() => {\n      new Vuex.Store({\n        getters: {\n          test: undefined\n        }\n      })\n    }).toThrowError(\n      /getters should be function but \"getters\\.test\" is undefined/\n    )\n\n    expect(() => {\n      new Vuex.Store({\n        modules: {\n          foo: {\n            modules: {\n              bar: {\n                getters: {\n                  test: true\n                }\n              }\n            }\n          }\n        }\n      })\n    }).toThrowError(\n      /getters should be function but \"getters\\.test\" in module \"foo\\.bar\" is true/\n    )\n  })\n})\n"
  },
  {
    "path": "test/unit/store.spec.js",
    "content": "import { nextTick } from 'vue'\nimport { mount } from 'test/helpers'\nimport Vuex from '@/index'\n\nconst TEST = 'TEST'\nconst isSSR = process.env.VUE_ENV === 'server'\n\ndescribe('Store', () => {\n  it('committing mutations', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations: {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      }\n    })\n    store.commit(TEST, 2)\n    expect(store.state.a).toBe(3)\n  })\n\n  it('committing with object style', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations: {\n        [TEST] (state, payload) {\n          state.a += payload.amount\n        }\n      }\n    })\n    store.commit({\n      type: TEST,\n      amount: 2\n    })\n    expect(store.state.a).toBe(3)\n  })\n\n  it('asserts committed type', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations: {\n        // Maybe registered with undefined type accidentally\n        // if the user has typo in a constant type\n        undefined (state, n) {\n          state.a += n\n        }\n      }\n    })\n    expect(() => {\n      store.commit(undefined, 2)\n    }).toThrowError(/expects string as the type, but found undefined/)\n    expect(store.state.a).toBe(1)\n  })\n\n  it('dispatching actions, sync', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations: {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      },\n      actions: {\n        [TEST] ({ commit }, n) {\n          commit(TEST, n)\n        }\n      }\n    })\n    store.dispatch(TEST, 2)\n    expect(store.state.a).toBe(3)\n  })\n\n  it('dispatching with object style', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations: {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      },\n      actions: {\n        [TEST] ({ commit }, payload) {\n          commit(TEST, payload.amount)\n        }\n      }\n    })\n    store.dispatch({\n      type: TEST,\n      amount: 2\n    })\n    expect(store.state.a).toBe(3)\n  })\n\n  it('dispatching actions, with returned Promise', done => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations: {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      },\n      actions: {\n        [TEST] ({ commit }, n) {\n          return new Promise(resolve => {\n            setTimeout(() => {\n              commit(TEST, n)\n              resolve()\n            }, 0)\n          })\n        }\n      }\n    })\n    expect(store.state.a).toBe(1)\n    store.dispatch(TEST, 2).then(() => {\n      expect(store.state.a).toBe(3)\n      done()\n    })\n  })\n\n  it('composing actions with async/await', done => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations: {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      },\n      actions: {\n        [TEST] ({ commit }, n) {\n          return new Promise(resolve => {\n            setTimeout(() => {\n              commit(TEST, n)\n              resolve()\n            }, 0)\n          })\n        },\n        two: async ({ commit, dispatch }, n) => {\n          await dispatch(TEST, 1)\n          expect(store.state.a).toBe(2)\n          commit(TEST, n)\n        }\n      }\n    })\n    expect(store.state.a).toBe(1)\n    store.dispatch('two', 3).then(() => {\n      expect(store.state.a).toBe(5)\n      done()\n    })\n  })\n\n  it('detecting action Promise errors', done => {\n    const store = new Vuex.Store({\n      actions: {\n        [TEST] () {\n          return new Promise((resolve, reject) => {\n            reject('no')\n          })\n        }\n      }\n    })\n    const spy = jest.fn()\n    store._devtoolHook = {\n      emit: spy\n    }\n    const thenSpy = jest.fn()\n    store.dispatch(TEST)\n      .then(thenSpy)\n      .catch(err => {\n        expect(thenSpy).not.toHaveBeenCalled()\n        expect(err).toBe('no')\n        expect(spy).toHaveBeenCalledWith('vuex:error', 'no')\n        done()\n      })\n  })\n\n  it('asserts dispatched type', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 1\n      },\n      mutations: {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      },\n      actions: {\n        // Maybe registered with undefined type accidentally\n        // if the user has typo in a constant type\n        undefined ({ commit }, n) {\n          commit(TEST, n)\n        }\n      }\n    })\n    expect(() => {\n      store.dispatch(undefined, 2)\n    }).toThrowError(/expects string as the type, but found undefined/)\n    expect(store.state.a).toBe(1)\n  })\n\n  it('getters', () => {\n    const store = new Vuex.Store({\n      state: {\n        a: 0\n      },\n      getters: {\n        state: state => state.a > 0 ? 'hasAny' : 'none'\n      },\n      mutations: {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      },\n      actions: {\n        check ({ getters }, value) {\n          // check for exposing getters into actions\n          expect(getters.state).toBe(value)\n        }\n      }\n    })\n    expect(store.getters.state).toBe('none')\n    store.dispatch('check', 'none')\n\n    store.commit(TEST, 1)\n\n    expect(store.getters.state).toBe('hasAny')\n    store.dispatch('check', 'hasAny')\n  })\n\n  it('store injection', () => {\n    const store = new Vuex.Store()\n    const vm = mount(store, {})\n    expect(vm.$store).toBe(store)\n  })\n\n  it('should warn silent option depreciation', () => {\n    jest.spyOn(console, 'warn').mockImplementation()\n\n    const store = new Vuex.Store({\n      mutations: {\n        [TEST] () {}\n      }\n    })\n    store.commit(TEST, {}, { silent: true })\n\n    expect(console.warn).toHaveBeenCalledWith(\n      `[vuex] mutation type: ${TEST}. Silent option has been removed. ` +\n      'Use the filter functionality in the vue-devtools'\n    )\n  })\n\n  it('asserts the call with the new operator', () => {\n    expect(() => {\n      Vuex.Store({})\n    }).toThrowError(/Cannot call a class as a function/)\n  })\n\n  it('should accept state as function', () => {\n    const store = new Vuex.Store({\n      state: () => ({\n        a: 1\n      }),\n      mutations: {\n        [TEST] (state, n) {\n          state.a += n\n        }\n      }\n    })\n    expect(store.state.a).toBe(1)\n    store.commit(TEST, 2)\n    expect(store.state.a).toBe(3)\n  })\n\n  it('should not call root state function twice', () => {\n    const spy = jest.fn().mockReturnValue(1)\n    new Vuex.Store({\n      state: spy\n    })\n    expect(spy).toHaveBeenCalledTimes(1)\n  })\n\n  it('subscribe: should handle subscriptions / unsubscriptions', () => {\n    const subscribeSpy = jest.fn()\n    const secondSubscribeSpy = jest.fn()\n    const testPayload = 2\n    const store = new Vuex.Store({\n      state: {},\n      mutations: {\n        [TEST]: () => {}\n      }\n    })\n\n    const unsubscribe = store.subscribe(subscribeSpy)\n    store.subscribe(secondSubscribeSpy)\n    store.commit(TEST, testPayload)\n    unsubscribe()\n    store.commit(TEST, testPayload)\n\n    expect(subscribeSpy).toHaveBeenCalledWith(\n      { type: TEST, payload: testPayload },\n      store.state\n    )\n    expect(secondSubscribeSpy).toHaveBeenCalled()\n    expect(subscribeSpy).toHaveBeenCalledTimes(1)\n    expect(secondSubscribeSpy).toHaveBeenCalledTimes(2)\n  })\n\n  it('subscribe: should handle subscriptions with synchronous unsubscriptions', () => {\n    const subscribeSpy = jest.fn()\n    const testPayload = 2\n    const store = new Vuex.Store({\n      state: {},\n      mutations: {\n        [TEST]: () => {}\n      }\n    })\n\n    const unsubscribe = store.subscribe(() => unsubscribe())\n    store.subscribe(subscribeSpy)\n    store.commit(TEST, testPayload)\n\n    expect(subscribeSpy).toHaveBeenCalledWith(\n      { type: TEST, payload: testPayload },\n      store.state\n    )\n    expect(subscribeSpy).toHaveBeenCalledTimes(1)\n  })\n\n  it('subscribeAction: should handle subscriptions with synchronous unsubscriptions', () => {\n    const subscribeSpy = jest.fn()\n    const testPayload = 2\n    const store = new Vuex.Store({\n      state: {},\n      actions: {\n        [TEST]: () => {}\n      }\n    })\n\n    const unsubscribe = store.subscribeAction(() => unsubscribe())\n    store.subscribeAction(subscribeSpy)\n    store.dispatch(TEST, testPayload)\n\n    expect(subscribeSpy).toHaveBeenCalledWith(\n      { type: TEST, payload: testPayload },\n      store.state\n    )\n    expect(subscribeSpy).toHaveBeenCalledTimes(1)\n  })\n\n  // store.watch should only be asserted in non-SSR environment\n  if (!isSSR) {\n    it('watch: with resetting vm', done => {\n      const store = new Vuex.Store({\n        state: {\n          count: 0\n        },\n        mutations: {\n          [TEST]: state => state.count++\n        }\n      })\n\n      const spy = jest.fn()\n      store.watch(state => state.count, spy)\n\n      // reset store vm\n      store.registerModule('test', {})\n\n      nextTick(() => {\n        store.commit(TEST)\n        expect(store.state.count).toBe(1)\n\n        nextTick(() => {\n          expect(spy).toHaveBeenCalled()\n          done()\n        })\n      })\n    })\n\n    it('watch: getter function has access to store\\'s getters object', done => {\n      const store = new Vuex.Store({\n        state: {\n          count: 0\n        },\n        mutations: {\n          [TEST]: state => state.count++\n        },\n        getters: {\n          getCount: state => state.count\n        }\n      })\n\n      const getter = function getter (state, getters) {\n        return state.count\n      }\n      const spy = jest.spyOn({ getter }, 'getter')\n      const spyCb = jest.fn()\n\n      store.watch(spy, spyCb)\n\n      nextTick(() => {\n        store.commit(TEST)\n        expect(store.state.count).toBe(1)\n\n        nextTick(() => {\n          expect(spy).toHaveBeenCalledWith(store.state, store.getters)\n          done()\n        })\n      })\n    })\n  }\n})\n"
  },
  {
    "path": "test/unit/util.spec.js",
    "content": "import { find, deepCopy, forEachValue, isObject, isPromise, assert } from '@/util'\n\ndescribe('util', () => {\n  it('find: returns item when it was found', () => {\n    const list = [33, 22, 112, 222, 43]\n    expect(find(list, function (a) { return a % 2 === 0 })).toEqual(22)\n  })\n\n  it('find: returns undefined when item was not found', () => {\n    const list = [1, 2, 3]\n    expect(find(list, function (a) { return a === 9000 })).toEqual(undefined)\n  })\n\n  it('deepCopy: normal structure', () => {\n    const original = {\n      a: 1,\n      b: 'string',\n      c: true,\n      d: null,\n      e: undefined\n    }\n    const copy = deepCopy(original)\n\n    expect(copy).toEqual(original)\n  })\n\n  it('deepCopy: nested structure', () => {\n    const original = {\n      a: {\n        b: 1,\n        c: [2, 3, {\n          d: 4\n        }]\n      }\n    }\n    const copy = deepCopy(original)\n\n    expect(copy).toEqual(original)\n  })\n\n  it('deepCopy: circular structure', () => {\n    const original = {\n      a: 1\n    }\n    original.circular = original\n\n    const copy = deepCopy(original)\n\n    expect(copy).toEqual(original)\n  })\n\n  it('forEachValue', () => {\n    let number = 1\n\n    function plus (value, key) {\n      number += value\n    }\n    const origin = {\n      a: 1,\n      b: 3\n    }\n\n    forEachValue(origin, plus)\n    expect(number).toEqual(5)\n  })\n\n  it('isObject', () => {\n    expect(isObject(1)).toBe(false)\n    expect(isObject('String')).toBe(false)\n    expect(isObject(undefined)).toBe(false)\n    expect(isObject({})).toBe(true)\n    expect(isObject(null)).toBe(false)\n    expect(isObject([])).toBe(true)\n    expect(isObject(new Function())).toBe(false)\n  })\n\n  it('isPromise', () => {\n    const promise = new Promise(() => {}, () => {})\n    expect(isPromise(1)).toBe(false)\n    expect(isPromise(promise)).toBe(true)\n    expect(isPromise(new Function())).toBe(false)\n  })\n\n  it('assert', () => {\n    expect(assert.bind(null, false, 'Hello')).toThrowError('[vuex] Hello')\n  })\n})\n"
  },
  {
    "path": "types/README.md",
    "content": "This is the TypeScript declaration of Vuex.\n\n## Testing\n\n```sh\n$ tsc -p test/tsconfig.json\n```\n"
  },
  {
    "path": "types/helpers.d.ts",
    "content": "import { ComponentPublicInstance } from 'vue';\nimport { Dispatch, Commit } from './index';\n\ntype Computed = () => any;\ntype InlineComputed<T extends Function> = T extends (...args: any[]) => infer R ? () => R : never\ntype MutationMethod = (...args: any[]) => void;\ntype ActionMethod = (...args: any[]) => Promise<any>;\ntype InlineMethod<T extends (fn: any, ...args: any[]) => any> = T extends (fn: any, ...args: infer Args) => infer R ? (...args: Args) => R : never\ntype CustomVue = ComponentPublicInstance & Record<string, any>;\n\ninterface Mapper<R> {\n  <Key extends string>(map: Key[]): { [K in Key]: R };\n  <Map extends Record<string, string>>(map: Map): { [K in keyof Map]: R };\n}\n\ninterface MapperWithNamespace<R> {\n  <Key extends string>(namespace: string, map: Key[]): { [K in Key]: R };\n  <Map extends Record<string, string>>(namespace: string, map: Map): { [K in keyof Map]: R };\n}\n\ninterface MapperForState {\n  <S, Map extends Record<string, (this: CustomVue, state: S, getters: any) => any> = {}>(\n    map: Map\n  ): { [K in keyof Map]: InlineComputed<Map[K]> };\n}\n\ninterface MapperForStateWithNamespace {\n  <S, Map extends Record<string, (this: CustomVue, state: S, getters: any) => any> = {}>(\n    namespace: string,\n    map: Map\n  ): { [K in keyof Map]: InlineComputed<Map[K]> };\n}\n\ninterface MapperForAction {\n  <Map extends Record<string, (this: CustomVue, dispatch: Dispatch, ...args: any[]) => any>>(\n    map: Map\n  ): { [K in keyof Map]: InlineMethod<Map[K]> };\n}\n\ninterface MapperForActionWithNamespace {\n  <Map extends Record<string, (this: CustomVue, dispatch: Dispatch, ...args: any[]) => any>>(\n    namespace: string,\n    map: Map\n  ): { [K in keyof Map]: InlineMethod<Map[K]> };\n}\n\ninterface MapperForMutation {\n  <Map extends Record<string, (this: CustomVue, commit: Commit, ...args: any[]) => any>>(\n    map: Map\n  ): { [K in keyof Map]: InlineMethod<Map[K]> };\n}\n\ninterface MapperForMutationWithNamespace {\n  <Map extends Record<string, (this: CustomVue, commit: Commit, ...args: any[]) => any>>(\n    namespace: string,\n    map: Map\n  ): { [K in keyof Map]: InlineMethod<Map[K]> };\n}\n\n\ninterface NamespacedMappers {\n  mapState: Mapper<Computed> & MapperForState;\n  mapMutations: Mapper<MutationMethod> & MapperForMutation;\n  mapGetters: Mapper<Computed>;\n  mapActions: Mapper<ActionMethod> & MapperForAction;\n}\n\nexport declare const mapState: Mapper<Computed>\n  & MapperWithNamespace<Computed>\n  & MapperForState\n  & MapperForStateWithNamespace;\n\nexport declare const mapMutations: Mapper<MutationMethod>\n  & MapperWithNamespace<MutationMethod>\n  & MapperForMutation\n  & MapperForMutationWithNamespace;\n\nexport declare const mapGetters: Mapper<Computed>\n  & MapperWithNamespace<Computed>;\n\nexport declare const mapActions: Mapper<ActionMethod>\n  & MapperWithNamespace<ActionMethod>\n  & MapperForAction\n  & MapperForActionWithNamespace;\n\nexport declare function createNamespacedHelpers(namespace: string): NamespacedMappers;\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "import { App, WatchOptions, InjectionKey } from \"vue\";\n\n// augment typings of Vue.js\nimport \"./vue\";\n\nimport { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from \"./helpers\";\nimport { createLogger } from \"./logger\";\n\nexport * from \"./helpers\";\nexport * from \"./logger\";\n\nexport declare class Store<S> {\n  constructor(options: StoreOptions<S>);\n\n  readonly state: S;\n  readonly getters: any;\n\n  install(app: App, injectKey?: InjectionKey<Store<any>> | string): void;\n\n  replaceState(state: S): void;\n\n  dispatch: Dispatch;\n  commit: Commit;\n\n  subscribe<P extends MutationPayload>(fn: (mutation: P, state: S) => any, options?: SubscribeOptions): () => void;\n  subscribeAction<P extends ActionPayload>(fn: SubscribeActionOptions<P, S>, options?: SubscribeOptions): () => void;\n  watch<T>(getter: (state: S, getters: any) => T, cb: (value: T, oldValue: T) => void, options?: WatchOptions): () => void;\n\n  registerModule<T>(path: string, module: Module<T, S>, options?: ModuleOptions): void;\n  registerModule<T>(path: string[], module: Module<T, S>, options?: ModuleOptions): void;\n\n  unregisterModule(path: string): void;\n  unregisterModule(path: string[]): void;\n\n  hasModule(path: string): boolean;\n  hasModule(path: string[]): boolean;\n\n  hotUpdate(options: {\n    actions?: ActionTree<S, S>;\n    mutations?: MutationTree<S>;\n    getters?: GetterTree<S, S>;\n    modules?: ModuleTree<S>;\n  }): void;\n}\n\nexport const storeKey: string;\n\nexport function createStore<S>(options: StoreOptions<S>): Store<S>;\n\nexport function useStore<S = any>(injectKey?: InjectionKey<Store<S>> | string): Store<S>;\n\nexport interface Dispatch {\n  (type: string, payload?: any, options?: DispatchOptions): Promise<any>;\n  <P extends Payload>(payloadWithType: P, options?: DispatchOptions): Promise<any>;\n}\n\nexport interface Commit {\n  (type: string, payload?: any, options?: CommitOptions): void;\n  <P extends Payload>(payloadWithType: P, options?: CommitOptions): void;\n}\n\nexport interface ActionContext<S, R> {\n  dispatch: Dispatch;\n  commit: Commit;\n  state: S;\n  getters: any;\n  rootState: R;\n  rootGetters: any;\n}\n\nexport interface Payload {\n  type: string;\n}\n\nexport interface MutationPayload extends Payload {\n  payload: any;\n}\n\nexport interface ActionPayload extends Payload {\n  payload: any;\n}\n\nexport interface SubscribeOptions {\n  prepend?: boolean\n}\n\nexport type ActionSubscriber<P, S> = (action: P, state: S) => any;\nexport type ActionErrorSubscriber<P, S> = (action: P, state: S, error: Error) => any;\n\nexport interface ActionSubscribersObject<P, S> {\n  before?: ActionSubscriber<P, S>;\n  after?: ActionSubscriber<P, S>;\n  error?: ActionErrorSubscriber<P, S>;\n}\n\nexport type SubscribeActionOptions<P, S> = ActionSubscriber<P, S> | ActionSubscribersObject<P, S>;\n\nexport interface DispatchOptions {\n  root?: boolean;\n}\n\nexport interface CommitOptions {\n  silent?: boolean;\n  root?: boolean;\n}\n\nexport interface StoreOptions<S> {\n  state?: S | (() => S);\n  getters?: GetterTree<S, S>;\n  actions?: ActionTree<S, S>;\n  mutations?: MutationTree<S>;\n  modules?: ModuleTree<S>;\n  plugins?: Plugin<S>[];\n  strict?: boolean;\n  devtools?: boolean;\n}\n\nexport type ActionHandler<S, R> = (this: Store<R>, injectee: ActionContext<S, R>, payload?: any) => any;\nexport interface ActionObject<S, R> {\n  root?: boolean;\n  handler: ActionHandler<S, R>;\n}\n\nexport type Getter<S, R> = (state: S, getters: any, rootState: R, rootGetters: any) => any;\nexport type Action<S, R> = ActionHandler<S, R> | ActionObject<S, R>;\nexport type Mutation<S> = (state: S, payload?: any) => any;\nexport type Plugin<S> = (store: Store<S>) => any;\n\nexport interface Module<S, R> {\n  namespaced?: boolean;\n  state?: S | (() => S);\n  getters?: GetterTree<S, R>;\n  actions?: ActionTree<S, R>;\n  mutations?: MutationTree<S>;\n  modules?: ModuleTree<R>;\n}\n\nexport interface ModuleOptions {\n  preserveState?: boolean;\n}\n\nexport interface GetterTree<S, R> {\n  [key: string]: Getter<S, R>;\n}\n\nexport interface ActionTree<S, R> {\n  [key: string]: Action<S, R>;\n}\n\nexport interface MutationTree<S> {\n  [key: string]: Mutation<S>;\n}\n\nexport interface ModuleTree<R> {\n  [key: string]: Module<any, R>;\n}\n\ndeclare const _default: {\n  Store: typeof Store;\n  mapState: typeof mapState,\n  mapMutations: typeof mapMutations,\n  mapGetters: typeof mapGetters,\n  mapActions: typeof mapActions,\n  createNamespacedHelpers: typeof createNamespacedHelpers,\n  createLogger: typeof createLogger\n};\nexport default _default;\n"
  },
  {
    "path": "types/logger.d.ts",
    "content": "import { Payload, Plugin } from \"./index\";\n\ninterface Logger extends Partial<Pick<Console, 'groupCollapsed' | 'group' | 'groupEnd'>> {\n  log(message: string, color: string, payload: any): void;\n  log(message: string): void;\n}\n\nexport interface LoggerOption<S> {\n  collapsed?: boolean;\n  filter?: <P extends Payload>(mutation: P, stateBefore: S, stateAfter: S) => boolean;\n  transformer?: (state: S) => any;\n  mutationTransformer?: <P extends Payload>(mutation: P) => any;\n  actionFilter?: <P extends Payload>(action: P, state: S) => boolean;\n  actionTransformer?: <P extends Payload>(action: P) => any;\n  logMutations?: boolean;\n  logActions?: boolean;\n  logger?: Logger;\n}\n\nexport function createLogger<S>(option?: LoggerOption<S>): Plugin<S>;\n"
  },
  {
    "path": "types/test/helpers.ts",
    "content": "import { createApp } from \"vue\";\n\nimport {\n  mapState,\n  mapGetters,\n  mapActions,\n  mapMutations,\n  createNamespacedHelpers\n} from \"../index\";\n\nconst helpers = createNamespacedHelpers('foo');\n\ncreateApp({\n  computed: {\n    ...mapState([\"a\"]),\n    ...mapState('foo', [\"b\"]),\n    ...mapState({\n      c: \"c\"\n    }),\n    ...mapState('foo', {\n      d: \"d\"\n    }),\n    ...mapState({\n      e: (state: any, getters: any) => state.a + getters.g\n    }),\n    ...mapState('foo', {\n      f: (state: any, getters: any) => state.a + getters.g\n    }),\n\n    ...mapGetters([\"g\"]),\n    ...mapGetters('foo', [\"h\"]),\n    ...mapGetters({\n      i: \"i\"\n    }),\n    ...mapGetters('foo', {\n      j: \"j\"\n    }),\n\n    ...helpers.mapState([\"k\"]),\n    ...helpers.mapState({\n      l: \"l\"\n    }),\n    ...helpers.mapState({\n      m: (state: any, getters: any) => state.a + getters.g,\n      useThis(state: any, getters: any): any {\n        return state.a + getters.g + this.whatever\n      }\n    }),\n\n    ...helpers.mapGetters([\"n\"]),\n    ...helpers.mapGetters({\n      o: \"o\"\n    }),\n\n\n    otherComputed () {\n      return \"\";\n    }\n  },\n\n  methods: {\n    ...mapActions([\"p\"]),\n    ...mapActions({\n      q: \"q\"\n    }),\n    ...mapActions({\n      r (dispatch, a: string, b: number, c: boolean) {\n        dispatch('p', { a, b, c })\n        dispatch({\n          type: 'p',\n          a,\n          b,\n          c\n        })\n      }\n    }),\n    ...mapActions('foo', [\"s\"]),\n    ...mapActions('foo', {\n      t: \"t\"\n    }),\n    ...mapActions('foo', {\n      u (dispatch, a: string, b: number, c: boolean) {\n        dispatch('p', { a, b, c })\n        dispatch({\n          type: 'p',\n          a,\n          b,\n          c\n        })\n      }\n    }),\n\n    ...mapMutations([\"v\"]),\n    ...mapMutations({\n      w: \"w\"\n    }),\n    ...mapMutations({\n      x (commit, a: string, b: number, c: boolean) {\n        commit('v', { a, b, c })\n        commit({\n          type: 'v',\n          a,\n          b,\n          c\n        })\n      }\n    }),\n    ...mapMutations('foo', [\"y\"]),\n    ...mapMutations('foo', {\n      z: \"z\"\n    }),\n    ...mapMutations('foo', {\n      aa (commit, a: string, b: number, c: boolean) {\n        commit('v', { a, b, c })\n        commit({\n          type: 'v',\n          a,\n          b,\n          c\n        })\n      }\n    }),\n\n    ...helpers.mapActions([\"ab\"]),\n    ...helpers.mapActions({\n      ac: \"ac\"\n    }),\n    ...helpers.mapActions({\n      ad (dispatch, value: string) {\n        dispatch('p', value)\n      }\n    }),\n\n    ...helpers.mapMutations([\"ae\"]),\n    ...helpers.mapMutations({\n      af: \"af\"\n    }),\n    ...helpers.mapMutations({\n      ag (commit, value: string) {\n        commit('v', value)\n      }\n    }),\n\n    otherMethod () {}\n  },\n\n  created() {\n    // Computed\n    this.a\n    this.b\n    this.c\n    this.d\n    this.e\n    this.f\n    this.g\n    this.h\n    this.i\n    this.j\n    this.k\n    this.l\n    this.m\n    this.n\n    this.o\n    this.otherComputed\n\n    // Methods\n    this.p()\n    this.q()\n    this.r('', 0, true)\n    this.s()\n    this.t()\n    this.u('', 0, true)\n    this.v()\n    this.w()\n    this.x('', 0, true)\n    this.y()\n    this.z()\n    this.aa('', 0, true)\n    this.ab()\n    this.ac()\n    this.ad('')\n    this.ae()\n    this.af()\n    this.ag('')\n    this.otherMethod()\n  }\n});\n"
  },
  {
    "path": "types/test/index.ts",
    "content": "import { InjectionKey } from \"vue\";\nimport * as Vuex from \"../index\";\n\nnamespace StoreInstance {\n  const store = new Vuex.Store({\n    state: {\n      value: 0\n    }\n  });\n\n  store.state.value;\n  store.getters.foo;\n\n  store.dispatch(\"foo\", { amount: 1 }).then(() => {});\n  store.dispatch({\n    type: \"foo\",\n    amount: 1\n  }).then(() => {});\n\n  store.commit(\"foo\", { amount: 1 });\n  store.commit({\n    type: \"foo\",\n    amount: 1\n  });\n\n  store.watch(state => state.value, value => {\n    value = value + 1;\n  }, {\n    immediate: true,\n    deep: true\n  });\n\n  store.subscribe((mutation, state) => {\n    mutation.type;\n    mutation.payload;\n    state.value;\n  });\n\n  store.subscribe(() => {}, { prepend: true });\n\n  store.subscribeAction((action, state) => {\n    action.type;\n    action.payload;\n    state.value;\n  });\n\n  store.subscribeAction({\n    before(action, state) {\n      action.type;\n      action.payload;\n      state.value;\n    }\n  });\n\n  store.subscribeAction({\n    before(action, state) {\n      action.type;\n      action.payload;\n      state.value;\n    },\n    after(action, state) {\n      action.type;\n      action.payload;\n      state.value;\n    }\n  });\n\n  store.subscribeAction({\n    before(action, state) {\n      action.type;\n      action.payload;\n      state.value;\n    },\n    error(action, state, error) {\n      action.type;\n      action.payload;\n      state.value;\n      error;\n    }\n  });\n\n  store.subscribeAction({\n    before(action, state) {\n      action.type;\n      action.payload;\n      state.value;\n    },\n    after(action, state) {\n      action.type;\n      action.payload;\n      state.value;\n    },\n    error(action, state, error) {\n      action.type;\n      action.payload;\n      state.value;\n      error;\n    }\n  });\n\n  store.subscribeAction({\n    after(action, state) {\n      action.type;\n      action.payload;\n      state.value;\n    }\n  });\n\n  store.subscribeAction({\n    after(action, state) {\n      action.type;\n      action.payload;\n      state.value;\n    },\n    error(action, state, error) {\n      action.type;\n      action.payload;\n      state.value;\n      error;\n    }\n  });\n\n  store.subscribeAction({\n    error(action, state, error) {\n      action.type;\n      action.payload;\n      state.value;\n      error;\n    }\n  });\n\n  store.subscribeAction({}, { prepend: true });\n\n  store.replaceState({ value: 10 });\n}\n\nnamespace UseStoreFunction {\n  interface State {\n    a: string\n  }\n\n  const key: InjectionKey<string> = Symbol('store')\n\n  const storeWithKey = Vuex.useStore(key)\n  storeWithKey.state.a\n\n  const storeWithKeyString = Vuex.useStore('store')\n  storeWithKeyString.state.a\n\n  const storeWithState = Vuex.useStore<State>()\n  storeWithState.state.a\n\n  const storeAsAny = Vuex.useStore()\n  storeAsAny.state.a\n}\n\nnamespace RootModule {\n  const store = new Vuex.Store({\n    state: {\n      value: 0\n    },\n    getters: {\n      count: state => state.value,\n      plus10: (_, { count }) => count + 10\n    },\n    actions: {\n      foo ({ state, getters, dispatch, commit }, payload) {\n        this.state.value;\n        state.value;\n        getters.count;\n        dispatch(\"bar\", {});\n        commit(\"bar\", {});\n      }\n    },\n    mutations: {\n      bar (state, payload) {}\n    },\n    strict: true,\n    devtools: true\n  });\n}\n\nnamespace RootDefaultModule {\n  const store = new Vuex.default.Store({\n    state: {\n      value: 0\n    },\n    getters: {\n      count: state => state.value,\n      plus10: (_, { count }) => count + 10\n    },\n    actions: {\n      foo ({ state, getters, dispatch, commit }, payload) {\n        this.state.value;\n        state.value;\n        getters.count;\n        dispatch(\"bar\", {});\n        commit(\"bar\", {});\n      }\n    },\n    mutations: {\n      bar (state, payload) {}\n    },\n    strict: true\n  });\n}\n\nnamespace InitialStateFunction {\n  const store = new Vuex.Store({\n    state: () => ({\n      value: 1\n    })\n  });\n  const n: number = store.state.value;\n}\n\nnamespace NestedModules {\n  interface RootState {\n    a: {\n      value: number;\n    };\n    b: {\n      c: {\n        value: number;\n      };\n      d: {\n        value: number;\n      },\n      e: {\n        value: number;\n      }\n    };\n  }\n\n  type ActionStore = Vuex.ActionContext<{ value: number }, RootState>\n\n  const module = {\n    state: {\n      value: 0\n    },\n    actions: {\n      foo (\n        { state, getters, dispatch, commit, rootState }: ActionStore,\n        payload: { amount: number }\n      ) {\n        state.value;\n        getters.root;\n        rootState.b.c.value;\n        dispatch(\"bar\", {});\n        commit(\"bar\", payload);\n      }\n    },\n    mutations: {\n      bar (state: { value: number }, payload: { amount: number }) {\n        state.value += payload.amount;\n      }\n    }\n  };\n\n  const store = new Vuex.Store<RootState>({\n    getters: {\n      root: state => state\n    },\n    modules: {\n      a: module,\n      b: {\n        modules: {\n          c: module,\n          d: module,\n          e: {\n            state: {\n              value: 0\n            },\n            actions: {\n              foo(context: ActionStore, payload) {\n                this.state.a;\n              }\n            }\n          }\n        }\n      }\n    }\n  });\n}\n\nnamespace NamespacedModule {\n  const store = new Vuex.Store({\n    state: { value: 0 },\n    getters: {\n      rootValue: state => state.value\n    },\n    actions: {\n      foo () {}\n    },\n    mutations: {\n      foo () {}\n    },\n    modules: {\n      a: {\n        namespaced: true,\n        state: { value: 1 },\n        actions: {\n          test: {\n            root: true,\n            handler ({ dispatch }) {\n              dispatch('foo')\n            }\n          },\n          test2: {\n            handler ({ dispatch }) {\n              dispatch('foo')\n            }\n          }\n        },\n        modules: {\n          b: {\n            state: { value: 2 }\n          },\n          c: {\n            namespaced: true,\n            state: { value: 3 },\n            getters: {\n              constant: () => 10,\n              count (state, getters, rootState, rootGetters) {\n                getters.constant;\n                rootGetters.rootValue;\n              }\n            },\n            actions: {\n              test ({ dispatch, commit, getters, rootGetters }) {\n                getters.constant;\n                rootGetters.rootValue;\n\n                dispatch(\"foo\");\n                dispatch(\"foo\", null, { root: true });\n\n                commit(\"foo\");\n                commit(\"foo\", null, { root: true });\n              },\n              foo () {}\n            },\n            mutations: {\n              foo () {}\n            }\n          }\n        }\n      }\n    }\n  });\n}\n\nnamespace RegisterModule {\n  interface RootState {\n    value: number;\n    a?: {\n      value: number;\n      b?: {\n        value: number;\n      }\n    };\n  }\n\n  const store = new Vuex.Store<RootState>({\n    state: {\n      value: 0\n    }\n  });\n\n  store.registerModule(\"a\", {\n    state: { value: 1 }\n  });\n\n  store.hasModule('a')\n\n  store.registerModule([\"a\", \"b\"], {\n    state: { value: 2 }\n  });\n\n  store.registerModule([\"a\", \"b\"], {\n    state: { value: 2 }\n  }, { preserveState: true });\n\n  store.hasModule(['a', 'b'])\n\n  store.unregisterModule([\"a\", \"b\"]);\n  store.unregisterModule(\"a\");\n}\n\nnamespace HotUpdate {\n  interface RootState {\n    value: number;\n    a: {\n      b: {\n        value: number;\n      };\n    };\n  };\n\n  type ActionStore = Vuex.ActionContext<{ value: number }, RootState>\n\n  const getters = {\n    rootValue: (state: RootState) => state.value\n  };\n\n  const actions = {\n    foo (store: ActionStore, payload: number) {}\n  };\n\n  const mutations = {\n    bar (state: { value: number }, payload: number) {}\n  };\n\n  const module = {\n    state: {\n      value: 0\n    },\n    getters: {\n      count: (state: { value: number }) => state.value\n    },\n    actions,\n    mutations\n  };\n\n  const modules = {\n    a: {\n      modules: {\n        b: module\n      }\n    }\n  };\n\n  const store = new Vuex.Store<RootState>({\n    state: {\n      value: 0\n    } as any,\n    getters,\n    actions,\n    mutations,\n    modules\n  });\n\n  store.hotUpdate({\n    getters,\n    actions,\n    mutations,\n    modules\n  });\n}\n\nnamespace Plugins {\n  function plugin (store: Vuex.Store<{ value: number }>) {\n    store.subscribe((mutation, state) => {\n      mutation.type;\n      state.value;\n    });\n  }\n\n  class MyLogger {\n    log(message: string) {\n       console.log(message);\n    }\n  }\n\n  const logger = Vuex.createLogger<{ value: number }>({\n    collapsed: true,\n    transformer: state => state.value,\n    mutationTransformer: (mutation: { type: string }) => mutation.type,\n    logger: new MyLogger()\n  });\n\n  const store = new Vuex.Store<{ value: number }>({\n    state: {\n      value: 0\n    },\n    plugins: [plugin, logger]\n  });\n}\n"
  },
  {
    "path": "types/test/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"lib\": [\n      \"esnext\",\n      \"dom\"\n    ],\n    \"types\": [\n      \"node\"\n    ],\n    \"strict\": true,\n    \"noEmit\": true\n  },\n  \"include\": [\n    \"*.ts\",\n    \"../*.d.ts\",\n    \"../../dist/logger.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "types/test/vue.ts",
    "content": "import { createApp } from \"vue\";\nimport * as Vuex from \"../index\";\n\nconst store = new Vuex.Store({\n  state: {\n    value: 1\n  }\n});\n\nconst app = createApp({\n  store\n});\n"
  },
  {
    "path": "types/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"lib\": [\n      \"esnext\",\n      \"dom\"\n    ],\n    \"types\": [\n      \"node\"\n    ],\n    \"strict\": true,\n    \"noEmit\": true\n  },\n  \"include\": [\n    \"*.d.ts\",\n    \"../dist/logger.d.ts\"\n  ]\n}\n"
  },
  {
    "path": "types/vue.d.ts",
    "content": "/**\n * Extends interfaces in Vue.js\n */\n\nimport { ComponentCustomOptions } from \"vue\";\nimport { Store } from \"./index\";\n\ndeclare module \"@vue/runtime-core\" {\n  interface ComponentCustomOptions {\n    store?: Store<any>;\n  }\n}\n"
  }
]