Full Code of gertqin/vuex-class-modules for AI

master c5d19b483358 cached
41 files
54.5 KB
15.4k tokens
140 symbols
1 requests
Download .txt
Repository: gertqin/vuex-class-modules
Branch: master
Commit: c5d19b483358
Files: 41
Total size: 54.5 KB

Directory structure:
gitextract_ot546s4y/

├── .gitignore
├── .vscode/
│   └── settings.json
├── LICENSE
├── README.md
├── example/
│   ├── index.html
│   ├── src/
│   │   ├── api/
│   │   │   └── shop.ts
│   │   ├── app.ts
│   │   ├── components/
│   │   │   ├── App.vue
│   │   │   ├── ProductList.vue
│   │   │   └── ShoppingCart.vue
│   │   ├── shims-vue.d.ts
│   │   └── store/
│   │       ├── cart.ts
│   │       ├── index.ts
│   │       └── products.ts
│   ├── tsconfig.json
│   └── webpack.config.js
├── jestconfig.json
├── package.json
├── src/
│   ├── VuexModule.ts
│   ├── actions.ts
│   ├── index.ts
│   ├── module-factory.ts
│   ├── module.ts
│   └── mutations.ts
├── test/
│   ├── actions-inheritance.ts
│   ├── actions.ts
│   ├── constructor.ts
│   ├── generate-mutations.ts
│   ├── getters-inheritance.ts
│   ├── getters.ts
│   ├── instanceof.ts
│   ├── local-functions-inheritance.ts
│   ├── local-functions.ts
│   ├── module-reference.ts
│   ├── mutations-inheritance.ts
│   ├── mutations.ts
│   ├── state.ts
│   ├── tsconfig.json
│   └── watch.ts
├── tsconfig.json
└── tslint.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules
/lib
/commonjs
/example/build.js
/example/build.js.map


================================================
FILE: .vscode/settings.json
================================================
{
  "editor.rulers": [ 120 ],
  "prettier.printWidth": 120,
  "prettier.disableLanguages": [],

  "[typescript]": {
    "editor.formatOnSave": true
  },
  "[vue]": {
    "editor.formatOnSave": true
  },
  "tslint.autoFixOnSave": true,

  "vetur.format.defaultFormatter.html": "none",
  "vetur.format.defaultFormatter.ts": "none"
}

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 gertqin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# vuex-class-modules

