├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── docs.yml │ └── npm-test.yml ├── .gitignore ├── .npmignore ├── .nvmrc ├── .prettierrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── deploy-docs.sh ├── dist ├── cjs │ ├── index.js │ └── index.js.map ├── esm │ ├── index.js │ └── index.js.map └── types │ ├── action.d.ts │ ├── config.d.ts │ ├── helpers.d.ts │ ├── index.d.ts │ ├── module │ ├── index.d.ts │ ├── stateFactory.d.ts │ └── staticGenerators.d.ts │ ├── moduleoptions.d.ts │ ├── mutation.d.ts │ ├── mutationaction.d.ts │ └── vuexmodule.d.ts ├── docs ├── .vuepress │ ├── components │ │ ├── content-center.vue │ │ ├── sponsor-cb-sidebar.vue │ │ └── sponsor-cb.vue │ ├── config.js │ └── public │ │ └── cblogo_big.png ├── README.md ├── pages │ ├── advanced │ │ ├── dynamic.md │ │ └── namespaced.md │ ├── core │ │ ├── actions.md │ │ ├── getters.md │ │ ├── mutationactions.md │ │ ├── mutations.md │ │ └── state.md │ ├── getting-started.md │ ├── installation.md │ └── overview.md └── sidebar.json ├── package-lock.json ├── package.json ├── postinstall.js ├── rollup.config.js ├── src ├── action.ts ├── config.ts ├── helpers.ts ├── index.ts ├── module │ ├── index.ts │ ├── stateFactory.ts │ └── staticGenerators.ts ├── moduleoptions.ts ├── mutation.ts ├── mutationaction.ts └── vuexmodule.ts ├── test ├── action_access_module_dynamic.ts ├── action_access_state.ts ├── action_with_inner_promise.ts ├── constructor.ts ├── dynamic_module.ts ├── getmodule │ ├── getmodule_action_mutation.ts │ ├── getmodule_dynamic.ts │ ├── getmodule_dynamic_namespaced.ts │ ├── getmodule_generated_on_store.ts │ ├── getmodule_generated_on_two_stores.ts │ ├── getmodule_getter.ts │ ├── getmodule_noname.ts │ ├── getmodule_nondynamic_noname.ts │ ├── getmodule_nondynamic_withname.ts │ └── getmodule_without_store.ts ├── getters.ts ├── getters_childmodule.ts ├── getters_rootstate.ts ├── global_config.ts ├── muation_and_action.ts ├── mutation.ts ├── mutationaction.ts ├── namespaced_getters.ts ├── namespaced_mutation.ts ├── reserved_keys_as_properties.ts ├── root_action_namespaced_module.ts ├── root_mutationaction_namespaced_module.ts ├── state_factory_state_isolation.ts ├── static_options.ts ├── tsconfig.json ├── vuex-persist.ts └── vuexmodule_constructor.ts ├── tsconfig.json └── tslint.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [championswimmer] 4 | patreon: championswimmer 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: championswimmer 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Build Docs 13 | run: | 14 | npm install 15 | npm run docs:build 16 | - name: Deploy 17 | uses: peaceiris/actions-gh-pages@v3 18 | with: 19 | github_token: ${{ secrets.GITHUB_TOKEN }} 20 | publish_dir: docs/.vuepress/dist 21 | -------------------------------------------------------------------------------- /.github/workflows/npm-test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [12.x] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - name: npm test 21 | run: | 22 | npm install 23 | npm test 24 | env: 25 | CI: true 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE 2 | .idea/ 3 | .vscode/ 4 | 5 | # Coverage 6 | coverage/ 7 | .nyc_output/ 8 | 9 | # NodeJS 10 | node_modules/ 11 | 12 | # Vuepress 13 | /docs/.vuepress/dist/ 14 | 15 | # Cache 16 | /.cache/ 17 | /.rpt2_cache/ 18 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !/dist/**/* 3 | !/README.md 4 | !/package*.json 5 | !/tsconfig.json 6 | !tslint.json 7 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "arrowParens": "always", 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "printWidth": 100 7 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | # - "6" 4 | # - "8" 5 | # - "10" 6 | - "12" 7 | - "14" 8 | install: 9 | - npm install -g codecov nyc mocha ts-node typescript 10 | - npm install -D 11 | cache: 12 | directories: 13 | - node_modules 14 | script: 15 | - npm run report 16 | after_success: 17 | - codecov -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | If `(beta)` or `(alpha)` is marked in front of any release, it can be 4 | installed as `npm install vuex-module-decorators@beta` (or alpha similar). 5 | 6 | ## 1.1.1 7 | - fix deployment issues when installing directly from git 8 | 9 | ## 1.1.0 10 | - add access to state and getters in MutationAction 11 | 12 | ## 1.0.0 13 | 14 | ### 0.17.0 15 | 16 | - allow changing rawError default across project via global config 17 | 18 | ### 0.14.0 19 | 20 | - support for `preserveState: true` in module options to use `vuex-persist` (OPTIONAL) 21 | 22 | ### 0.13.0 23 | 24 | - tslib update, latest versions of all typescript compilers and runtimes 25 | 26 | ### 0.11.0 27 | 28 | - fix support for SSR (with NUXT) 29 | 30 | ### 0.10.0 31 | 32 | - Updated to TypeScript 3.5 33 | 34 | #### 0.9.9 35 | 36 | - added github actions 37 | 38 | #### 0.9.5 39 | 40 | - more typesafe `@MutationAction` 41 | - you cannot `mutate` keys not in the module 42 | - the returned object must be a partial of the module 43 | 44 | #### 0.9.4 45 | 46 | - initializing properties with `null` and then running `@MutationAction` is possible now 47 | 48 | #### 0.9.3 49 | 50 | - we will distribute in ES5 as a lot of people still use ES5 target for their websites 51 | 52 | #### 0.9.1 53 | 54 | - fix context getting lost in actions 55 | - via [pr 55](https://github.com/championswimmer/vuex-module-decorators/pull/55) 56 | - add ability to access getters inside actions simply as `this.getterName` 57 | 58 | ### 0.9.0 59 | 60 | - distribute as ES2015 (users need to transpile) 61 | 62 | ### 0.8.0 63 | 64 | ##### 0.8.0-4 (beta) 65 | 66 | - inside getters we can access `rootState` and `rootGetters` 67 | - Use `this.context.rootState` and `this.context.rootGetters` 68 | 69 | ##### 0.8.0-3 (beta) 70 | 71 | - in `@Action` and `@MutationAction` functions - 72 | - Now introduces `rawError` decorator option 73 | - By default they are set to false to keep the old behavior 74 | - Old behaviour - it is wrapped in a helper message 75 | - If set to true, errors inside actions will be thrown as it is 76 | - in`@Action` functions - 77 | - `commit` decorator option can now be optional 78 | 79 | ##### 0.8.0-2 (beta) 80 | 81 | - in `@Action` functions - 82 | - `this.stateField` works pointing to fields in the module's state 83 | - `this.context.commit('mutationName', payload)` is way to trigger mutation 84 | - `this.context.getters['getterName'])` is the way to use getters 85 | - **iff your module is dynamic** you get more typesafety 86 | - calling `this.mutationName(payload)` will work as well 87 | - accessing `this.getterName` will work as well 88 | 89 | ##### 0.8.0-0 (beta) 90 | 91 | - allow `getModule()` even for non-dynamic modules 92 | 93 | > **NOTE:** From now on you have to use`getModule(ModuleClass)` 94 | > instead of the earlier `getModule(ModuleClass.prototype)` 95 | 96 | - update to prettier code formatting 97 | 98 | #### 0.7.1 99 | 100 | - fix `unable to construct without new` error for transpiled ES5 101 | 102 | ### 0.7.0 103 | 104 | - add `module` field to package.json for ES6 module loaders 105 | - tree-shaking supported 106 | 107 | ### 0.6.0 108 | 109 | - distribute cjs, esm and minified cdn package separately 110 | 111 | ### 0.1.0 112 | 113 | #### 0.0.1 114 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Arnav Gupta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vuex-module-decorators 2 | 3 | [![Usage Guide](https://img.shields.io/badge/usage-guide-1e90ff.svg?style=for-the-badge&longCache=true)](https://championswimmer.in/vuex-module-decorators/) 4 | Detailed Guide: https://championswimmer.in/vuex-module-decorators/ 5 | 6 | Typescript/ES7 Decorators to make Vuex modules a breeze 7 | 8 | [![Build Status](https://travis-ci.org/championswimmer/vuex-module-decorators.svg?branch=master)](https://travis-ci.org/championswimmer/vuex-module-decorators) 9 | [![npm:size:gzip](https://img.shields.io/bundlephobia/minzip/vuex-module-decorators.svg?label=npm:size:gzip)](https://bundlephobia.com/result?p=vuex-module-decorators) 10 | [![cdn:min:gzip](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/vuex-module-decorators.svg?label=cdn:min:gzip&compression=gzip)](https://cdn.jsdelivr.net/npm/vuex-module-decorators/dist/cjs/index.min.js) 11 | [![codecov](https://codecov.io/gh/championswimmer/vuex-module-decorators/branch/master/graph/badge.svg)](https://codecov.io/gh/championswimmer/vuex-module-decorators) 12 | [![npm](https://img.shields.io/npm/v/vuex-module-decorators.svg)](https://www.npmjs.com/package/vuex-module-decorators) 13 | [![npm](https://img.shields.io/npm/dw/vuex-module-decorators.svg?colorB=ff0033)](https://www.npmjs.com/package/vuex-module-decorators) 14 | ![npm type definitions](https://img.shields.io/npm/types/vuex-module-decorators.svg) 15 | [![Maintainability](https://api.codeclimate.com/v1/badges/5b1dfa8d3d4bdf409b60/maintainability)](https://codeclimate.com/github/championswimmer/vuex-module-decorators/maintainability) 16 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/b7944c579d5c4c1d949f71a91a538d77)](https://www.codacy.com/app/championswimmer/vuex-module-decorators?utm_source=github.com&utm_medium=referral&utm_content=championswimmer/vuex-module-decorators&utm_campaign=Badge_Grade) 17 | [![codebeat badge](https://codebeat.co/badges/0272746c-8a7d-428b-a20d-387d22bfbcfb)](https://codebeat.co/projects/github-com-championswimmer-vuex-module-decorators-master) 18 | [![Total alerts](https://img.shields.io/lgtm/alerts/g/championswimmer/vuex-module-decorators.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/championswimmer/vuex-module-decorators/alerts/) 19 | [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/championswimmer/vuex-module-decorators.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/championswimmer/vuex-module-decorators/context:javascript) 20 | 21 | ## Patrons 22 | While I have a day job and I really maintain open source libraries for fun, any sponsors are extremely graciously thanked for their contributions, and goes a long way 😇 ❤️ 23 | 24 | - [Thomas Woo](https://www.patreon.com/user/creators?u=37365136) 25 | 26 | ## CHANGELOG 27 | 28 | - There are major type-checking changes (could be breaking) in v0.9.7 29 | 30 | - There are major usage improvements (non backwards compatible) in 0.8.0 31 | 32 | Please check [CHANGELOG](CHANGELOG.md) 33 | 34 | ## Examples 35 | 36 | Read the rest of the README to figure out how to use, or if you readily want to jump into a production codebase and see how this is used, you can check out - 37 | 38 | - 39 | - 40 | - 41 | 42 | ## Installation 43 | 44 | ```shell 45 | npm install -D vuex-module-decorators 46 | ``` 47 | 48 | ### Babel 6/7 49 | 50 | > **NOTE** This is **not** necessary for `vue-cli@3` projects, since `@vue/babel-preset-app` already includes this plugin 51 | 52 | 1. You need to install `babel-plugin-transform-decorators` 53 | 54 | ### TypeScript 55 | 56 | 1. set `experimentalDecorators` to true 57 | 2. For reduced code with decorators, set `importHelpers: true` in `tsconfig.json` 58 | 3. _(only for TypeScript 2)_ set `emitHelpers: true` in `tsconfig.json` 59 | 60 | ## Configuration 61 | 62 | ### Using with `target: es5` 63 | 64 | > **NOTE** Since version `0.9.3` we distribute as ES5, so this section is applicable only to v0.9.2 and below 65 | 66 | This package generates code in `es2015` format. If your Vue project targets ES6 or ES2015 then 67 | you need not do anything. But in case your project uses `es5` target (to support old browsers), then 68 | you need to tell Vue CLI / Babel to transpile this package. 69 | 70 | ```js 71 | // in your vue.config.js 72 | module.exports = { 73 | /* ... other settings */ 74 | transpileDependencies: ['vuex-module-decorators'] 75 | } 76 | ``` 77 | 78 | ## Usage 79 | 80 | #### The conventional old & boring way 81 | 82 | Remember how vuex modules used to be made ? 83 | 84 | ```js 85 | const moduleA = { 86 | state: { ... }, 87 | mutations: { ... }, 88 | actions: { ... }, 89 | getters: { ... } 90 | } 91 | 92 | const moduleB = { 93 | state: { ... }, 94 | mutations: { ... }, 95 | actions: { ... } 96 | } 97 | 98 | const store = new Vuex.Store({ 99 | modules: { 100 | a: moduleA, 101 | b: moduleB 102 | } 103 | }) 104 | ``` 105 | 106 | #### Hello Decorators ! 107 | 108 | Well not anymore. Now you get better syntax. Inspired by `vue-class-component` 109 | 110 | ```typescript 111 | import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators' 112 | 113 | @Module 114 | export default class Counter2 extends VuexModule { 115 | count = 0 116 | 117 | @Mutation 118 | increment(delta: number) { 119 | this.count += delta 120 | } 121 | @Mutation 122 | decrement(delta: number) { 123 | this.count -= delta 124 | } 125 | 126 | // action 'incr' commits mutation 'increment' when done with return value as payload 127 | @Action({ commit: 'increment' }) 128 | incr() { 129 | return 5 130 | } 131 | // action 'decr' commits mutation 'decrement' when done with return value as payload 132 | @Action({ commit: 'decrement' }) 133 | decr() { 134 | return 5 135 | } 136 | } 137 | ``` 138 | 139 | #### async MutationAction === magic 140 | 141 | Want to see something even better ? 142 | 143 | ```typescript 144 | import { Module, VuexModule, MutationAction } from 'vuex-module-decorators' 145 | import { ConferencesEntity, EventsEntity } from '@/models/definitions' 146 | 147 | @Module 148 | export default class HGAPIModule extends VuexModule { 149 | conferences: Array = [] 150 | events: Array = [] 151 | 152 | // 'events' and 'conferences' are replaced by returned object 153 | // whose shape must be `{events: [...], conferences: [...] }` 154 | @MutationAction({ mutate: ['events', 'conferences'] }) 155 | async fetchAll() { 156 | const response: Response = await getJSON('https://hasgeek.github.io/events/api/events.json') 157 | return response 158 | } 159 | } 160 | ``` 161 | 162 | #### Automatic getter detection 163 | 164 | ```typescript 165 | @Module 166 | class MyModule extends VuexModule { 167 | wheels = 2 168 | 169 | @Mutation 170 | incrWheels(extra) { 171 | this.wheels += extra 172 | } 173 | 174 | get axles() { 175 | return this.wheels / 2 176 | } 177 | } 178 | ``` 179 | 180 | this is turned into the equivalent 181 | 182 | ```javascript 183 | const module = { 184 | state: { wheels: 2 }, 185 | mutations: { 186 | incrWheels(state, extra) { 187 | state.wheels += extra 188 | } 189 | }, 190 | getters: { 191 | axles: (state) => state.wheels / 2 192 | } 193 | } 194 | ``` 195 | 196 | ## Parameters inside a getter 197 | 198 | In order to handle parameters, simply return a function like so: 199 | 200 | ``` 201 | get getUser() { 202 | return function (id: number) { 203 | return this.users.filter(user => user.id === id)[0]; 204 | } 205 | } 206 | ``` 207 | 208 | ### Putting into the store 209 | 210 | Use the modules just like you would earlier 211 | 212 | ```typescript 213 | import Vue from 'nativescript-vue' 214 | import Vuex, { Module } from 'vuex' 215 | 216 | import counter from './modules/Counter2' 217 | import hgapi from './modules/HGAPIModule' 218 | 219 | Vue.use(Vuex) 220 | 221 | const store = new Vuex.Store({ 222 | state: {}, 223 | modules: { 224 | counter, 225 | hgapi 226 | } 227 | }) 228 | ``` 229 | 230 | ### Module re-use, use with NuxtJS 231 | 232 | If you need to support [module reuse](https://vuex.vuejs.org/guide/modules.html#module-reuse) 233 | or to use modules with NuxtJS, you can have a state factory function generated instead 234 | of a static state object instance by using `stateFactory` option to `@Module`, like so: 235 | 236 | ```typescript 237 | @Module({ stateFactory: true }) 238 | class MyModule extends VuexModule { 239 | wheels = 2 240 | 241 | @Mutation 242 | incrWheels(extra) { 243 | this.wheels += extra 244 | } 245 | 246 | get axles() { 247 | return this.wheels / 2 248 | } 249 | } 250 | ``` 251 | 252 | this is turned into the equivalent 253 | 254 | ```javascript 255 | const module = { 256 | state() { 257 | return { wheels: 2 } 258 | }, 259 | 260 | mutations: { 261 | incrWheels(state, extra) { 262 | state.wheels += extra 263 | } 264 | }, 265 | getters: { 266 | axles: (state) => state.wheels / 2 267 | } 268 | } 269 | ``` 270 | 271 | ### Dynamic Modules 272 | 273 | Vuex allows us to register modules into store at runtime after store is 274 | constructed. We can do the following to create dynamic modules 275 | 276 | ```typescript 277 | interface StoreType { 278 | mm: MyModule 279 | } 280 | // Declare empty store first 281 | const store = new Vuex.Store({}) 282 | 283 | // Create module later in your code (it will register itself automatically) 284 | // In the decorator we pass the store object into which module is injected 285 | // NOTE: When you set dynamic true, make sure you give module a name 286 | @Module({ dynamic: true, store: store, name: 'mm' }) 287 | class MyModule extends VuexModule { 288 | count = 0 289 | 290 | @Mutation 291 | incrCount(delta) { 292 | this.count += delta 293 | } 294 | } 295 | ``` 296 | 297 | If you would like to preserve the state e.g when loading in the state from [vuex-persist](https://www.npmjs.com/package/vuex-persist) 298 | 299 | ```diff 300 | ... 301 | 302 | -- @Module({ dynamic: true, store: store, name: 'mm' }) 303 | ++ @Module({ dynamic: true, store: store, name: 'mm', preserveState: true }) 304 | class MyModule extends VuexModule { 305 | 306 | ... 307 | ``` 308 | 309 | Or when it doesn't have a initial state and you load the state from the localStorage 310 | 311 | ```diff 312 | ... 313 | 314 | -- @Module({ dynamic: true, store: store, name: 'mm' }) 315 | ++ @Module({ dynamic: true, store: store, name: 'mm', preserveState: localStorage.getItem('vuex') !== null }) 316 | class MyModule extends VuexModule { 317 | 318 | ... 319 | ``` 320 | 321 | ### Accessing modules with NuxtJS 322 | 323 | There are many possible ways to construct your modules. Here is one way for drop-in use with NuxtJS (you simply need to add your modules to `~/utils/store-accessor.ts` and then just import the modules from `~/store`): 324 | 325 | `~/store/index.ts`: 326 | 327 | ```typescript 328 | import { Store } from 'vuex' 329 | import { initialiseStores } from '~/utils/store-accessor' 330 | const initializer = (store: Store) => initialiseStores(store) 331 | export const plugins = [initializer] 332 | export * from '~/utils/store-accessor' 333 | ``` 334 | 335 | `~/utils/store-accessor.ts`: 336 | 337 | ```typescript 338 | import { Store } from 'vuex' 339 | import { getModule } from 'vuex-module-decorators' 340 | import example from '~/store/example' 341 | 342 | let exampleStore: example 343 | 344 | function initialiseStores(store: Store): void { 345 | exampleStore = getModule(example, store) 346 | } 347 | 348 | export { initialiseStores, exampleStore } 349 | ``` 350 | 351 | Now you can access stores in a type-safe way by doing the following from a component or page - no extra initialization required. 352 | 353 | ```typescript 354 | import { exampleStore } from '~/store' 355 | ... 356 | someMethod() { 357 | return exampleStore.exampleGetter 358 | } 359 | ``` 360 | 361 | ### Using the decorators with ServerSideRender 362 | 363 | When SSR is involved the store is recreated on each request. Every time the module is accessed 364 | using `getModule` function the current store instance must be provided and the module must 365 | be manually registered to the root store modules 366 | 367 | #### Example 368 | 369 | ```typescript 370 | // store/modules/MyStoreModule.ts 371 | import { Module, VuexModule, Mutation } from 'vuex-module-decorators' 372 | 373 | @Module({ 374 | name: 'modules/MyStoreModule', 375 | namespaced: true, 376 | stateFactory: true, 377 | }) 378 | export default class MyStoreModule extends VuexModule { 379 | public test: string = 'initial' 380 | 381 | @Mutation 382 | public setTest(val: string) { 383 | this.test = val 384 | } 385 | } 386 | 387 | 388 | // store/index.ts 389 | import Vuex from 'vuex' 390 | import MyStoreModule from '~/store/modules/MyStoreModule' 391 | 392 | export function createStore() { 393 | return new Vuex.Store({ 394 | modules: { 395 | MyStoreModule, 396 | } 397 | }) 398 | } 399 | 400 | // components/Random.tsx 401 | import { Component, Vue } from 'vue-property-decorator'; 402 | import { getModule } from 'vuex-module-decorators'; 403 | import MyStoreModule from '~/store/modules/MyStoreModule' 404 | 405 | @Component 406 | export default class extends Vue { 407 | public created() { 408 | const MyModuleInstance = getModule(MyStoreModule, this.$store); 409 | // Do stuff with module 410 | MyModuleInstance.setTest('random') 411 | } 412 | } 413 | ``` 414 | 415 | ## Configuration 416 | 417 | There is a global configuration object that can be used to set options across the 418 | whole module: 419 | 420 | ```typescript 421 | import { config } from 'vuex-module-decorators' 422 | // Set rawError to true by default on all @Action decorators 423 | config.rawError = true 424 | ``` 425 | -------------------------------------------------------------------------------- /deploy-docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # abort on errors 4 | set -e 5 | 6 | # build 7 | npm run docs:build 8 | 9 | # navigate into the build output directory 10 | cd docs/.vuepress/dist 11 | 12 | # if you are deploying to a custom domain 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | COMMIT_MSG="deploy docs : $(date)" 18 | git commit -m "${COMMIT_MSG}" 19 | 20 | # if you are deploying to https://.github.io 21 | # git push -f git@github.com:/.github.io.git master 22 | 23 | # if you are deploying to https://.github.io/ 24 | git push -f git@github.com:championswimmer/vuex-module-decorators.git master:gh-pages 25 | 26 | cd - -------------------------------------------------------------------------------- /dist/cjs/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | 5 | /** 6 | * Takes the properties on object from parameter source and adds them to the object 7 | * parameter target 8 | * @param {object} target Object to have properties copied onto from y 9 | * @param {object} source Object with properties to be copied to x 10 | */ 11 | function addPropertiesToObject(target, source) { 12 | for (let k of Object.keys(source || {})) { 13 | Object.defineProperty(target, k, { 14 | get: () => source[k] 15 | }); 16 | } 17 | } 18 | /** 19 | * Returns a namespaced name of the module to be used as a store getter 20 | * @param module 21 | */ 22 | function getModuleName(module) { 23 | if (!module._vmdModuleName) { 24 | throw new Error(`ERR_GET_MODULE_NAME : Could not get module accessor. 25 | Make sure your module has name, we can't make accessors for unnamed modules 26 | i.e. @Module({ name: 'something' })`); 27 | } 28 | return `vuexModuleDecorators/${module._vmdModuleName}`; 29 | } 30 | 31 | class VuexModule { 32 | constructor(module) { 33 | this.actions = module.actions; 34 | this.mutations = module.mutations; 35 | this.state = module.state; 36 | this.getters = module.getters; 37 | this.namespaced = module.namespaced; 38 | this.modules = module.modules; 39 | } 40 | } 41 | function getModule(moduleClass, store) { 42 | const moduleName = getModuleName(moduleClass); 43 | if (store && store.getters[moduleName]) { 44 | return store.getters[moduleName]; 45 | } 46 | else if (moduleClass._statics) { 47 | return moduleClass._statics; 48 | } 49 | const genStatic = moduleClass._genStatic; 50 | if (!genStatic) { 51 | throw new Error(`ERR_GET_MODULE_NO_STATICS : Could not get module accessor. 52 | Make sure your module has name, we can't make accessors for unnamed modules 53 | i.e. @Module({ name: 'something' })`); 54 | } 55 | const storeModule = genStatic(store); 56 | if (store) { 57 | store.getters[moduleName] = storeModule; 58 | } 59 | else { 60 | moduleClass._statics = storeModule; 61 | } 62 | return storeModule; 63 | } 64 | 65 | const reservedKeys = ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit']; 66 | function stateFactory(module) { 67 | const state = new module.prototype.constructor({}); 68 | const s = {}; 69 | Object.keys(state).forEach((key) => { 70 | if (reservedKeys.indexOf(key) !== -1) { 71 | if (typeof state[key] !== 'undefined') { 72 | throw new Error(`ERR_RESERVED_STATE_KEY_USED: You cannot use the following 73 | ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit'] 74 | as fields in your module. These are reserved as they have special purpose in Vuex`); 75 | } 76 | return; 77 | } 78 | if (state.hasOwnProperty(key)) { 79 | if (typeof state[key] !== 'function') { 80 | s[key] = state[key]; 81 | } 82 | } 83 | }); 84 | return s; 85 | } 86 | 87 | function staticStateGenerator(module, modOpt, statics) { 88 | const state = modOpt.stateFactory ? module.state() : module.state; 89 | Object.keys(state).forEach((key) => { 90 | if (state.hasOwnProperty(key)) { 91 | // If not undefined or function means it is a state value 92 | if (['undefined', 'function'].indexOf(typeof state[key]) === -1) { 93 | Object.defineProperty(statics, key, { 94 | get() { 95 | const path = modOpt.name.split('/'); 96 | let data = statics.store.state; 97 | for (let segment of path) { 98 | data = data[segment]; 99 | } 100 | return data[key]; 101 | } 102 | }); 103 | } 104 | } 105 | }); 106 | } 107 | function staticGetterGenerator(module, modOpt, statics) { 108 | Object.keys(module.getters).forEach((key) => { 109 | if (module.namespaced) { 110 | Object.defineProperty(statics, key, { 111 | get() { 112 | return statics.store.getters[`${modOpt.name}/${key}`]; 113 | } 114 | }); 115 | } 116 | else { 117 | Object.defineProperty(statics, key, { 118 | get() { 119 | return statics.store.getters[key]; 120 | } 121 | }); 122 | } 123 | }); 124 | } 125 | function staticMutationGenerator(module, modOpt, statics) { 126 | Object.keys(module.mutations).forEach((key) => { 127 | if (module.namespaced) { 128 | statics[key] = function (...args) { 129 | statics.store.commit(`${modOpt.name}/${key}`, ...args); 130 | }; 131 | } 132 | else { 133 | statics[key] = function (...args) { 134 | statics.store.commit(key, ...args); 135 | }; 136 | } 137 | }); 138 | } 139 | function staticActionGenerators(module, modOpt, statics) { 140 | Object.keys(module.actions).forEach((key) => { 141 | if (module.namespaced) { 142 | statics[key] = async function (...args) { 143 | return statics.store.dispatch(`${modOpt.name}/${key}`, ...args); 144 | }; 145 | } 146 | else { 147 | statics[key] = async function (...args) { 148 | return statics.store.dispatch(key, ...args); 149 | }; 150 | } 151 | }); 152 | } 153 | 154 | function registerDynamicModule(module, modOpt) { 155 | if (!modOpt.name) { 156 | throw new Error('Name of module not provided in decorator options'); 157 | } 158 | if (!modOpt.store) { 159 | throw new Error('Store not provided in decorator options when using dynamic option'); 160 | } 161 | modOpt.store.registerModule(modOpt.name, // TODO: Handle nested modules too in future 162 | module, { preserveState: modOpt.preserveState || false }); 163 | } 164 | function addGettersToModule(targetModule, srcModule) { 165 | Object.getOwnPropertyNames(srcModule.prototype).forEach((funcName) => { 166 | const descriptor = Object.getOwnPropertyDescriptor(srcModule.prototype, funcName); 167 | if (descriptor.get && targetModule.getters) { 168 | targetModule.getters[funcName] = function (state, getters, rootState, rootGetters) { 169 | const thisObj = { context: { state, getters, rootState, rootGetters } }; 170 | addPropertiesToObject(thisObj, state); 171 | addPropertiesToObject(thisObj, getters); 172 | const got = descriptor.get.call(thisObj); 173 | return got; 174 | }; 175 | } 176 | }); 177 | } 178 | function moduleDecoratorFactory(moduleOptions) { 179 | return function (constructor) { 180 | const module = constructor; 181 | const stateFactory$1 = () => stateFactory(module); 182 | if (!module.state) { 183 | module.state = moduleOptions && moduleOptions.stateFactory ? stateFactory$1 : stateFactory$1(); 184 | } 185 | if (!module.getters) { 186 | module.getters = {}; 187 | } 188 | if (!module.namespaced) { 189 | module.namespaced = moduleOptions && moduleOptions.namespaced; 190 | } 191 | let parentModule = Object.getPrototypeOf(module); 192 | while (parentModule.name !== 'VuexModule' && parentModule.name !== '') { 193 | addGettersToModule(module, parentModule); 194 | parentModule = Object.getPrototypeOf(parentModule); 195 | } 196 | addGettersToModule(module, module); 197 | const modOpt = moduleOptions; 198 | if (modOpt.name) { 199 | Object.defineProperty(constructor, '_genStatic', { 200 | value: (store) => { 201 | let statics = { store: store || modOpt.store }; 202 | if (!statics.store) { 203 | throw new Error(`ERR_STORE_NOT_PROVIDED: To use getModule(), either the module 204 | should be decorated with store in decorator, i.e. @Module({store: store}) or 205 | store should be passed when calling getModule(), i.e. getModule(MyModule, this.$store)`); 206 | } 207 | // =========== For statics ============== 208 | // ------ state ------- 209 | staticStateGenerator(module, modOpt, statics); 210 | // ------- getters ------- 211 | if (module.getters) { 212 | staticGetterGenerator(module, modOpt, statics); 213 | } 214 | // -------- mutations -------- 215 | if (module.mutations) { 216 | staticMutationGenerator(module, modOpt, statics); 217 | } 218 | // -------- actions --------- 219 | if (module.actions) { 220 | staticActionGenerators(module, modOpt, statics); 221 | } 222 | return statics; 223 | } 224 | }); 225 | Object.defineProperty(constructor, '_vmdModuleName', { 226 | value: modOpt.name 227 | }); 228 | } 229 | if (modOpt.dynamic) { 230 | registerDynamicModule(module, modOpt); 231 | } 232 | return constructor; 233 | }; 234 | } 235 | function Module(modOrOpt) { 236 | if (typeof modOrOpt === 'function') { 237 | /* 238 | * @Module decorator called without options (directly on the class definition) 239 | */ 240 | moduleDecoratorFactory({})(modOrOpt); 241 | } 242 | else { 243 | /* 244 | * @Module({...}) decorator called with options 245 | */ 246 | return moduleDecoratorFactory(modOrOpt); 247 | } 248 | } 249 | 250 | const config = {}; 251 | 252 | function actionDecoratorFactory(params) { 253 | const { commit = undefined, rawError = !!config.rawError, root = false } = params || {}; 254 | return function (target, key, descriptor) { 255 | const module = target.constructor; 256 | if (!module.hasOwnProperty('actions')) { 257 | module.actions = Object.assign({}, module.actions); 258 | } 259 | const actionFunction = descriptor.value; 260 | const action = async function (context, payload) { 261 | try { 262 | let actionPayload = null; 263 | if (module._genStatic) { 264 | const moduleName = getModuleName(module); 265 | const moduleAccessor = context.rootGetters[moduleName] 266 | ? context.rootGetters[moduleName] 267 | : getModule(module); 268 | moduleAccessor.context = context; 269 | actionPayload = await actionFunction.call(moduleAccessor, payload); 270 | } 271 | else { 272 | const thisObj = { context }; 273 | addPropertiesToObject(thisObj, context.state); 274 | addPropertiesToObject(thisObj, context.getters); 275 | actionPayload = await actionFunction.call(thisObj, payload); 276 | } 277 | if (commit) { 278 | context.commit(commit, actionPayload); 279 | } 280 | return actionPayload; 281 | } 282 | catch (e) { 283 | throw rawError 284 | ? e 285 | : new Error('ERR_ACTION_ACCESS_UNDEFINED: Are you trying to access ' + 286 | 'this.someMutation() or this.someGetter inside an @Action? \n' + 287 | 'That works only in dynamic modules. \n' + 288 | 'If not dynamic use this.context.commit("mutationName", payload) ' + 289 | 'and this.context.getters["getterName"]' + 290 | '\n' + 291 | new Error(`Could not perform action ${key.toString()}`).stack + 292 | '\n' + 293 | e.stack); 294 | } 295 | }; 296 | module.actions[key] = root ? { root, handler: action } : action; 297 | }; 298 | } 299 | /** 300 | * The @Action decorator turns an async function into an Vuex action 301 | * 302 | * @param targetOrParams the module class 303 | * @param key name of the action 304 | * @param descriptor the action function descriptor 305 | * @constructor 306 | */ 307 | function Action(targetOrParams, key, descriptor) { 308 | if (!key && !descriptor) { 309 | /* 310 | * This is the case when `targetOrParams` is params. 311 | * i.e. when used as - 312 | *
313 |             @Action({commit: 'incrCount'})
314 |             async getCountDelta() {
315 |               return 5
316 |             }
317 |          * 
318 | */ 319 | return actionDecoratorFactory(targetOrParams); 320 | } 321 | else { 322 | /* 323 | * This is the case when @Action is called on action function 324 | * without any params 325 | *
326 |          *   @Action
327 |          *   async doSomething() {
328 |          *    ...
329 |          *   }
330 |          * 
331 | */ 332 | actionDecoratorFactory()(targetOrParams, key, descriptor); 333 | } 334 | } 335 | 336 | function Mutation(target, key, descriptor) { 337 | const module = target.constructor; 338 | if (!module.hasOwnProperty('mutations')) { 339 | module.mutations = Object.assign({}, module.mutations); 340 | } 341 | const mutationFunction = descriptor.value; 342 | const mutation = function (state, payload) { 343 | mutationFunction.call(state, payload); 344 | }; 345 | module.mutations[key] = mutation; 346 | } 347 | 348 | function mutationActionDecoratorFactory(params) { 349 | return function (target, key, descriptor) { 350 | const module = target.constructor; 351 | if (!module.hasOwnProperty('mutations')) { 352 | module.mutations = Object.assign({}, module.mutations); 353 | } 354 | if (!module.hasOwnProperty('actions')) { 355 | module.actions = Object.assign({}, module.actions); 356 | } 357 | const mutactFunction = descriptor.value; 358 | const action = async function (context, payload) { 359 | try { 360 | const thisObj = { context }; 361 | addPropertiesToObject(thisObj, context.state); 362 | addPropertiesToObject(thisObj, context.getters); 363 | const actionPayload = await mutactFunction.call(thisObj, payload); 364 | if (actionPayload === undefined) 365 | return; 366 | context.commit(key, actionPayload); 367 | } 368 | catch (e) { 369 | if (params.rawError) { 370 | throw e; 371 | } 372 | else { 373 | console.error('Could not perform action ' + key.toString()); 374 | console.error(e); 375 | return Promise.reject(e); 376 | } 377 | } 378 | }; 379 | const mutation = function (state, payload) { 380 | if (!params.mutate) { 381 | params.mutate = Object.keys(payload); 382 | } 383 | for (let stateItem of params.mutate) { 384 | if (state.hasOwnProperty(stateItem) && payload.hasOwnProperty(stateItem)) { 385 | state[stateItem] = payload[stateItem]; 386 | } 387 | else { 388 | throw new Error(`ERR_MUTATE_PARAMS_NOT_IN_PAYLOAD 389 | In @MutationAction, mutate: ['a', 'b', ...] array keys must 390 | match with return type = {a: {}, b: {}, ...} and must 391 | also be in state.`); 392 | } 393 | } 394 | }; 395 | module.actions[key] = params.root ? { root: true, handler: action } : action; 396 | module.mutations[key] = mutation; 397 | }; 398 | } 399 | /** 400 | * The @MutationAction decorator turns this into an action that further calls a mutation 401 | * Both the action and the mutation are generated for you 402 | * 403 | * @param paramsOrTarget the params or the target class 404 | * @param key the name of the function 405 | * @param descriptor the function body 406 | * @constructor 407 | */ 408 | function MutationAction(paramsOrTarget, key, descriptor) { 409 | if (!key && !descriptor) { 410 | /* 411 | * This is the case when `paramsOrTarget` is params. 412 | * i.e. when used as - 413 | *
414 |             @MutationAction({mutate: ['incrCount']})
415 |             async getCountDelta() {
416 |               return {incrCount: 5}
417 |             }
418 |          * 
419 | */ 420 | return mutationActionDecoratorFactory(paramsOrTarget); 421 | } 422 | else { 423 | /* 424 | * This is the case when `paramsOrTarget` is target. 425 | * i.e. when used as - 426 | *
427 |             @MutationAction
428 |             async getCountDelta() {
429 |               return {incrCount: 5}
430 |             }
431 |          * 
432 | */ 433 | mutationActionDecoratorFactory({})(paramsOrTarget, key, descriptor); 434 | } 435 | } 436 | 437 | exports.Action = Action; 438 | exports.Module = Module; 439 | exports.Mutation = Mutation; 440 | exports.MutationAction = MutationAction; 441 | exports.VuexModule = VuexModule; 442 | exports.config = config; 443 | exports.getModule = getModule; 444 | //# sourceMappingURL=index.js.map 445 | -------------------------------------------------------------------------------- /dist/cjs/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sources":["../../src/helpers.ts","../../src/vuexmodule.ts","../../src/module/stateFactory.ts","../../src/module/staticGenerators.ts","../../src/module/index.ts","../../src/config.ts","../../src/action.ts","../../src/mutation.ts","../../src/mutationaction.ts"],"sourcesContent":["/**\n * Takes the properties on object from parameter source and adds them to the object\n * parameter target\n * @param {object} target Object to have properties copied onto from y\n * @param {object} source Object with properties to be copied to x\n */\nexport function addPropertiesToObject(target: any, source: any) {\n for (let k of Object.keys(source || {})) {\n Object.defineProperty(target, k, {\n get: () => source[k]\n })\n }\n}\n\n/**\n * Returns a namespaced name of the module to be used as a store getter\n * @param module\n */\nexport function getModuleName(module: any): string {\n if (!module._vmdModuleName) {\n throw new Error(`ERR_GET_MODULE_NAME : Could not get module accessor.\n Make sure your module has name, we can't make accessors for unnamed modules\n i.e. @Module({ name: 'something' })`)\n }\n return `vuexModuleDecorators/${module._vmdModuleName}`\n}\n","import {\n ActionTree,\n GetterTree,\n Module as Mod,\n ModuleTree,\n MutationTree,\n Store,\n ActionContext\n} from 'vuex'\nimport { getModuleName } from './helpers'\n\nexport class VuexModule, R = any> implements Mod {\n /*\n * To use with `extends Class` syntax along with decorators\n */\n static namespaced?: boolean\n static state?: any | (() => any)\n static getters?: GetterTree\n static actions?: ActionTree\n static mutations?: MutationTree\n static modules?: ModuleTree\n\n /*\n * To use with `new VuexModule({})` syntax\n */\n\n modules?: ModuleTree\n namespaced?: boolean\n getters?: GetterTree\n state?: S | (() => S)\n mutations?: MutationTree\n actions?: ActionTree\n context!: ActionContext\n\n constructor(module: Mod) {\n this.actions = module.actions\n this.mutations = module.mutations\n this.state = module.state\n this.getters = module.getters\n this.namespaced = module.namespaced\n this.modules = module.modules\n }\n}\ntype ConstructorOf = { new (...args: any[]): C }\n\nexport function getModule(\n moduleClass: ConstructorOf,\n store?: Store\n): M {\n const moduleName = getModuleName(moduleClass)\n if (store && store.getters[moduleName]) {\n return store.getters[moduleName]\n } else if ((moduleClass as any)._statics) {\n return (moduleClass as any)._statics\n }\n\n const genStatic: (providedStore?: Store) => M = (moduleClass as any)._genStatic\n if (!genStatic) {\n throw new Error(`ERR_GET_MODULE_NO_STATICS : Could not get module accessor.\n Make sure your module has name, we can't make accessors for unnamed modules\n i.e. @Module({ name: 'something' })`)\n }\n\n const storeModule = genStatic(store)\n\n if (store) {\n store.getters[moduleName] = storeModule\n } else {\n ;(moduleClass as any)._statics = storeModule\n }\n\n return storeModule\n}\n","import { Module as Mod } from 'vuex'\n\nconst reservedKeys = ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit']\nexport function stateFactory(module: Function & Mod) {\n const state = new module.prototype.constructor({})\n const s = {} as S\n Object.keys(state).forEach((key: string) => {\n if (reservedKeys.indexOf(key) !== -1) {\n if (typeof state[key] !== 'undefined') {\n throw new Error(\n `ERR_RESERVED_STATE_KEY_USED: You cannot use the following\n ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit']\n as fields in your module. These are reserved as they have special purpose in Vuex`\n )\n }\n return\n }\n if (state.hasOwnProperty(key)) {\n if (typeof state[key] !== 'function') {\n ;(s as any)[key] = state[key]\n }\n }\n })\n\n return s\n}\n","import { ActionTree, GetterTree, Module as Mod, MutationTree } from 'vuex'\nimport { DynamicModuleOptions } from '../moduleoptions'\n\nexport function staticStateGenerator(\n module: Function & Mod,\n modOpt: DynamicModuleOptions,\n statics: any\n) {\n const state: S = modOpt.stateFactory ? (module as any).state() : module.state\n Object.keys(state).forEach((key) => {\n if (state.hasOwnProperty(key)) {\n // If not undefined or function means it is a state value\n if (['undefined', 'function'].indexOf(typeof (state as any)[key]) === -1) {\n Object.defineProperty(statics, key, {\n get() {\n const path = modOpt.name.split('/')\n let data = statics.store.state\n for (let segment of path) {\n data = data[segment]\n }\n return data[key]\n }\n })\n }\n }\n })\n}\n\nexport function staticGetterGenerator(\n module: Function & Mod,\n modOpt: DynamicModuleOptions,\n statics: any\n) {\n Object.keys(module.getters as GetterTree).forEach((key) => {\n if (module.namespaced) {\n Object.defineProperty(statics, key, {\n get() {\n return statics.store.getters[`${modOpt.name}/${key}`]\n }\n })\n } else {\n Object.defineProperty(statics, key, {\n get() {\n return statics.store.getters[key]\n }\n })\n }\n })\n}\n\nexport function staticMutationGenerator(\n module: Function & Mod,\n modOpt: DynamicModuleOptions,\n statics: any\n) {\n Object.keys(module.mutations as MutationTree).forEach((key) => {\n if (module.namespaced) {\n statics[key] = function (...args: any[]) {\n statics.store.commit(`${modOpt.name}/${key}`, ...args)\n }\n } else {\n statics[key] = function (...args: any[]) {\n statics.store.commit(key, ...args)\n }\n }\n })\n}\n\nexport function staticActionGenerators(\n module: Function & Mod,\n modOpt: DynamicModuleOptions,\n statics: any\n) {\n Object.keys(module.actions as ActionTree).forEach((key) => {\n if (module.namespaced) {\n statics[key] = async function (...args: any[]) {\n return statics.store.dispatch(`${modOpt.name}/${key}`, ...args)\n }\n } else {\n statics[key] = async function (...args: any[]) {\n return statics.store.dispatch(key, ...args)\n }\n }\n })\n}\n","import { GetterTree, Module as Mod, Store } from 'vuex'\nimport { DynamicModuleOptions, ModuleOptions } from '../moduleoptions'\nimport { stateFactory as sf } from './stateFactory'\nimport { addPropertiesToObject } from '../helpers'\nimport {\n staticActionGenerators,\n staticGetterGenerator,\n staticMutationGenerator,\n staticStateGenerator\n} from './staticGenerators'\n\nfunction registerDynamicModule(module: Mod, modOpt: DynamicModuleOptions) {\n if (!modOpt.name) {\n throw new Error('Name of module not provided in decorator options')\n }\n\n if (!modOpt.store) {\n throw new Error('Store not provided in decorator options when using dynamic option')\n }\n\n modOpt.store.registerModule(\n modOpt.name, // TODO: Handle nested modules too in future\n module,\n { preserveState: modOpt.preserveState || false }\n )\n}\n\nfunction addGettersToModule(\n targetModule: Function & Mod,\n srcModule: Function & Mod\n) {\n Object.getOwnPropertyNames(srcModule.prototype).forEach((funcName: string) => {\n const descriptor = Object.getOwnPropertyDescriptor(\n srcModule.prototype,\n funcName\n ) as PropertyDescriptor\n if (descriptor.get && targetModule.getters) {\n targetModule.getters[funcName] = function (\n state: S,\n getters: GetterTree,\n rootState: any,\n rootGetters: GetterTree\n ) {\n const thisObj = { context: { state, getters, rootState, rootGetters } }\n addPropertiesToObject(thisObj, state)\n addPropertiesToObject(thisObj, getters)\n const got = (descriptor.get as Function).call(thisObj)\n return got\n }\n }\n })\n}\n\nfunction moduleDecoratorFactory(moduleOptions: ModuleOptions) {\n return function (constructor: TFunction): TFunction | void {\n const module: Function & Mod = constructor\n const stateFactory = () => sf(module)\n\n if (!module.state) {\n module.state = moduleOptions && moduleOptions.stateFactory ? stateFactory : stateFactory()\n }\n if (!module.getters) {\n module.getters = {} as GetterTree\n }\n if (!module.namespaced) {\n module.namespaced = moduleOptions && moduleOptions.namespaced\n }\n let parentModule = Object.getPrototypeOf(module)\n while (parentModule.name !== 'VuexModule' && parentModule.name !== '') {\n addGettersToModule(module, parentModule)\n parentModule = Object.getPrototypeOf(parentModule)\n }\n addGettersToModule(module, module)\n const modOpt = moduleOptions as DynamicModuleOptions\n if (modOpt.name) {\n Object.defineProperty(constructor, '_genStatic', {\n value: (store?: Store) => {\n let statics = { store: store || modOpt.store }\n if (!statics.store) {\n throw new Error(`ERR_STORE_NOT_PROVIDED: To use getModule(), either the module\n should be decorated with store in decorator, i.e. @Module({store: store}) or\n store should be passed when calling getModule(), i.e. getModule(MyModule, this.$store)`)\n }\n // =========== For statics ==============\n // ------ state -------\n staticStateGenerator(module, modOpt, statics)\n\n // ------- getters -------\n if (module.getters) {\n staticGetterGenerator(module, modOpt, statics)\n }\n\n // -------- mutations --------\n if (module.mutations) {\n staticMutationGenerator(module, modOpt, statics)\n }\n // -------- actions ---------\n if (module.actions) {\n staticActionGenerators(module, modOpt, statics)\n }\n return statics\n }\n })\n\n Object.defineProperty(constructor, '_vmdModuleName', {\n value: modOpt.name\n })\n }\n\n if (modOpt.dynamic) {\n registerDynamicModule(module, modOpt)\n }\n return constructor\n }\n}\n\nexport function Module(module: Function & Mod): void\nexport function Module(options: ModuleOptions): ClassDecorator\n\nexport function Module(modOrOpt: ModuleOptions | (Function & Mod)) {\n if (typeof (modOrOpt as any) === 'function') {\n /*\n * @Module decorator called without options (directly on the class definition)\n */\n moduleDecoratorFactory({})(modOrOpt as Function & Mod)\n } else {\n /*\n * @Module({...}) decorator called with options\n */\n return moduleDecoratorFactory(modOrOpt)\n }\n}\n","export const config: IConfig = {}\n\nexport interface IConfig {\n rawError?: boolean\n}\n","import { Action as Act, ActionContext, Module as Mod, Payload } from 'vuex'\nimport { getModule, VuexModule } from './vuexmodule'\nimport { addPropertiesToObject, getModuleName } from './helpers'\nimport { config } from './config'\n\n/**\n * Parameters that can be passed to the @Action decorator\n */\nexport interface ActionDecoratorParams {\n commit?: string\n rawError?: boolean\n root?: boolean\n}\nfunction actionDecoratorFactory(params?: ActionDecoratorParams): MethodDecorator {\n const { commit = undefined, rawError = !!config.rawError, root = false } = params || {}\n return function (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor) {\n const module = target.constructor as Mod\n if (!module.hasOwnProperty('actions')) {\n module.actions = Object.assign({}, module.actions)\n }\n const actionFunction: Function = descriptor.value\n const action: Act = async function (\n context: ActionContext,\n payload: Payload\n ) {\n try {\n let actionPayload = null\n\n if ((module as any)._genStatic) {\n const moduleName = getModuleName(module)\n const moduleAccessor = context.rootGetters[moduleName]\n ? context.rootGetters[moduleName]\n : getModule(module as typeof VuexModule)\n moduleAccessor.context = context\n actionPayload = await actionFunction.call(moduleAccessor, payload)\n } else {\n const thisObj = { context }\n addPropertiesToObject(thisObj, context.state)\n addPropertiesToObject(thisObj, context.getters)\n actionPayload = await actionFunction.call(thisObj, payload)\n }\n if (commit) {\n context.commit(commit, actionPayload)\n }\n return actionPayload\n } catch (e: any) {\n throw rawError\n ? e\n : new Error(\n 'ERR_ACTION_ACCESS_UNDEFINED: Are you trying to access ' +\n 'this.someMutation() or this.someGetter inside an @Action? \\n' +\n 'That works only in dynamic modules. \\n' +\n 'If not dynamic use this.context.commit(\"mutationName\", payload) ' +\n 'and this.context.getters[\"getterName\"]' +\n '\\n' +\n new Error(`Could not perform action ${key.toString()}`).stack +\n '\\n' +\n e.stack\n )\n }\n }\n module.actions![key as string] = root ? { root, handler: action } : action\n }\n}\n\nexport function Action(\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => R>\n): void\nexport function Action(params: ActionDecoratorParams): MethodDecorator\n\n/**\n * The @Action decorator turns an async function into an Vuex action\n *\n * @param targetOrParams the module class\n * @param key name of the action\n * @param descriptor the action function descriptor\n * @constructor\n */\nexport function Action(\n targetOrParams: T | ActionDecoratorParams,\n key?: string | symbol,\n descriptor?: TypedPropertyDescriptor<(...args: any[]) => R>\n) {\n if (!key && !descriptor) {\n /*\n * This is the case when `targetOrParams` is params.\n * i.e. when used as -\n *
\n        @Action({commit: 'incrCount'})\n        async getCountDelta() {\n          return 5\n        }\n     * 
\n */\n return actionDecoratorFactory(targetOrParams as ActionDecoratorParams)\n } else {\n /*\n * This is the case when @Action is called on action function\n * without any params\n *
\n     *   @Action\n     *   async doSomething() {\n     *    ...\n     *   }\n     * 
\n */\n actionDecoratorFactory()(targetOrParams, key!, descriptor!)\n }\n}\n","import { Module as Mod, Mutation as Mut, Payload } from 'vuex'\n\nexport function Mutation(\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => R>\n) {\n const module = target.constructor as Mod\n if (!module.hasOwnProperty('mutations')) {\n module.mutations = Object.assign({}, module.mutations)\n }\n const mutationFunction: Function = descriptor.value!\n const mutation: Mut = function (state: typeof target, payload: Payload) {\n mutationFunction.call(state, payload)\n }\n module.mutations![key as string] = mutation\n}\n","import { Action as Act, ActionContext, Module as Mod, Mutation as Mut, Payload, Store } from 'vuex'\nimport { addPropertiesToObject } from './helpers'\n\nexport interface MutationActionParams {\n mutate?: (keyof Partial)[]\n rawError?: boolean\n root?: boolean\n}\n\nfunction mutationActionDecoratorFactory(params: MutationActionParams) {\n return function (\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>>\n ) {\n const module = target.constructor as Mod\n if (!module.hasOwnProperty('mutations')) {\n module.mutations = Object.assign({}, module.mutations)\n }\n if (!module.hasOwnProperty('actions')) {\n module.actions = Object.assign({}, module.actions)\n }\n const mutactFunction = descriptor.value as (payload: any) => Promise\n\n const action: Act = async function (\n context: ActionContext,\n payload: Payload\n ) {\n try {\n const thisObj = { context }\n addPropertiesToObject(thisObj, context.state)\n addPropertiesToObject(thisObj, context.getters)\n const actionPayload = await mutactFunction.call(thisObj, payload)\n if (actionPayload === undefined) return\n context.commit(key as string, actionPayload)\n } catch (e: any) {\n if (params.rawError) {\n throw e\n } else {\n console.error('Could not perform action ' + key.toString())\n console.error(e)\n return Promise.reject(e)\n }\n }\n }\n\n const mutation: Mut = function (\n state: typeof target | Store,\n payload: Payload & { [k in keyof T]: any }\n ) {\n if (!params.mutate) {\n params.mutate = Object.keys(payload) as (keyof T)[]\n }\n for (let stateItem of params.mutate) {\n if (state.hasOwnProperty(stateItem) && payload.hasOwnProperty(stateItem)) {\n ;(state as T)[stateItem] = payload[stateItem]\n } else {\n throw new Error(`ERR_MUTATE_PARAMS_NOT_IN_PAYLOAD\n In @MutationAction, mutate: ['a', 'b', ...] array keys must\n match with return type = {a: {}, b: {}, ...} and must\n also be in state.`)\n }\n }\n }\n module.actions![key as string] = params.root ? { root: true, handler: action } : action\n module.mutations![key as string] = mutation\n }\n}\n\nexport function MutationAction(\n target: { [k in keyof T]: T[k] | null },\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise>\n): void\n\nexport function MutationAction(\n params: MutationActionParams\n): (\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise>\n) => void\n\n/**\n * The @MutationAction decorator turns this into an action that further calls a mutation\n * Both the action and the mutation are generated for you\n *\n * @param paramsOrTarget the params or the target class\n * @param key the name of the function\n * @param descriptor the function body\n * @constructor\n */\nexport function MutationAction(\n paramsOrTarget: MutationActionParams | M,\n key?: string | symbol,\n descriptor?: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>>\n):\n | ((\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>>\n ) => void)\n | void {\n if (!key && !descriptor) {\n /*\n * This is the case when `paramsOrTarget` is params.\n * i.e. when used as -\n *
\n        @MutationAction({mutate: ['incrCount']})\n        async getCountDelta() {\n          return {incrCount: 5}\n        }\n     * 
\n */\n return mutationActionDecoratorFactory(paramsOrTarget as MutationActionParams)\n } else {\n /*\n * This is the case when `paramsOrTarget` is target.\n * i.e. when used as -\n *
\n        @MutationAction\n        async getCountDelta() {\n          return {incrCount: 5}\n        }\n     * 
\n */\n mutationActionDecoratorFactory({} as MutationActionParams)(\n paramsOrTarget as K,\n key!,\n descriptor!\n )\n }\n}\n"],"names":["stateFactory","sf"],"mappings":";;;;AAAA;;;;;;SAMgB,qBAAqB,CAAC,MAAW,EAAE,MAAW;IAC5D,KAAK,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE;QACvC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE;YAC/B,GAAG,EAAE,MAAM,MAAM,CAAC,CAAC,CAAC;SACrB,CAAC,CAAA;KACH;AACH,CAAC;AAED;;;;SAIgB,aAAa,CAAC,MAAW;IACvC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;QAC1B,MAAM,IAAI,KAAK,CAAC;;0CAEsB,CAAC,CAAA;KACxC;IACD,OAAO,wBAAwB,MAAM,CAAC,cAAc,EAAE,CAAA;AACxD;;MCda,UAAU;IAuBrB,YAAY,MAAmB;QAC7B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;QAC7B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;QACjC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAA;QACzB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;QAC7B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAA;QACnC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;KAC9B;CACF;SAGe,SAAS,CACvB,WAA6B,EAC7B,KAAkB;IAElB,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAA;IAC7C,IAAI,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;QACtC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;KACjC;SAAM,IAAK,WAAmB,CAAC,QAAQ,EAAE;QACxC,OAAQ,WAAmB,CAAC,QAAQ,CAAA;KACrC;IAED,MAAM,SAAS,GAAuC,WAAmB,CAAC,UAAU,CAAA;IACpF,IAAI,CAAC,SAAS,EAAE;QACd,MAAM,IAAI,KAAK,CAAC;;0CAEsB,CAAC,CAAA;KACxC;IAED,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IAEpC,IAAI,KAAK,EAAE;QACT,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,WAAW,CAAA;KACxC;SAAM;QACH,WAAmB,CAAC,QAAQ,GAAG,WAAW,CAAA;KAC7C;IAED,OAAO,WAAW,CAAA;AACpB;;ACtEA,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAA;SACpF,YAAY,CAAI,MAA8B;IAC5D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;IAClD,MAAM,CAAC,GAAG,EAAO,CAAA;IACjB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,GAAW;QACrC,IAAI,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE;YACpC,IAAI,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,WAAW,EAAE;gBACrC,MAAM,IAAI,KAAK,CACb;;0FAEgF,CACjF,CAAA;aACF;YACD,OAAM;SACP;QACD,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;YAC7B,IAAI,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,UAAU,EAAE;gBAClC,CAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;aAC9B;SACF;KACF,CAAC,CAAA;IAEF,OAAO,CAAC,CAAA;AACV;;SCtBgB,oBAAoB,CAClC,MAA8B,EAC9B,MAA4B,EAC5B,OAAY;IAEZ,MAAM,KAAK,GAAM,MAAM,CAAC,YAAY,GAAI,MAAc,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,KAAK,CAAA;IAC7E,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG;QAC7B,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;;YAE7B,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,OAAQ,KAAa,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE;gBACxE,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE;oBAClC,GAAG;wBACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;wBACnC,IAAI,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAA;wBAC9B,KAAK,IAAI,OAAO,IAAI,IAAI,EAAE;4BACxB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;yBACrB;wBACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;qBACjB;iBACF,CAAC,CAAA;aACH;SACF;KACF,CAAC,CAAA;AACJ,CAAC;SAEe,qBAAqB,CACnC,MAA8B,EAC9B,MAA4B,EAC5B,OAAY;IAEZ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAA6B,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG;QAC5D,IAAI,MAAM,CAAC,UAAU,EAAE;YACrB,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE;gBAClC,GAAG;oBACD,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAA;iBACtD;aACF,CAAC,CAAA;SACH;aAAM;YACL,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE;gBAClC,GAAG;oBACD,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;iBAClC;aACF,CAAC,CAAA;SACH;KACF,CAAC,CAAA;AACJ,CAAC;SAEe,uBAAuB,CACrC,MAA8B,EAC9B,MAA4B,EAC5B,OAAY;IAEZ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAA4B,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG;QAC3D,IAAI,MAAM,CAAC,UAAU,EAAE;YACrB,OAAO,CAAC,GAAG,CAAC,GAAG,UAAU,GAAG,IAAW;gBACrC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAA;aACvD,CAAA;SACF;aAAM;YACL,OAAO,CAAC,GAAG,CAAC,GAAG,UAAU,GAAG,IAAW;gBACrC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;aACnC,CAAA;SACF;KACF,CAAC,CAAA;AACJ,CAAC;SAEe,sBAAsB,CACpC,MAA8B,EAC9B,MAA4B,EAC5B,OAAY;IAEZ,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAA6B,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG;QAC5D,IAAI,MAAM,CAAC,UAAU,EAAE;YACrB,OAAO,CAAC,GAAG,CAAC,GAAG,gBAAgB,GAAG,IAAW;gBAC3C,OAAO,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAA;aAChE,CAAA;SACF;aAAM;YACL,OAAO,CAAC,GAAG,CAAC,GAAG,gBAAgB,GAAG,IAAW;gBAC3C,OAAO,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;aAC5C,CAAA;SACF;KACF,CAAC,CAAA;AACJ;;ACzEA,SAAS,qBAAqB,CAAI,MAAmB,EAAE,MAA4B;IACjF,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAChB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;KACpE;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;QACjB,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAA;KACrF;IAED,MAAM,CAAC,KAAK,CAAC,cAAc,CACzB,MAAM,CAAC,IAAI;IACX,MAAM,EACN,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,KAAK,EAAE,CACjD,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB,CACzB,YAAoC,EACpC,SAAiC;IAEjC,MAAM,CAAC,mBAAmB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,QAAgB;QACvE,MAAM,UAAU,GAAG,MAAM,CAAC,wBAAwB,CAChD,SAAS,CAAC,SAAS,EACnB,QAAQ,CACa,CAAA;QACvB,IAAI,UAAU,CAAC,GAAG,IAAI,YAAY,CAAC,OAAO,EAAE;YAC1C,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,UAC/B,KAAQ,EACR,OAA2B,EAC3B,SAAc,EACd,WAAiC;gBAEjC,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,CAAA;gBACvE,qBAAqB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;gBACrC,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;gBACvC,MAAM,GAAG,GAAI,UAAU,CAAC,GAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBACtD,OAAO,GAAG,CAAA;aACX,CAAA;SACF;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAI,aAA4B;IAC7D,OAAO,UAAsC,WAAsB;QACjE,MAAM,MAAM,GAA2B,WAAW,CAAA;QAClD,MAAMA,cAAY,GAAG,MAAMC,YAAE,CAAC,MAAM,CAAC,CAAA;QAErC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;YACjB,MAAM,CAAC,KAAK,GAAG,aAAa,IAAI,aAAa,CAAC,YAAY,GAAGD,cAAY,GAAGA,cAAY,EAAE,CAAA;SAC3F;QACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YACnB,MAAM,CAAC,OAAO,GAAG,EAAwB,CAAA;SAC1C;QACD,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;YACtB,MAAM,CAAC,UAAU,GAAG,aAAa,IAAI,aAAa,CAAC,UAAU,CAAA;SAC9D;QACD,IAAI,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA;QAChD,OAAO,YAAY,CAAC,IAAI,KAAK,YAAY,IAAI,YAAY,CAAC,IAAI,KAAK,EAAE,EAAE;YACrE,kBAAkB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;YACxC,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;SACnD;QACD,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAClC,MAAM,MAAM,GAAG,aAAqC,CAAA;QACpD,IAAI,MAAM,CAAC,IAAI,EAAE;YACf,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,YAAY,EAAE;gBAC/C,KAAK,EAAE,CAAC,KAAkB;oBACxB,IAAI,OAAO,GAAG,EAAE,KAAK,EAAE,KAAK,IAAI,MAAM,CAAC,KAAK,EAAE,CAAA;oBAC9C,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;wBAClB,MAAM,IAAI,KAAK,CAAC;;mGAEuE,CAAC,CAAA;qBACzF;;;oBAGD,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;;oBAG7C,IAAI,MAAM,CAAC,OAAO,EAAE;wBAClB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;qBAC/C;;oBAGD,IAAI,MAAM,CAAC,SAAS,EAAE;wBACpB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;qBACjD;;oBAED,IAAI,MAAM,CAAC,OAAO,EAAE;wBAClB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;qBAChD;oBACD,OAAO,OAAO,CAAA;iBACf;aACF,CAAC,CAAA;YAEF,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,gBAAgB,EAAE;gBACnD,KAAK,EAAE,MAAM,CAAC,IAAI;aACnB,CAAC,CAAA;SACH;QAED,IAAI,MAAM,CAAC,OAAO,EAAE;YAClB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;SACtC;QACD,OAAO,WAAW,CAAA;KACnB,CAAA;AACH,CAAC;SAKe,MAAM,CAAI,QAAkD;IAC1E,IAAI,OAAQ,QAAgB,KAAK,UAAU,EAAE;;;;QAI3C,sBAAsB,CAAC,EAAE,CAAC,CAAC,QAAkC,CAAC,CAAA;KAC/D;SAAM;;;;QAIL,OAAO,sBAAsB,CAAC,QAAQ,CAAC,CAAA;KACxC;AACH;;MCnIa,MAAM,GAAY;;ACa/B,SAAS,sBAAsB,CAAI,MAA8B;IAC/D,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,GAAG,KAAK,EAAE,GAAG,MAAM,IAAI,EAAE,CAAA;IACvF,OAAO,UAAU,MAAc,EAAE,GAAoB,EAAE,UAAwC;QAC7F,MAAM,MAAM,GAAG,MAAM,CAAC,WAA0B,CAAA;QAChD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE;YACrC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;SACnD;QACD,MAAM,cAAc,GAAa,UAAU,CAAC,KAAK,CAAA;QACjD,MAAM,MAAM,GAA4B,gBACtC,OAA0C,EAC1C,OAAgB;YAEhB,IAAI;gBACF,IAAI,aAAa,GAAG,IAAI,CAAA;gBAExB,IAAK,MAAc,CAAC,UAAU,EAAE;oBAC9B,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;oBACxC,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC;0BAClD,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC;0BAC/B,SAAS,CAAC,MAA2B,CAAC,CAAA;oBAC1C,cAAc,CAAC,OAAO,GAAG,OAAO,CAAA;oBAChC,aAAa,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;iBACnE;qBAAM;oBACL,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,CAAA;oBAC3B,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;oBAC7C,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;oBAC/C,aAAa,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;iBAC5D;gBACD,IAAI,MAAM,EAAE;oBACV,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;iBACtC;gBACD,OAAO,aAAa,CAAA;aACrB;YAAC,OAAO,CAAM,EAAE;gBACf,MAAM,QAAQ;sBACV,CAAC;sBACD,IAAI,KAAK,CACP,wDAAwD;wBACtD,8DAA8D;wBAC9D,wCAAwC;wBACxC,kEAAkE;wBAClE,wCAAwC;wBACxC,IAAI;wBACJ,IAAI,KAAK,CAAC,4BAA4B,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK;wBAC7D,IAAI;wBACJ,CAAC,CAAC,KAAK,CACV,CAAA;aACN;SACF,CAAA;QACD,MAAM,CAAC,OAAQ,CAAC,GAAa,CAAC,GAAG,IAAI,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;KAC3E,CAAA;AACH,CAAC;AASD;;;;;;;;SAQgB,MAAM,CACpB,cAAyC,EACzC,GAAqB,EACrB,UAA2D;IAE3D,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE;;;;;;;;;;;QAWvB,OAAO,sBAAsB,CAAC,cAAuC,CAAC,CAAA;KACvE;SAAM;;;;;;;;;;;QAWL,sBAAsB,EAAE,CAAC,cAAc,EAAE,GAAI,EAAE,UAAW,CAAC,CAAA;KAC5D;AACH;;SC5GgB,QAAQ,CACtB,MAAS,EACT,GAAoB,EACpB,UAA0D;IAE1D,MAAM,MAAM,GAAG,MAAM,CAAC,WAA0B,CAAA;IAChD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE;QACvC,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;KACvD;IACD,MAAM,gBAAgB,GAAa,UAAU,CAAC,KAAM,CAAA;IACpD,MAAM,QAAQ,GAAuB,UAAU,KAAoB,EAAE,OAAgB;QACnF,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;KACtC,CAAA;IACD,MAAM,CAAC,SAAU,CAAC,GAAa,CAAC,GAAG,QAAQ,CAAA;AAC7C;;ACPA,SAAS,8BAA8B,CAAmB,MAA+B;IACvF,OAAO,UACL,MAAS,EACT,GAAoB,EACpB,UAAwF;QAExF,MAAM,MAAM,GAAG,MAAM,CAAC,WAA0B,CAAA;QAChD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE;YACvC,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAA;SACvD;QACD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE;YACrC,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;SACnD;QACD,MAAM,cAAc,GAAG,UAAU,CAAC,KAAuC,CAAA;QAEzE,MAAM,MAAM,GAA4B,gBACtC,OAA0C,EAC1C,OAAgB;YAEhB,IAAI;gBACF,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,CAAA;gBAC3B,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;gBAC7C,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;gBAC/C,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;gBACjE,IAAI,aAAa,KAAK,SAAS;oBAAE,OAAM;gBACvC,OAAO,CAAC,MAAM,CAAC,GAAa,EAAE,aAAa,CAAC,CAAA;aAC7C;YAAC,OAAO,CAAM,EAAE;gBACf,IAAI,MAAM,CAAC,QAAQ,EAAE;oBACnB,MAAM,CAAC,CAAA;iBACR;qBAAM;oBACL,OAAO,CAAC,KAAK,CAAC,2BAA2B,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;oBAC3D,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;oBAChB,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;iBACzB;aACF;SACF,CAAA;QAED,MAAM,QAAQ,GAAuB,UACnC,KAA+B,EAC/B,OAA0C;YAE1C,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;gBAClB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAgB,CAAA;aACpD;YACD,KAAK,IAAI,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE;gBACnC,IAAI,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE;oBACtE,KAAW,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;iBAC9C;qBAAM;oBACL,MAAM,IAAI,KAAK,CAAC;;;4BAGE,CAAC,CAAA;iBACpB;aACF;SACF,CAAA;QACD,MAAM,CAAC,OAAQ,CAAC,GAAa,CAAC,GAAG,MAAM,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;QACvF,MAAM,CAAC,SAAU,CAAC,GAAa,CAAC,GAAG,QAAQ,CAAA;KAC5C,CAAA;AACH,CAAC;AAgBD;;;;;;;;;SASgB,cAAc,CAC5B,cAA2C,EAC3C,GAAqB,EACrB,UAAyF;IAQzF,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE;;;;;;;;;;;QAWvB,OAAO,8BAA8B,CAAC,cAAyC,CAAC,CAAA;KACjF;SAAM;;;;;;;;;;;QAWL,8BAA8B,CAAC,EAA6B,CAAC,CAC3D,cAAmB,EACnB,GAAI,EACJ,UAAW,CACZ,CAAA;KACF;AACH;;;;;;;;;;"} -------------------------------------------------------------------------------- /dist/esm/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Takes the properties on object from parameter source and adds them to the object 3 | * parameter target 4 | * @param {object} target Object to have properties copied onto from y 5 | * @param {object} source Object with properties to be copied to x 6 | */ 7 | function addPropertiesToObject(target, source) { 8 | for (let k of Object.keys(source || {})) { 9 | Object.defineProperty(target, k, { 10 | get: () => source[k] 11 | }); 12 | } 13 | } 14 | /** 15 | * Returns a namespaced name of the module to be used as a store getter 16 | * @param module 17 | */ 18 | function getModuleName(module) { 19 | if (!module._vmdModuleName) { 20 | throw new Error(`ERR_GET_MODULE_NAME : Could not get module accessor. 21 | Make sure your module has name, we can't make accessors for unnamed modules 22 | i.e. @Module({ name: 'something' })`); 23 | } 24 | return `vuexModuleDecorators/${module._vmdModuleName}`; 25 | } 26 | 27 | class VuexModule { 28 | constructor(module) { 29 | this.actions = module.actions; 30 | this.mutations = module.mutations; 31 | this.state = module.state; 32 | this.getters = module.getters; 33 | this.namespaced = module.namespaced; 34 | this.modules = module.modules; 35 | } 36 | } 37 | function getModule(moduleClass, store) { 38 | const moduleName = getModuleName(moduleClass); 39 | if (store && store.getters[moduleName]) { 40 | return store.getters[moduleName]; 41 | } 42 | else if (moduleClass._statics) { 43 | return moduleClass._statics; 44 | } 45 | const genStatic = moduleClass._genStatic; 46 | if (!genStatic) { 47 | throw new Error(`ERR_GET_MODULE_NO_STATICS : Could not get module accessor. 48 | Make sure your module has name, we can't make accessors for unnamed modules 49 | i.e. @Module({ name: 'something' })`); 50 | } 51 | const storeModule = genStatic(store); 52 | if (store) { 53 | store.getters[moduleName] = storeModule; 54 | } 55 | else { 56 | moduleClass._statics = storeModule; 57 | } 58 | return storeModule; 59 | } 60 | 61 | const reservedKeys = ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit']; 62 | function stateFactory(module) { 63 | const state = new module.prototype.constructor({}); 64 | const s = {}; 65 | Object.keys(state).forEach((key) => { 66 | if (reservedKeys.indexOf(key) !== -1) { 67 | if (typeof state[key] !== 'undefined') { 68 | throw new Error(`ERR_RESERVED_STATE_KEY_USED: You cannot use the following 69 | ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit'] 70 | as fields in your module. These are reserved as they have special purpose in Vuex`); 71 | } 72 | return; 73 | } 74 | if (state.hasOwnProperty(key)) { 75 | if (typeof state[key] !== 'function') { 76 | s[key] = state[key]; 77 | } 78 | } 79 | }); 80 | return s; 81 | } 82 | 83 | function staticStateGenerator(module, modOpt, statics) { 84 | const state = modOpt.stateFactory ? module.state() : module.state; 85 | Object.keys(state).forEach((key) => { 86 | if (state.hasOwnProperty(key)) { 87 | // If not undefined or function means it is a state value 88 | if (['undefined', 'function'].indexOf(typeof state[key]) === -1) { 89 | Object.defineProperty(statics, key, { 90 | get() { 91 | const path = modOpt.name.split('/'); 92 | let data = statics.store.state; 93 | for (let segment of path) { 94 | data = data[segment]; 95 | } 96 | return data[key]; 97 | } 98 | }); 99 | } 100 | } 101 | }); 102 | } 103 | function staticGetterGenerator(module, modOpt, statics) { 104 | Object.keys(module.getters).forEach((key) => { 105 | if (module.namespaced) { 106 | Object.defineProperty(statics, key, { 107 | get() { 108 | return statics.store.getters[`${modOpt.name}/${key}`]; 109 | } 110 | }); 111 | } 112 | else { 113 | Object.defineProperty(statics, key, { 114 | get() { 115 | return statics.store.getters[key]; 116 | } 117 | }); 118 | } 119 | }); 120 | } 121 | function staticMutationGenerator(module, modOpt, statics) { 122 | Object.keys(module.mutations).forEach((key) => { 123 | if (module.namespaced) { 124 | statics[key] = function (...args) { 125 | statics.store.commit(`${modOpt.name}/${key}`, ...args); 126 | }; 127 | } 128 | else { 129 | statics[key] = function (...args) { 130 | statics.store.commit(key, ...args); 131 | }; 132 | } 133 | }); 134 | } 135 | function staticActionGenerators(module, modOpt, statics) { 136 | Object.keys(module.actions).forEach((key) => { 137 | if (module.namespaced) { 138 | statics[key] = async function (...args) { 139 | return statics.store.dispatch(`${modOpt.name}/${key}`, ...args); 140 | }; 141 | } 142 | else { 143 | statics[key] = async function (...args) { 144 | return statics.store.dispatch(key, ...args); 145 | }; 146 | } 147 | }); 148 | } 149 | 150 | function registerDynamicModule(module, modOpt) { 151 | if (!modOpt.name) { 152 | throw new Error('Name of module not provided in decorator options'); 153 | } 154 | if (!modOpt.store) { 155 | throw new Error('Store not provided in decorator options when using dynamic option'); 156 | } 157 | modOpt.store.registerModule(modOpt.name, // TODO: Handle nested modules too in future 158 | module, { preserveState: modOpt.preserveState || false }); 159 | } 160 | function addGettersToModule(targetModule, srcModule) { 161 | Object.getOwnPropertyNames(srcModule.prototype).forEach((funcName) => { 162 | const descriptor = Object.getOwnPropertyDescriptor(srcModule.prototype, funcName); 163 | if (descriptor.get && targetModule.getters) { 164 | targetModule.getters[funcName] = function (state, getters, rootState, rootGetters) { 165 | const thisObj = { context: { state, getters, rootState, rootGetters } }; 166 | addPropertiesToObject(thisObj, state); 167 | addPropertiesToObject(thisObj, getters); 168 | const got = descriptor.get.call(thisObj); 169 | return got; 170 | }; 171 | } 172 | }); 173 | } 174 | function moduleDecoratorFactory(moduleOptions) { 175 | return function (constructor) { 176 | const module = constructor; 177 | const stateFactory$1 = () => stateFactory(module); 178 | if (!module.state) { 179 | module.state = moduleOptions && moduleOptions.stateFactory ? stateFactory$1 : stateFactory$1(); 180 | } 181 | if (!module.getters) { 182 | module.getters = {}; 183 | } 184 | if (!module.namespaced) { 185 | module.namespaced = moduleOptions && moduleOptions.namespaced; 186 | } 187 | let parentModule = Object.getPrototypeOf(module); 188 | while (parentModule.name !== 'VuexModule' && parentModule.name !== '') { 189 | addGettersToModule(module, parentModule); 190 | parentModule = Object.getPrototypeOf(parentModule); 191 | } 192 | addGettersToModule(module, module); 193 | const modOpt = moduleOptions; 194 | if (modOpt.name) { 195 | Object.defineProperty(constructor, '_genStatic', { 196 | value: (store) => { 197 | let statics = { store: store || modOpt.store }; 198 | if (!statics.store) { 199 | throw new Error(`ERR_STORE_NOT_PROVIDED: To use getModule(), either the module 200 | should be decorated with store in decorator, i.e. @Module({store: store}) or 201 | store should be passed when calling getModule(), i.e. getModule(MyModule, this.$store)`); 202 | } 203 | // =========== For statics ============== 204 | // ------ state ------- 205 | staticStateGenerator(module, modOpt, statics); 206 | // ------- getters ------- 207 | if (module.getters) { 208 | staticGetterGenerator(module, modOpt, statics); 209 | } 210 | // -------- mutations -------- 211 | if (module.mutations) { 212 | staticMutationGenerator(module, modOpt, statics); 213 | } 214 | // -------- actions --------- 215 | if (module.actions) { 216 | staticActionGenerators(module, modOpt, statics); 217 | } 218 | return statics; 219 | } 220 | }); 221 | Object.defineProperty(constructor, '_vmdModuleName', { 222 | value: modOpt.name 223 | }); 224 | } 225 | if (modOpt.dynamic) { 226 | registerDynamicModule(module, modOpt); 227 | } 228 | return constructor; 229 | }; 230 | } 231 | function Module(modOrOpt) { 232 | if (typeof modOrOpt === 'function') { 233 | /* 234 | * @Module decorator called without options (directly on the class definition) 235 | */ 236 | moduleDecoratorFactory({})(modOrOpt); 237 | } 238 | else { 239 | /* 240 | * @Module({...}) decorator called with options 241 | */ 242 | return moduleDecoratorFactory(modOrOpt); 243 | } 244 | } 245 | 246 | const config = {}; 247 | 248 | function actionDecoratorFactory(params) { 249 | const { commit = undefined, rawError = !!config.rawError, root = false } = params || {}; 250 | return function (target, key, descriptor) { 251 | const module = target.constructor; 252 | if (!module.hasOwnProperty('actions')) { 253 | module.actions = Object.assign({}, module.actions); 254 | } 255 | const actionFunction = descriptor.value; 256 | const action = async function (context, payload) { 257 | try { 258 | let actionPayload = null; 259 | if (module._genStatic) { 260 | const moduleName = getModuleName(module); 261 | const moduleAccessor = context.rootGetters[moduleName] 262 | ? context.rootGetters[moduleName] 263 | : getModule(module); 264 | moduleAccessor.context = context; 265 | actionPayload = await actionFunction.call(moduleAccessor, payload); 266 | } 267 | else { 268 | const thisObj = { context }; 269 | addPropertiesToObject(thisObj, context.state); 270 | addPropertiesToObject(thisObj, context.getters); 271 | actionPayload = await actionFunction.call(thisObj, payload); 272 | } 273 | if (commit) { 274 | context.commit(commit, actionPayload); 275 | } 276 | return actionPayload; 277 | } 278 | catch (e) { 279 | throw rawError 280 | ? e 281 | : new Error('ERR_ACTION_ACCESS_UNDEFINED: Are you trying to access ' + 282 | 'this.someMutation() or this.someGetter inside an @Action? \n' + 283 | 'That works only in dynamic modules. \n' + 284 | 'If not dynamic use this.context.commit("mutationName", payload) ' + 285 | 'and this.context.getters["getterName"]' + 286 | '\n' + 287 | new Error(`Could not perform action ${key.toString()}`).stack + 288 | '\n' + 289 | e.stack); 290 | } 291 | }; 292 | module.actions[key] = root ? { root, handler: action } : action; 293 | }; 294 | } 295 | /** 296 | * The @Action decorator turns an async function into an Vuex action 297 | * 298 | * @param targetOrParams the module class 299 | * @param key name of the action 300 | * @param descriptor the action function descriptor 301 | * @constructor 302 | */ 303 | function Action(targetOrParams, key, descriptor) { 304 | if (!key && !descriptor) { 305 | /* 306 | * This is the case when `targetOrParams` is params. 307 | * i.e. when used as - 308 | *
309 |             @Action({commit: 'incrCount'})
310 |             async getCountDelta() {
311 |               return 5
312 |             }
313 |          * 
314 | */ 315 | return actionDecoratorFactory(targetOrParams); 316 | } 317 | else { 318 | /* 319 | * This is the case when @Action is called on action function 320 | * without any params 321 | *
322 |          *   @Action
323 |          *   async doSomething() {
324 |          *    ...
325 |          *   }
326 |          * 
327 | */ 328 | actionDecoratorFactory()(targetOrParams, key, descriptor); 329 | } 330 | } 331 | 332 | function Mutation(target, key, descriptor) { 333 | const module = target.constructor; 334 | if (!module.hasOwnProperty('mutations')) { 335 | module.mutations = Object.assign({}, module.mutations); 336 | } 337 | const mutationFunction = descriptor.value; 338 | const mutation = function (state, payload) { 339 | mutationFunction.call(state, payload); 340 | }; 341 | module.mutations[key] = mutation; 342 | } 343 | 344 | function mutationActionDecoratorFactory(params) { 345 | return function (target, key, descriptor) { 346 | const module = target.constructor; 347 | if (!module.hasOwnProperty('mutations')) { 348 | module.mutations = Object.assign({}, module.mutations); 349 | } 350 | if (!module.hasOwnProperty('actions')) { 351 | module.actions = Object.assign({}, module.actions); 352 | } 353 | const mutactFunction = descriptor.value; 354 | const action = async function (context, payload) { 355 | try { 356 | const thisObj = { context }; 357 | addPropertiesToObject(thisObj, context.state); 358 | addPropertiesToObject(thisObj, context.getters); 359 | const actionPayload = await mutactFunction.call(thisObj, payload); 360 | if (actionPayload === undefined) 361 | return; 362 | context.commit(key, actionPayload); 363 | } 364 | catch (e) { 365 | if (params.rawError) { 366 | throw e; 367 | } 368 | else { 369 | console.error('Could not perform action ' + key.toString()); 370 | console.error(e); 371 | return Promise.reject(e); 372 | } 373 | } 374 | }; 375 | const mutation = function (state, payload) { 376 | if (!params.mutate) { 377 | params.mutate = Object.keys(payload); 378 | } 379 | for (let stateItem of params.mutate) { 380 | if (state.hasOwnProperty(stateItem) && payload.hasOwnProperty(stateItem)) { 381 | state[stateItem] = payload[stateItem]; 382 | } 383 | else { 384 | throw new Error(`ERR_MUTATE_PARAMS_NOT_IN_PAYLOAD 385 | In @MutationAction, mutate: ['a', 'b', ...] array keys must 386 | match with return type = {a: {}, b: {}, ...} and must 387 | also be in state.`); 388 | } 389 | } 390 | }; 391 | module.actions[key] = params.root ? { root: true, handler: action } : action; 392 | module.mutations[key] = mutation; 393 | }; 394 | } 395 | /** 396 | * The @MutationAction decorator turns this into an action that further calls a mutation 397 | * Both the action and the mutation are generated for you 398 | * 399 | * @param paramsOrTarget the params or the target class 400 | * @param key the name of the function 401 | * @param descriptor the function body 402 | * @constructor 403 | */ 404 | function MutationAction(paramsOrTarget, key, descriptor) { 405 | if (!key && !descriptor) { 406 | /* 407 | * This is the case when `paramsOrTarget` is params. 408 | * i.e. when used as - 409 | *
410 |             @MutationAction({mutate: ['incrCount']})
411 |             async getCountDelta() {
412 |               return {incrCount: 5}
413 |             }
414 |          * 
415 | */ 416 | return mutationActionDecoratorFactory(paramsOrTarget); 417 | } 418 | else { 419 | /* 420 | * This is the case when `paramsOrTarget` is target. 421 | * i.e. when used as - 422 | *
423 |             @MutationAction
424 |             async getCountDelta() {
425 |               return {incrCount: 5}
426 |             }
427 |          * 
428 | */ 429 | mutationActionDecoratorFactory({})(paramsOrTarget, key, descriptor); 430 | } 431 | } 432 | 433 | export { Action, Module, Mutation, MutationAction, VuexModule, config, getModule }; 434 | //# sourceMappingURL=index.js.map 435 | -------------------------------------------------------------------------------- /dist/esm/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sources":["../../src/helpers.ts","../../src/vuexmodule.ts","../../src/module/stateFactory.ts","../../src/module/staticGenerators.ts","../../src/module/index.ts","../../src/config.ts","../../src/action.ts","../../src/mutation.ts","../../src/mutationaction.ts"],"sourcesContent":["/**\n * Takes the properties on object from parameter source and adds them to the object\n * parameter target\n * @param {object} target Object to have properties copied onto from y\n * @param {object} source Object with properties to be copied to x\n */\nexport function addPropertiesToObject(target: any, source: any) {\n for (let k of Object.keys(source || {})) {\n Object.defineProperty(target, k, {\n get: () => source[k]\n })\n }\n}\n\n/**\n * Returns a namespaced name of the module to be used as a store getter\n * @param module\n */\nexport function getModuleName(module: any): string {\n if (!module._vmdModuleName) {\n throw new Error(`ERR_GET_MODULE_NAME : Could not get module accessor.\n Make sure your module has name, we can't make accessors for unnamed modules\n i.e. @Module({ name: 'something' })`)\n }\n return `vuexModuleDecorators/${module._vmdModuleName}`\n}\n","import {\n ActionTree,\n GetterTree,\n Module as Mod,\n ModuleTree,\n MutationTree,\n Store,\n ActionContext\n} from 'vuex'\nimport { getModuleName } from './helpers'\n\nexport class VuexModule, R = any> implements Mod {\n /*\n * To use with `extends Class` syntax along with decorators\n */\n static namespaced?: boolean\n static state?: any | (() => any)\n static getters?: GetterTree\n static actions?: ActionTree\n static mutations?: MutationTree\n static modules?: ModuleTree\n\n /*\n * To use with `new VuexModule({})` syntax\n */\n\n modules?: ModuleTree\n namespaced?: boolean\n getters?: GetterTree\n state?: S | (() => S)\n mutations?: MutationTree\n actions?: ActionTree\n context!: ActionContext\n\n constructor(module: Mod) {\n this.actions = module.actions\n this.mutations = module.mutations\n this.state = module.state\n this.getters = module.getters\n this.namespaced = module.namespaced\n this.modules = module.modules\n }\n}\ntype ConstructorOf = { new (...args: any[]): C }\n\nexport function getModule(\n moduleClass: ConstructorOf,\n store?: Store\n): M {\n const moduleName = getModuleName(moduleClass)\n if (store && store.getters[moduleName]) {\n return store.getters[moduleName]\n } else if ((moduleClass as any)._statics) {\n return (moduleClass as any)._statics\n }\n\n const genStatic: (providedStore?: Store) => M = (moduleClass as any)._genStatic\n if (!genStatic) {\n throw new Error(`ERR_GET_MODULE_NO_STATICS : Could not get module accessor.\n Make sure your module has name, we can't make accessors for unnamed modules\n i.e. @Module({ name: 'something' })`)\n }\n\n const storeModule = genStatic(store)\n\n if (store) {\n store.getters[moduleName] = storeModule\n } else {\n ;(moduleClass as any)._statics = storeModule\n }\n\n return storeModule\n}\n","import { Module as Mod } from 'vuex'\n\nconst reservedKeys = ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit']\nexport function stateFactory(module: Function & Mod) {\n const state = new module.prototype.constructor({})\n const s = {} as S\n Object.keys(state).forEach((key: string) => {\n if (reservedKeys.indexOf(key) !== -1) {\n if (typeof state[key] !== 'undefined') {\n throw new Error(\n `ERR_RESERVED_STATE_KEY_USED: You cannot use the following\n ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit']\n as fields in your module. These are reserved as they have special purpose in Vuex`\n )\n }\n return\n }\n if (state.hasOwnProperty(key)) {\n if (typeof state[key] !== 'function') {\n ;(s as any)[key] = state[key]\n }\n }\n })\n\n return s\n}\n","import { ActionTree, GetterTree, Module as Mod, MutationTree } from 'vuex'\nimport { DynamicModuleOptions } from '../moduleoptions'\n\nexport function staticStateGenerator(\n module: Function & Mod,\n modOpt: DynamicModuleOptions,\n statics: any\n) {\n const state: S = modOpt.stateFactory ? (module as any).state() : module.state\n Object.keys(state).forEach((key) => {\n if (state.hasOwnProperty(key)) {\n // If not undefined or function means it is a state value\n if (['undefined', 'function'].indexOf(typeof (state as any)[key]) === -1) {\n Object.defineProperty(statics, key, {\n get() {\n const path = modOpt.name.split('/')\n let data = statics.store.state\n for (let segment of path) {\n data = data[segment]\n }\n return data[key]\n }\n })\n }\n }\n })\n}\n\nexport function staticGetterGenerator(\n module: Function & Mod,\n modOpt: DynamicModuleOptions,\n statics: any\n) {\n Object.keys(module.getters as GetterTree).forEach((key) => {\n if (module.namespaced) {\n Object.defineProperty(statics, key, {\n get() {\n return statics.store.getters[`${modOpt.name}/${key}`]\n }\n })\n } else {\n Object.defineProperty(statics, key, {\n get() {\n return statics.store.getters[key]\n }\n })\n }\n })\n}\n\nexport function staticMutationGenerator(\n module: Function & Mod,\n modOpt: DynamicModuleOptions,\n statics: any\n) {\n Object.keys(module.mutations as MutationTree).forEach((key) => {\n if (module.namespaced) {\n statics[key] = function (...args: any[]) {\n statics.store.commit(`${modOpt.name}/${key}`, ...args)\n }\n } else {\n statics[key] = function (...args: any[]) {\n statics.store.commit(key, ...args)\n }\n }\n })\n}\n\nexport function staticActionGenerators(\n module: Function & Mod,\n modOpt: DynamicModuleOptions,\n statics: any\n) {\n Object.keys(module.actions as ActionTree).forEach((key) => {\n if (module.namespaced) {\n statics[key] = async function (...args: any[]) {\n return statics.store.dispatch(`${modOpt.name}/${key}`, ...args)\n }\n } else {\n statics[key] = async function (...args: any[]) {\n return statics.store.dispatch(key, ...args)\n }\n }\n })\n}\n","import { GetterTree, Module as Mod, Store } from 'vuex'\nimport { DynamicModuleOptions, ModuleOptions } from '../moduleoptions'\nimport { stateFactory as sf } from './stateFactory'\nimport { addPropertiesToObject } from '../helpers'\nimport {\n staticActionGenerators,\n staticGetterGenerator,\n staticMutationGenerator,\n staticStateGenerator\n} from './staticGenerators'\n\nfunction registerDynamicModule(module: Mod, modOpt: DynamicModuleOptions) {\n if (!modOpt.name) {\n throw new Error('Name of module not provided in decorator options')\n }\n\n if (!modOpt.store) {\n throw new Error('Store not provided in decorator options when using dynamic option')\n }\n\n modOpt.store.registerModule(\n modOpt.name, // TODO: Handle nested modules too in future\n module,\n { preserveState: modOpt.preserveState || false }\n )\n}\n\nfunction addGettersToModule(\n targetModule: Function & Mod,\n srcModule: Function & Mod\n) {\n Object.getOwnPropertyNames(srcModule.prototype).forEach((funcName: string) => {\n const descriptor = Object.getOwnPropertyDescriptor(\n srcModule.prototype,\n funcName\n ) as PropertyDescriptor\n if (descriptor.get && targetModule.getters) {\n targetModule.getters[funcName] = function (\n state: S,\n getters: GetterTree,\n rootState: any,\n rootGetters: GetterTree\n ) {\n const thisObj = { context: { state, getters, rootState, rootGetters } }\n addPropertiesToObject(thisObj, state)\n addPropertiesToObject(thisObj, getters)\n const got = (descriptor.get as Function).call(thisObj)\n return got\n }\n }\n })\n}\n\nfunction moduleDecoratorFactory(moduleOptions: ModuleOptions) {\n return function (constructor: TFunction): TFunction | void {\n const module: Function & Mod = constructor\n const stateFactory = () => sf(module)\n\n if (!module.state) {\n module.state = moduleOptions && moduleOptions.stateFactory ? stateFactory : stateFactory()\n }\n if (!module.getters) {\n module.getters = {} as GetterTree\n }\n if (!module.namespaced) {\n module.namespaced = moduleOptions && moduleOptions.namespaced\n }\n let parentModule = Object.getPrototypeOf(module)\n while (parentModule.name !== 'VuexModule' && parentModule.name !== '') {\n addGettersToModule(module, parentModule)\n parentModule = Object.getPrototypeOf(parentModule)\n }\n addGettersToModule(module, module)\n const modOpt = moduleOptions as DynamicModuleOptions\n if (modOpt.name) {\n Object.defineProperty(constructor, '_genStatic', {\n value: (store?: Store) => {\n let statics = { store: store || modOpt.store }\n if (!statics.store) {\n throw new Error(`ERR_STORE_NOT_PROVIDED: To use getModule(), either the module\n should be decorated with store in decorator, i.e. @Module({store: store}) or\n store should be passed when calling getModule(), i.e. getModule(MyModule, this.$store)`)\n }\n // =========== For statics ==============\n // ------ state -------\n staticStateGenerator(module, modOpt, statics)\n\n // ------- getters -------\n if (module.getters) {\n staticGetterGenerator(module, modOpt, statics)\n }\n\n // -------- mutations --------\n if (module.mutations) {\n staticMutationGenerator(module, modOpt, statics)\n }\n // -------- actions ---------\n if (module.actions) {\n staticActionGenerators(module, modOpt, statics)\n }\n return statics\n }\n })\n\n Object.defineProperty(constructor, '_vmdModuleName', {\n value: modOpt.name\n })\n }\n\n if (modOpt.dynamic) {\n registerDynamicModule(module, modOpt)\n }\n return constructor\n }\n}\n\nexport function Module(module: Function & Mod): void\nexport function Module(options: ModuleOptions): ClassDecorator\n\nexport function Module(modOrOpt: ModuleOptions | (Function & Mod)) {\n if (typeof (modOrOpt as any) === 'function') {\n /*\n * @Module decorator called without options (directly on the class definition)\n */\n moduleDecoratorFactory({})(modOrOpt as Function & Mod)\n } else {\n /*\n * @Module({...}) decorator called with options\n */\n return moduleDecoratorFactory(modOrOpt)\n }\n}\n","export const config: IConfig = {}\n\nexport interface IConfig {\n rawError?: boolean\n}\n","import { Action as Act, ActionContext, Module as Mod, Payload } from 'vuex'\nimport { getModule, VuexModule } from './vuexmodule'\nimport { addPropertiesToObject, getModuleName } from './helpers'\nimport { config } from './config'\n\n/**\n * Parameters that can be passed to the @Action decorator\n */\nexport interface ActionDecoratorParams {\n commit?: string\n rawError?: boolean\n root?: boolean\n}\nfunction actionDecoratorFactory(params?: ActionDecoratorParams): MethodDecorator {\n const { commit = undefined, rawError = !!config.rawError, root = false } = params || {}\n return function (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor) {\n const module = target.constructor as Mod\n if (!module.hasOwnProperty('actions')) {\n module.actions = Object.assign({}, module.actions)\n }\n const actionFunction: Function = descriptor.value\n const action: Act = async function (\n context: ActionContext,\n payload: Payload\n ) {\n try {\n let actionPayload = null\n\n if ((module as any)._genStatic) {\n const moduleName = getModuleName(module)\n const moduleAccessor = context.rootGetters[moduleName]\n ? context.rootGetters[moduleName]\n : getModule(module as typeof VuexModule)\n moduleAccessor.context = context\n actionPayload = await actionFunction.call(moduleAccessor, payload)\n } else {\n const thisObj = { context }\n addPropertiesToObject(thisObj, context.state)\n addPropertiesToObject(thisObj, context.getters)\n actionPayload = await actionFunction.call(thisObj, payload)\n }\n if (commit) {\n context.commit(commit, actionPayload)\n }\n return actionPayload\n } catch (e: any) {\n throw rawError\n ? e\n : new Error(\n 'ERR_ACTION_ACCESS_UNDEFINED: Are you trying to access ' +\n 'this.someMutation() or this.someGetter inside an @Action? \\n' +\n 'That works only in dynamic modules. \\n' +\n 'If not dynamic use this.context.commit(\"mutationName\", payload) ' +\n 'and this.context.getters[\"getterName\"]' +\n '\\n' +\n new Error(`Could not perform action ${key.toString()}`).stack +\n '\\n' +\n e.stack\n )\n }\n }\n module.actions![key as string] = root ? { root, handler: action } : action\n }\n}\n\nexport function Action(\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => R>\n): void\nexport function Action(params: ActionDecoratorParams): MethodDecorator\n\n/**\n * The @Action decorator turns an async function into an Vuex action\n *\n * @param targetOrParams the module class\n * @param key name of the action\n * @param descriptor the action function descriptor\n * @constructor\n */\nexport function Action(\n targetOrParams: T | ActionDecoratorParams,\n key?: string | symbol,\n descriptor?: TypedPropertyDescriptor<(...args: any[]) => R>\n) {\n if (!key && !descriptor) {\n /*\n * This is the case when `targetOrParams` is params.\n * i.e. when used as -\n *
\n        @Action({commit: 'incrCount'})\n        async getCountDelta() {\n          return 5\n        }\n     * 
\n */\n return actionDecoratorFactory(targetOrParams as ActionDecoratorParams)\n } else {\n /*\n * This is the case when @Action is called on action function\n * without any params\n *
\n     *   @Action\n     *   async doSomething() {\n     *    ...\n     *   }\n     * 
\n */\n actionDecoratorFactory()(targetOrParams, key!, descriptor!)\n }\n}\n","import { Module as Mod, Mutation as Mut, Payload } from 'vuex'\n\nexport function Mutation(\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => R>\n) {\n const module = target.constructor as Mod\n if (!module.hasOwnProperty('mutations')) {\n module.mutations = Object.assign({}, module.mutations)\n }\n const mutationFunction: Function = descriptor.value!\n const mutation: Mut = function (state: typeof target, payload: Payload) {\n mutationFunction.call(state, payload)\n }\n module.mutations![key as string] = mutation\n}\n","import { Action as Act, ActionContext, Module as Mod, Mutation as Mut, Payload, Store } from 'vuex'\nimport { addPropertiesToObject } from './helpers'\n\nexport interface MutationActionParams {\n mutate?: (keyof Partial)[]\n rawError?: boolean\n root?: boolean\n}\n\nfunction mutationActionDecoratorFactory(params: MutationActionParams) {\n return function (\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>>\n ) {\n const module = target.constructor as Mod\n if (!module.hasOwnProperty('mutations')) {\n module.mutations = Object.assign({}, module.mutations)\n }\n if (!module.hasOwnProperty('actions')) {\n module.actions = Object.assign({}, module.actions)\n }\n const mutactFunction = descriptor.value as (payload: any) => Promise\n\n const action: Act = async function (\n context: ActionContext,\n payload: Payload\n ) {\n try {\n const thisObj = { context }\n addPropertiesToObject(thisObj, context.state)\n addPropertiesToObject(thisObj, context.getters)\n const actionPayload = await mutactFunction.call(thisObj, payload)\n if (actionPayload === undefined) return\n context.commit(key as string, actionPayload)\n } catch (e: any) {\n if (params.rawError) {\n throw e\n } else {\n console.error('Could not perform action ' + key.toString())\n console.error(e)\n return Promise.reject(e)\n }\n }\n }\n\n const mutation: Mut = function (\n state: typeof target | Store,\n payload: Payload & { [k in keyof T]: any }\n ) {\n if (!params.mutate) {\n params.mutate = Object.keys(payload) as (keyof T)[]\n }\n for (let stateItem of params.mutate) {\n if (state.hasOwnProperty(stateItem) && payload.hasOwnProperty(stateItem)) {\n ;(state as T)[stateItem] = payload[stateItem]\n } else {\n throw new Error(`ERR_MUTATE_PARAMS_NOT_IN_PAYLOAD\n In @MutationAction, mutate: ['a', 'b', ...] array keys must\n match with return type = {a: {}, b: {}, ...} and must\n also be in state.`)\n }\n }\n }\n module.actions![key as string] = params.root ? { root: true, handler: action } : action\n module.mutations![key as string] = mutation\n }\n}\n\nexport function MutationAction(\n target: { [k in keyof T]: T[k] | null },\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise>\n): void\n\nexport function MutationAction(\n params: MutationActionParams\n): (\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise>\n) => void\n\n/**\n * The @MutationAction decorator turns this into an action that further calls a mutation\n * Both the action and the mutation are generated for you\n *\n * @param paramsOrTarget the params or the target class\n * @param key the name of the function\n * @param descriptor the function body\n * @constructor\n */\nexport function MutationAction(\n paramsOrTarget: MutationActionParams | M,\n key?: string | symbol,\n descriptor?: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>>\n):\n | ((\n target: T,\n key: string | symbol,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>>\n ) => void)\n | void {\n if (!key && !descriptor) {\n /*\n * This is the case when `paramsOrTarget` is params.\n * i.e. when used as -\n *
\n        @MutationAction({mutate: ['incrCount']})\n        async getCountDelta() {\n          return {incrCount: 5}\n        }\n     * 
\n */\n return mutationActionDecoratorFactory(paramsOrTarget as MutationActionParams)\n } else {\n /*\n * This is the case when `paramsOrTarget` is target.\n * i.e. when used as -\n *
\n        @MutationAction\n        async getCountDelta() {\n          return {incrCount: 5}\n        }\n     * 
\n */\n mutationActionDecoratorFactory({} as MutationActionParams)(\n paramsOrTarget as K,\n key!,\n descriptor!\n )\n }\n}\n"],"names":["stateFactory","sf"],"mappings":"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"} -------------------------------------------------------------------------------- /dist/types/action.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Parameters that can be passed to the @Action decorator 3 | */ 4 | export interface ActionDecoratorParams { 5 | commit?: string; 6 | rawError?: boolean; 7 | root?: boolean; 8 | } 9 | export declare function Action(target: T, key: string | symbol, descriptor: TypedPropertyDescriptor<(...args: any[]) => R>): void; 10 | export declare function Action(params: ActionDecoratorParams): MethodDecorator; 11 | -------------------------------------------------------------------------------- /dist/types/config.d.ts: -------------------------------------------------------------------------------- 1 | export declare const config: IConfig; 2 | export interface IConfig { 3 | rawError?: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /dist/types/helpers.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Takes the properties on object from parameter source and adds them to the object 3 | * parameter target 4 | * @param {object} target Object to have properties copied onto from y 5 | * @param {object} source Object with properties to be copied to x 6 | */ 7 | export declare function addPropertiesToObject(target: any, source: any): void; 8 | /** 9 | * Returns a namespaced name of the module to be used as a store getter 10 | * @param module 11 | */ 12 | export declare function getModuleName(module: any): string; 13 | -------------------------------------------------------------------------------- /dist/types/index.d.ts: -------------------------------------------------------------------------------- 1 | export { VuexModule, getModule } from './vuexmodule'; 2 | export { Module } from './module'; 3 | export { Action } from './action'; 4 | export { Mutation } from './mutation'; 5 | export { MutationAction } from './mutationaction'; 6 | export { config } from './config'; 7 | -------------------------------------------------------------------------------- /dist/types/module/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Module as Mod } from 'vuex'; 2 | import { ModuleOptions } from '../moduleoptions'; 3 | export declare function Module(module: Function & Mod): void; 4 | export declare function Module(options: ModuleOptions): ClassDecorator; 5 | -------------------------------------------------------------------------------- /dist/types/module/stateFactory.d.ts: -------------------------------------------------------------------------------- 1 | import { Module as Mod } from 'vuex'; 2 | export declare function stateFactory(module: Function & Mod): S; 3 | -------------------------------------------------------------------------------- /dist/types/module/staticGenerators.d.ts: -------------------------------------------------------------------------------- 1 | import { Module as Mod } from 'vuex'; 2 | import { DynamicModuleOptions } from '../moduleoptions'; 3 | export declare function staticStateGenerator(module: Function & Mod, modOpt: DynamicModuleOptions, statics: any): void; 4 | export declare function staticGetterGenerator(module: Function & Mod, modOpt: DynamicModuleOptions, statics: any): void; 5 | export declare function staticMutationGenerator(module: Function & Mod, modOpt: DynamicModuleOptions, statics: any): void; 6 | export declare function staticActionGenerators(module: Function & Mod, modOpt: DynamicModuleOptions, statics: any): void; 7 | -------------------------------------------------------------------------------- /dist/types/moduleoptions.d.ts: -------------------------------------------------------------------------------- 1 | import { Store } from 'vuex'; 2 | /** 3 | * Options to pass to the @Module decorator 4 | */ 5 | export interface StaticModuleOptions { 6 | /** 7 | * name of module, if being namespaced 8 | */ 9 | name?: string; 10 | /** 11 | * whether or not the module is namespaced 12 | */ 13 | namespaced?: boolean; 14 | /** 15 | * Whether to generate a plain state object, or a state factory for the module 16 | */ 17 | stateFactory?: boolean; 18 | } 19 | export interface DynamicModuleOptions { 20 | /** 21 | * If this is a dynamic module (added to store after store is created) 22 | */ 23 | dynamic: true; 24 | /** 25 | * The store into which this module will be injected 26 | */ 27 | store: Store; 28 | /** 29 | * name of module, compulsory for dynamic modules 30 | */ 31 | name: string; 32 | /** 33 | * If this is enabled it will preserve the state when loading the module 34 | */ 35 | preserveState?: boolean; 36 | /** 37 | * whether or not the module is namespaced 38 | */ 39 | namespaced?: boolean; 40 | /** 41 | * Whether to generate a plain state object, or a state factory for the module 42 | */ 43 | stateFactory?: boolean; 44 | } 45 | export declare type ModuleOptions = StaticModuleOptions | DynamicModuleOptions; 46 | -------------------------------------------------------------------------------- /dist/types/mutation.d.ts: -------------------------------------------------------------------------------- 1 | export declare function Mutation(target: T, key: string | symbol, descriptor: TypedPropertyDescriptor<(...args: any[]) => R>): void; 2 | -------------------------------------------------------------------------------- /dist/types/mutationaction.d.ts: -------------------------------------------------------------------------------- 1 | export interface MutationActionParams { 2 | mutate?: (keyof Partial)[]; 3 | rawError?: boolean; 4 | root?: boolean; 5 | } 6 | export declare function MutationAction(target: { 7 | [k in keyof T]: T[k] | null; 8 | }, key: string | symbol, descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise>): void; 9 | export declare function MutationAction(params: MutationActionParams): (target: T, key: string | symbol, descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise>) => void; 10 | -------------------------------------------------------------------------------- /dist/types/vuexmodule.d.ts: -------------------------------------------------------------------------------- 1 | import { ActionTree, GetterTree, Module as Mod, ModuleTree, MutationTree, Store, ActionContext } from 'vuex'; 2 | export declare class VuexModule, R = any> implements Mod { 3 | static namespaced?: boolean; 4 | static state?: any | (() => any); 5 | static getters?: GetterTree; 6 | static actions?: ActionTree; 7 | static mutations?: MutationTree; 8 | static modules?: ModuleTree; 9 | modules?: ModuleTree; 10 | namespaced?: boolean; 11 | getters?: GetterTree; 12 | state?: S | (() => S); 13 | mutations?: MutationTree; 14 | actions?: ActionTree; 15 | context: ActionContext; 16 | constructor(module: Mod); 17 | } 18 | declare type ConstructorOf = { 19 | new (...args: any[]): C; 20 | }; 21 | export declare function getModule(moduleClass: ConstructorOf, store?: Store): M; 22 | export {}; 23 | -------------------------------------------------------------------------------- /docs/.vuepress/components/content-center.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /docs/.vuepress/components/sponsor-cb-sidebar.vue: -------------------------------------------------------------------------------- 1 | 9 | 35 | -------------------------------------------------------------------------------- /docs/.vuepress/components/sponsor-cb.vue: -------------------------------------------------------------------------------- 1 | 12 | 30 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | const sidebar = require('../sidebar') 2 | module.exports = { 3 | title: "vuex-module-decorators", 4 | description: "Typescript/ES7 Decorators to make Vuex modules a breeze", 5 | base: '/vuex-module-decorators/', 6 | ga: 'UA-51064506-1', 7 | evergreen: true, 8 | themeConfig: { 9 | repo: "championswimmer/vuex-module-decorators", 10 | docsDir: "docs", 11 | editLinks: true, 12 | sidebar 13 | }, 14 | } -------------------------------------------------------------------------------- /docs/.vuepress/public/cblogo_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/championswimmer/vuex-module-decorators/29c027e380a53ed11c8449e4f0a221d9429ccab3/docs/.vuepress/public/cblogo_big.png -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: trueac 3 | actionText: "Get Started →" 4 | actionLink: "/pages/installation" 5 | features: 6 | - title: "Typescript classes with strict type safety" 7 | details: "Create modules where nothing can go wrong. Compile time type-checking 8 | ensures you cannot mutate data not part of module, or access unavailable fields" 9 | - title: "Decorators for declarative code" 10 | details: "Annotate your functions with @Action or @Mutation to automatically 11 | turn then into Vuex module methods" 12 | - title: "Autocomplete for actions and mutations" 13 | details: "The shape of modules is fully typed, so you can 14 | access action and mutation functions with type-safety and 15 | get autocomplete help" 16 | --- 17 | 18 | 19 | 20 | 21 | 22 | [![Build Status](https://travis-ci.org/championswimmer/vuex-module-decorators.svg?branch=master)](https://travis-ci.org/championswimmer/vuex-module-decorators) 23 | [![npm:size:gzip](https://img.shields.io/bundlephobia/minzip/vuex-module-decorators.svg?label=npm:size:gzip)](https://bundlephobia.com/result?p=vuex-module-decorators) 24 | [![codecov](https://codecov.io/gh/championswimmer/vuex-module-decorators/branch/master/graph/badge.svg)](https://codecov.io/gh/championswimmer/vuex-module-decorators) 25 | [![npm](https://img.shields.io/npm/v/vuex-module-decorators.svg)](https://www.npmjs.com/package/vuex-module-decorators) 26 | [![npm](https://img.shields.io/npm/dw/vuex-module-decorators.svg?colorB=ff0033)](https://www.npmjs.com/package/vuex-module-decorators) 27 | ![npm type definitions](https://img.shields.io/npm/types/vuex-module-decorators.svg) 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/pages/advanced/dynamic.md: -------------------------------------------------------------------------------- 1 | # Dynamic Modules 2 | 3 | :::tip 4 | Before you read this secion, it is advised that you understand how 5 | [dynamic module registration works](https://vuex.vuejs.org/guide/modules.html#dynamic-module-registration) 6 | ::: 7 | 8 | Modules can be registered dynamically simply by passing a few properties into 9 | the `@Module` decorator, but an important part of the process is, we first 10 | create the store, and then pass the store to the module. 11 | 12 | ## Step 1: Create the Store 13 | 14 | ```typescript 15 | // @/store/index.ts 16 | import Vuex from 'vuex' 17 | 18 | const store = new Vuex.Store({ 19 | /* 20 | Ideally if all your modules are dynamic 21 | then your store is registered initially 22 | as a completely empty object 23 | */ 24 | }) 25 | ``` 26 | 27 | ## Step 2: Create the Dynamic Module 28 | 29 | ```typescript 30 | // @/store/modules/MyModule.ts 31 | import store from '@/store' 32 | import {Module, VuexModule} from 'vuex-module-decorators' 33 | 34 | @Module({dynamic: true, store, name: 'mm'}) 35 | export default class MyModule extends VuexModule { 36 | /* 37 | Your module definition as usual 38 | */ 39 | } 40 | 41 | ``` 42 | 43 | :::warning NOTE 44 | As of now, we do not support dynamic + nested modules. 45 | ::: 46 | 47 | :::danger IMPORTANT ⛔️ 48 | Make sure your imports/requires are ordered in such a way that 49 | the store definition is executed before the module class is created. 50 | 51 | It is important for the store to exist, and be passed into the 52 | `@Module` decorator for the module to get registered dynamically 53 | ::: 54 | -------------------------------------------------------------------------------- /docs/pages/advanced/namespaced.md: -------------------------------------------------------------------------------- 1 | # Namespaced Modules 2 | 3 | :::tip 4 | Before reading this, it is imperative you understand what are 5 | [namespaced modules](https://vuex.vuejs.org/guide/modules.html#namespacing) 6 | ::: 7 | 8 | If you intend to use your module in a namespaced way, then 9 | you need to specify so in the `@Module` decorator. 10 | 11 | ```typescript {1,17} 12 | @Module({ namespaced: true, name: 'mm' }) 13 | class MyModule extends VuexModule { 14 | wheels = 2 15 | 16 | @Mutation 17 | incrWheels(extra: number) { 18 | this.wheels += extra 19 | } 20 | 21 | get axles() { 22 | return this.wheels / 2 23 | } 24 | } 25 | 26 | const store = new Vuex.Store({ 27 | modules: { 28 | mm: MyModule 29 | } 30 | }) 31 | ``` 32 | 33 | :::danger NOTE 34 | The `name` field in the decorator should match the actual name 35 | that you will assign the module to, when you create the store. 36 | 37 | It isn't exactly elegant to manually keep these two same, but it 38 | is important. We have to convert `this.store.dispatch('action')` 39 | calls into `this.store.dispatch('name/action')`, and we need the 40 | `name` to be correct in the decorator to make it work 41 | ::: 42 | 43 | ### Registering global actions inside namespaced modules 44 | In order to [register actions of namespaced modules globally](https://vuex.vuejs.org/guide/modules.html#register-global-action-in-namespaced-modules 45 | ) you can add a parameter `root: true` to `@Action` and `@MutationAction` decorated methods. 46 | ```typescript {1,17} 47 | @Module({ namespaced: true, name: 'mm' }) 48 | class MyModule extends VuexModule { 49 | wheels = 2 50 | 51 | @Mutation 52 | setWheels(wheels: number) { 53 | this.wheels = wheels 54 | } 55 | 56 | @Action({ root: true, commit: 'setWheels' }) 57 | clear() { 58 | return 0 59 | } 60 | 61 | get axles() { 62 | return this.wheels / 2 63 | } 64 | } 65 | 66 | const store = new Vuex.Store({ 67 | modules: { 68 | mm: MyModule 69 | } 70 | }) 71 | ``` 72 | This way the `@Action` _clear_ of `MyModule` will be called by dispatching `clear` although being in the namespaced module `mm`. 73 | The same thing works for `@MutationAction` by just passing `{ root: true } ` to the decorator-options. 74 | 75 | :::danger NOTE 76 | When registering an action globally it can not be called by the namespace's name. 77 | For the example that means, that the action can not be called by dispatching `mm/clear`! 78 | ::: 79 | -------------------------------------------------------------------------------- /docs/pages/core/actions.md: -------------------------------------------------------------------------------- 1 | # Actions 2 | 3 | 4 | 5 | All functions that are decorated with `@Action` are converted into 6 | vuex actions. 7 | 8 | For example this code - 9 | 10 | ```typescript {13-17} 11 | import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators' 12 | import { get } from 'request' 13 | 14 | @Module 15 | export default class Vehicle extends VuexModule { 16 | wheels = 2 17 | 18 | @Mutation 19 | addWheel(n: number) { 20 | this.wheels = this.wheels + n 21 | } 22 | 23 | @Action 24 | async fetchNewWheels(wheelStore: string) { 25 | const wheels = await get(wheelStore) 26 | this.context.commit('addWheel', wheels) 27 | } 28 | } 29 | ``` 30 | 31 | is equivalent of this - 32 | 33 | ```js {11-15} 34 | const request = require('request') 35 | export default { 36 | state: { 37 | wheels: 2 38 | }, 39 | mutations: { 40 | addWheel: (state, payload) => { 41 | state.wheels = state.wheels + payload 42 | } 43 | }, 44 | actions: { 45 | fetchNewWheels: async (context, payload) => { 46 | const wheels = await request.get(payload) 47 | context.commit('addWheel', wheels) 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | :::tip NOTE 54 | Once decorated with `@Action` the function will be called with `this` 55 | having the following shape - `{...[all fields of state], context}` 56 | The action payload comes as an argument. 57 | So to commit a mutation manually from within action's body 58 | simply call **`this.context.commit('mutationName', mutPayload)`** 59 | ::: 60 | 61 | :::danger 🚨️️ WARNING 62 | If you are doing a long running task inside your action, it is recommended 63 | to define it as an **async** function. But even if you do not, this library 64 | will wrap your function into a **Promise** and _await_ it. 65 | 66 | If you want something to **actually** happen synchronously, make it a `Mutation` instead 67 | 68 | Also **do not** define them as arrow :arrow_right: functions, since we need to rebind them at runtime. 69 | ::: 70 | -------------------------------------------------------------------------------- /docs/pages/core/getters.md: -------------------------------------------------------------------------------- 1 | # Getters 2 | 3 | 4 | 5 | All ES6 getter functions of the class are converted into vuex getters 6 | 7 | For example, the following code - 8 | 9 | ```typescript {6-8} 10 | import { Module, VuexModule } from 'vuex-module-decorators' 11 | 12 | @Module 13 | export default class Vehicle extends VuexModule { 14 | wheels = 2 15 | get axles() { 16 | return this.wheels / 2 17 | } 18 | } 19 | ``` 20 | 21 | is equivalent of this - 22 | 23 | ```js {6} 24 | export default { 25 | state: { 26 | wheels: 2 27 | }, 28 | getters: { 29 | axles: (state) => state.wheels / 2 30 | } 31 | } 32 | ``` 33 | For Method-Style Access use vanilla vuex and return a function: 34 | 35 | ```typescript 36 | @Module 37 | export default class Vehicle extends VuexModule { 38 | companies = [] 39 | get company() { 40 | return (companyName: string) => { this.companies.find(company => company.name === companyName) }; 41 | } 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/pages/core/mutationactions.md: -------------------------------------------------------------------------------- 1 | # MutationActions 2 | 3 | If you have understood how [Actions](./actions.html) and [Mutations](./muatations.html) work 4 | you might have requirements for some functions that - 5 | 6 | 1. first do an asynchronous action 7 | 2. and then commit the resultant value to the store via a mutation 8 | 9 | This is where a `@MutationAction` comes to picture. 10 | 11 | 12 | Here is a basic example 13 | 14 | ```ts 15 | import {VuexModule, Module, MutationAction} from 'vuex-module-decorators' 16 | 17 | @Module 18 | class TypicodeModule extends VuexModule { 19 | posts: Post[] = [] 20 | users: User[] = [] 21 | 22 | @MutationAction 23 | async function updatePosts() { 24 | const posts = await axios.get('https://jsonplaceholder.typicode.com/posts') 25 | 26 | return { posts } 27 | } 28 | } 29 | 30 | ``` 31 | 32 | That gets converted to something like this 33 | 34 | ```js 35 | 36 | const typicodeModule = { 37 | state: { 38 | posts: [], 39 | users: [] 40 | }, 41 | mutations: { 42 | updatePosts: function (state, posts) { 43 | state.posts = posts 44 | } 45 | }, 46 | actions: { 47 | updatePosts: async function (context) { 48 | const posts = await axios.get('https://jsonplaceholder.typicode.com/posts') 49 | context.commit('updatePosts', posts) 50 | } 51 | } 52 | } 53 | 54 | ``` 55 | 56 | :::tip NOTE 57 | Note that if **S** denotes the type of _state_, then the object returned from a 58 | `MutationAction` function must of type **Partial\** 59 | The keys present inside the return value (for eg, here `posts`) are replaced into 60 | the store. 61 | ::: 62 | 63 | :::tip NOTE 64 | When a `MutationAction` function returns `undefined`, the mutation part of the 65 | `MutationAction` will not be called, and the state will remain the same. 66 | ::: 67 | -------------------------------------------------------------------------------- /docs/pages/core/mutations.md: -------------------------------------------------------------------------------- 1 | # Mutations 2 | 3 | 4 | 5 | All functions decorated with `@Mutation` are converted into Vuex mutations 6 | For example, the following code - 7 | 8 | ```typescript {7-10} 9 | import { Module, VuexModule, Mutation } from 'vuex-module-decorators' 10 | 11 | @Module 12 | export default class Vehicle extends VuexModule { 13 | wheels = 2 14 | 15 | @Mutation 16 | puncture(n: number) { 17 | this.wheels = this.wheels - n 18 | } 19 | } 20 | ``` 21 | 22 | is equivalent of this - 23 | 24 | ```js {6-8} 25 | export default { 26 | state: { 27 | wheels: 2 28 | }, 29 | mutations: { 30 | puncture: (state, payload) => { 31 | state.wheels = state.wheels - payload 32 | } 33 | } 34 | } 35 | ``` 36 | 37 | :::tip NOTE 38 | Once decorated with the `@Mutation` decorator _Mutations_ are run with **this** (context) set to the _state_ 39 | So when you want to change things in the state, 40 | `state.item++` is simply `this.item++` 41 | ::: 42 | 43 | :::danger 🚨 WARNING 44 | Mutation functions **MUST NOT** be _async_ functions. 45 | Also **do not** define them as arrow :arrow_right: functions, since we need to rebind them at runtime. 46 | ::: 47 | -------------------------------------------------------------------------------- /docs/pages/core/state.md: -------------------------------------------------------------------------------- 1 | # State 2 | 3 | 4 | 5 | All properties of the class are converted into state props. 6 | For example, the following code - 7 | 8 | ```typescript {5} 9 | import { Module, VuexModule } from 'vuex-module-decorators' 10 | 11 | @Module 12 | export default class Vehicle extends VuexModule { 13 | wheels = 2 14 | } 15 | ``` 16 | 17 | is equivalent of this - 18 | 19 | ```js {3} 20 | export default { 21 | state: { 22 | wheels: 2 23 | } 24 | } 25 | ``` 26 | 27 | :::danger 🚨 WARNING 28 | If state value cannot be determined, it **MUST** be initialized with `null`. Just like `wheels: number | null = null`. 29 | ::: 30 | -------------------------------------------------------------------------------- /docs/pages/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | 4 | 5 | [[toc]] 6 | 7 | ## Define a module 8 | 9 | To define a module, create a class that extends from `VuexModule` 10 | and **must be** decorated with `Module` decorator 11 | 12 | ```typescript 13 | // eg. /app/store/mymodule.ts 14 | import { Module, VuexModule } from 'vuex-module-decorators' 15 | 16 | @Module 17 | export default class MyModule extends VuexModule { 18 | someField: string = 'somedata' 19 | } 20 | ``` 21 | 22 | :::warning CAREFUL 23 | There is a `Module` class in the `vuex` package too, which is **not** a 24 | decorator. Make sure you import correct Module decorator from from 25 | `vuex-module-decorators` 26 | 27 | :x: `import {Module} from 'vuex'` 28 | :heavy_check_mark: `import {Module} from 'vuex-module-decorators'` 29 | ::: 30 | 31 | ## Use in store 32 | 33 | In your store, you use the `MyModule` class itself as a module. 34 | 35 | ```typescript 36 | import Vuex from 'vuex' 37 | import MyModule from '~/store/mymodule' 38 | 39 | const store = new Vuex.Store({ 40 | modules: { 41 | myMod: MyModule 42 | } 43 | }) 44 | ``` 45 | 46 | :::tip NOTE 47 | The way we use the MyModule class is different from classical object-oriented programming 48 | and similar to how [vue-class-component](https://npmjs.com/vue-class-component) works. 49 | We use the class itself as module, not an object _constructed_ by the class 50 | 51 | `new MyModule()` :x: 52 | ::: 53 | 54 | ## Access State 55 | 56 | All the usual ways of accessing the module works - 57 | 58 | 1. Import The store 59 | 60 | ```typescript {3} 61 | import store from '~/store' 62 | 63 | store.state.myMod.someField 64 | ``` 65 | 66 | 2. Use `this.$store` if in component 67 | 68 | ```javascript {1} 69 | this.$store.state.myMod.someField 70 | ``` 71 | 72 | In addition to that, for a much more typesafe access, we can use `getModule()` 73 | 74 | 3. Use `getModule()` to create type-safe accessor 75 | 76 | ```typescript {8} 77 | import { Module, VuexModule, getModule } from 'vuex-module-decorators' 78 | import store from '@/store' 79 | 80 | @Module({ dynamic: true, store, name: 'mymod' }) 81 | class MyModule extends VuexModule { 82 | someField: number = 10 83 | } 84 | const myMod = getModule(MyModule) 85 | myMod.someField //works 86 | myMod.someOtherField //Typescript will error, as field doesn't exist 87 | ``` 88 | -------------------------------------------------------------------------------- /docs/pages/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | 4 | 5 | ```bash 6 | npm install vuex-module-decorators 7 | # or 8 | yarn add vuex-module-decorators 9 | ``` 10 | 11 | ## ES5 Transpilation 12 | 13 | This package is distributed with ES2015 style code. Which means it is perfectly fine 14 | for modern browsers (Chrome, Firefox, Safari), but will not work on IE11. 15 | If you are using IE11 you are probably having a Babel-based transpilation setup to 16 | generate ES5 code. If that's the case, you need to make sure this package also gets 17 | transpiled. 18 | 19 | Add this in your `vue.config.js` (Vue CLI v3) 20 | 21 | ```js 22 | // vue.config.js 23 | module.exports = { 24 | // ... your other options 25 | transpileDependencies: [ 26 | 'vuex-module-decorators' 27 | ] 28 | } 29 | ``` 30 | 31 | ## Transpiler Configurations 32 | 33 | ### Babel 6/7 34 | 35 | 1. You need to install `babel-plugin-transform-decorators` 36 | 37 | ### Typescript 38 | 39 | 1. set `experimentalDecorators` to true 40 | 2. (Tip) For reduced code with decorators, set `importHelpers: true` in `tsconfig.json` 41 | 3. *(only for TypeScript 2)* set `emitHelpers: true` in `tsconfig.json` 42 | 43 | :::tip NOTE 44 | We do not need `emitDecoratorMetadata` as we do not depend on `reflect-metadata` 45 | ::: 46 | -------------------------------------------------------------------------------- /docs/pages/overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | 4 | 5 | ## What it does ? 6 | 7 | With this library, you can write `vuex` modules in this format - 8 | 9 | ```typescript 10 | // eg. /app/store/posts.ts 11 | import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators' 12 | import { get } from 'axios' 13 | 14 | interface PostEntity { 15 | comments: string[] 16 | } 17 | 18 | @Module 19 | export default class Posts extends VuexModule { 20 | posts: PostEntity[] = [] // initialize empty for now 21 | 22 | get totalComments(): number { 23 | return this.posts 24 | .filter(post => { 25 | // Take those posts that have comments 26 | return post.comments && post.comments.length 27 | }) 28 | .reduce((sum, post) => { 29 | // Sum all the lengths of comments arrays 30 | return sum + post.comments.length 31 | }, 0) 32 | } 33 | 34 | @Mutation 35 | updatePosts(posts: PostEntity[]) { 36 | this.posts = posts 37 | } 38 | 39 | @Action({ commit: 'updatePosts' }) 40 | async fetchPosts() { 41 | return get('https://jsonplaceholder.typicode.com/posts') 42 | } 43 | } 44 | 45 | ``` 46 | 47 | The resultant `/app/store/posts` file output would be 48 | 49 | ```javascript 50 | // equivalent eg. /app/store/posts.js 51 | module.exports = { 52 | state: { 53 | posts: [] 54 | }, 55 | getters: { 56 | totalComments: (state) => { 57 | return state.posts 58 | .filter((post) => { 59 | return post.comments && post.comments.length 60 | }) 61 | .reduce((sum, post) => { 62 | return sum + post.comments.length 63 | }, 0) 64 | } 65 | }, 66 | mutations: { 67 | updatePosts: (state, posts) => { 68 | // 'posts' is payload 69 | state.posts = posts 70 | } 71 | }, 72 | actions: { 73 | fetchPosts: async (context) => { 74 | // the return of the function is passed as payload 75 | const payload = await get('https://jsonplaceholder.typicode.com/posts') 76 | // the value of 'commit' in decorator is the mutation used 77 | context.commit('updatePosts', payload) 78 | } 79 | } 80 | } 81 | ``` 82 | 83 | ## Benefits of type-safety 84 | 85 | Instead of using the usual way to dispatch and commit ... 86 | 87 | ```javascript 88 | store.commit('updatePosts', posts) 89 | await store.dispatch('fetchPosts') 90 | ``` 91 | 92 | ... which provide no typesafety for the payload and no autocomplete help in IDEs, 93 | you can now use more type safe mechanism using the `getModule` accessor 94 | 95 | ```typescript 96 | import { getModule } from 'vuex-module-decorators' 97 | import Posts from `~/store/posts.js` 98 | 99 | const postsModule = getModule(Posts) 100 | 101 | // access posts 102 | const posts = postsModule.posts 103 | 104 | // use getters 105 | const commentCount = postsModule.totalComments 106 | 107 | // commit mutation 108 | postsModule.updatePosts(newPostsArray) 109 | 110 | // dispatch action 111 | await postsModule.fetchPosts() 112 | ``` 113 | -------------------------------------------------------------------------------- /docs/sidebar.json: -------------------------------------------------------------------------------- 1 | [ 2 | "/pages/installation", 3 | "/pages/overview", 4 | "/pages/getting-started", 5 | { 6 | "title": "Core Concepts", 7 | "collapsable": false, 8 | "children": [ 9 | "/pages/core/state", 10 | "/pages/core/getters", 11 | "/pages/core/mutations", 12 | "/pages/core/actions", 13 | "/pages/core/mutationactions" 14 | ] 15 | }, 16 | { 17 | "title": "Advanced Usage", 18 | "collapsable": false, 19 | "children": [ 20 | "/pages/advanced/namespaced", 21 | "/pages/advanced/dynamic" 22 | ] 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-module-decorators", 3 | "version": "2.0.0", 4 | "description": "Decorators to make class-like Vuex modules", 5 | "main": "dist/cjs/index.js", 6 | "types": "dist/types/index.d.ts", 7 | "typings": "dist/types/index.d.ts", 8 | "module": "dist/esm/index.js", 9 | "sideEffects": false, 10 | "scripts": { 11 | "clean": "rimraf dist .rpt2_cache", 12 | "distclean": "rimraf .nyc_output coverage dist .rpt2_cache", 13 | "postinstall": "node -e \"try{require('./postinstall')}catch(e){}\"", 14 | "prebuild": "npm run clean", 15 | "build": "rollup -c", 16 | "prepublishOnly": "npm run build", 17 | "pretest": "npm run build && npm run lint", 18 | "test": "cd test && mocha -r ts-node/register \"**/*.ts\"", 19 | "test:dirty": "cd test && mocha -r ts-node/register \"**/*.ts\"", 20 | "cover": "nyc npm test", 21 | "prereport": "npm run cover", 22 | "report": "nyc report --reporter lcov --reporter html", 23 | "docs:build": "vuepress build docs", 24 | "docs:serve": "vuepress dev docs", 25 | "lint": "tslint --project .", 26 | "lint:fix": "tslint --project . --fix" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "git+https://github.com/championswimmer/vuex-module-decorators.git" 31 | }, 32 | "keywords": [ 33 | "vuex", 34 | "vue", 35 | "typescript", 36 | "decorators" 37 | ], 38 | "author": "Arnav Gupta ", 39 | "license": "MIT", 40 | "bugs": { 41 | "url": "https://github.com/championswimmer/vuex-module-decorators/issues" 42 | }, 43 | "peerDependencies": { 44 | "vue": ">=3", 45 | "vuex": ">=4" 46 | }, 47 | "homepage": "https://github.com/championswimmer/vuex-module-decorators#readme", 48 | "devDependencies": { 49 | "@types/chai": "^4.2.22", 50 | "@types/mocha": "^9.0.0", 51 | "chai": "^4.3.4", 52 | "mocha": "^9.1.3", 53 | "mock-local-storage": "^1.1.8", 54 | "nyc": "^15.1.0", 55 | "prettier": "^2.1.2", 56 | "rimraf": "^3.0.2", 57 | "rollup": "^2.27.1", 58 | "rollup-plugin-typescript2": "^0.31.0", 59 | "rollup-plugin-uglify": "^6.0.4", 60 | "ts-node": "^9.0.0", 61 | "tslib": "^2.3.1", 62 | "tslint": "^6.1.3", 63 | "tslint-config-prettier": "^1.18.0", 64 | "tslint-config-standard": "^9.0.0", 65 | "tslint-eslint-rules": "^5.4.0", 66 | "tslint-plugin-prettier": "^2.3.0", 67 | "typescript": "^4.5.2", 68 | "vue": "^3.2.22", 69 | "vuepress": "^1.0.3", 70 | "vuex": "^4.0.2", 71 | "vuex-persist": "^2.2.0" 72 | }, 73 | "dependencies": {}, 74 | "engines": { 75 | "node": ">= 8", 76 | "npm": ">= 5", 77 | "yarn": ">= 1" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /postinstall.js: -------------------------------------------------------------------------------- 1 | const RESET = `\u001B[0m` 2 | const BLACK = '\u001b[30m' 3 | const RED = '\u001b[31m' 4 | const GREEN = '\u001b[32m' 5 | const YELLOW = '\u001b[33m' 6 | const BLUE = '\u001b[34m' 7 | const MAGENTA = '\u001b[35m' 8 | const CYAN = '\u001b[36m' 9 | const WHITE = '\u001b[37m' 10 | const BOLD = `\u001b[1m` 11 | const UNDERLINE = `\u001b[4m` 12 | 13 | const BANNER = ` 14 | ${GREEN}Thank you for using ${YELLOW}${BOLD} vuex-module-decorators ${RESET} 15 | ${GREEN}This package had been unmaintained for a long time, but I am maintaining it again.${RESET} 16 | ${GREEN}Maintaining open source projects take time, and I definitely would gracefully accept donations${RESET} 17 | 18 | ${CYAN} - ${UNDERLINE}https://www.patreon.com/championswimmer${RESET} 19 | ${CYAN} - ${UNDERLINE}https://liberapay.com/championswimmer${RESET} 20 | 21 | ${RED}${BOLD}NOTE: ${RESET}${RED}If you are using Vue 3+ and Vuex 4+ please use ${YELLOW}${BOLD}v2.x ${RESET}${RED}of this package 22 | ` 23 | 24 | console.log(BANNER) -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2' 2 | 3 | export default [ 4 | { 5 | input: 'src/index.ts', 6 | output: ['cjs', 'esm'].map(format => ({ 7 | file: `dist/${format}/index.js`, 8 | format, 9 | name: 'vuex-module-decorators', 10 | sourcemap: true, 11 | exports: 'named' 12 | })), 13 | external: ['vuex'], 14 | plugins: [typescript({useTsconfigDeclarationDir: true})] 15 | } 16 | ] -------------------------------------------------------------------------------- /src/action.ts: -------------------------------------------------------------------------------- 1 | import { Action as Act, ActionContext, Module as Mod, Payload } from 'vuex' 2 | import { getModule, VuexModule } from './vuexmodule' 3 | import { addPropertiesToObject, getModuleName } from './helpers' 4 | import { config } from './config' 5 | 6 | /** 7 | * Parameters that can be passed to the @Action decorator 8 | */ 9 | export interface ActionDecoratorParams { 10 | commit?: string 11 | rawError?: boolean 12 | root?: boolean 13 | } 14 | function actionDecoratorFactory(params?: ActionDecoratorParams): MethodDecorator { 15 | const { commit = undefined, rawError = !!config.rawError, root = false } = params || {} 16 | return function (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor) { 17 | const module = target.constructor as Mod 18 | if (!module.hasOwnProperty('actions')) { 19 | module.actions = Object.assign({}, module.actions) 20 | } 21 | const actionFunction: Function = descriptor.value 22 | const action: Act = async function ( 23 | context: ActionContext, 24 | payload: Payload 25 | ) { 26 | try { 27 | let actionPayload = null 28 | 29 | if ((module as any)._genStatic) { 30 | const moduleName = getModuleName(module) 31 | const moduleAccessor = context.rootGetters[moduleName] 32 | ? context.rootGetters[moduleName] 33 | : getModule(module as typeof VuexModule) 34 | moduleAccessor.context = context 35 | actionPayload = await actionFunction.call(moduleAccessor, payload) 36 | } else { 37 | const thisObj = { context } 38 | addPropertiesToObject(thisObj, context.state) 39 | addPropertiesToObject(thisObj, context.getters) 40 | actionPayload = await actionFunction.call(thisObj, payload) 41 | } 42 | if (commit) { 43 | context.commit(commit, actionPayload) 44 | } 45 | return actionPayload 46 | } catch (e: any) { 47 | throw rawError 48 | ? e 49 | : new Error( 50 | 'ERR_ACTION_ACCESS_UNDEFINED: Are you trying to access ' + 51 | 'this.someMutation() or this.someGetter inside an @Action? \n' + 52 | 'That works only in dynamic modules. \n' + 53 | 'If not dynamic use this.context.commit("mutationName", payload) ' + 54 | 'and this.context.getters["getterName"]' + 55 | '\n' + 56 | new Error(`Could not perform action ${key.toString()}`).stack + 57 | '\n' + 58 | e.stack 59 | ) 60 | } 61 | } 62 | module.actions![key as string] = root ? { root, handler: action } : action 63 | } 64 | } 65 | 66 | export function Action( 67 | target: T, 68 | key: string | symbol, 69 | descriptor: TypedPropertyDescriptor<(...args: any[]) => R> 70 | ): void 71 | export function Action(params: ActionDecoratorParams): MethodDecorator 72 | 73 | /** 74 | * The @Action decorator turns an async function into an Vuex action 75 | * 76 | * @param targetOrParams the module class 77 | * @param key name of the action 78 | * @param descriptor the action function descriptor 79 | * @constructor 80 | */ 81 | export function Action( 82 | targetOrParams: T | ActionDecoratorParams, 83 | key?: string | symbol, 84 | descriptor?: TypedPropertyDescriptor<(...args: any[]) => R> 85 | ) { 86 | if (!key && !descriptor) { 87 | /* 88 | * This is the case when `targetOrParams` is params. 89 | * i.e. when used as - 90 | *
 91 |         @Action({commit: 'incrCount'})
 92 |         async getCountDelta() {
 93 |           return 5
 94 |         }
 95 |      * 
96 | */ 97 | return actionDecoratorFactory(targetOrParams as ActionDecoratorParams) 98 | } else { 99 | /* 100 | * This is the case when @Action is called on action function 101 | * without any params 102 | *
103 |      *   @Action
104 |      *   async doSomething() {
105 |      *    ...
106 |      *   }
107 |      * 
108 | */ 109 | actionDecoratorFactory()(targetOrParams, key!, descriptor!) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | export const config: IConfig = {} 2 | 3 | export interface IConfig { 4 | rawError?: boolean 5 | } 6 | -------------------------------------------------------------------------------- /src/helpers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Takes the properties on object from parameter source and adds them to the object 3 | * parameter target 4 | * @param {object} target Object to have properties copied onto from y 5 | * @param {object} source Object with properties to be copied to x 6 | */ 7 | export function addPropertiesToObject(target: any, source: any) { 8 | for (let k of Object.keys(source || {})) { 9 | Object.defineProperty(target, k, { 10 | get: () => source[k] 11 | }) 12 | } 13 | } 14 | 15 | /** 16 | * Returns a namespaced name of the module to be used as a store getter 17 | * @param module 18 | */ 19 | export function getModuleName(module: any): string { 20 | if (!module._vmdModuleName) { 21 | throw new Error(`ERR_GET_MODULE_NAME : Could not get module accessor. 22 | Make sure your module has name, we can't make accessors for unnamed modules 23 | i.e. @Module({ name: 'something' })`) 24 | } 25 | return `vuexModuleDecorators/${module._vmdModuleName}` 26 | } 27 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { VuexModule, getModule } from './vuexmodule' 2 | export { Module } from './module' 3 | export { Action } from './action' 4 | export { Mutation } from './mutation' 5 | export { MutationAction } from './mutationaction' 6 | export { config } from './config' 7 | -------------------------------------------------------------------------------- /src/module/index.ts: -------------------------------------------------------------------------------- 1 | import { GetterTree, Module as Mod, Store } from 'vuex' 2 | import { DynamicModuleOptions, ModuleOptions } from '../moduleoptions' 3 | import { stateFactory as sf } from './stateFactory' 4 | import { addPropertiesToObject } from '../helpers' 5 | import { 6 | staticActionGenerators, 7 | staticGetterGenerator, 8 | staticMutationGenerator, 9 | staticStateGenerator 10 | } from './staticGenerators' 11 | 12 | function registerDynamicModule(module: Mod, modOpt: DynamicModuleOptions) { 13 | if (!modOpt.name) { 14 | throw new Error('Name of module not provided in decorator options') 15 | } 16 | 17 | if (!modOpt.store) { 18 | throw new Error('Store not provided in decorator options when using dynamic option') 19 | } 20 | 21 | modOpt.store.registerModule( 22 | modOpt.name, // TODO: Handle nested modules too in future 23 | module, 24 | { preserveState: modOpt.preserveState || false } 25 | ) 26 | } 27 | 28 | function addGettersToModule( 29 | targetModule: Function & Mod, 30 | srcModule: Function & Mod 31 | ) { 32 | Object.getOwnPropertyNames(srcModule.prototype).forEach((funcName: string) => { 33 | const descriptor = Object.getOwnPropertyDescriptor( 34 | srcModule.prototype, 35 | funcName 36 | ) as PropertyDescriptor 37 | if (descriptor.get && targetModule.getters) { 38 | targetModule.getters[funcName] = function ( 39 | state: S, 40 | getters: GetterTree, 41 | rootState: any, 42 | rootGetters: GetterTree 43 | ) { 44 | const thisObj = { context: { state, getters, rootState, rootGetters } } 45 | addPropertiesToObject(thisObj, state) 46 | addPropertiesToObject(thisObj, getters) 47 | const got = (descriptor.get as Function).call(thisObj) 48 | return got 49 | } 50 | } 51 | }) 52 | } 53 | 54 | function moduleDecoratorFactory(moduleOptions: ModuleOptions) { 55 | return function (constructor: TFunction): TFunction | void { 56 | const module: Function & Mod = constructor 57 | const stateFactory = () => sf(module) 58 | 59 | if (!module.state) { 60 | module.state = moduleOptions && moduleOptions.stateFactory ? stateFactory : stateFactory() 61 | } 62 | if (!module.getters) { 63 | module.getters = {} as GetterTree 64 | } 65 | if (!module.namespaced) { 66 | module.namespaced = moduleOptions && moduleOptions.namespaced 67 | } 68 | let parentModule = Object.getPrototypeOf(module) 69 | while (parentModule.name !== 'VuexModule' && parentModule.name !== '') { 70 | addGettersToModule(module, parentModule) 71 | parentModule = Object.getPrototypeOf(parentModule) 72 | } 73 | addGettersToModule(module, module) 74 | const modOpt = moduleOptions as DynamicModuleOptions 75 | if (modOpt.name) { 76 | Object.defineProperty(constructor, '_genStatic', { 77 | value: (store?: Store) => { 78 | let statics = { store: store || modOpt.store } 79 | if (!statics.store) { 80 | throw new Error(`ERR_STORE_NOT_PROVIDED: To use getModule(), either the module 81 | should be decorated with store in decorator, i.e. @Module({store: store}) or 82 | store should be passed when calling getModule(), i.e. getModule(MyModule, this.$store)`) 83 | } 84 | // =========== For statics ============== 85 | // ------ state ------- 86 | staticStateGenerator(module, modOpt, statics) 87 | 88 | // ------- getters ------- 89 | if (module.getters) { 90 | staticGetterGenerator(module, modOpt, statics) 91 | } 92 | 93 | // -------- mutations -------- 94 | if (module.mutations) { 95 | staticMutationGenerator(module, modOpt, statics) 96 | } 97 | // -------- actions --------- 98 | if (module.actions) { 99 | staticActionGenerators(module, modOpt, statics) 100 | } 101 | return statics 102 | } 103 | }) 104 | 105 | Object.defineProperty(constructor, '_vmdModuleName', { 106 | value: modOpt.name 107 | }) 108 | } 109 | 110 | if (modOpt.dynamic) { 111 | registerDynamicModule(module, modOpt) 112 | } 113 | return constructor 114 | } 115 | } 116 | 117 | export function Module(module: Function & Mod): void 118 | export function Module(options: ModuleOptions): ClassDecorator 119 | 120 | export function Module(modOrOpt: ModuleOptions | (Function & Mod)) { 121 | if (typeof (modOrOpt as any) === 'function') { 122 | /* 123 | * @Module decorator called without options (directly on the class definition) 124 | */ 125 | moduleDecoratorFactory({})(modOrOpt as Function & Mod) 126 | } else { 127 | /* 128 | * @Module({...}) decorator called with options 129 | */ 130 | return moduleDecoratorFactory(modOrOpt) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/module/stateFactory.ts: -------------------------------------------------------------------------------- 1 | import { Module as Mod } from 'vuex' 2 | 3 | const reservedKeys = ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit'] 4 | export function stateFactory(module: Function & Mod) { 5 | const state = new module.prototype.constructor({}) 6 | const s = {} as S 7 | Object.keys(state).forEach((key: string) => { 8 | if (reservedKeys.indexOf(key) !== -1) { 9 | if (typeof state[key] !== 'undefined') { 10 | throw new Error( 11 | `ERR_RESERVED_STATE_KEY_USED: You cannot use the following 12 | ['actions', 'getters', 'mutations', 'modules', 'state', 'namespaced', 'commit'] 13 | as fields in your module. These are reserved as they have special purpose in Vuex` 14 | ) 15 | } 16 | return 17 | } 18 | if (state.hasOwnProperty(key)) { 19 | if (typeof state[key] !== 'function') { 20 | ;(s as any)[key] = state[key] 21 | } 22 | } 23 | }) 24 | 25 | return s 26 | } 27 | -------------------------------------------------------------------------------- /src/module/staticGenerators.ts: -------------------------------------------------------------------------------- 1 | import { ActionTree, GetterTree, Module as Mod, MutationTree } from 'vuex' 2 | import { DynamicModuleOptions } from '../moduleoptions' 3 | 4 | export function staticStateGenerator( 5 | module: Function & Mod, 6 | modOpt: DynamicModuleOptions, 7 | statics: any 8 | ) { 9 | const state: S = modOpt.stateFactory ? (module as any).state() : module.state 10 | Object.keys(state).forEach((key) => { 11 | if (state.hasOwnProperty(key)) { 12 | // If not undefined or function means it is a state value 13 | if (['undefined', 'function'].indexOf(typeof (state as any)[key]) === -1) { 14 | Object.defineProperty(statics, key, { 15 | get() { 16 | const path = modOpt.name.split('/') 17 | let data = statics.store.state 18 | for (let segment of path) { 19 | data = data[segment] 20 | } 21 | return data[key] 22 | } 23 | }) 24 | } 25 | } 26 | }) 27 | } 28 | 29 | export function staticGetterGenerator( 30 | module: Function & Mod, 31 | modOpt: DynamicModuleOptions, 32 | statics: any 33 | ) { 34 | Object.keys(module.getters as GetterTree).forEach((key) => { 35 | if (module.namespaced) { 36 | Object.defineProperty(statics, key, { 37 | get() { 38 | return statics.store.getters[`${modOpt.name}/${key}`] 39 | } 40 | }) 41 | } else { 42 | Object.defineProperty(statics, key, { 43 | get() { 44 | return statics.store.getters[key] 45 | } 46 | }) 47 | } 48 | }) 49 | } 50 | 51 | export function staticMutationGenerator( 52 | module: Function & Mod, 53 | modOpt: DynamicModuleOptions, 54 | statics: any 55 | ) { 56 | Object.keys(module.mutations as MutationTree).forEach((key) => { 57 | if (module.namespaced) { 58 | statics[key] = function (...args: any[]) { 59 | statics.store.commit(`${modOpt.name}/${key}`, ...args) 60 | } 61 | } else { 62 | statics[key] = function (...args: any[]) { 63 | statics.store.commit(key, ...args) 64 | } 65 | } 66 | }) 67 | } 68 | 69 | export function staticActionGenerators( 70 | module: Function & Mod, 71 | modOpt: DynamicModuleOptions, 72 | statics: any 73 | ) { 74 | Object.keys(module.actions as ActionTree).forEach((key) => { 75 | if (module.namespaced) { 76 | statics[key] = async function (...args: any[]) { 77 | return statics.store.dispatch(`${modOpt.name}/${key}`, ...args) 78 | } 79 | } else { 80 | statics[key] = async function (...args: any[]) { 81 | return statics.store.dispatch(key, ...args) 82 | } 83 | } 84 | }) 85 | } 86 | -------------------------------------------------------------------------------- /src/moduleoptions.ts: -------------------------------------------------------------------------------- 1 | import { Store } from 'vuex' 2 | /** 3 | * Options to pass to the @Module decorator 4 | */ 5 | export interface StaticModuleOptions { 6 | /** 7 | * name of module, if being namespaced 8 | */ 9 | name?: string 10 | /** 11 | * whether or not the module is namespaced 12 | */ 13 | namespaced?: boolean 14 | /** 15 | * Whether to generate a plain state object, or a state factory for the module 16 | */ 17 | stateFactory?: boolean 18 | } 19 | 20 | export interface DynamicModuleOptions { 21 | /** 22 | * If this is a dynamic module (added to store after store is created) 23 | */ 24 | dynamic: true 25 | 26 | /** 27 | * The store into which this module will be injected 28 | */ 29 | store: Store 30 | 31 | /** 32 | * name of module, compulsory for dynamic modules 33 | */ 34 | name: string 35 | 36 | /** 37 | * If this is enabled it will preserve the state when loading the module 38 | */ 39 | preserveState?: boolean 40 | 41 | /** 42 | * whether or not the module is namespaced 43 | */ 44 | namespaced?: boolean 45 | 46 | /** 47 | * Whether to generate a plain state object, or a state factory for the module 48 | */ 49 | stateFactory?: boolean 50 | } 51 | 52 | export type ModuleOptions = StaticModuleOptions | DynamicModuleOptions 53 | -------------------------------------------------------------------------------- /src/mutation.ts: -------------------------------------------------------------------------------- 1 | import { Module as Mod, Mutation as Mut, Payload } from 'vuex' 2 | 3 | export function Mutation( 4 | target: T, 5 | key: string | symbol, 6 | descriptor: TypedPropertyDescriptor<(...args: any[]) => R> 7 | ) { 8 | const module = target.constructor as Mod 9 | if (!module.hasOwnProperty('mutations')) { 10 | module.mutations = Object.assign({}, module.mutations) 11 | } 12 | const mutationFunction: Function = descriptor.value! 13 | const mutation: Mut = function (state: typeof target, payload: Payload) { 14 | mutationFunction.call(state, payload) 15 | } 16 | module.mutations![key as string] = mutation 17 | } 18 | -------------------------------------------------------------------------------- /src/mutationaction.ts: -------------------------------------------------------------------------------- 1 | import { Action as Act, ActionContext, Module as Mod, Mutation as Mut, Payload, Store } from 'vuex' 2 | import { addPropertiesToObject } from './helpers' 3 | 4 | export interface MutationActionParams { 5 | mutate?: (keyof Partial)[] 6 | rawError?: boolean 7 | root?: boolean 8 | } 9 | 10 | function mutationActionDecoratorFactory(params: MutationActionParams) { 11 | return function ( 12 | target: T, 13 | key: string | symbol, 14 | descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>> 15 | ) { 16 | const module = target.constructor as Mod 17 | if (!module.hasOwnProperty('mutations')) { 18 | module.mutations = Object.assign({}, module.mutations) 19 | } 20 | if (!module.hasOwnProperty('actions')) { 21 | module.actions = Object.assign({}, module.actions) 22 | } 23 | const mutactFunction = descriptor.value as (payload: any) => Promise 24 | 25 | const action: Act = async function ( 26 | context: ActionContext, 27 | payload: Payload 28 | ) { 29 | try { 30 | const thisObj = { context } 31 | addPropertiesToObject(thisObj, context.state) 32 | addPropertiesToObject(thisObj, context.getters) 33 | const actionPayload = await mutactFunction.call(thisObj, payload) 34 | if (actionPayload === undefined) return 35 | context.commit(key as string, actionPayload) 36 | } catch (e: any) { 37 | if (params.rawError) { 38 | throw e 39 | } else { 40 | console.error('Could not perform action ' + key.toString()) 41 | console.error(e) 42 | return Promise.reject(e) 43 | } 44 | } 45 | } 46 | 47 | const mutation: Mut = function ( 48 | state: typeof target | Store, 49 | payload: Payload & { [k in keyof T]: any } 50 | ) { 51 | if (!params.mutate) { 52 | params.mutate = Object.keys(payload) as (keyof T)[] 53 | } 54 | for (let stateItem of params.mutate) { 55 | if (state.hasOwnProperty(stateItem) && payload.hasOwnProperty(stateItem)) { 56 | ;(state as T)[stateItem] = payload[stateItem] 57 | } else { 58 | throw new Error(`ERR_MUTATE_PARAMS_NOT_IN_PAYLOAD 59 | In @MutationAction, mutate: ['a', 'b', ...] array keys must 60 | match with return type = {a: {}, b: {}, ...} and must 61 | also be in state.`) 62 | } 63 | } 64 | } 65 | module.actions![key as string] = params.root ? { root: true, handler: action } : action 66 | module.mutations![key as string] = mutation 67 | } 68 | } 69 | 70 | export function MutationAction( 71 | target: { [k in keyof T]: T[k] | null }, 72 | key: string | symbol, 73 | descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise> 74 | ): void 75 | 76 | export function MutationAction( 77 | params: MutationActionParams 78 | ): ( 79 | target: T, 80 | key: string | symbol, 81 | descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise> 82 | ) => void 83 | 84 | /** 85 | * The @MutationAction decorator turns this into an action that further calls a mutation 86 | * Both the action and the mutation are generated for you 87 | * 88 | * @param paramsOrTarget the params or the target class 89 | * @param key the name of the function 90 | * @param descriptor the function body 91 | * @constructor 92 | */ 93 | export function MutationAction( 94 | paramsOrTarget: MutationActionParams | M, 95 | key?: string | symbol, 96 | descriptor?: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>> 97 | ): 98 | | (( 99 | target: T, 100 | key: string | symbol, 101 | descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise | undefined>> 102 | ) => void) 103 | | void { 104 | if (!key && !descriptor) { 105 | /* 106 | * This is the case when `paramsOrTarget` is params. 107 | * i.e. when used as - 108 | *
109 |         @MutationAction({mutate: ['incrCount']})
110 |         async getCountDelta() {
111 |           return {incrCount: 5}
112 |         }
113 |      * 
114 | */ 115 | return mutationActionDecoratorFactory(paramsOrTarget as MutationActionParams) 116 | } else { 117 | /* 118 | * This is the case when `paramsOrTarget` is target. 119 | * i.e. when used as - 120 | *
121 |         @MutationAction
122 |         async getCountDelta() {
123 |           return {incrCount: 5}
124 |         }
125 |      * 
126 | */ 127 | mutationActionDecoratorFactory({} as MutationActionParams)( 128 | paramsOrTarget as K, 129 | key!, 130 | descriptor! 131 | ) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/vuexmodule.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ActionTree, 3 | GetterTree, 4 | Module as Mod, 5 | ModuleTree, 6 | MutationTree, 7 | Store, 8 | ActionContext 9 | } from 'vuex' 10 | import { getModuleName } from './helpers' 11 | 12 | export class VuexModule, R = any> implements Mod { 13 | /* 14 | * To use with `extends Class` syntax along with decorators 15 | */ 16 | static namespaced?: boolean 17 | static state?: any | (() => any) 18 | static getters?: GetterTree 19 | static actions?: ActionTree 20 | static mutations?: MutationTree 21 | static modules?: ModuleTree 22 | 23 | /* 24 | * To use with `new VuexModule({})` syntax 25 | */ 26 | 27 | modules?: ModuleTree 28 | namespaced?: boolean 29 | getters?: GetterTree 30 | state?: S | (() => S) 31 | mutations?: MutationTree 32 | actions?: ActionTree 33 | context!: ActionContext 34 | 35 | constructor(module: Mod) { 36 | this.actions = module.actions 37 | this.mutations = module.mutations 38 | this.state = module.state 39 | this.getters = module.getters 40 | this.namespaced = module.namespaced 41 | this.modules = module.modules 42 | } 43 | } 44 | type ConstructorOf = { new (...args: any[]): C } 45 | 46 | export function getModule( 47 | moduleClass: ConstructorOf, 48 | store?: Store 49 | ): M { 50 | const moduleName = getModuleName(moduleClass) 51 | if (store && store.getters[moduleName]) { 52 | return store.getters[moduleName] 53 | } else if ((moduleClass as any)._statics) { 54 | return (moduleClass as any)._statics 55 | } 56 | 57 | const genStatic: (providedStore?: Store) => M = (moduleClass as any)._genStatic 58 | if (!genStatic) { 59 | throw new Error(`ERR_GET_MODULE_NO_STATICS : Could not get module accessor. 60 | Make sure your module has name, we can't make accessors for unnamed modules 61 | i.e. @Module({ name: 'something' })`) 62 | } 63 | 64 | const storeModule = genStatic(store) 65 | 66 | if (store) { 67 | store.getters[moduleName] = storeModule 68 | } else { 69 | ;(moduleClass as any)._statics = storeModule 70 | } 71 | 72 | return storeModule 73 | } 74 | -------------------------------------------------------------------------------- /test/action_access_module_dynamic.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod, Store } from 'vuex' 2 | import { createApp } from 'vue' 3 | import { Action, Module, Mutation, VuexModule } from '..' 4 | import { expect } from 'chai' 5 | import { getModule } from '../src/vuexmodule' 6 | 7 | const store = new Vuex.Store({}) 8 | 9 | @Module({ dynamic: true, store, name: 'mm' }) 10 | class MyModule extends VuexModule { 11 | fieldFoo = 'foo' 12 | fieldBar = 'bar' 13 | 14 | @Mutation 15 | setFoo(data: string) { 16 | this.fieldFoo += data 17 | } 18 | @Mutation 19 | setBar(data: string) { 20 | this.fieldBar += data 21 | } 22 | 23 | @Action 24 | async concatFooOrBar(newstr: string) { 25 | if (this.fieldFoo.length < this.fieldBar.length) { 26 | this.setFoo(newstr) 27 | } else { 28 | this.setBar(newstr) 29 | } 30 | } 31 | } 32 | const app = createApp({}) 33 | app.use(store) 34 | 35 | 36 | describe('@Action with dynamic module', () => { 37 | it('should concat foo & bar', async function () { 38 | const mm = getModule(MyModule) 39 | await store.dispatch('concatFooOrBar', 't1') 40 | expect(mm.fieldBar).to.equal('bart1') 41 | await store.dispatch('concatFooOrBar', 't1') 42 | expect(mm.fieldFoo).to.equal('foot1') 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/action_access_state.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod, Store } from 'vuex' 2 | import { createApp } from 'vue' 3 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 4 | import { expect } from 'chai' 5 | 6 | @Module 7 | class MyModule extends VuexModule { 8 | fieldFoo = 'foo' 9 | fieldBar = 'bar' 10 | 11 | @Mutation 12 | resetFoo(data: string) { 13 | this.fieldFoo = 'foo' 14 | } 15 | @Mutation 16 | resetBar(data: string) { 17 | this.fieldBar = 'bar' 18 | } 19 | @Mutation 20 | setFoo(data: string) { 21 | this.fieldFoo += data 22 | } 23 | @Mutation 24 | setBar(data: string) { 25 | this.fieldBar += data 26 | } 27 | 28 | @Action 29 | async concatFooOrBar(newstr: string) { 30 | if (this.fieldFoo.length < this.fieldBar.length) { 31 | this.context.commit('setFoo', newstr) 32 | } else { 33 | this.context.commit('setBar', newstr) 34 | } 35 | } 36 | @Action 37 | async concatFooOrBarWithThis(newstr: string) { 38 | if (this.fieldFoo.length < this.fieldBar.length) { 39 | this.setFoo(newstr) 40 | } else { 41 | this.setBar(newstr) 42 | } 43 | } 44 | @Action({ rawError: true }) 45 | async testStateInAction(payload: string) { 46 | this.context.commit('setFoo', payload) 47 | expect((this.context.state as any).fieldFoo).to.equal('foo' + payload) 48 | expect(this.fieldFoo).to.equal('foo' + payload) 49 | } 50 | 51 | @Action({ rawError: true }) 52 | async alwaysFail() { 53 | throw Error('Foo Bar!') 54 | } 55 | } 56 | 57 | const store = new Vuex.Store({ 58 | modules: { 59 | mm: MyModule 60 | } 61 | }) 62 | const app = createApp({}) 63 | app.use(store) 64 | 65 | 66 | describe('@Action with non-dynamic module', () => { 67 | it('should concat foo & bar', async function() { 68 | const { 69 | state: { mm } 70 | } = store 71 | await store.dispatch('concatFooOrBar', 't1') 72 | expect(mm.fieldBar).to.equal('bart1') 73 | await store.dispatch('concatFooOrBar', 't1') 74 | expect(mm.fieldFoo).to.equal('foot1') 75 | }) 76 | it('should error if this.mutation() is used in non-dynamic', async function() { 77 | try { 78 | await store.dispatch('concatFooOrBarWithThis', 't1') 79 | } catch (e: any) { 80 | expect(e.message).to.contain('ERR_ACTION_ACCESS_UNDEFINED') 81 | } 82 | }) 83 | it('should save original error', async function() { 84 | try { 85 | await store.dispatch('alwaysFail') 86 | } catch (e: any) { 87 | expect(e.message).to.equal('Foo Bar!') 88 | } 89 | }) 90 | it('should have access to the state even if the state changes', async function() { 91 | const { 92 | state: { mm } 93 | } = store 94 | store.commit('resetFoo') 95 | expect(mm.fieldFoo).to.equal('foo') 96 | await store.dispatch('testStateInAction', 'bar') 97 | expect(mm.fieldFoo).to.equal('foobar') 98 | }) 99 | }) 100 | -------------------------------------------------------------------------------- /test/action_with_inner_promise.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module 8 | class MyModule extends VuexModule { 9 | foo = '' 10 | 11 | @Action 12 | public value() { 13 | return 'Test1' 14 | } 15 | 16 | @Action 17 | public promise() { 18 | return Promise.resolve('Test2') 19 | } 20 | 21 | @MutationAction({ mutate: ['foo'], rawError: true }) 22 | public promise2(payload: string) { 23 | return Promise.resolve({ foo: payload }) 24 | } 25 | } 26 | 27 | const store = new Vuex.Store({ 28 | modules: { 29 | mm: MyModule 30 | } 31 | }) 32 | const app = createApp({}) 33 | app.use(store) 34 | 35 | describe('actions return inner promises', () => { 36 | it('should return resolved value', async function() { 37 | const value = await store.dispatch('value') 38 | expect(value).to.equal('Test1') 39 | }) 40 | 41 | it('should return resolved promise', async function() { 42 | const value = await store.dispatch('promise') 43 | expect(value).to.equal('Test2') 44 | }) 45 | 46 | it('should not return resolved promise on a MutationAction', async function() { 47 | // Purposefully not returning value from the action on a MutationAction because it is 48 | // designed to mutate the state and you should access the value off the state 49 | const { 50 | state: { mm } 51 | } = store 52 | let value = 'Test3' 53 | const resp = await store.dispatch('promise2', value) 54 | expect(resp).to.equal(void 0) 55 | expect(mm.foo).to.equal(value) 56 | }) 57 | }) 58 | -------------------------------------------------------------------------------- /test/constructor.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { VuexModule } from '..' 5 | import { expect } from 'chai' 6 | import { promisify } from 'util' 7 | 8 | const setTimeoutPromise = promisify(setTimeout) 9 | 10 | const mm = new VuexModule({ 11 | state: { wheels: 2 }, 12 | mutations: { 13 | incrWheels(state, extra: number) { 14 | state.wheels += extra 15 | } 16 | }, 17 | actions: { 18 | async addWheels(context) { 19 | await setTimeoutPromise(1000) 20 | context.commit('incrWheels', 10) 21 | } 22 | }, 23 | getters: { 24 | axles(state) { 25 | return state.wheels / 2 26 | } 27 | } 28 | }) 29 | 30 | const store = new Vuex.Store({ 31 | modules: { mm } 32 | }) 33 | const app = createApp({}) 34 | app.use(store) 35 | 36 | describe('creating with new VuexModule() works', () => { 37 | it('should increase axles', async function() { 38 | store.commit('incrWheels', 4) 39 | expect(parseInt(store.getters.axles)).to.equal(3) 40 | await store.dispatch('addWheels') 41 | expect(parseInt(store.getters.axles)).to.equal(8) 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /test/dynamic_module.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | interface StoreType { 8 | mm: MyModule 9 | } 10 | const store = new Vuex.Store({}) 11 | 12 | @Module({ dynamic: true, store, name: 'mm' }) 13 | class MyModule extends VuexModule { 14 | count = 0 15 | 16 | @Mutation 17 | incrCount(delta: number) { 18 | this.count += delta 19 | } 20 | } 21 | const app = createApp({}) 22 | app.use(store) 23 | 24 | describe('mutation works on dynamic module', () => { 25 | it('should update count', function() { 26 | store.commit('incrCount', 5) 27 | expect(store.state.mm.count).to.equal(5) 28 | }) 29 | }) 30 | 31 | describe('dynamic module', () => { 32 | it('should error without store in decorator', function() { 33 | expect(() => { 34 | @Module({ name: 'mm', dynamic: true }) 35 | class MyModule extends VuexModule {} 36 | }).to.throw('Store not provided in decorator options when using dynamic option') 37 | }) 38 | 39 | it('should error without name in decorator', function() { 40 | expect(() => { 41 | const store = new Vuex.Store({}) 42 | 43 | // Ignore the TS error when module options are missing required name property 44 | // @ts-ignore 45 | @Module({ 46 | store, 47 | dynamic: true 48 | }) 49 | class MyDynamicModule extends VuexModule {} 50 | }).to.throw('Name of module not provided in decorator options') 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_action_mutation.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { getModule, Module, Action, Mutation, VuexModule } from '../../' 5 | import { expect } from 'chai' 6 | 7 | const store = new Vuex.Store({}) 8 | 9 | const defaultValue = 10 10 | 11 | @Module({ name: 'mm', store, dynamic: true }) 12 | class MyModule extends VuexModule { 13 | public value = defaultValue 14 | 15 | @Mutation 16 | public setValue(value: number): void { 17 | this.value = value 18 | } 19 | 20 | @Action({ commit: 'setValue' }) 21 | public async resetValue(): Promise { 22 | return defaultValue 23 | } 24 | } 25 | 26 | @Module({ name: 'mnm', store, dynamic: true, namespaced: true }) 27 | class MyNamespacedModule extends VuexModule { 28 | public value = defaultValue 29 | 30 | @Mutation 31 | public setValue(value: number): void { 32 | this.value = value 33 | } 34 | 35 | @Action({ commit: 'setValue' }) 36 | public async resetValue(): Promise { 37 | return defaultValue 38 | } 39 | } 40 | 41 | describe('actions and mutations on getModule()', () => { 42 | it('mutation should set provided value', function() { 43 | const module = getModule(MyModule) 44 | expect(module.value).to.equal(defaultValue) 45 | 46 | const newValue = defaultValue + 2 47 | module.setValue(newValue) 48 | expect(module.value).to.equal(newValue) 49 | }) 50 | 51 | it('action should reset value to default', function() { 52 | const module = getModule(MyModule) 53 | return module.resetValue().then(() => { 54 | expect(module.value).to.equal(defaultValue) 55 | }) 56 | }) 57 | 58 | it('mutation should set provided value on namespaced module', function() { 59 | const module = getModule(MyNamespacedModule) 60 | expect(module.value).to.equal(defaultValue) 61 | 62 | const newValue = defaultValue + 2 63 | module.setValue(newValue) 64 | expect(module.value).to.equal(newValue) 65 | }) 66 | 67 | it('action should reset value to default on namespaced module', function() { 68 | const module = getModule(MyNamespacedModule) 69 | return module.resetValue().then(() => { 70 | expect(module.value).to.equal(defaultValue) 71 | }) 72 | }) 73 | }) 74 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_dynamic.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, getModule, Module, Mutation, MutationAction, VuexModule } from '../..' 5 | import { expect } from 'chai' 6 | 7 | interface StoreType { 8 | mm: MyModule 9 | } 10 | const store = new Vuex.Store({}) 11 | 12 | @Module({ dynamic: true, store, name: 'mm' }) 13 | class MyModule extends VuexModule { 14 | count = 0 15 | 16 | @Mutation 17 | incrCount(delta: number) { 18 | this.count += delta 19 | } 20 | 21 | @Action({ commit: 'incrCount' }) 22 | async getCountDelta(retVal: number = 5) { 23 | return retVal 24 | } 25 | 26 | get halfCount() { 27 | return (this.count / 2).toPrecision(1) 28 | } 29 | } 30 | 31 | describe('accessing statics works on dynamic module', () => { 32 | it('should update count', async function() { 33 | const mm = getModule(MyModule) 34 | expect(mm.count).to.equal(0) 35 | 36 | mm.incrCount(5) 37 | expect(mm.count).to.equal(5) 38 | expect(parseInt(mm.halfCount)).to.equal(3) 39 | await mm.getCountDelta() 40 | expect(parseInt(mm.halfCount)).to.equal(5) 41 | await mm.getCountDelta(5) 42 | expect(parseInt(mm.halfCount)).to.equal(8) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_dynamic_namespaced.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule, getModule } from '../..' 5 | import { expect } from 'chai' 6 | 7 | interface StoreType { 8 | mm: MyModule 9 | } 10 | const store = new Vuex.Store({}) 11 | 12 | @Module({ dynamic: true, store, name: 'mm', namespaced: true }) 13 | class MyModule extends VuexModule { 14 | count = 0 15 | 16 | @Mutation 17 | incrCount(delta: number) { 18 | this.count += delta 19 | } 20 | 21 | @Action({ commit: 'incrCount' }) 22 | async getCountDelta(retVal: number = 5) { 23 | return retVal 24 | } 25 | 26 | get halfCount() { 27 | return (this.count / 2).toPrecision(1) 28 | } 29 | } 30 | 31 | describe('accessing statics works on dynamic (namespaced) module', () => { 32 | it('should update count', async function() { 33 | const mm = getModule(MyModule) 34 | expect(mm.count).to.equal(0) 35 | 36 | mm.incrCount(5) 37 | expect(mm.count).to.equal(5) 38 | expect(parseInt(mm.halfCount)).to.equal(3) 39 | 40 | await mm.getCountDelta() 41 | expect(parseInt(mm.halfCount)).to.equal(5) 42 | await mm.getCountDelta(5) 43 | expect(parseInt(mm.halfCount)).to.equal(8) 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_generated_on_store.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { getModule, Module, Mutation, VuexModule } from '../..' 5 | import { expect } from 'chai' 6 | import { getModuleName } from '../../src/helpers' 7 | 8 | interface StoreType { 9 | mm: MyModule 10 | } 11 | 12 | @Module({ name: 'mm', stateFactory: true }) 13 | class MyModule extends VuexModule { 14 | count = 0 15 | 16 | @Mutation 17 | public incrCount() { 18 | ++this.count 19 | } 20 | } 21 | 22 | const store = new Vuex.Store({ 23 | modules: { 24 | mm: MyModule 25 | } 26 | }) 27 | 28 | describe('module generated on a single store', () => { 29 | it('should generate module in store getters', function() { 30 | const module = getModule(MyModule, store) 31 | expect(store.getters[getModuleName(MyModule)]).to.equal(module) 32 | }) 33 | 34 | it('should retain state between getModule calls', function() { 35 | const module = getModule(MyModule, store) 36 | module.incrCount() 37 | expect(module.count).to.equal(1) 38 | 39 | const secondModule = getModule(MyModule, store) 40 | expect(secondModule.count).to.equal(1) 41 | 42 | secondModule.incrCount() 43 | expect(module.count).to.equal(2) 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_generated_on_two_stores.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { getModule, Module, Mutation, VuexModule } from '../..' 5 | import { expect } from 'chai' 6 | 7 | interface StoreType { 8 | mm: MyModule 9 | } 10 | 11 | @Module({ name: 'mm', stateFactory: true }) 12 | class MyModule extends VuexModule { 13 | count = 0 14 | 15 | @Mutation 16 | public incrCount() { 17 | ++this.count 18 | } 19 | } 20 | 21 | const firstStore = new Vuex.Store({ 22 | modules: { 23 | mm: MyModule 24 | } 25 | }) 26 | 27 | const secondStore = new Vuex.Store({ 28 | modules: { 29 | mm: MyModule 30 | } 31 | }) 32 | 33 | describe('modules generated on two different stores', () => { 34 | it('should each have their own state', function() { 35 | const module = getModule(MyModule, firstStore) 36 | const secondModule = getModule(MyModule, secondStore) 37 | 38 | module.incrCount() 39 | expect(module.count).to.equal(1) 40 | expect(secondModule.count).to.equal(0) 41 | 42 | secondModule.incrCount() 43 | expect(module.count).to.equal(1) 44 | expect(secondModule.count).to.equal(1) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_getter.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { getModule, Module, Action, Mutation, VuexModule } from '../..' 5 | import { expect } from 'chai' 6 | 7 | const store = new Vuex.Store({}) 8 | 9 | @Module({ name: 'mm', store, dynamic: true }) 10 | class MyModule extends VuexModule { 11 | public value = 10 12 | 13 | public get twofold(): number { 14 | return this.value * 2 15 | } 16 | } 17 | 18 | @Module({ name: 'mnm', store, dynamic: true, namespaced: true }) 19 | class MyNamespacedModule extends VuexModule { 20 | public value = 10 21 | 22 | public get twofold(): number { 23 | return this.value * 2 24 | } 25 | } 26 | 27 | describe('using getters on getModule()', () => { 28 | it('getter should return adjusted value', function() { 29 | expect(getModule(MyModule).value).to.equal(10) 30 | expect(getModule(MyModule).twofold).to.equal(20) 31 | }) 32 | 33 | it('getter should return adjusted value on namespaced module', function() { 34 | expect(getModule(MyNamespacedModule).value).to.equal(10) 35 | expect(getModule(MyNamespacedModule).twofold).to.equal(20) 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_noname.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { getModule, Module, VuexModule } from '../..' 5 | import { expect } from 'chai' 6 | 7 | @Module 8 | class MyModule extends VuexModule {} 9 | 10 | describe('getModule() on unnamed module', () => { 11 | it('should error without name in decorator', function() { 12 | expect(() => getModule(MyModule)).to.throw(/ERR_GET_MODULE_NAME .*/) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_nondynamic_noname.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, getModule, Module, Mutation, MutationAction, VuexModule } from '../..' 5 | import { expect } from 'chai' 6 | 7 | interface StoreType { 8 | mm: MyModule 9 | } 10 | 11 | @Module 12 | class MyModule extends VuexModule { 13 | count = 0 14 | 15 | @Mutation 16 | incrCount(delta: number) { 17 | this.count += delta 18 | } 19 | 20 | @Action({ commit: 'incrCount' }) 21 | async getCountDelta(retVal: number = 5) { 22 | return retVal 23 | } 24 | 25 | get halfCount() { 26 | return (this.count / 2).toPrecision(1) 27 | } 28 | } 29 | 30 | const store = new Vuex.Store({ 31 | modules: { 32 | mm: MyModule 33 | } 34 | }) 35 | 36 | describe('getModule() on unnamed non-dynamic module', () => { 37 | it('should error without name in decorator', function() { 38 | expect(() => getModule(MyModule)).to.throw('ERR_GET_MODULE_NAME') 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_nondynamic_withname.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, getModule, Module, Mutation, MutationAction, VuexModule } from '../..' 5 | import { expect } from 'chai' 6 | 7 | interface StoreType { 8 | mm: MyModule 9 | } 10 | 11 | @Module({ name: 'mm' }) 12 | class MyModule extends VuexModule { 13 | count = 0 14 | 15 | @Mutation 16 | incrCount(delta: number) { 17 | this.count += delta 18 | } 19 | 20 | @Action({ commit: 'incrCount' }) 21 | async getCountDelta(retVal: number = 5) { 22 | return retVal 23 | } 24 | 25 | get halfCount() { 26 | return (this.count / 2).toPrecision(1) 27 | } 28 | } 29 | 30 | const store = new Vuex.Store({ 31 | modules: { 32 | mm: MyModule 33 | } 34 | }) 35 | 36 | describe('getModule() on named non-dynamic module', () => { 37 | it('should error if getModule() is called without store', function() { 38 | expect(() => getModule(MyModule)).to.throw('ERR_STORE_NOT_PROVIDED') 39 | }) 40 | 41 | it('should work when store is passed in getModule()', async function() { 42 | const mm = getModule(MyModule, store) 43 | expect(mm.count).to.equal(0) 44 | 45 | mm.incrCount(5) 46 | expect(mm.count).to.equal(5) 47 | expect(parseInt(mm.halfCount)).to.equal(3) 48 | 49 | await mm.getCountDelta() 50 | expect(parseInt(mm.halfCount)).to.equal(5) 51 | 52 | await mm.getCountDelta(5) 53 | expect(parseInt(mm.halfCount)).to.equal(8) 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /test/getmodule/getmodule_without_store.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { getModule, Module, VuexModule } from '../..' 5 | import { expect } from 'chai' 6 | 7 | const store = new Vuex.Store({}) 8 | 9 | @Module({ name: 'mm', store }) 10 | class MyModule extends VuexModule {} 11 | 12 | @Module({ name: 'mmws' }) 13 | class MyModuleWithoutStore extends VuexModule {} 14 | 15 | describe('getModule() without providing store', () => { 16 | it('should generate the module on statics property', function() { 17 | const module = getModule(MyModule) 18 | expect((MyModule as any)._statics).to.equal(module) 19 | }) 20 | 21 | it('should error without defining store on the module', function() { 22 | expect(() => getModule(MyModuleWithoutStore)).to.throw(/ERR_STORE_NOT_PROVIDED.*/) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /test/getters.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module 8 | class MyModule extends VuexModule { 9 | wheels = 2 10 | 11 | @Mutation 12 | incrWheels(extra: number) { 13 | this.wheels += extra 14 | } 15 | 16 | @Action({ rawError: true }) 17 | async incrWheelsAction(payload: number) { 18 | const context = this.context 19 | this.context.commit('incrWheels', payload) 20 | const axles = this.context.getters.axles 21 | expect(this.context).to.equal(context) 22 | expect(this.axles).to.equal(axles) 23 | } 24 | 25 | get axles() { 26 | return this.wheels / 2 27 | } 28 | get axlesAndWheels() { 29 | return { axles: this.axles, wheels: this.wheels } 30 | } 31 | } 32 | 33 | const store = new Vuex.Store({ 34 | state: {}, 35 | modules: { 36 | mm: MyModule 37 | } 38 | }) 39 | const app = createApp({}) 40 | app.use(store) 41 | 42 | describe('fetching via getters works', () => { 43 | it('should not override the context in the action', async () => { 44 | await store.dispatch('incrWheelsAction', 2) 45 | const axles = store.getters.axles 46 | expect(axles).to.equal(2) 47 | }) 48 | it('should increase axles', function() { 49 | store.commit('incrWheels', 2) 50 | const axles = store.getters.axles 51 | expect(axles).to.equal(3) 52 | }) 53 | it(`should be able to access a getter within a getter with this['key']`, async () => { 54 | const axlesAndWheels = store.getters.axlesAndWheels 55 | expect(axlesAndWheels.axles).to.equal(3) 56 | }) 57 | }) 58 | -------------------------------------------------------------------------------- /test/getters_childmodule.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | class ParentModule extends VuexModule { 8 | wheels = 2 9 | 10 | @Mutation 11 | incrWheels(extra: number) { 12 | this.wheels += extra 13 | } 14 | 15 | @Action({ rawError: true }) 16 | async incrWheelsAction(payload: number) { 17 | const context = this.context 18 | this.context.commit('incrWheels', payload) 19 | const axles = this.context.getters.axles 20 | expect(this.context).to.equal(context) 21 | expect(this.axles).to.equal(axles) 22 | } 23 | 24 | get axles() { 25 | return this.wheels / 2 26 | } 27 | get axlesAndWheels() { 28 | return { axles: this.axles, wheels: this.wheels } 29 | } 30 | } 31 | 32 | @Module 33 | class ChildModule extends ParentModule { 34 | get axlesAndWheels() { 35 | return { axles: this.axles, axlesDouble: this.axlesDouble, wheels: this.wheels } 36 | } 37 | 38 | get axlesDouble() { 39 | return this.wheels 40 | } 41 | } 42 | 43 | 44 | 45 | const store = new Vuex.Store({ 46 | state: {}, 47 | modules: { 48 | mm: ChildModule 49 | } 50 | }) 51 | const app = createApp({}) 52 | app.use(store) 53 | 54 | describe('fetching via getters works', () => { 55 | 56 | it('should be able to access parent getter', async () => { 57 | await store.dispatch('incrWheelsAction', 2) 58 | const axles = store.getters.axles 59 | expect(axles).to.equal(2) 60 | }) 61 | 62 | it('should be able to override axlesAndWheels', async function() { 63 | await store.dispatch('incrWheelsAction', 2) 64 | const axlesAndWheels = store.getters.axlesAndWheels 65 | expect(axlesAndWheels.axlesDouble).to.equal(6) 66 | }) 67 | 68 | }) 69 | -------------------------------------------------------------------------------- /test/getters_rootstate.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module 8 | class MyModule extends VuexModule { 9 | wheels = 2 10 | 11 | @Mutation 12 | incrWheels(extra: number) { 13 | this.wheels += extra 14 | } 15 | 16 | get axles() { 17 | return (this.wheels / 2) * this.context.rootState.cars 18 | } 19 | } 20 | 21 | const store = new Vuex.Store({ 22 | state: { 23 | cars: 10 24 | }, 25 | modules: { 26 | mm: MyModule 27 | } 28 | }) 29 | const app = createApp({}) 30 | app.use(store) 31 | 32 | describe('fetching rootState via getters works', () => { 33 | it('should increase axles * cars', function() { 34 | store.commit('incrWheels', 4) 35 | const axles = store.getters.axles 36 | expect(axles).to.equal(30) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /test/global_config.ts: -------------------------------------------------------------------------------- 1 | import { config, Module, VuexModule, Action } from '..' 2 | import { Store } from 'vuex' 3 | import { expect } from 'chai' 4 | import { ActionDecoratorParams } from '../src/action' 5 | 6 | describe('Global config', function() { 7 | afterEach(function() { 8 | for (const key in config) { 9 | delete (config as any)[key] 10 | } 11 | }) 12 | 13 | describe('rawError', function() { 14 | const WRAPPED_ERROR = 'ERR_ACTION_ACCESS_UNDEFINED' 15 | 16 | it('wraps errors by default', async function() { 17 | const store = buildStore() 18 | 19 | let error 20 | try { 21 | await store.dispatch('alwaysFail') 22 | } catch (e: any) { 23 | error = e 24 | } 25 | 26 | expect(error.message).to.contain(WRAPPED_ERROR) 27 | }) 28 | 29 | it('unwraps errors when rawError is set globally', async function() { 30 | config.rawError = true 31 | const store = buildStore() 32 | 33 | let error 34 | try { 35 | await store.dispatch('alwaysFail') 36 | } catch (e: any) { 37 | error = e 38 | } 39 | 40 | expect(error.message).not.to.contain(WRAPPED_ERROR) 41 | }) 42 | 43 | it('overrides the global config with @Action params', async function() { 44 | config.rawError = true 45 | const store = buildStore({ rawError: false }) 46 | 47 | let error 48 | try { 49 | await store.dispatch('alwaysFail') 50 | } catch (e: any) { 51 | error = e 52 | } 53 | 54 | expect(error.message).to.contain(WRAPPED_ERROR) 55 | }) 56 | }) 57 | 58 | function buildStore(params: ActionDecoratorParams = {}) { 59 | @Module 60 | class MyModule extends VuexModule { 61 | @Action(params) 62 | async alwaysFail() { 63 | throw new Error('Foo Bar!') 64 | } 65 | } 66 | 67 | return new Store({ 68 | modules: { 69 | mm: MyModule 70 | } 71 | }) 72 | } 73 | }) 74 | -------------------------------------------------------------------------------- /test/muation_and_action.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod, Store } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module 8 | class MyModule extends VuexModule { 9 | count = 0 10 | 11 | @Mutation 12 | incrCount(delta: number) { 13 | this.count += delta 14 | } 15 | 16 | @Action({ commit: 'incrCount' }) 17 | async getCountDelta() { 18 | return 5 19 | } 20 | 21 | @Action 22 | fetchCountDelta() { 23 | this.context.commit('incrCount', 5) 24 | } 25 | 26 | @Action({ rawError: true }) 27 | async incrCountAction(payload: number) { 28 | const context = this.context 29 | await this.context.dispatch('getCountDelta') 30 | expect(this.context).to.equal(context) 31 | } 32 | } 33 | 34 | const store = new Vuex.Store({ 35 | modules: { 36 | mm: MyModule 37 | } 38 | }) 39 | const app = createApp({}) 40 | app.use(store) 41 | 42 | describe('dispatching action which mutates works', () => { 43 | it('should update count', async function() { 44 | await store.dispatch('getCountDelta') 45 | expect(parseInt(store.state.mm.count)).to.equal(5) 46 | }) 47 | it('should update count (sync)', async function() { 48 | store.dispatch('fetchCountDelta') 49 | expect(parseInt(store.state.mm.count)).to.equal(10) 50 | }) 51 | }) 52 | 53 | describe('dispatching action which dipatches actions', () => { 54 | it(`should not remove the context off the first action's this`, async function() { 55 | await store.dispatch('incrCountAction') 56 | expect(parseInt(store.state.mm.count)).to.equal(15) 57 | }) 58 | }) 59 | -------------------------------------------------------------------------------- /test/mutation.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module 8 | class MyModule extends VuexModule { 9 | count = 0 10 | 11 | @Mutation 12 | incrCount(delta: number) { 13 | this.count += delta 14 | } 15 | } 16 | 17 | const store = new Vuex.Store({ 18 | modules: { 19 | mm: MyModule 20 | } 21 | }) 22 | const app = createApp({}) 23 | app.use(store) 24 | 25 | describe('committing mutation works', () => { 26 | it('should update count', function() { 27 | store.commit('incrCount', 5) 28 | expect(parseInt(store.state.mm.count)).to.equal(5) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /test/mutationaction.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | import { Module, MutationAction, VuexModule } from '..' 4 | import { expect } from 'chai' 5 | 6 | 7 | 8 | @Module 9 | class MyModule extends VuexModule { 10 | count: number = 0 11 | anotherCount: number = 0 12 | fruit: string = 'Apple' 13 | vegetable: string | null = null 14 | 15 | 16 | @MutationAction({ mutate: ['count'] }) 17 | async updateCount(newcount: number) { 18 | return { count: newcount } 19 | } 20 | 21 | @MutationAction 22 | async updateAnotherCountConditionally({ newCount, shouldUpdate }: { newCount: number, shouldUpdate: boolean }) { 23 | if (!shouldUpdate) return 24 | return { anotherCount: newCount } 25 | } 26 | 27 | @MutationAction 28 | async changeVeggie() { 29 | return {vegetable: 'Carrot'} 30 | } 31 | 32 | @MutationAction 33 | async changeFruit(fruitName: string) { 34 | await new Promise(resolve => setTimeout(resolve, 500)) 35 | return {fruit: fruitName || 'Guava'} 36 | } 37 | 38 | // Newer more type-safe 'mutate' param removes need for this test 39 | // @MutationAction({ mutate: ['definitelyNotCount'], rawError: true }) 40 | // async updateCountButNoSuchPayload(newcount: number) { 41 | // return { definitelyNotCount: newcount } 42 | // } 43 | 44 | @MutationAction({ mutate: ['count'], rawError: true }) 45 | async updateCountOnlyOnEven(newcount: number) { 46 | if (newcount % 2 !== 0) { 47 | throw new Error('The number provided is not an even number') 48 | } 49 | 50 | return {count: newcount} 51 | } 52 | 53 | @MutationAction({ mutate: ['count'] }) 54 | async incrementCount() { 55 | return { count: this.count + 1 } 56 | } 57 | } 58 | 59 | const store = new Vuex.Store({ 60 | modules: { 61 | mm: MyModule 62 | } 63 | }) 64 | const app = createApp({}) 65 | app.use(store) 66 | 67 | describe('dispatching moduleaction works', () => { 68 | it('should update count', async function() { 69 | await store.dispatch('updateCount', 2) 70 | expect(parseInt(store.state.mm.count, 10)).to.equal(2) 71 | 72 | await store.dispatch('updateCountOnlyOnEven', 8) 73 | expect(parseInt(store.state.mm.count, 10)).to.equal(8) 74 | 75 | // try { 76 | // await store.dispatch('updateCountButNoSuchPayload', '1337') 77 | // } catch (e: any) { 78 | // expect(e.message).to.contain('ERR_MUTATE_PARAMS_NOT_IN_PAYLOAD') 79 | // } 80 | 81 | try { 82 | await store.dispatch('updateCountOnlyOnEven', 7) 83 | } catch (e: any) { 84 | expect(e.message).to.contain('not an even number') 85 | } 86 | }) 87 | 88 | it('should update fruitname', async function() { 89 | await store.dispatch('changeFruit', 'Guava') 90 | expect(store.state.mm.fruit).to.equal('Guava') 91 | }) 92 | 93 | it('should be able to skip update', async function () { 94 | expect(store.state.mm.anotherCount).to.equal(0) 95 | 96 | await store.dispatch('updateAnotherCountConditionally', { newCount: 5, shouldUpdate: true }) 97 | expect(store.state.mm.anotherCount).to.equal(5) 98 | 99 | await store.dispatch('updateAnotherCountConditionally', { newCount: 10, shouldUpdate: false }) 100 | expect(store.state.mm.anotherCount).to.equal(5) 101 | }) 102 | 103 | it('can access state', async function() { 104 | await store.dispatch('updateCount', 0) 105 | expect(store.state.mm.count).to.equal(0) 106 | await store.dispatch('incrementCount') 107 | expect(store.state.mm.count).to.equal(1) 108 | }) 109 | }) 110 | -------------------------------------------------------------------------------- /test/namespaced_getters.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module({ namespaced: true }) 8 | class MyModule extends VuexModule { 9 | wheels = 2 10 | 11 | @Mutation 12 | incrWheels(extra: number) { 13 | this.wheels += extra 14 | } 15 | 16 | get axles() { 17 | return this.wheels / 2 18 | } 19 | } 20 | 21 | const store = new Vuex.Store({ 22 | modules: { 23 | mm: MyModule 24 | } 25 | }) 26 | const app = createApp({}) 27 | app.use(store) 28 | 29 | describe('fetching via namespaced getters works', () => { 30 | it('should increase axles', function() { 31 | store.commit('mm/incrWheels', 4) 32 | const axles = store.getters['mm/axles'] 33 | expect(axles).to.equal(3) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /test/namespaced_mutation.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module({ namespaced: true }) 8 | class MyModule extends VuexModule { 9 | count = 0 10 | 11 | @Mutation 12 | incrCount(delta: number) { 13 | this.count += delta 14 | } 15 | } 16 | 17 | const store = new Vuex.Store({ 18 | modules: { 19 | mm: MyModule 20 | } 21 | }) 22 | const app = createApp({}) 23 | app.use(store) 24 | 25 | describe('committing mutation works', () => { 26 | it('should update count', function() { 27 | store.commit('mm/incrCount', 5) 28 | expect(parseInt(store.state.mm.count)).to.equal(5) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /test/reserved_keys_as_properties.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | describe('prevent using reserved keys', () => { 8 | it('as module properties', function() { 9 | expect(() => { 10 | @Module 11 | class MyModule extends VuexModule { 12 | actions: any = null 13 | } 14 | }).to.throw(/ERR_RESERVED_STATE_KEY_USED: .*/) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /test/root_action_namespaced_module.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module({ namespaced: true }) 8 | class MyModule extends VuexModule { 9 | count = 100 10 | 11 | @Mutation 12 | modifyCount(count: number) { 13 | this.count = count 14 | } 15 | 16 | 17 | @Action({ commit: 'modifyCount', root: true, rawError: true }) 18 | async setCount(count: number) { 19 | return count 20 | } 21 | } 22 | 23 | const store = new Vuex.Store({ 24 | modules: { 25 | mm: MyModule 26 | } 27 | }) 28 | const app = createApp({}) 29 | app.use(store) 30 | 31 | describe('root action works', () => { 32 | it('should set count to 0', async function() { 33 | await store.dispatch('setCount', 0) 34 | expect(parseInt(store.state.mm.count)).to.equal(0) 35 | }) 36 | 37 | it('should not modify count', async function() { 38 | try { 39 | await store.dispatch('mm/setCount', 200) 40 | } catch (e: any) { 41 | expect(e).to.exist 42 | } 43 | expect(parseInt(store.state.mm.count)).to.equal(0) 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /test/root_mutationaction_namespaced_module.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Module, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module({ namespaced: true }) 8 | class MyModule extends VuexModule { 9 | count = 100 10 | 11 | @MutationAction({ mutate: ['count'], root: true, rawError: true }) 12 | async setCount(count: number) { 13 | return { count } 14 | } 15 | } 16 | 17 | const store = new Vuex.Store({ 18 | modules: { 19 | mm: MyModule 20 | } 21 | }) 22 | const app = createApp({}) 23 | app.use(store) 24 | 25 | describe('root mutationaction works', () => { 26 | it('should set count to 0', async function() { 27 | await store.dispatch('setCount', 0) 28 | expect(parseInt(store.state.mm.count)).to.equal(0) 29 | }) 30 | 31 | it('should not modify count', async function() { 32 | try { 33 | await store.dispatch('mm/setCount', 200) 34 | } catch (e: any) { 35 | expect(e).to.exist 36 | } 37 | expect(parseInt(store.state.mm.count)).to.equal(0) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /test/state_factory_state_isolation.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { Module as Mod } from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | @Module({ stateFactory: true, namespaced: true }) 8 | class FactoryModule extends VuexModule { 9 | wheels = 2 10 | 11 | @Mutation 12 | incrWheels(extra: number) { 13 | this.wheels += extra 14 | } 15 | 16 | get axles() { 17 | return this.wheels / 2 18 | } 19 | } 20 | 21 | @Module({ namespaced: true }) 22 | class StateObjectModule extends VuexModule { 23 | wheels = 2 24 | 25 | @Mutation 26 | incrWheels(extra: number) { 27 | this.wheels += extra 28 | } 29 | 30 | get axles() { 31 | return this.wheels / 2 32 | } 33 | } 34 | 35 | const store = new Vuex.Store({ 36 | modules: { 37 | factoryModA: FactoryModule, 38 | factoryModB: FactoryModule, 39 | objectModA: StateObjectModule, 40 | objectModB: StateObjectModule 41 | } 42 | }) 43 | const app = createApp({}) 44 | app.use(store) 45 | 46 | describe('state isolation', () => { 47 | it('should share state by default when reused', function() { 48 | store.commit('objectModA/incrWheels', 4) 49 | const axlesA = store.getters['objectModA/axles'] 50 | const axlesB = store.getters['objectModB/axles'] 51 | 52 | expect(axlesA).to.equal(3) 53 | expect(axlesB).to.equal(3) 54 | }) 55 | it('should isolate state using factories when reused', function() { 56 | store.commit('factoryModA/incrWheels', 4) 57 | const axlesA = store.getters['factoryModA/axles'] 58 | const axlesB = store.getters['factoryModB/axles'] 59 | 60 | expect(axlesA).to.equal(3) 61 | expect(axlesB).to.equal(1) 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /test/static_options.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | 4 | import { Action, Module, Mutation, MutationAction, VuexModule } from '..' 5 | import { expect } from 'chai' 6 | 7 | interface MyModule { 8 | count: number 9 | } 10 | 11 | @Module 12 | class MyModule extends VuexModule { 13 | static namespaced = true 14 | 15 | static state () { 16 | return { count: 0 } 17 | } 18 | 19 | @Mutation 20 | incrCount(delta: number) { 21 | this.count += delta 22 | } 23 | } 24 | 25 | const store = new Vuex.Store({ 26 | modules: { 27 | mm: MyModule 28 | } 29 | }) 30 | const app = createApp({}) 31 | app.use(store) 32 | 33 | describe('static module properties work', () => { 34 | it('should update count', function() { 35 | store.commit('mm/incrCount', 5) 36 | expect(parseInt(store.state.mm.count)).to.equal(5) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2015", 5 | "lib": ["dom", "es2015"], 6 | "experimentalDecorators": true, 7 | "allowSyntheticDefaultImports": true, 8 | "esModuleInterop": true, 9 | "moduleResolution": "node", 10 | "strict": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/vuex-persist.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import 'mock-local-storage' 3 | import { createApp } from 'vue' 4 | import Vuex from 'vuex' 5 | import { VuexPersistence } from 'vuex-persist' 6 | import { Module, Mutation, VuexModule } from '..' 7 | import { getModule } from '../src' 8 | 9 | 10 | 11 | interface StoreType { 12 | mm: MyModule 13 | } 14 | 15 | localStorage.setItem( 16 | 'vuex', 17 | JSON.stringify({ 18 | mm: { 19 | count: 20 20 | } 21 | }) 22 | ) 23 | 24 | let vuexLocal = new VuexPersistence({ 25 | storage: localStorage 26 | }) 27 | 28 | let store = new Vuex.Store({ 29 | plugins: [vuexLocal.plugin] 30 | }) 31 | 32 | @Module({ 33 | dynamic: true, 34 | namespaced: true, 35 | store: store, 36 | name: 'mm', 37 | preserveState: localStorage.getItem('vuex') !== null 38 | }) 39 | class MyModule extends VuexModule { 40 | count = 0 41 | 42 | @Mutation 43 | incrCount(delta: number) { 44 | this.count += delta 45 | } 46 | } 47 | 48 | @Module({ dynamic: true, namespaced: true, store: store, name: 'msm' }) 49 | class MySecondModule extends VuexModule { 50 | count = 0 51 | 52 | @Mutation 53 | incrCount(delta: number) { 54 | this.count += delta 55 | } 56 | } 57 | const app = createApp({}) 58 | app.use(store) 59 | 60 | describe('state restored by vuex-persist', () => { 61 | it('should restore state', function() { 62 | const mm = getModule(MyModule) 63 | mm.incrCount(5) 64 | expect(mm.count).to.equal(25) 65 | mm.incrCount(10) 66 | expect(mm.count).to.equal(35) 67 | 68 | const msm = getModule(MySecondModule) 69 | msm.incrCount(5) 70 | expect(msm.count).to.equal(5) 71 | msm.incrCount(10) 72 | expect(msm.count).to.equal(15) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /test/vuexmodule_constructor.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import { createApp } from 'vue' 3 | import { VuexModule } from '..' 4 | import { expect } from 'chai' 5 | 6 | 7 | 8 | const vehicle = new VuexModule({ 9 | state: { 10 | wheels: 2 11 | }, 12 | mutations: { 13 | incrWheels(state, extra) { 14 | state.wheels += extra 15 | } 16 | }, 17 | getters: { 18 | axles(state, rootState) { 19 | return state.wheels / 2 20 | } 21 | } 22 | }) 23 | 24 | const store = new Vuex.Store({ 25 | modules: { 26 | vehicle 27 | } 28 | }) 29 | const app = createApp({}) 30 | app.use(store) 31 | 32 | describe('new VuexModule() constuctor works', () => { 33 | it('should increase axles', function() { 34 | store.commit('incrWheels', 4) 35 | const axles = store.getters.axles 36 | expect(axles).to.equal(3) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2020", 4 | "target": "es2020", 5 | "moduleResolution": "node", 6 | "importHelpers": true, 7 | "sourceMap": true, 8 | "declaration": true, 9 | "declarationDir": "dist/types", 10 | "rootDir": "src", 11 | "outDir": "dist", 12 | "sourceRoot": "src", 13 | "strict": true, 14 | "removeComments": false, 15 | "strictNullChecks": true 16 | }, 17 | "include": [ 18 | "src" 19 | ], 20 | "exclude": [ 21 | "node_modules", 22 | "test" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint-config-standard", "tslint-config-prettier"], 4 | "jsRules": {}, 5 | "rules": { 6 | "prettier": [ 7 | true, 8 | { 9 | "semi": false, 10 | "arrowParens": "always", 11 | "singleQuote": true, 12 | "trailingComma": "none", 13 | "printWidth": 100 14 | } 15 | ], 16 | "radix": false 17 | }, 18 | "rulesDirectory": ["tslint-plugin-prettier"] 19 | } 20 | --------------------------------------------------------------------------------