This is yet another package to introduce a simple type-safe class style syntax for your vuex modules, inspired by [vue-class-component](https://github.com/vuejs/vue-class-component).

[![npm](https://img.shields.io/npm/v/vuex-class-modules.svg)](https://www.npmjs.com/package/vuex-class-modules)

## Installation

`npm install vuex-class-modules`

And make sure to have the `--experimentalDecorators` flag enabled.

Both a `commonjs` and a `esm` module build are published. If you have a webpack-based setup, it will use the `esm` modules by default.

## Usage

Vuex modules can be written using decorators as a class:

```typescript
// user-module.ts
import { VuexModule, Module, Mutation, Action } from "vuex-class-modules";

@Module
class UserModule extends VuexModule {
  // state
  firstName = "Foo";
  lastName = "Bar";

  // getters
  get fullName() {
    return this.firstName + " " + this.lastName;
  }

  // mutations
  @Mutation
  setFirstName(firstName: string) {
    this.firstName = firstName;
  }
  @Mutation
  setLastName(lastName: string) {
    this.lastName = lastName;
  }

  // actions
  @Action
  async loadUser() {
    const user = await fetchUser();
    this.setFirstName(user.firstName);
    this.setLastName(user.lastName);
  }
}

// register module (could be in any file)
import store from "path/to/store";
export const userModule = new UserModule({ store, name: "user" });
```

The module will automatically be registered to the store as a namespaced dynamic module when it is instantiated. (The modules are namespaced to avoid name conflicts between modules for getters/mutations/actions.)

The module can then be used in vue components as follows:

```ts
// MyComponent.vue
import Vue from "vue";
import { userModule } from "path/to/user-module.ts";

export class MyComponent extends Vue {
  get firstName() {
    return userModule.firstName; // -> store.state.user.firstName
  }
  get fullName() {
    return userModule.fullName; // -> store.getters["user/fullName]
  }

  created() {
    userModule.setFirstName("Foo"); // -> store.commit("user/setFirstName", "Foo")
    userModule.loadUser(); // -> store.dispatch("user/loadUser")
  }
}
```

### What about `rootState` and `rootGetters`?

There are two ways to access other modules within a module, or dispatch actions to other modules.

1. Simply import the instantiated module (suitable if the modules are instantiated in the same file as they are defined):

```ts
// my-module.ts

// import the module instance
import { otherModule } from "./other-module";

@Module
class MyModule extends VuexModule {
  get myGetter() {
    return otherModule.foo;
  }

  @Action
  async myAction() {
    await otherModule.someAction();
    // ...
  }
}
```

2. The other module can be registered through the constructor (suitable if the modules are instantiated elsewhere)

```ts
// my-module.ts

// import the class, not the instance
import { OtherModule } from "./other-module";

@Module
export class MyModule extends VuexModule {
  private otherModule: OtherModule;

  constructor(otherModule: OtherModule, options: RegisterOptions) {
    super(options);
    this.otherModule = otherModule;
  }

  get myGetter() {
    return this.otherModule.foo;
  }

  @Action
  async myAction() {
    await this.otherModule.someAction();
    // ...
  }
}

// register-modules.ts
import store from "path/to/store";
import { OtherModule } from "path/to/other-module";
import { MyModule } from "path/to/my-module";

export const otherModule = new OtherModule({ store, name: "otherModule" });
export const myModule = new MyModule(otherModule, { store, name: "myModule" });
```

The local modules will not be part of the state and cannot be accessed from the outside, so they should always be declared private.

```ts
myModule.otherModule; // -> undefined
```

### The `store.watch` function

Vuex can also be used ouside of vue modules. To listen for changes to the state, vuex provides a [watch method](https://vuex.vuejs.org/api/#watch).

This api is also provided by vuex-class-modules under the method name `$watch` to prevent name collisions. For example you can do:

```ts
import store from "./store";
import { MyModule } from "./my-module";

const myModule = new MyModule({ store, name: "MyModule" });
myModule.$watch(
  (theModule) => theModule.fullName,
  (newName: string, oldName: string) => {
    // ...
  },
  {
    deep: false,
    immediate: false,
  }
);
```

and to unwatch:

```ts
const unwatch = myModule.$watch(...);
unwatch();
```

### Register options

- `name` [required]: Name of the module
- `store` [required]: The vuex store - which can just be instantiated as empty:

```ts
// store.ts
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({});
```

### Module options

The module decorator can also accept options:

- `generateMutationSetters` [optional, default=false]: Whether automatic mutation setters for the state properties should be generated, see [Generate Mutation Setters](#generate-mutation-setters).

## Example

The vuex shopping cart example rewritten using `vue-class-component` and `vuex-class-modules` can be found in the [example directory](/example). Build the example using:

`npm run example`

## Caveats of `this`

As for vue-class-component `this` inside the module is just a proxy object to the store. It can therefore only access what the corresponding vuex module function would be able to access:

```ts
@Module
class MyModule extends VuexModule {
  foo = "bar";

  get someGetter() {
    return 123;
  }
  get myGetter() {
    this.foo; // -> "bar"
    this.someGetter; // -> 123
    this.someMutation(); // undefined, getters cannot call mutations
    this.someAction(); // -> undefined, getters cannot call actions
  }

  @Mutation
  someMutation() {
    /* ... */
  }
  @Mutation
  myMutation() {
    this.foo; // -> "bar"
    this.someGetter; // -> undefined, mutations dont have access to getters
    this.someMutation(); // -> undefined, mutations cannot call other mutations
    this.someAction(); // -> undefined, mutations cannot call actions
  }

  @Action
  async someAction() {
    /* ... */
  }
  @Action
  async myAction() {
    this.foo; // -> "bar"
    this.someGetter; // -> 123
    this.myMutation(); // Ok
    await this.someAction(); // Ok
  }
}
```

## Local Functions

The module can have non-mutation/action functions which can be used inside the module. As for local modules, these functions will not be exposed outside the module and should therefore be private. `this` will be passed on to the local function from the getter/mutation/action.

```ts
@Module
class MyModule extends VuexModule {
  get myGetter() {
    return myGetterHelper();
  }
  private myGetterHelper() {
    // same 'this' context as myGetter
  }

  @Mutation
  myMutation() {
    this.myMutationHelper();
  }

  // should be private
  myMutationHelper() { /* ... */}
}
const myModule = new MyModule({ store, name: "myModule });
myModule.myMutationHelper // -> undefined.
```

## Generate Mutation Setters

As I often find myself writing a lot of simple setter mutations like

```ts
@Module
class UserModule extends VuexModule {
  firstName = "Foo";
  lastName = "Bar";

  @Mutation
  setFirstName(firstName: string) {
    this.firstName = firstName;
  }
  @Mutation
  setLastName(lastName: string) {
    this.lastName = lastName;
  }
}
```

a module option `generateMutationSetters` has been added, which when enabled will generate a setter mutation for each state property. The state can then be modified directly from the actions:

```ts
@Module({ generateMutationSetters: true })
class UserModule extends VuexModule {
  firstName = "Foo";
  lastName = "Bar";

  // Auto generated:
  // @Mutation set__firstName(val: any) { this.firstName = val }
  // @Mutation set__lastName(val: any) { this.lastName = val }

  @Action
  async loadUser() {
    const user = await fetchUser();
    this.firstName = user.firstName; // -> this.set__firstName(user.firstName);
    this.lastName = user.lastName; // -> this.set__lastName(user.lastName);
  }
}
```

_NOTE:_ Setters are only generated for root-level state properties, so in order to update a property of an object you have to use a mutation or replace the entire object:

```ts
@Module({ generateMutationSetters: true })
class UserModule extends VuexModule {
  user = {
    id: 123,
    name: "Foo",
  };

  @Mutation
  setUserName() {
    this.user.name = "Bar"; // OK!
  }

  @Action
  async loadUser() {
    this.user.name = "Bar"; // Bad, the state is mutated outside a mutation
    this.user = { ...this.user, name: "Bar" }; // OK!
  }
}
```

## Vite HMR

[Vite](https://vitejs.dev/) (and possibly other bundlers) uses `import.meta.hot` for HMR, which `vuex-class-modules` doesn't support currently. Instead a static property

```ts
VuexModule.__useHotUpdate = true; // default false
```

is provided, which will force hot updates to the store instead of throwing an error when a module with a duplicate name is registered. This could for instance be set only in dev mode

```ts
VuexModule.__useHotUpdate = import.meta.env.DEV;
```

## License

[MIT](http://opensource.org/licenses/MIT)


================================================
FILE: example/index.html
================================================

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Vuex Class Modules Example</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="build.js"></script>
  </body>
</html>

================================================
FILE: example/src/api/shop.ts
================================================
/**
 * Mocking client-server processing
 */
export interface Product {
  id: number;
  title: string;
  price: number;
  inventory: number;
}

export interface CartItem {
  id: number;
  quantity: number;
}

const products: Product[] = [
  { id: 1, title: "iPad 4 Mini", price: 500.01, inventory: 2 },
  { id: 2, title: "H&M T-Shirt White", price: 10.99, inventory: 10 },
  { id: 3, title: "Charli XCX - Sucker CD", price: 19.99, inventory: 5 }
];

export default {
  async getProducts() {
    await new Promise(resolve => setTimeout(resolve, 100));
    return products;
  },

  async buyProducts(items: CartItem[]) {
    await new Promise(resolve => setTimeout(resolve, 100));

    if (Math.random() > 0.5) {
      throw Error();
    }
  }
};


================================================
FILE: example/src/app.ts
================================================
import Vue from "vue";
import App from "./components/App.vue";
import store from "./store";

new Vue({
  el: "#app",
  store,
  render: h => h(App)
});


================================================
FILE: example/src/components/App.vue
================================================
<template>
  <div id="app">
    <h1>Shopping Cart Example</h1>
    <hr />
    <h2>Products</h2>
    <ProductList />
    <hr />
    <ShoppingCart />
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import ProductList from "./ProductList.vue";
import ShoppingCart from "./ShoppingCart.vue";

@Component({
  components: { ProductList, ShoppingCart }
})
export default class App extends Vue {}
</script>


================================================
FILE: example/src/components/ProductList.vue
================================================
<template>
  <ul>
    <li v-for="product in products" :key="product.id">
      {{ product.title }} - {{ product.price }}€<br />
      <button :disabled="!product.inventory" @click="addProductToCart(product);">Add to cart</button>
    </li>
  </ul>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import { productsModule } from "../store/products";
import { cartModule } from "../store/cart";
import { Product } from "../api/shop";

@Component
export default class ProductList extends Vue {
  get products() {
    return productsModule.all;
  }

  created() {
    productsModule.getAllProducts();
  }

  addProductToCart(product: Product) {
    cartModule.addProductToCart(product);
  }
}
</script>


================================================
FILE: example/src/components/ShoppingCart.vue
================================================
<template>
  <div class="cart">
    <h2>Your Cart</h2>
    <p v-show="!products.length"><i>Please add some products to cart.</i></p>
    <ul>
      <li v-for="product in products" :key="product.id">
        {{ product.title }} - {{ product.price }}€ x {{ product.quantity }}
      </li>
    </ul>
    <p>Total: {{ total }}€</p>
    <p><button :disabled="!products.length" @click="checkout(products);">Checkout</button></p>
    <p v-show="checkoutStatus">Checkout {{ checkoutStatus }}.</p>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";
import { cartModule } from "../store/cart";

@Component
export default class ShoppingCart extends Vue {
  get checkoutStatus() {
    return cartModule.checkoutStatus;
  }
  get products() {
    return cartModule.cartProducts;
  }
  get total() {
    return cartModule.cartTotalPrice;
  }

  checkout() {
    cartModule.checkout();
  }
}
</script>


================================================
FILE: example/src/shims-vue.d.ts
================================================
declare module "*.vue" {
  import Vue from "vue";
  export default Vue;
}


================================================
FILE: example/src/store/cart.ts
================================================
import store from "./";
import shop, { CartItem, Product } from "../api/shop";
import { Module, Mutation, Action, VuexModule } from "../../../lib/index";
import { productsModule } from "./products";

@Module({ generateMutationSetters: true })
class Cart extends VuexModule {
  items: CartItem[] = [];
  checkoutStatus = "";

  get cartProducts() {
    return this.items.map(({ id, quantity }) => {
      const product = productsModule.all.find(p => p.id === id);
      return {
        title: product!.title,
        price: product!.price,
        quantity
      };
    });
  }

  get cartTotalPrice() {
    return this.cartProducts.reduce((total, product) => {
      return total + product.price * product.quantity;
    }, 0);
  }

  @Mutation
  pushProductToCart(id: number) {
    this.items.push({
      id,
      quantity: 1
    });
  }

  @Mutation
  incrementItemQuantity(id: number) {
    const cartItem = this.items.find(item => item.id === id);
    cartItem!.quantity++;
  }

  @Action
  async addProductToCart(product: Product) {
    this.checkoutStatus = "";

    if (product.inventory > 0) {
      const cartItem = this.items.find(item => item.id === product.id);
      if (!cartItem) {
        this.pushProductToCart(product.id);
      } else {
        this.incrementItemQuantity(cartItem.id);
      }
      // remove 1 item from stock
      productsModule.decrementProductInventory(product.id);
    }
  }

  @Action
  async checkout() {
    const savedCartItems = [...this.items];
    this.checkoutStatus = "";

    // empty cart
    this.items = [];

    try {
      await shop.buyProducts(savedCartItems);
      this.checkoutStatus = "successful";
    } catch (e) {
      this.items = savedCartItems;
      this.checkoutStatus = "failed";
    }
  }
}

export const cartModule = new Cart({ store, name: "cart" });


================================================
FILE: example/src/store/index.ts
================================================
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);

export default new Vuex.Store({});


================================================
FILE: example/src/store/products.ts
================================================
import store from "./";
import shop, { Product } from "../api/shop";
import { Module, Mutation, Action, VuexModule } from "../../../lib/index";

@Module({ generateMutationSetters: true })
class Products extends VuexModule {
  all: Product[] = [];

  @Mutation
  decrementProductInventory(id: number) {
    const product = this.all.find(p => p.id === id);
    product!.inventory--;
  }

  @Action
  async getAllProducts() {
    this.all = await shop.getProducts();
  }
}

export const productsModule = new Products({ store, name: "products" });


================================================
FILE: example/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "esnext",
    "lib": [
      "dom",
      "esnext"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": false
  },
  "include": [
    "./**/*.ts",
  ]
}

================================================
FILE: example/webpack.config.js
================================================
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  mode: 'development',
  context: __dirname,
  entry: './src/app.ts',
  output: {
    path: __dirname,
    filename: 'build.js'
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js']
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              appendTsSuffixTo: [/\.vue$/],
              appendTsxSuffixTo: [/\.vue$/]
            }
          }
        ]
      },
      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },
  devtool: 'source-map',
  plugins: [
    new VueLoaderPlugin()
  ]
}

================================================
FILE: jestconfig.json
================================================
{
  "preset": "ts-jest",
  "rootDir": "./test",
  "testMatch": ["<rootDir>/**/*.ts"],
  "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
  "globals": {
    "ts-jest": {
      "tsConfig": {
        "isolatedModules": false,
        "esModuleInterop": true
      }
    }
  }
}

================================================
FILE: package.json
================================================
{
  "name": "vuex-class-modules",
  "version": "1.3.0",
  "description": "Typescript class decorators for class-style vuex modules.",
  "main": "commonjs/index.js",
  "module": "lib/index.js",
  "exports": {
    ".": {
      "require": "./commonjs/index.js",
      "default": "./lib/index.js"
    }
  },
  "types": "lib/index.d.ts",
  "files": [
    "lib",
    "commonjs"
  ],
  "scripts": {
    "test": "jest --config jestconfig.json",
    "build": "npm run build:es2015 && npm run build:commonjs",
    "build:es2015": "tsc",
    "build:commonjs": "tsc -m commonjs --outDir ./commonjs",
    "lint": "tslint -p tsconfig.json --fix",
    "example": "npm run build && webpack --config ./example/webpack.config.js",
    "prepare": "npm run build",
    "prepublishOnly": "npm test && npm run lint",
    "preversion": "npm run lint",
    "version": "git add -A src",
    "postversion": "git push && git push --tags"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/gertqin/vuex-class-modules.git"
  },
  "keywords": [
    "vue",
    "vuex",
    "typescript",
    "class",
    "decorators"
  ],
  "author": "Gert Qin Hansen",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/gertqin/vuex-class-modules/issues"
  },
  "homepage": "https://github.com/gertqin/vuex-class-modules#readme",
  "devDependencies": {
    "@types/node": "12.12.2",
    "@types/jest": "^26.0.14",
    "@types/webpack-env": "^1.13.9",
    "css-loader": "^3.2.0",
    "jest": "^26.4.0",
    "ts-jest": "^26.4.0",
    "ts-loader": "^6.2.0",
    "tslint": "^5.20.0",
    "tslint-config-prettier": "^1.18.0",
    "tslint-plugin-prettier": "^2.0.1",
    "typescript": "^3.8.4",
    "vue": "^2.6.10",
    "vue-class-component": "^7.1.0",
    "vue-loader": "^15.7.0",
    "vue-template-compiler": "^2.6.10",
    "vuex": "^3.1.1",
    "webpack": "^4.44.2",
    "webpack-cli": "^3.3.12"
  }
}


================================================
FILE: src/VuexModule.ts
================================================
import { RegisterOptions } from "./module-factory";
import { WatchOptions } from "vue";

export class VuexModule {
  private __options: RegisterOptions;

  static __useHotUpdate: boolean = false;

  constructor(options: RegisterOptions) {
    this.__options = options;
  }

  $watch<T>(fn: (arg: this) => T, callback: (newValue: T, oldValue: T) => void, options?: WatchOptions): Function {
    return function() {};
  }
}


================================================
FILE: src/actions.ts
================================================
import { ModulePrototype } from "./module-factory";

export function Action<T extends Object>(
  target: T,
  key: string | symbol,
  descriptor: TypedPropertyDescriptor<(arg?: any) => any>
) {
  const vuexModule = target.constructor as ModulePrototype;
  if (!vuexModule.__actions) {
    vuexModule.__actions = {};
  }
  if (descriptor.value) {
    vuexModule.__actions[key as string] = descriptor.value;
  }
}


================================================
FILE: src/index.ts
================================================
export { RegisterOptions, ModuleOptions } from "./module-factory";
export { Action } from "./actions";
export { Module } from "./module";
export { Mutation } from "./mutations";
export { VuexModule } from "./VuexModule";


================================================
FILE: src/module-factory.ts
================================================
import { Store, Module as StoreModule, GetterTree, ActionContext, Dispatch, Commit } from "vuex";
import { WatchOptions } from "vue";
import { VuexModule } from "./VuexModule";

export interface ModuleOptions {
  generateMutationSetters?: boolean;
}

export interface RegisterOptions {
  store: Store<any>;
  name: string;
}

export interface IVuexModule extends Dictionary<any> {
  __options: RegisterOptions;
}
export interface IModulePrototype {
  __mutations?: Dictionary<(payload?: any) => void>;
  __actions?: Dictionary<(payload?: any) => Promise<void>>;
}
export type ModulePrototype = IModulePrototype & Function;

type Dictionary<T> = { [k: string]: T };

interface ModuleDefinition {
  state: Dictionary<any>;
  moduleRefs: Dictionary<VuexModule>;
  getters: Dictionary<() => void>;
  mutations: Dictionary<(payload?: any) => void>;
  actions: Dictionary<(payload?: any) => Promise<void>>;
  localFunctions: Dictionary<(...args: any[]) => any>;
}
interface StoreProxyDefinition {
  state?: Dictionary<any>;
  stateSetter?: (key: string, val: any) => void;

  getters?: Dictionary<any>;
  commit?: Commit;
  dispatch?: Dispatch;

  useNamespaceKey?: boolean;
  excludeModuleRefs?: boolean;
  excludeLocalFunctions?: boolean;
}

export class VuexClassModuleFactory {
  moduleOptions: ModuleOptions;
  instance: IVuexModule;
  registerOptions: RegisterOptions;

  definition: ModuleDefinition = {
    state: {},
    moduleRefs: {},
    getters: {},
    mutations: {},
    actions: {},
    localFunctions: {}
  };

  constructor(classModule: ModulePrototype, instance: IVuexModule, moduleOptions: ModuleOptions) {
    this.moduleOptions = moduleOptions;
    this.instance = instance;
    this.registerOptions = instance.__options;
    this.init(classModule);
  }

  private init(classModule: ModulePrototype) {
    // state
    for (const key of Object.keys(this.instance)) {
      const val = this.instance[key];
      if (key !== "__options" && this.instance.hasOwnProperty(key)) {
        if (val instanceof VuexModule) {
          this.definition.moduleRefs[key] = val;
        } else {
          this.definition.state[key] = this.instance[key];
        }
      }
    }

    const actionKeys = Object.keys(classModule.__actions || {});
    const mutationKeys = Object.keys(classModule.__mutations || {});
    const isAction = (key: string) => actionKeys.indexOf(key) !== -1;
    const isMutation = (key: string) => mutationKeys.indexOf(key) !== -1;

    for (const module of getModulePrototypes(classModule)) {
      for (const key of Object.getOwnPropertyNames(module.prototype)) {
        const descriptor = Object.getOwnPropertyDescriptor(module.prototype, key) as PropertyDescriptor;

        const isGetter = !!descriptor.get;
        if (isGetter && !(key in this.definition.getters)) {
          this.definition.getters[key] = descriptor.get!;
        }

        if (isAction(key) && !(key in this.definition.actions) && descriptor.value) {
          this.definition.actions[key] = module.prototype[key];
        }
        if (isMutation(key) && !(key in this.definition.mutations) && descriptor.value) {
          this.definition.mutations[key] = module.prototype[key];
        }

        const isHelperFunction =
          descriptor.value &&
          typeof module.prototype[key] === "function" &&
          !isAction(key) &&
          !isMutation(key) &&
          key !== "constructor";

        if (isHelperFunction && !(key in this.definition.localFunctions)) {
          this.definition.localFunctions[key] = module.prototype[key];
        }
      }
    }
  }

  registerVuexModule() {
    const vuexModule: StoreModule<any, any> = {
      state: this.definition.state,
      getters: {},
      mutations: {},
      actions: {},
      namespaced: true
    };

    // getters
    mapValues(vuexModule.getters!, this.definition.getters, getter => {
      return (state: any, getters: GetterTree<any, any>) => {
        const thisObj = this.buildThisProxy({ state, getters });
        return getter.call(thisObj);
      };
    });

    // mutations
    mapValues(vuexModule.mutations!, this.definition.mutations, mutation => {
      return (state: any, payload: any) => {
        const thisObj = this.buildThisProxy({
          state,
          stateSetter: (stateField: string, val: any) => {
            state[stateField] = val;
          }
        });
        mutation.call(thisObj, payload);
      };
    });
    if (this.moduleOptions.generateMutationSetters) {
      for (const stateKey of Object.keys(this.definition.state)) {
        const mutation = (state: any, payload: any) => {
          state[stateKey] = payload;
        };
        vuexModule.mutations![this.getMutationSetterName(stateKey)] = mutation;
      }
    }

    // actions
    mapValues(vuexModule.actions!, this.definition.actions, action => {
      return (context: ActionContext<any, any>, payload: any) => {
        const proxyDefinition: StoreProxyDefinition = {
          ...context,
          stateSetter: this.moduleOptions.generateMutationSetters
            ? (field: string, val: any) => {
                context.commit(this.getMutationSetterName(field), val);
              }
            : undefined
        };
        const thisObj = this.buildThisProxy(proxyDefinition);

        return action.call(thisObj, payload);
      };
    });

    // register module
    const { store, name } = this.registerOptions;
    if (store.state[name]) {
      if (VuexModule.__useHotUpdate || (typeof module !== "undefined" && module.hot)) {
        store.hotUpdate({
          modules: {
            [name]: vuexModule
          }
        });
      } else {
        throw Error(`[vuex-class-module]: A module with name '${name}' already exists.`);
      }
    } else {
      store.registerModule(this.registerOptions.name, vuexModule);
    }
  }

  buildAccessor() {
    const { store, name } = this.registerOptions;

    const stateSetter = this.moduleOptions.generateMutationSetters
      ? (field: string, val: any) => {
          store.commit(`${name}/${this.getMutationSetterName(field)}`, val);
        }
      : undefined;

    const accessorModule = this.buildThisProxy({
      ...store,
      state: store.state[name],
      stateSetter,
      useNamespaceKey: true,
      excludeModuleRefs: true,
      excludeLocalFunctions: true
    });

    // watch API
    accessorModule.$watch = (
      fn: (arg: VuexModule) => any,
      callback: (newValue: any, oldValue: any) => void,
      options?: WatchOptions
    ) => {
      return store.watch(
        (state: any, getters: any) =>
          fn(
            this.buildThisProxy({
              state: state[name],
              getters,
              useNamespaceKey: true
            })
          ),
        callback,
        options
      );
    };

    Object.setPrototypeOf(accessorModule, Object.getPrototypeOf(this.instance));
    Object.freeze(accessorModule);

    return accessorModule;
  }

  private buildThisProxy(proxyDefinition: StoreProxyDefinition) {
    const obj: any = {};

    if (proxyDefinition.state) {
      mapValuesToProperty(
        obj,
        this.definition.state,
        key => proxyDefinition.state![key],
        proxyDefinition.stateSetter
          ? (key, val) => proxyDefinition.stateSetter!(key, val)
          : () => {
              throw Error("[vuex-class-module]: Cannot modify state outside mutations.");
            }
      );
    }
    if (!proxyDefinition.excludeModuleRefs) {
      mapValues(obj, this.definition.moduleRefs, val => val);
    }

    const namespaceKey = proxyDefinition.useNamespaceKey ? this.registerOptions.name + "/" : "";

    if (proxyDefinition.getters) {
      mapValuesToProperty(obj, this.definition.getters, key => proxyDefinition.getters![`${namespaceKey}${key}`]);
    }

    if (proxyDefinition.commit) {
      mapValues(obj, this.definition.mutations, (mutation, key) => {
        return (payload?: any) => proxyDefinition.commit!(`${namespaceKey}${key}`, payload);
      });
    }

    if (proxyDefinition.dispatch) {
      mapValues(obj, this.definition.actions, (action, key) => {
        return (payload?: any) => proxyDefinition.dispatch!(`${namespaceKey}${key}`, payload);
      });
    }

    if (!proxyDefinition.excludeLocalFunctions) {
      mapValues(obj, this.definition.localFunctions, localFunction => {
        return (...args: any[]) => localFunction.apply(obj, args);
      });
    }

    return obj;
  }

  private getMutationSetterName(stateKey: string) {
    return "set__" + stateKey;
  }
}

function mapValues<S, V>(target: Dictionary<any>, source: Dictionary<S>, mapFunc: (val: S, key: string) => V) {
  for (const key of Object.keys(source)) {
    target[key] = mapFunc(source[key], key);
  }
}

function mapValuesToProperty<S, V>(
  target: Dictionary<any>,
  source: Dictionary<S>,
  get: (key: string) => any,
  set?: (key: string, val: any) => void
) {
  for (const key of Object.keys(source)) {
    Object.defineProperty(target, key, {
      get: () => get(key),
      set: set ? (val: string) => set(key, val) : undefined
    });
  }
}

function getModulePrototypes(module: ModulePrototype): ModulePrototype[] {
  const prototypes: ModulePrototype[] = [];

  for (let prototype = module; prototype && prototype !== VuexModule; prototype = Object.getPrototypeOf(prototype)) {
    prototypes.push(prototype);
  }

  return prototypes;
}


================================================
FILE: src/module.ts
================================================
import { VuexClassModuleFactory, ModuleOptions, IVuexModule } from "./module-factory";
import { VuexModule } from "./VuexModule";

type VuexModuleClass = new (...args: any[]) => VuexModule;
export function Module<T extends VuexModuleClass>(target: T): T;
export function Module(options?: ModuleOptions): ClassDecorator;
export function Module<T extends VuexModuleClass>(arg?: ModuleOptions | T): ClassDecorator | T {
  if (typeof arg === "function") {
    return moduleDecoratorFactory()(arg) as T;
  } else {
    return moduleDecoratorFactory(arg);
  }
}

function moduleDecoratorFactory(moduleOptions?: ModuleOptions) {
  return <TFunction extends Function>(constructor: TFunction): TFunction => {
    const accessor: any = function(...args: any[]) {
      const instance = new constructor.prototype.constructor(...args) as IVuexModule;
      Object.setPrototypeOf(instance, accessor.prototype);

      const factory = new VuexClassModuleFactory(constructor, instance, moduleOptions || {});

      factory.registerVuexModule();
      return factory.buildAccessor();
    };
    accessor.prototype = Object.create(constructor.prototype);
    accessor.prototype.constructor = accessor;
    return accessor;
  };
}


================================================
FILE: src/mutations.ts
================================================
import { ModulePrototype } from "./module-factory";

export function Mutation<T extends Object>(
  target: T,
  key: string | symbol,
  descriptor: TypedPropertyDescriptor<(arg?: any) => void>
) {
  const vuexModule = target.constructor as ModulePrototype;
  if (!vuexModule.__mutations) {
    vuexModule.__mutations = {};
  }
  if (descriptor.value) {
    vuexModule.__mutations[key as string] = descriptor.value;
  }
}


================================================
FILE: test/actions-inheritance.ts
================================================
import { Action, Module, Mutation, VuexModule, RegisterOptions } from "../src";
import Vuex, { Store } from "vuex";
import Vue from "vue";

Vue.use(Vuex);

abstract class ParentModule extends VuexModule {
  foo = "init";

  get bigFoo() {
    return this.foo.toUpperCase();
  }

  get decoratedFoo() {
    return `***${this.foo}***`;
  }

  @Mutation
  updateFoo(value: string) {
    this.foo = value;
  }

  @Action
  action1() {
    //
  }

  @Action
  action2() {
    //
  }

  @Action
  action3() {
    //
  }

  @Action
  action4() {
    //
  }

  @Action
  action5() {
    this.updateFoo(this.foo + "action5");
  }

  @Action
  action6() {
    this.updateFoo(this.foo + "polymorphicCallOf");
    this.action7();
  }

  abstract action7(): void;
}

@Module
class Module1 extends ParentModule {
  private tag = "child1";
  foo: string = "init" + this.tag;

  get doubleFoo() {
    return this.foo + this.foo;
  }

  @Mutation
  setFooToExample() {
    this.foo = "example" + this.tag;
  }

  @Action
  action1() {
    this.setFooToExample();
  }

  @Action
  action2() {
    this.updateFoo("bar" + this.tag);
  }

  @Action
  action3() {
    this.updateFoo(this.doubleFoo);
  }

  @Action
  action4() {
    this.updateFoo(this.bigFoo);
  }

  @Action
  action5() {
    super.action5();
    this.updateFoo(this.foo + this.tag);
  }

  @Action
  action7(): void {
    this.updateFoo(this.foo + "action7" + this.tag);
  }
}

@Module
class Module2 extends ParentModule {
  private tag = "child2";

  constructor(options: RegisterOptions) {
    super(options);
    this.foo = this.foo + this.tag;
  }

  get tripleFoo() {
    return this.foo + this.foo + this.foo;
  }

  @Mutation
  setFooToAnotherExample() {
    this.foo = "example" + this.tag;
  }

  @Action
  action1() {
    this.setFooToAnotherExample();
  }

  @Action
  action2() {
    this.updateFoo("baz" + this.tag);
  }

  @Action
  action3() {
    this.updateFoo(this.tripleFoo);
  }

  @Action
  action4() {
    this.updateFoo(this.decoratedFoo);
  }

  @Action
  action5() {
    super.action5();
    this.updateFoo(this.foo + this.tag);
  }

  @Action
  action7(): void {
    this.updateFoo(this.foo + "action7" + this.tag);
  }
}

describe("actions-inheritance", () => {
  let store: Store<any>;
  let child1: Module1;
  let child2: Module2;

  beforeEach(() => {
    store = new Vuex.Store({});
    child1 = new Module1({ store, name: "child1" });
    child2 = new Module2({ store, name: "child2" });
  });

  test("overriden action has access to mutations", () => {
    child1.action1();
    child2.action1();
    expect(child1.foo).toBe("examplechild1");
    expect(child2.foo).toBe("examplechild2");
  });

  test("overriden action has access to parent mutations", () => {
    child1.action2();
    child2.action2();
    expect(child1.foo).toBe("barchild1");
    expect(child2.foo).toBe("bazchild2");
  });

  test("overriden action has access to getters", () => {
    child1.action3();
    child2.action3();
    expect(child1.foo).toBe("initchild1initchild1");
    expect(child2.foo).toBe("initchild2initchild2initchild2");
  });

  test("overriden action has access to parent getters", () => {
    child1.action4();
    child2.action4();
    expect(child1.foo).toBe("INITCHILD1");
    expect(child2.foo).toBe("***initchild2***");
  });

  test("overriden action has access to parent method implementation", () => {
    child1.action5();
    child2.action5();
    expect(child1.foo).toBe("initchild1action5child1");
    expect(child2.foo).toBe("initchild2action5child2");
  });

  test("parent action access derived action polymorphically", () => {
    child1.action6();
    child2.action6();
    expect(child1.foo).toBe("initchild1polymorphicCallOfaction7child1");
    expect(child2.foo).toBe("initchild2polymorphicCallOfaction7child2");
  });
  test("access action7 directly", () => {
    child1.action7();
    child2.action7();
    expect(child1.foo).toBe("initchild1action7child1");
    expect(child2.foo).toBe("initchild2action7child2");
  });
});


================================================
FILE: test/actions.ts
================================================
import { Module, Mutation, Action, VuexModule } from "../src";
import Vuex, { Payload, MutationPayload } from "vuex";
import Vue from "vue";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module
class MyModule extends VuexModule {
  documentId = 0;
  text = "";

  get documentHasText() {
    return this.documentId > 10;
  }

  @Mutation
  setDocumentId(id: number) {
    this.documentId = id;
  }
  @Mutation
  setText(text: string) {
    this.text = text;
  }

  @Action
  async dummyAction(payload: any) {
    // to test accessor
  }

  @Action
  async loadText(documentId: number) {
    if (this.documentId === 0) {
      this.setDocumentId(documentId);

      if (this.documentHasText) {
        const text = await Promise.resolve("some other text");
        this.setText(text);
      }
    }
  }
}

const myModule = new MyModule({ store, name: "myModule" });

interface ActionPayload extends Payload {
  payload?: any;
}

describe("actions", () => {
  test("accessor dispatches action", async () => {
    // subscribeAction missing from vuex typings
    const actionObserver = jest.fn((action: ActionPayload) => action);
    (store as any).subscribeAction(actionObserver);

    await myModule.dummyAction(5);

    expect(actionObserver.mock.calls.length).toBe(1);

    const mutationPayload = actionObserver.mock.results[0].value as ActionPayload;
    expect(mutationPayload.type).toBe("myModule/dummyAction");
    expect(mutationPayload.payload).toBe(5);
  });

  test("'this' matches vuex context", async () => {
    const mutationObserver = jest.fn((mutation: MutationPayload) => mutation);
    store.subscribe(mutationObserver);

    await store.dispatch("myModule/loadText", 11);

    expect(mutationObserver.mock.calls.length).toBe(2);

    const firstMutation = mutationObserver.mock.results[0].value as MutationPayload;
    expect(firstMutation.type).toBe("myModule/setDocumentId");
    expect(firstMutation.payload).toBe(11);

    const secondMutation = mutationObserver.mock.results[1].value as MutationPayload;
    expect(secondMutation.type).toBe("myModule/setText");
    expect(secondMutation.payload).toBe("some other text");
  });
});


================================================
FILE: test/constructor.ts
================================================
import { Module, VuexModule, RegisterOptions } from "../src";
import Vuex from "vuex";
import Vue from "vue";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module
class MyModule extends VuexModule {
  foo: string;

  constructor(foo: string, options: RegisterOptions) {
    super(options);
    this.foo = foo;
  }
}

test("constructor", () => {
  const myModule = new MyModule("bar", { store, name: "myModule" });
  expect(myModule.foo).toBe("bar");
});


================================================
FILE: test/generate-mutations.ts
================================================
import Vue from "vue";
import Vuex, { MutationPayload } from "vuex";
import { Action, Module, VuexModule } from "../src";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module({ generateMutationSetters: true })
class MyModule extends VuexModule {
  id = 0;
  text = "";

  @Action
  async loadData() {
    const { id, text } = await Promise.resolve({ id: 1, text: "some text" });
    this.id = id;
    this.text = text;
  }
}

const myModule = new MyModule({ store, name: "myModule" });

test("generate-mutations", async () => {
  const mutationObserver = jest.fn((mutation: MutationPayload) => mutation);
  store.subscribe(mutationObserver);

  await myModule.loadData();

  const firstMutation = mutationObserver.mock.results[0].value as MutationPayload;
  expect(firstMutation.type).toBe("myModule/set__id");
  expect(firstMutation.payload).toBe(1);

  const secondMutation = mutationObserver.mock.results[1].value as MutationPayload;
  expect(secondMutation.type).toBe("myModule/set__text");
  expect(secondMutation.payload).toBe("some text");

  // change state directly using generated mutation
  myModule.text = "some other text";

  const thirdMutation = mutationObserver.mock.results[2].value as MutationPayload;
  expect(thirdMutation.type).toBe("myModule/set__text");
  expect(thirdMutation.payload).toBe("some other text");
});


================================================
FILE: test/getters-inheritance.ts
================================================
import { Action, Module, Mutation, VuexModule } from "../src";
import Vuex, { Store } from "vuex";
import Vue from "vue";

Vue.use(Vuex);

class ParentModule extends VuexModule {
  foo = "bar";

  get bigFoo() {
    return this.foo.toUpperCase();
  }

  get snakeFoo() {
    return "__";
  }

  @Mutation
  myMutation(value: string) {
    this.foo = value;
  }

  @Action
  myAction() {
    if (this.bigFoo === "BAR") {
      this.myMutation("ok");
    }
    if (this.bigFoo === "BAZ") {
      this.myMutation("alright");
    }
  }
}

@Module
class Module1 extends ParentModule {
  private tag = "child1";

  get snakeFoo() {
    return `_${this.foo}_${this.tag}_`;
  }
}

@Module
class Module2 extends ParentModule {
  private tag = "child2";
  foo = "baz";

  get snakeFoo() {
    return `_${this.foo}_${this.tag}_`;
  }
}

describe("getters-inheritance", () => {
  let store: Store<any>;
  let child1: Module1;
  let child2: Module2;

  beforeEach(() => {
    store = new Vuex.Store({});
    child1 = new Module1({ store, name: "child1" });
    child2 = new Module2({ store, name: "child2" });
  });

  test("allows the use of getters from an inheriting class", () => {
    expect(child1.bigFoo).toBe("BAR");
    expect(child1.bigFoo).toBe(store.getters["child1/bigFoo"]);
    expect(child2.bigFoo).toBe("BAZ");
    expect(child2.bigFoo).toBe(store.getters["child2/bigFoo"]);
  });

  test("allows the use of getters in inherited class", () => {
    child1.myAction();
    child2.myAction();
    expect(child1.bigFoo).toBe("OK");
    expect(child1.bigFoo).toBe(store.getters["child1/bigFoo"]);
    expect(child2.bigFoo).toBe("ALRIGHT");
    expect(child2.bigFoo).toBe(store.getters["child2/bigFoo"]);
  });

  test("overriden getters behave as expected", () => {
    expect(child1.snakeFoo).toBe("_bar_child1_");
    expect(child1.snakeFoo).toBe(store.getters["child1/snakeFoo"]);
    expect(child2.snakeFoo).toBe("_baz_child2_");
    expect(child2.snakeFoo).toBe(store.getters["child2/snakeFoo"]);
  });
});


================================================
FILE: test/getters.ts
================================================
import { Module, VuexModule } from "../src";
import Vuex from "vuex";
import Vue from "vue";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module
class MyModule extends VuexModule {
  foo = {
    text: "some text"
  };

  get textTransforms() {
    return {
      original: this.foo.text,
      upperCase: this.foo.text.toUpperCase()
    };
  }
}

const myModule = new MyModule({ store, name: "myModule" });

test("getters", () => {
  expect(myModule.textTransforms).toBe(store.getters["myModule/textTransforms"]);
  expect(myModule.textTransforms.upperCase).toBe("SOME TEXT");
});


================================================
FILE: test/instanceof.ts
================================================
import { Module, VuexModule } from "../src";
import Vuex from "vuex";
import Vue from "vue";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

class OriginalModule extends VuexModule {
  foo = {
    text: "some text"
  };
  bar = 1;
}

/** Manually apply decorator, to have access to initial class definition */
const MyModule = Module(OriginalModule);
const myModule = new MyModule({ store, name: "myModule" });

test("instance of", () => {
  expect(myModule instanceof OriginalModule).toBe(true);
  expect(myModule instanceof MyModule).toBe(true);
  expect(myModule instanceof VuexModule).toBe(true);
});


================================================
FILE: test/local-functions-inheritance.ts
================================================
import Vue from "vue";
import Vuex, { Store } from "vuex";
import { Action, Module, Mutation, VuexModule } from "../src";

Vue.use(Vuex);

abstract class Parent extends VuexModule {
  canTransform = true;
  text = "parent text";

  get upperCaseText() {
    return this.text.toUpperCase();
  }

  get noSpaceText() {
    return this.snakeText();
  }

  private snakeText() {
    // 'this' has access to state & getters
    return this.canTransform ? this.upperCaseText.replace(/ /g, "_") : "";
  }

  @Mutation
  setText(text: string) {
    this.localSetText(text);
  }

  @Mutation
  clearText() {
    this.text = "";
  }

  protected abstract localSetText(text: string): void;
  protected localLoadText() {
    this.setText("parent: yet another text");
  }
}

@Module
class Module1 extends Parent {
  private tag = "child1";
  canTransform = true;
  text = `${this.tag} text`;

  get upperCaseText() {
    return this.text.toUpperCase();
  }

  protected localSetText(text: string) {
    // 'this' has state
    this.text = `${text} ${this.tag}`;
  }

  @Action
  async loadText() {
    this.localLoadText();
  }

  protected localLoadText() {
    // 'this' has getters & mutations
    if (!this.upperCaseText) {
      this.setText(`${this.tag.toUpperCase()}: yet another text`);
    }
  }
}

@Module
class Module2 extends Parent {
  private tag = "child2";
  canTransform = true;
  text = `${this.tag} text`;

  get upperCaseText() {
    return this.text.toUpperCase();
  }
  get noSpaceText() {
    return this.dashText();
  }

  private dashText() {
    // 'this' has access to state & getters
    return this.canTransform ? this.upperCaseText.replace(/ /g, "--") : "";
  }

  protected localSetText(text: string) {
    // 'this' has state
    this.text = `***${text}*** ${this.tag}`;
  }

  @Action
  async loadText() {
    this.localLoadText();
  }

  protected localLoadText() {
    // 'this' has getters & mutations
    if (!this.upperCaseText) {
      this.setText(`${this.tag}: yet another text`);
    }
  }
}

describe("local-functions", () => {
  let child1: Module1;
  let child2: Module2;
  let store: Store<any>;

  beforeEach(() => {
    store = new Vuex.Store({});
    child1 = new Module1({ store, name: "myModule1" });
    child2 = new Module2({ store, name: "myModule2" });
  });

  test("from getter", () => {
    expect(child1.noSpaceText).toBe("CHILD1_TEXT");
    expect(child2.noSpaceText).toBe("CHILD2--TEXT");
  });

  test("from mutation", () => {
    child1.setText("some other text");
    child2.setText("some other text");
    expect(child1.text).toBe("some other text child1");
    expect(child2.text).toBe("***some other text*** child2");
  });

  test("from action", async () => {
    child1.clearText();
    child2.clearText();

    await child1.loadText();
    await child2.loadText();
    expect(child1.text).toBe("CHILD1: yet another text child1");
    expect(child2.text).toBe("***child2: yet another text*** child2");
  });
});


================================================
FILE: test/local-functions.ts
================================================
import Vue from "vue";
import Vuex from "vuex";
import { Action, Module, Mutation, VuexModule } from "../src";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module
class MyModule extends VuexModule {
  canTransform = true;
  text = "some text";

  get upperCaseText() {
    return this.text.toUpperCase();
  }
  get pascalText() {
    return this.transformText();
  }
  private transformText() {
    // 'this' has access to state & getters
    return this.canTransform ? this.upperCaseText.replace(/ /g, "_") : "";
  }

  @Mutation
  setText(text: string) {
    this.localSetText(text);
  }
  private localSetText(text: string) {
    // 'this' has state
    this.text = text;
  }

  @Action
  async loadText() {
    this.localLoadText();
  }
  private localLoadText() {
    // 'this' has getters & mutations
    if (!this.upperCaseText) {
      this.setText("yet another text");
    }
  }
}

const myModule = new MyModule({ store, name: "myModule" });

describe("local-functions", () => {
  test("from getter", () => {
    expect(myModule.pascalText).toBe("SOME_TEXT");
  });

  test("from mutation", () => {
    myModule.setText("some other text");
    expect(myModule.text).toBe("some other text");
  });

  test("from action", async () => {
    myModule.setText("");

    await myModule.loadText();
    expect(myModule.text).toBe("yet another text");
  });
});


================================================
FILE: test/module-reference.ts
================================================
import { Module, VuexModule, RegisterOptions } from "../src";
import Vuex from "vuex";
import Vue from "vue";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module
class MyModule extends VuexModule {
  foo = "bar";
}

@Module
class OtherModule extends VuexModule {
  private myModule: MyModule;

  get moduleRef() {
    return this.myModule;
  }

  constructor(myModule: MyModule, options: RegisterOptions) {
    super(options);
    this.myModule = myModule;
  }
}

test("module references", () => {
  const myModule = new MyModule({ store, name: "myModule" });
  const otherModule = new OtherModule(myModule, { store, name: "otherModule" });
  expect(store.state.otherModule.myModule).toBeUndefined();
  expect(otherModule.moduleRef).toBe(myModule);
});


================================================
FILE: test/mutations-inheritance.ts
================================================
import { Module, Mutation, VuexModule } from "../src";
import Vuex, { Store } from "vuex";
import Vue from "vue";

Vue.use(Vuex);

class ParentModule extends VuexModule {
  foo = "init";

  @Mutation
  mutation1(value: string) {
    //
  }

  @Mutation
  mutation2(value: string) {
    //
  }

  @Mutation
  mutation3(value: string) {
    this.foo = value;
  }
}

@Module
class Module1 extends ParentModule {
  private tag = "child1";
  baz = "init" + this.tag;

  @Mutation
  mutation1(value: string) {
    this.baz = value + this.tag;
  }

  @Mutation
  mutation2(value: string) {
    this.foo = value + this.tag;
  }

  @Mutation
  mutation3(value: string) {
    super.mutation3(value);
    this.foo = this.foo + this.tag;
  }
}

@Module
class Module2 extends ParentModule {
  private tag = "child2";
  bar = "init" + this.tag;
  baz = "init" + this.tag;

  @Mutation
  mutation1(value: string) {
    this.bar = value + this.tag;
  }

  @Mutation
  mutation2(value: string) {
    this.baz = value + this.tag;
  }

  @Mutation
  mutation3(value: string) {
    super.mutation3(value);
    this.foo = this.foo + this.tag;
  }
}

describe("mutations-inheritance", () => {
  let store: Store<any>;
  let parent: ParentModule;
  let child1: Module1;
  let child2: Module2;

  beforeEach(() => {
    store = new Vuex.Store({});
    parent = new ParentModule({ store, name: "parentModule" });
    child1 = new Module1({ store, name: "myModule1" });
    child2 = new Module2({ store, name: "myModule2" });
  });

  test("overriden mutation can modify state", () => {
    parent.mutation1("_");
    child1.mutation1("bar1");
    child2.mutation1("bar2");
    expect(parent.foo).toBe("init");
    expect(child1.baz).toBe("bar1child1");
    expect(child2.bar).toBe("bar2child2");
    expect(child2.baz).toBe("initchild2");
  });

  test("overriden mutation can modify parent state", () => {
    parent.mutation2("_");
    child1.mutation2("bar");
    child2.mutation2("baz");
    expect(parent.foo).toBe("init");
    expect(child1.foo).toBe("barchild1");
    expect(child2.bar).toBe("initchild2");
    expect(child2.baz).toBe("bazchild2");
  });

  test("overriden mutation has access to parent method implementation", () => {
    parent.mutation3("foo_");
    child1.mutation3("foo1");
    child2.mutation3("foo2");
    expect(parent.foo).toBe("foo_");
    expect(child1.foo).toBe("foo1child1");
    expect(child1.baz).toBe("initchild1");
    expect(child2.foo).toBe("foo2child2");
    expect(child2.bar).toBe("initchild2");
    expect(child2.baz).toBe("initchild2");
  });
});


================================================
FILE: test/mutations.ts
================================================
import { Module, Mutation, VuexModule } from "../src";
import Vuex, { MutationPayload } from "vuex";
import Vue from "vue";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module
class MyModule extends VuexModule {
  shouldUpdate = true;
  text = "";

  @Mutation
  setText(text: string) {
    if (this.shouldUpdate) {
      this.text = text;
    }
  }
}

const myModule = new MyModule({ store, name: "myModule" });

describe("mutations", () => {
  test("accessor calls commit", () => {
    const mutationObserver = jest.fn((mutation: MutationPayload) => mutation);
    store.subscribe(mutationObserver);

    myModule.setText("some text");

    expect(mutationObserver.mock.calls.length).toBe(1);

    const mutationPayload = mutationObserver.mock.results[0].value as MutationPayload;
    expect(mutationPayload.type).toBe("myModule/setText");
    expect(mutationPayload.payload).toBe("some text");
  });

  test("updates store", () => {
    store.commit("myModule/setText", "some other text");
    expect(store.state.myModule.text).toBe("some other text");
  });
});


================================================
FILE: test/state.ts
================================================
import { Module, VuexModule } from "../src";
import Vuex from "vuex";
import Vue from "vue";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module
class MyModule extends VuexModule {
  foo = {
    text: "some text"
  };
  bar = 1;

  square = (num: number) => num * num;
}

const myModule = new MyModule({ store, name: "myModule" });

test("state", () => {
  expect(myModule.foo).toBe(store.state.myModule.foo);
  expect(myModule.foo.text).toBe("some text");

  expect(myModule.bar).toBe(store.state.myModule.bar);
  expect(myModule.bar).toBe(1);

  expect(myModule.square).toBe(store.state.myModule.square);
  expect(myModule.square(2)).toBe(4);
});


================================================
FILE: test/tsconfig.json
================================================
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "",
    "experimentalDecorators": true,
    "declaration": false
  },
  "include": [
    "./**/*.ts"
  ]
}

================================================
FILE: test/watch.ts
================================================
import { Module, Mutation, Action, VuexModule } from "../src";
import Vuex from "vuex";
import Vue from "vue";

Vue.use(Vuex);
const store = new Vuex.Store<any>({});

@Module
class MyModule extends VuexModule {
  text = "";

  get getText() {
    return this.text;
  }

  @Mutation
  setText(text: string) {
    this.text = text;
  }

  @Action
  async changeText(text: string) {
    this.setText(text);
  }
}

const myModule = new MyModule({ store, name: "myModule" });

describe("watch", () => {
  test("watch callback is called", async () => {
    const watchCallback = jest.fn((newValue: string, oldValue: string) => undefined);

    myModule.setText("bar");
    myModule.$watch(theModule => theModule.getText, watchCallback);
    await myModule.changeText("foo");

    expect(watchCallback.mock.calls.length).toBe(1);
    expect(watchCallback.mock.calls[0].length).toBe(2);
    expect(watchCallback.mock.calls[0][0]).toBe("foo");
    expect(watchCallback.mock.calls[0][1]).toBe("bar");
  });

  test("watch for state changes as well", async () => {
    const watchCallback = jest.fn((newValue: string, oldValue: string) => undefined);

    myModule.setText("bar");
    myModule.$watch(theModule => theModule.text, watchCallback);
    await myModule.changeText("foo");

    expect(watchCallback.mock.calls.length).toBe(1);
    expect(watchCallback.mock.calls[0].length).toBe(2);
    expect(watchCallback.mock.calls[0][0]).toBe("foo");
    expect(watchCallback.mock.calls[0][1]).toBe("bar");
  });

  test("watch should return unwatch func", async () => {
    const watchCallback = jest.fn((newValue: string, oldValue: string) => undefined);

    myModule.setText("bar");
    const unwatch = myModule.$watch(theModule => theModule.text, watchCallback);
    await myModule.changeText("foo1");

    expect(watchCallback.mock.calls.length).toBe(1);

    unwatch();
    await myModule.changeText("foo2");

    expect(watchCallback.mock.calls.length).toBe(1);
  });
});


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es5",
    "module": "es2015",
    "moduleResolution": "node",
    "lib": [
      "dom",
      "es2015"
    ],
    "declaration": true,
    "outDir": "./lib",
    "strict": true,

    "experimentalDecorators": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "**/__tests__/*"]
}

================================================
FILE: tslint.json
================================================
{
  "extends": [
    "tslint:recommended",
    "tslint-config-prettier"
  ],
  "rulesDirectory": ["tslint-plugin-prettier"],
  "rules": {
    "prettier": [true, { "printWidth": 120 }],

    "no-namespace": false,
    "max-line-length": false,
    "interface-name": false,

    "arrow-parens": [false],
    "object-literal-sort-keys": false,
    "ordered-imports": [
      false
    ],
    "member-access": [
      true, "no-public"
    ],
    "max-classes-per-file": false,
    "trailing-comma": [
      false
    ],
    "interface-over-type-literal": false,
    "no-console": [false],
    "one-line": false,
    "curly": false,
    "no-empty": [true, "allow-empty-catch", "allow-empty-functions"],
    "member-ordering": false,
    "no-unused-expression": false,
    "only-arrow-functions": false,
    "ban-types": [true, "Function"],
    "variable-name": false
  },
  "defaultSeverity": "warning"
}
Download .txt
gitextract_ot546s4y/

├── .gitignore
├── .vscode/
│   └── settings.json
├── LICENSE
├── README.md
├── example/
│   ├── index.html
│   ├── src/
│   │   ├── api/
│   │   │   └── shop.ts
│   │   ├── app.ts
│   │   ├── components/
│   │   │   ├── App.vue
│   │   │   ├── ProductList.vue
│   │   │   └── ShoppingCart.vue
│   │   ├── shims-vue.d.ts
│   │   └── store/
│   │       ├── cart.ts
│   │       ├── index.ts
│   │       └── products.ts
│   ├── tsconfig.json
│   └── webpack.config.js
├── jestconfig.json
├── package.json
├── src/
│   ├── VuexModule.ts
│   ├── actions.ts
│   ├── index.ts
│   ├── module-factory.ts
│   ├── module.ts
│   └── mutations.ts
├── test/
│   ├── actions-inheritance.ts
│   ├── actions.ts
│   ├── constructor.ts
│   ├── generate-mutations.ts
│   ├── getters-inheritance.ts
│   ├── getters.ts
│   ├── instanceof.ts
│   ├── local-functions-inheritance.ts
│   ├── local-functions.ts
│   ├── module-reference.ts
│   ├── mutations-inheritance.ts
│   ├── mutations.ts
│   ├── state.ts
│   ├── tsconfig.json
│   └── watch.ts
├── tsconfig.json
└── tslint.json
Download .txt
SYMBOL INDEX (140 symbols across 22 files)

FILE: example/src/api/shop.ts
  type Product (line 4) | interface Product {
  type CartItem (line 11) | interface CartItem {
  method getProducts (line 23) | async getProducts() {
  method buyProducts (line 28) | async buyProducts(items: CartItem[]) {

FILE: example/src/store/cart.ts
  class Cart (line 6) | @Module({ generateMutationSetters: true })
    method cartProducts (line 11) | get cartProducts() {
    method cartTotalPrice (line 22) | get cartTotalPrice() {
    method pushProductToCart (line 29) | pushProductToCart(id: number) {
    method incrementItemQuantity (line 37) | incrementItemQuantity(id: number) {
    method addProductToCart (line 43) | async addProductToCart(product: Product) {
    method checkout (line 59) | async checkout() {

FILE: example/src/store/products.ts
  class Products (line 5) | @Module({ generateMutationSetters: true })
    method decrementProductInventory (line 10) | decrementProductInventory(id: number) {
    method getAllProducts (line 16) | async getAllProducts() {

FILE: src/VuexModule.ts
  class VuexModule (line 4) | class VuexModule {
    method constructor (line 9) | constructor(options: RegisterOptions) {
    method $watch (line 13) | $watch<T>(fn: (arg: this) => T, callback: (newValue: T, oldValue: T) =...

FILE: src/actions.ts
  function Action (line 3) | function Action<T extends Object>(

FILE: src/module-factory.ts
  type ModuleOptions (line 5) | interface ModuleOptions {
  type RegisterOptions (line 9) | interface RegisterOptions {
  type IVuexModule (line 14) | interface IVuexModule extends Dictionary<any> {
  type IModulePrototype (line 17) | interface IModulePrototype {
  type ModulePrototype (line 21) | type ModulePrototype = IModulePrototype & Function;
  type Dictionary (line 23) | type Dictionary<T> = { [k: string]: T };
  type ModuleDefinition (line 25) | interface ModuleDefinition {
  type StoreProxyDefinition (line 33) | interface StoreProxyDefinition {
  class VuexClassModuleFactory (line 46) | class VuexClassModuleFactory {
    method constructor (line 60) | constructor(classModule: ModulePrototype, instance: IVuexModule, modul...
    method init (line 67) | private init(classModule: ModulePrototype) {
    method registerVuexModule (line 115) | registerVuexModule() {
    method buildAccessor (line 187) | buildAccessor() {
    method buildThisProxy (line 231) | private buildThisProxy(proxyDefinition: StoreProxyDefinition) {
    method getMutationSetterName (line 277) | private getMutationSetterName(stateKey: string) {
  function mapValues (line 282) | function mapValues<S, V>(target: Dictionary<any>, source: Dictionary<S>,...
  function mapValuesToProperty (line 288) | function mapValuesToProperty<S, V>(
  function getModulePrototypes (line 302) | function getModulePrototypes(module: ModulePrototype): ModulePrototype[] {

FILE: src/module.ts
  type VuexModuleClass (line 4) | type VuexModuleClass = new (...args: any[]) => VuexModule;
  function Module (line 7) | function Module<T extends VuexModuleClass>(arg?: ModuleOptions | T): Cla...
  function moduleDecoratorFactory (line 15) | function moduleDecoratorFactory(moduleOptions?: ModuleOptions) {

FILE: src/mutations.ts
  function Mutation (line 3) | function Mutation<T extends Object>(

FILE: test/actions-inheritance.ts
  method bigFoo (line 10) | get bigFoo() {
  method decoratedFoo (line 14) | get decoratedFoo() {
  method updateFoo (line 19) | updateFoo(value: string) {
  method action1 (line 24) | action1() {
  method action2 (line 29) | action2() {
  method action3 (line 34) | action3() {
  method action4 (line 39) | action4() {
  method action5 (line 44) | action5() {
  method action6 (line 49) | action6() {
  class Module1 (line 57) | @Module
    method doubleFoo (line 62) | get doubleFoo() {
    method setFooToExample (line 67) | setFooToExample() {
    method action1 (line 72) | action1() {
    method action2 (line 77) | action2() {
    method action3 (line 82) | action3() {
    method action4 (line 87) | action4() {
    method action5 (line 92) | action5() {
    method action7 (line 98) | action7(): void {
  class Module2 (line 103) | @Module
    method constructor (line 107) | constructor(options: RegisterOptions) {
    method tripleFoo (line 112) | get tripleFoo() {
    method setFooToAnotherExample (line 117) | setFooToAnotherExample() {
    method action1 (line 122) | action1() {
    method action2 (line 127) | action2() {
    method action3 (line 132) | action3() {
    method action4 (line 137) | action4() {
    method action5 (line 142) | action5() {
    method action7 (line 148) | action7(): void {

FILE: test/actions.ts
  class MyModule (line 8) | @Module
    method documentHasText (line 13) | get documentHasText() {
    method setDocumentId (line 18) | setDocumentId(id: number) {
    method setText (line 22) | setText(text: string) {
    method dummyAction (line 27) | async dummyAction(payload: any) {
    method loadText (line 32) | async loadText(documentId: number) {
  type ActionPayload (line 46) | interface ActionPayload extends Payload {

FILE: test/constructor.ts
  class MyModule (line 8) | @Module
    method constructor (line 12) | constructor(foo: string, options: RegisterOptions) {

FILE: test/generate-mutations.ts
  class MyModule (line 8) | @Module({ generateMutationSetters: true })
    method loadData (line 14) | async loadData() {

FILE: test/getters-inheritance.ts
  class ParentModule (line 7) | class ParentModule extends VuexModule {
    method bigFoo (line 10) | get bigFoo() {
    method snakeFoo (line 14) | get snakeFoo() {
    method myMutation (line 19) | myMutation(value: string) {
    method myAction (line 24) | myAction() {
  class Module1 (line 34) | @Module
    method snakeFoo (line 38) | get snakeFoo() {
  class Module2 (line 43) | @Module
    method snakeFoo (line 48) | get snakeFoo() {

FILE: test/getters.ts
  class MyModule (line 8) | @Module
    method textTransforms (line 14) | get textTransforms() {

FILE: test/instanceof.ts
  class OriginalModule (line 8) | class OriginalModule extends VuexModule {

FILE: test/local-functions-inheritance.ts
  method upperCaseText (line 11) | get upperCaseText() {
  method noSpaceText (line 15) | get noSpaceText() {
  method snakeText (line 19) | private snakeText() {
  method setText (line 25) | setText(text: string) {
  method clearText (line 30) | clearText() {
  method localLoadText (line 35) | protected localLoadText() {
  class Module1 (line 40) | @Module
    method upperCaseText (line 46) | get upperCaseText() {
    method localSetText (line 50) | protected localSetText(text: string) {
    method loadText (line 56) | async loadText() {
    method localLoadText (line 60) | protected localLoadText() {
  class Module2 (line 68) | @Module
    method upperCaseText (line 74) | get upperCaseText() {
    method noSpaceText (line 77) | get noSpaceText() {
    method dashText (line 81) | private dashText() {
    method localSetText (line 86) | protected localSetText(text: string) {
    method loadText (line 92) | async loadText() {
    method localLoadText (line 96) | protected localLoadText() {

FILE: test/local-functions.ts
  class MyModule (line 8) | @Module
    method upperCaseText (line 13) | get upperCaseText() {
    method pascalText (line 16) | get pascalText() {
    method transformText (line 19) | private transformText() {
    method setText (line 25) | setText(text: string) {
    method localSetText (line 28) | private localSetText(text: string) {
    method loadText (line 34) | async loadText() {
    method localLoadText (line 37) | private localLoadText() {

FILE: test/module-reference.ts
  class MyModule (line 8) | @Module
  class OtherModule (line 13) | @Module
    method moduleRef (line 17) | get moduleRef() {
    method constructor (line 21) | constructor(myModule: MyModule, options: RegisterOptions) {

FILE: test/mutations-inheritance.ts
  class ParentModule (line 7) | class ParentModule extends VuexModule {
    method mutation1 (line 11) | mutation1(value: string) {
    method mutation2 (line 16) | mutation2(value: string) {
    method mutation3 (line 21) | mutation3(value: string) {
  class Module1 (line 26) | @Module
    method mutation1 (line 32) | mutation1(value: string) {
    method mutation2 (line 37) | mutation2(value: string) {
    method mutation3 (line 42) | mutation3(value: string) {
  class Module2 (line 48) | @Module
    method mutation1 (line 55) | mutation1(value: string) {
    method mutation2 (line 60) | mutation2(value: string) {
    method mutation3 (line 65) | mutation3(value: string) {

FILE: test/mutations.ts
  class MyModule (line 8) | @Module
    method setText (line 14) | setText(text: string) {

FILE: test/state.ts
  class MyModule (line 8) | @Module

FILE: test/watch.ts
  class MyModule (line 8) | @Module
    method getText (line 12) | get getText() {
    method setText (line 17) | setText(text: string) {
    method changeText (line 22) | async changeText(text: string) {
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (61K chars).
[
  {
    "path": ".gitignore",
    "chars": 68,
    "preview": "node_modules\n/lib\n/commonjs\n/example/build.js\n/example/build.js.map\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 330,
    "preview": "{\n  \"editor.rulers\": [ 120 ],\n  \"prettier.printWidth\": 120,\n  \"prettier.disableLanguages\": [],\n\n  \"[typescript]\": {\n    "
  },
  {
    "path": "LICENSE",
    "chars": 1064,
    "preview": "MIT License\n\nCopyright (c) 2018 gertqin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
  },
  {
    "path": "README.md",
    "chars": 9210,
    "preview": "# vuex-class-modules\n\nThis is yet another package to introduce a simple type-safe class style syntax for your vuex modul"
  },
  {
    "path": "example/index.html",
    "chars": 214,
    "preview": "\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>Vuex Class Modules Example</title>\n  </"
  },
  {
    "path": "example/src/api/shop.ts",
    "chars": 744,
    "preview": "/**\n * Mocking client-server processing\n */\nexport interface Product {\n  id: number;\n  title: string;\n  price: number;\n "
  },
  {
    "path": "example/src/app.ts",
    "chars": 152,
    "preview": "import Vue from \"vue\";\nimport App from \"./components/App.vue\";\nimport store from \"./store\";\n\nnew Vue({\n  el: \"#app\",\n  s"
  },
  {
    "path": "example/src/components/App.vue",
    "chars": 460,
    "preview": "<template>\n  <div id=\"app\">\n    <h1>Shopping Cart Example</h1>\n    <hr />\n    <h2>Products</h2>\n    <ProductList />\n    "
  },
  {
    "path": "example/src/components/ProductList.vue",
    "chars": 750,
    "preview": "<template>\n  <ul>\n    <li v-for=\"product in products\" :key=\"product.id\">\n      {{ product.title }} - {{ product.price }}"
  },
  {
    "path": "example/src/components/ShoppingCart.vue",
    "chars": 945,
    "preview": "<template>\n  <div class=\"cart\">\n    <h2>Your Cart</h2>\n    <p v-show=\"!products.length\"><i>Please add some products to c"
  },
  {
    "path": "example/src/shims-vue.d.ts",
    "chars": 74,
    "preview": "declare module \"*.vue\" {\n  import Vue from \"vue\";\n  export default Vue;\n}\n"
  },
  {
    "path": "example/src/store/cart.ts",
    "chars": 1829,
    "preview": "import store from \"./\";\nimport shop, { CartItem, Product } from \"../api/shop\";\nimport { Module, Mutation, Action, VuexMo"
  },
  {
    "path": "example/src/store/index.ts",
    "chars": 99,
    "preview": "import Vue from \"vue\";\nimport Vuex from \"vuex\";\nVue.use(Vuex);\n\nexport default new Vuex.Store({});\n"
  },
  {
    "path": "example/src/store/products.ts",
    "chars": 544,
    "preview": "import store from \"./\";\nimport shop, { Product } from \"../api/shop\";\nimport { Module, Mutation, Action, VuexModule } fro"
  },
  {
    "path": "example/tsconfig.json",
    "chars": 311,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"lib\": [\n      \"dom\",\n      \"esnext\"\n    ],\n    \"module\": \"es2015\","
  },
  {
    "path": "example/webpack.config.js",
    "chars": 722,
    "preview": "const VueLoaderPlugin = require('vue-loader/lib/plugin')\n\nmodule.exports = {\n  mode: 'development',\n  context: __dirname"
  },
  {
    "path": "jestconfig.json",
    "chars": 293,
    "preview": "{\n  \"preset\": \"ts-jest\",\n  \"rootDir\": \"./test\",\n  \"testMatch\": [\"<rootDir>/**/*.ts\"],\n  \"moduleFileExtensions\": [\"ts\", \""
  },
  {
    "path": "package.json",
    "chars": 1891,
    "preview": "{\n  \"name\": \"vuex-class-modules\",\n  \"version\": \"1.3.0\",\n  \"description\": \"Typescript class decorators for class-style vu"
  },
  {
    "path": "src/VuexModule.ts",
    "chars": 422,
    "preview": "import { RegisterOptions } from \"./module-factory\";\nimport { WatchOptions } from \"vue\";\n\nexport class VuexModule {\n  pri"
  },
  {
    "path": "src/actions.ts",
    "chars": 412,
    "preview": "import { ModulePrototype } from \"./module-factory\";\n\nexport function Action<T extends Object>(\n  target: T,\n  key: strin"
  },
  {
    "path": "src/index.ts",
    "chars": 221,
    "preview": "export { RegisterOptions, ModuleOptions } from \"./module-factory\";\nexport { Action } from \"./actions\";\nexport { Module }"
  },
  {
    "path": "src/module-factory.ts",
    "chars": 9407,
    "preview": "import { Store, Module as StoreModule, GetterTree, ActionContext, Dispatch, Commit } from \"vuex\";\nimport { WatchOptions "
  },
  {
    "path": "src/module.ts",
    "chars": 1213,
    "preview": "import { VuexClassModuleFactory, ModuleOptions, IVuexModule } from \"./module-factory\";\nimport { VuexModule } from \"./Vue"
  },
  {
    "path": "src/mutations.ts",
    "chars": 421,
    "preview": "import { ModulePrototype } from \"./module-factory\";\n\nexport function Mutation<T extends Object>(\n  target: T,\n  key: str"
  },
  {
    "path": "test/actions-inheritance.ts",
    "chars": 4024,
    "preview": "import { Action, Module, Mutation, VuexModule, RegisterOptions } from \"../src\";\nimport Vuex, { Store } from \"vuex\";\nimpo"
  },
  {
    "path": "test/actions.ts",
    "chars": 2167,
    "preview": "import { Module, Mutation, Action, VuexModule } from \"../src\";\nimport Vuex, { Payload, MutationPayload } from \"vuex\";\nim"
  },
  {
    "path": "test/constructor.ts",
    "chars": 465,
    "preview": "import { Module, VuexModule, RegisterOptions } from \"../src\";\nimport Vuex from \"vuex\";\nimport Vue from \"vue\";\n\nVue.use(V"
  },
  {
    "path": "test/generate-mutations.ts",
    "chars": 1350,
    "preview": "import Vue from \"vue\";\nimport Vuex, { MutationPayload } from \"vuex\";\nimport { Action, Module, VuexModule } from \"../src\""
  },
  {
    "path": "test/getters-inheritance.ts",
    "chars": 2012,
    "preview": "import { Action, Module, Mutation, VuexModule } from \"../src\";\nimport Vuex, { Store } from \"vuex\";\nimport Vue from \"vue\""
  },
  {
    "path": "test/getters.ts",
    "chars": 593,
    "preview": "import { Module, VuexModule } from \"../src\";\nimport Vuex from \"vuex\";\nimport Vue from \"vue\";\n\nVue.use(Vuex);\nconst store"
  },
  {
    "path": "test/instanceof.ts",
    "chars": 613,
    "preview": "import { Module, VuexModule } from \"../src\";\nimport Vuex from \"vuex\";\nimport Vue from \"vue\";\n\nVue.use(Vuex);\nconst store"
  },
  {
    "path": "test/local-functions-inheritance.ts",
    "chars": 2968,
    "preview": "import Vue from \"vue\";\nimport Vuex, { Store } from \"vuex\";\nimport { Action, Module, Mutation, VuexModule } from \"../src\""
  },
  {
    "path": "test/local-functions.ts",
    "chars": 1375,
    "preview": "import Vue from \"vue\";\nimport Vuex from \"vuex\";\nimport { Action, Module, Mutation, VuexModule } from \"../src\";\n\nVue.use("
  },
  {
    "path": "test/module-reference.ts",
    "chars": 765,
    "preview": "import { Module, VuexModule, RegisterOptions } from \"../src\";\nimport Vuex from \"vuex\";\nimport Vue from \"vue\";\n\nVue.use(V"
  },
  {
    "path": "test/mutations-inheritance.ts",
    "chars": 2570,
    "preview": "import { Module, Mutation, VuexModule } from \"../src\";\nimport Vuex, { Store } from \"vuex\";\nimport Vue from \"vue\";\n\nVue.u"
  },
  {
    "path": "test/mutations.ts",
    "chars": 1078,
    "preview": "import { Module, Mutation, VuexModule } from \"../src\";\nimport Vuex, { MutationPayload } from \"vuex\";\nimport Vue from \"vu"
  },
  {
    "path": "test/state.ts",
    "chars": 661,
    "preview": "import { Module, VuexModule } from \"../src\";\nimport Vuex from \"vuex\";\nimport Vue from \"vue\";\n\nVue.use(Vuex);\nconst store"
  },
  {
    "path": "test/tsconfig.json",
    "chars": 178,
    "preview": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"outDir\": \"\",\n    \"experimentalDecorators\": true,\n    \"dec"
  },
  {
    "path": "test/watch.ts",
    "chars": 1968,
    "preview": "import { Module, Mutation, Action, VuexModule } from \"../src\";\nimport Vuex from \"vuex\";\nimport Vue from \"vue\";\n\nVue.use("
  },
  {
    "path": "tsconfig.json",
    "chars": 330,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"module\": \"es2015\",\n    \"moduleResolution\": \"node\",\n    \"lib\": [\n     "
  },
  {
    "path": "tslint.json",
    "chars": 900,
    "preview": "{\n  \"extends\": [\n    \"tslint:recommended\",\n    \"tslint-config-prettier\"\n  ],\n  \"rulesDirectory\": [\"tslint-plugin-prettie"
  }
]

About this extraction

This page contains the full source code of the gertqin/vuex-class-modules GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 41 files (54.5 KB), approximately 15.4k tokens, and a symbol index with 140 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!