├── .vscode └── settings.json ├── .DS_Store ├── captures ├── hotmodule.png ├── actionlogger.png ├── autocomplete1.png ├── autocomplete2.png ├── autocomplete3.png └── autocomplete4.png ├── .prettierrc ├── types ├── modules │ ├── helpers │ │ └── index.d.ts │ ├── hooks.d.ts │ ├── dynamic.d.ts │ └── default.d.ts ├── index.d.ts ├── Database.d.ts ├── utils │ └── modifiers.d.ts ├── tests.d.ts └── types.d.ts ├── src ├── index.ts ├── modules │ ├── helpers │ │ └── index.ts │ ├── hooks.ts │ ├── dynamic.ts │ └── default.ts ├── tests.ts ├── utils │ └── modifiers.ts ├── database.ts └── types.ts ├── tsconfig.json ├── .gitignore ├── package.json ├── README.md └── yarn.lock /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorgarciaesgi/vuex-typed-modules/HEAD/.DS_Store -------------------------------------------------------------------------------- /captures/hotmodule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorgarciaesgi/vuex-typed-modules/HEAD/captures/hotmodule.png -------------------------------------------------------------------------------- /captures/actionlogger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorgarciaesgi/vuex-typed-modules/HEAD/captures/actionlogger.png -------------------------------------------------------------------------------- /captures/autocomplete1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorgarciaesgi/vuex-typed-modules/HEAD/captures/autocomplete1.png -------------------------------------------------------------------------------- /captures/autocomplete2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorgarciaesgi/vuex-typed-modules/HEAD/captures/autocomplete2.png -------------------------------------------------------------------------------- /captures/autocomplete3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorgarciaesgi/vuex-typed-modules/HEAD/captures/autocomplete3.png -------------------------------------------------------------------------------- /captures/autocomplete4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/victorgarciaesgi/vuex-typed-modules/HEAD/captures/autocomplete4.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "trailingComma": "es5", 5 | "singleQuote": true, 6 | "semi": true, 7 | "bracketSpacing": true 8 | } 9 | -------------------------------------------------------------------------------- /types/modules/helpers/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as Vuex from 'vuex'; 2 | export declare const setHelpers: (mutations?: Vuex.MutationTree | undefined) => Vuex.MutationTree; 3 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { Database } from './database'; 2 | export { createTestStore } from './tests' 3 | export { VuexModule, VuexModuleArgs, createVuexModule } from './modules/default'; 4 | export { VuexModuleHook } from './modules/hooks'; 5 | export { VuexDynamicModule, ModuleToInstance, createVuexDynamicModule } from './modules/dynamic'; 6 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | export { Database } from './database'; 2 | export { createTestStore } from './tests'; 3 | export { VuexModule, VuexModuleArgs, createVuexModule } from './modules/default'; 4 | export { VuexModuleHook } from './modules/hooks'; 5 | export { VuexDynamicModule, ModuleToInstance, createVuexDynamicModule } from './modules/dynamic'; 6 | -------------------------------------------------------------------------------- /types/Database.d.ts: -------------------------------------------------------------------------------- 1 | import * as Vuex from 'vuex'; 2 | import { VuexModule } from './modules/default'; 3 | import { VuexDynamicModule } from './modules/dynamic'; 4 | interface DataBaseOptions { 5 | logger?: boolean; 6 | } 7 | declare type DefaultModule = VuexModule | VuexDynamicModule; 8 | export declare class Database { 9 | private store; 10 | private options; 11 | private loggerBlackList; 12 | constructor(options: DataBaseOptions); 13 | private install; 14 | deploy(vuexModules: DefaultModule[]): (store: Vuex.Store) => void; 15 | private createLogger; 16 | } 17 | export {}; 18 | -------------------------------------------------------------------------------- /types/utils/modifiers.d.ts: -------------------------------------------------------------------------------- 1 | import * as Vuex from 'vuex'; 2 | export declare function createModuleLayers(store: Vuex.Store, moduleName: string): { 3 | commit: (name: string) => (payload: any) => void; 4 | dispatch: (name: string) => (payload: any) => Promise; 5 | read: (name: string) => () => any; 6 | readonly state: () => any; 7 | }; 8 | export declare function buildModifiers(store: Vuex.Store, name: string): { 9 | registerMutations: (mutations?: Record | undefined) => any; 10 | registerActions: (actions?: Record | undefined) => any; 11 | registerGetters: (getters?: Record | undefined) => any; 12 | reactiveState: () => any; 13 | }; 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2018", 5 | "moduleResolution": "node", 6 | "allowSyntheticDefaultImports": true, 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "esModuleInterop": true, 10 | "removeComments": true, 11 | "noImplicitAny": true, 12 | "noUnusedLocals": false, 13 | "strictNullChecks": true, 14 | "strict": true, 15 | "pretty": true, 16 | "sourceMap": false, 17 | "downlevelIteration": true, 18 | "skipLibCheck": true, 19 | "declarationDir": "./types", 20 | "baseUrl": ".", 21 | "declaration": true, 22 | "outDir": "./dist", 23 | "types": ["node", "webpack-env"], 24 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"] 25 | }, 26 | "include": ["src"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /src/modules/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import { isVue2, isVue3 } from 'vue-demi'; 3 | import * as Vuex from 'vuex'; 4 | 5 | export const setHelpers = (mutations?: Vuex.MutationTree) => { 6 | let _mutations = mutations ?? {}; 7 | _mutations.resetState = (moduleState, initialState) => { 8 | Object.keys(moduleState).map((key) => { 9 | if (isVue2) { 10 | Vue.set(moduleState, key, initialState[key]); 11 | } else if (isVue3) { 12 | moduleState[key] = initialState[key]; 13 | } 14 | }); 15 | }; 16 | _mutations.updateState = (moduleState, params) => { 17 | Object.keys(params).map((key) => { 18 | if (isVue2) { 19 | Vue.set(moduleState, key, params[key]); 20 | } else if (isVue3) { 21 | moduleState[key] = params[key]; 22 | } 23 | }); 24 | }; 25 | return _mutations; 26 | }; 27 | -------------------------------------------------------------------------------- /types/tests.d.ts: -------------------------------------------------------------------------------- 1 | import { CommitOptions, DispatchOptions, Store } from 'vuex'; 2 | declare type StoreDefaults = { 3 | mutations: any; 4 | getters: any; 5 | state: any; 6 | actions: any; 7 | }; 8 | declare type GenerateTypedStoreReturn = Omit, 'getters' | 'commit' | 'dispatch'> & { 9 | commit[1]>(key: K, payload?: P, options?: CommitOptions): ReturnType; 10 | } & { 11 | dispatch(key: K, payload?: Parameters[1], options?: DispatchOptions): ReturnType; 12 | } & { 13 | getters: { 14 | [K in keyof T['getters']]: ReturnType; 15 | }; 16 | }; 17 | declare const createTestStore: (options: T) => GenerateTypedStoreReturn; 18 | export { createTestStore }; 19 | -------------------------------------------------------------------------------- /src/tests.ts: -------------------------------------------------------------------------------- 1 | import Vuex, { CommitOptions, DispatchOptions, Store } from 'vuex'; 2 | 3 | type StoreDefaults = { mutations: any; getters: any; state: any; actions: any }; 4 | 5 | type GenerateTypedStoreReturn = Omit< 6 | Store, 7 | 'getters' | 'commit' | 'dispatch' 8 | > & { 9 | commit[1]>( 10 | key: K, 11 | payload?: P, 12 | options?: CommitOptions 13 | ): ReturnType; 14 | } & { 15 | dispatch( 16 | key: K, 17 | payload?: Parameters[1], 18 | options?: DispatchOptions 19 | ): ReturnType; 20 | } & { 21 | getters: { 22 | [K in keyof T['getters']]: ReturnType; 23 | }; 24 | }; 25 | 26 | const createTestStore = (options: T): GenerateTypedStoreReturn => 27 | new Vuex.Store({ 28 | ...options, 29 | }) as unknown as GenerateTypedStoreReturn; 30 | 31 | export { createTestStore }; 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | dist 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | *.pid.lock 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # Bower dependency directory (https://bower.io/) 28 | bower_components 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (https://nodejs.org/api/addons.html) 34 | build/Release 35 | 36 | # Dependency directories 37 | node_modules/ 38 | jspm_packages/ 39 | 40 | # TypeScript v1 declaration files 41 | typings/ 42 | 43 | # Optional npm cache directory 44 | .npm 45 | 46 | # Optional eslint cache 47 | .eslintcache 48 | 49 | # Optional REPL history 50 | .node_repl_history 51 | 52 | # Output of 'npm pack' 53 | *.tgz 54 | 55 | # Yarn Integrity file 56 | .yarn-integrity 57 | 58 | # dotenv environment variables file 59 | .env 60 | 61 | # next.js build output 62 | .next 63 | -------------------------------------------------------------------------------- /types/modules/hooks.d.ts: -------------------------------------------------------------------------------- 1 | import { VuexModuleArgs } from './default'; 2 | import { MutationTree, Store, GetterTree } from 'vuex'; 3 | import { ReturnedGetters, ReturnedActions, ReturnedMutations, ActionBush, SharedMutations } from '../types'; 4 | import { ToRefs } from 'vue-demi'; 5 | export declare const useStore: (name: string) => Store; 6 | export interface VuexModuleHookOptions { 7 | unwrap: TWrap; 8 | } 9 | export declare type VuexModuleHook, M extends MutationTree, G extends GetterTree, A extends ActionBush, TWrap extends boolean = false> = { 10 | state: TWrap extends true ? S : ToRefs; 11 | getters: ReturnedGetters; 12 | mutations: ReturnedMutations; 13 | actions: ReturnedActions; 14 | } & SharedMutations; 15 | export declare function createDefaultModuleHook, M extends MutationTree, G extends GetterTree, A extends ActionBush, TWrap extends boolean>({ name, state, actions, getters, mutations, hookOptions, }: VuexModuleArgs & { 16 | hookOptions?: VuexModuleHookOptions; 17 | }): VuexModuleHook; 18 | export declare function createModuleHook, M extends MutationTree, G extends GetterTree, A extends ActionBush>(params: VuexModuleArgs): (hookOptions?: VuexModuleHookOptions | undefined) => VuexModuleHook; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-typed-modules", 3 | "version": "4.2.1", 4 | "description": "A typescript wrapper for Vuex store with fully typed exposure", 5 | "keywords": [ 6 | "vuex", 7 | "vuex ts", 8 | "vuex typescript", 9 | "vuex typed", 10 | "vuex modules", 11 | "typecript vuex", 12 | "typescript vue", 13 | "vuex typed modules" 14 | ], 15 | "author": { 16 | "name": "Victor Garcia", 17 | "url": "https://github.com/victorgarciaesgi" 18 | }, 19 | "files": [ 20 | "dist", 21 | "types" 22 | ], 23 | "main": "dist/index.js", 24 | "typings": "types/index.d.ts", 25 | "license": "MIT", 26 | "peerDependencies": { 27 | "@nuxtjs/composition-api": "^0.23.4", 28 | "@vue/composition-api": "^1.0.0-rc.9", 29 | "vue": "^2.0.0 || >=3.0.0-rc.0", 30 | "vuex": "^3.0.0 || >=4.0.0" 31 | }, 32 | "devDependencies": { 33 | "@nuxtjs/composition-api": "^0.24.7", 34 | "@types/lodash": "^4.14.171", 35 | "@types/node": "^15.3.1", 36 | "@types/webpack-env": "^1.16.2", 37 | "@vue/composition-api": "^1.0.0-rc.14", 38 | "lodash": "^4.17.21", 39 | "rimraf": "^3.0.2", 40 | "vue": "^2.6.14", 41 | "vuex": "^3.6.2" 42 | }, 43 | "dependencies": { 44 | "typescript": "^4.3.5", 45 | "vue-demi": "^0.10.1" 46 | }, 47 | "repository": { 48 | "type": "git", 49 | "url": "git+https://github.com/victorgarciaesgi/Vuex-typed-modules.git" 50 | }, 51 | "homepage": "https://github.com/victorgarciaesgi/Vuex-typed-modules#readme", 52 | "scripts": { 53 | "clean": "rimraf dist && rimraf types", 54 | "compile": "tsc --pretty", 55 | "dev": "tsc --pretty --watch", 56 | "build": "yarn run clean && yarn run compile", 57 | "prepublish": "yarn build" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /types/modules/dynamic.d.ts: -------------------------------------------------------------------------------- 1 | import { ActionBush } from 'src/types'; 2 | import * as Vuex from 'vuex'; 3 | import { VuexModule, VuexModuleArgs } from './default'; 4 | import { VuexModuleHook } from './hooks'; 5 | export declare type ModuleToInstance = TModule extends VuexDynamicModule ? DynamicModuleInstance : TModule; 6 | export declare class VuexDynamicModule, M extends Vuex.MutationTree, G extends Vuex.GetterTree, A extends ActionBush> { 7 | private nestedName?; 8 | private namespaceName; 9 | private module; 10 | private state; 11 | private getters; 12 | private mutations; 13 | private actions; 14 | private options?; 15 | private store; 16 | protected _logger: boolean; 17 | private get params(); 18 | get name(): string; 19 | constructor({ name, mutations, state, actions, getters, options, logger, }: VuexModuleArgs); 20 | save(store: Vuex.Store): void; 21 | instance(moduleKey?: string): [DynamicModuleInstance, () => VuexModuleHook]; 22 | } 23 | export declare class DynamicModuleInstance, M extends Vuex.MutationTree, G extends Vuex.GetterTree, A extends Record>> extends VuexModule { 24 | private nestedName?; 25 | isRegistered: boolean; 26 | constructor({ store, ...args }: VuexModuleArgs & { 27 | store: Vuex.Store; 28 | }); 29 | register(): void; 30 | unregister(): void; 31 | } 32 | export declare const createVuexDynamicModule: , G extends Vuex.GetterTree, M extends Vuex.MutationTree, A extends Record>>(params: VuexModuleArgs) => VuexDynamicModule; 33 | -------------------------------------------------------------------------------- /types/modules/default.d.ts: -------------------------------------------------------------------------------- 1 | import * as Vuex from 'vuex'; 2 | import { ReturnedGetters, ReturnedActions, ReturnedMutations, ActionBush } from '../types'; 3 | import { VuexModuleHook, VuexModuleHookOptions } from './hooks'; 4 | export interface VuexModuleArgs, G extends Vuex.GetterTree = never, M extends Vuex.MutationTree = never, A extends ActionBush = never> { 5 | name: string; 6 | state: S; 7 | getters?: G; 8 | mutations?: M; 9 | actions?: A; 10 | options?: Vuex.ModuleOptions; 11 | logger?: boolean; 12 | } 13 | export declare class VuexModule, M extends Vuex.MutationTree, G extends Vuex.GetterTree, A extends ActionBush> { 14 | protected name: string; 15 | protected initialState: S; 16 | protected _getters?: Vuex.GetterTree; 17 | protected _mutations?: Vuex.MutationTree; 18 | protected _actions?: A; 19 | protected _options?: Vuex.ModuleOptions; 20 | protected _logger: boolean; 21 | protected _state: S; 22 | protected store: Vuex.Store; 23 | getters: ReturnedGetters; 24 | actions: ReturnedActions; 25 | mutations: ReturnedMutations; 26 | state: S; 27 | constructor({ name, state, actions, getters, mutations, options, logger, }: VuexModuleArgs); 28 | resetState(): void; 29 | updateState(callback: ((state: S) => Partial | void) | Partial): void; 30 | extract(): { 31 | name: string; 32 | state: S; 33 | getters: Vuex.GetterTree | undefined; 34 | actions: any; 35 | mutations: Vuex.MutationTree | undefined; 36 | options: Vuex.ModuleOptions | undefined; 37 | }; 38 | protected activate(store: Vuex.Store): void; 39 | deploy(store: Vuex.Store): void; 40 | } 41 | export declare const createVuexModule: , G extends Vuex.GetterTree, M extends Vuex.MutationTree, A extends ActionBush>(params: VuexModuleArgs) => [VuexModule, (hookOptions?: VuexModuleHookOptions | undefined) => VuexModuleHook]; 42 | -------------------------------------------------------------------------------- /src/utils/modifiers.ts: -------------------------------------------------------------------------------- 1 | import * as Vuex from 'vuex'; 2 | 3 | export function createModuleLayers(store: Vuex.Store, moduleName: string) { 4 | function commit(name: string) { 5 | return (payload: any) => store.commit(moduleName + '/' + name, payload); 6 | } 7 | 8 | function dispatch(name: string) { 9 | return (payload: any) => store.dispatch(moduleName + '/' + name, payload); 10 | } 11 | 12 | function read(name: string) { 13 | return () => { 14 | if (store) { 15 | return store.getters[moduleName + '/' + name]; 16 | } 17 | return () => {}; 18 | }; 19 | } 20 | 21 | return { 22 | commit, 23 | dispatch, 24 | read, 25 | get state() { 26 | return () => store.state[moduleName]; 27 | }, 28 | }; 29 | } 30 | 31 | export function buildModifiers(store: Vuex.Store, name: string) { 32 | const { commit, dispatch, read, state } = createModuleLayers(store, name); 33 | 34 | const registerMutations = (mutations?: Record) => { 35 | const renderedMutations = {} as Record; 36 | if (mutations) { 37 | Object.keys(mutations).forEach((key) => { 38 | renderedMutations[key] = commit(key); 39 | }); 40 | } 41 | return renderedMutations as any; 42 | }; 43 | 44 | const registerActions = (actions?: Record) => { 45 | const renderedActions = {} as Record; 46 | if (actions) { 47 | Object.keys(actions).forEach((key) => { 48 | renderedActions[key] = dispatch(key); 49 | }); 50 | } 51 | return renderedActions as any; 52 | }; 53 | 54 | const registerGetters = (getters?: Record) => { 55 | const renderedGetters = {}; 56 | if (getters) { 57 | Object.keys(getters).forEach((key: any) => { 58 | Object.defineProperty(renderedGetters, key, { 59 | enumerable: true, 60 | configurable: true, 61 | get() { 62 | return read(key)(); 63 | }, 64 | }); 65 | }); 66 | } 67 | return renderedGetters as any; 68 | }; 69 | 70 | return { 71 | registerMutations, 72 | registerActions, 73 | registerGetters, 74 | reactiveState: state, 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /src/database.ts: -------------------------------------------------------------------------------- 1 | import * as Vuex from 'vuex'; 2 | import { VuexModule } from './modules/default'; 3 | import { setHelpers } from './modules/helpers'; 4 | import { VuexDynamicModule } from './modules/dynamic'; 5 | 6 | interface DataBaseOptions { 7 | logger?: boolean; 8 | } 9 | 10 | type DefaultModule = VuexModule | VuexDynamicModule; 11 | 12 | export class Database { 13 | private store!: Vuex.Store; 14 | private options!: DataBaseOptions; 15 | private loggerBlackList: string[] = []; 16 | 17 | constructor(options: DataBaseOptions) { 18 | this.options = options; 19 | } 20 | 21 | private install(vuexModules: DefaultModule[]): void { 22 | vuexModules.forEach((vuexmodule) => { 23 | if (vuexmodule instanceof VuexDynamicModule) { 24 | vuexmodule.save(this.store); 25 | } else { 26 | vuexmodule.deploy(this.store); 27 | } 28 | }); 29 | } 30 | 31 | public deploy(vuexModules: DefaultModule[]) { 32 | this.loggerBlackList = vuexModules 33 | .filter((mod: any) => { 34 | return !mod['_logger']; 35 | }) 36 | .map((mod: any) => mod['name']); 37 | return (store: Vuex.Store): void => { 38 | this.store = store; 39 | this.install(vuexModules); 40 | if (this.options.logger) this.createLogger(); 41 | }; 42 | } 43 | 44 | private createLogger() { 45 | if (this.options.logger) { 46 | this.store.subscribeAction({ 47 | before: (action, state) => { 48 | const moduleName = action.type.split('/')[0]; 49 | if (!this.loggerBlackList.includes(moduleName)) { 50 | const type = action.type.split('/')[1]; 51 | console.groupCollapsed( 52 | `%c Vuex Action %c ${moduleName} %c ${type ? `${type}` : '-'} %c`, 53 | 'background: #451382 ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff', 54 | 'background:#fff;padding: 1px;color: #451382', 55 | 'background:#2788d2;padding: 1px;border-radius: 0 3px 3px 0;color: #fff', 56 | 'background:transparent' 57 | ); 58 | console.log('PAYLOAD', action.payload); 59 | console.log('STATE', state); 60 | console.groupEnd(); 61 | } 62 | }, 63 | }); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /types/types.d.ts: -------------------------------------------------------------------------------- 1 | import { Getter, GetterTree, ActionHandler, MutationTree, Store, Dispatch } from 'vuex'; 2 | export declare type IsValidArg = T extends unknown ? keyof Exclude extends never ? false : true : true; 3 | export declare type Dictionary = { 4 | [x: string]: T; 5 | }; 6 | export declare type KeepProperties = Pick; 9 | export declare type ParameterName any> = T extends (context: any, ...args: infer P) => any ? P : never; 10 | export declare type inferMutations = T extends (state: any, payload: infer P) => void ? IsValidArg

extends true ? (...args: ParameterName) => void : () => void : () => void; 11 | export declare type inferActions> = T extends (context: any, payload: infer P) => any ? IsValidArg

extends true ? (...args: ParameterName) => ReturnType : () => ReturnType : ReturnType; 12 | export declare type inferGetters> = T extends (state: any, getters?: any) => infer R ? R : void; 13 | export interface RichActionContext, M extends ReturnedMutations> { 14 | dispatch: Dispatch; 15 | mutations: M; 16 | state: S; 17 | getters: G; 18 | } 19 | export declare type RichAction, M extends ReturnedMutations> = (this: Store, injectee: RichActionContext, payload?: any) => any; 20 | export interface RichActionTree, M extends ReturnedMutations> { 21 | [x: string]: RichAction; 22 | } 23 | export declare type ActionBush = Record>; 24 | export declare type ReturnedGetters> = { 25 | [K in keyof T]: inferGetters; 26 | }; 27 | export declare type ReturnedActions> = { 28 | [K in keyof T]: inferActions; 29 | }; 30 | export declare type ReturnedMutations> = { 31 | [K in keyof T]: inferMutations; 32 | }; 33 | export declare type StoreModuleType = { 34 | getters?: ReturnedGetters; 35 | actions?: ReturnedActions; 36 | mutations?: ReturnedMutations; 37 | state: any; 38 | } & SharedMutations; 39 | export declare type SharedMutations = { 40 | resetState: () => void; 41 | updateState: (callback: ((state: S) => Partial | void) | Partial) => void; 42 | }; 43 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { Getter, GetterTree, ActionHandler, MutationTree, Store, Dispatch } from 'vuex'; 2 | 3 | export type IsValidArg = T extends unknown 4 | ? keyof Exclude extends never 5 | ? false 6 | : true 7 | : true; 8 | 9 | export type Dictionary = { [x: string]: T }; 10 | export type KeepProperties = Pick; 11 | 12 | export type ParameterName any> = T extends ( 13 | context: any, 14 | ...args: infer P 15 | ) => any 16 | ? P 17 | : never; 18 | 19 | export type inferMutations = T extends (state: any, payload: infer P) => void 20 | ? IsValidArg

extends true 21 | ? (...args: ParameterName) => void 22 | : () => void 23 | : () => void; 24 | 25 | export type inferActions> = T extends ( 26 | context: any, 27 | payload: infer P 28 | ) => any 29 | ? IsValidArg

extends true 30 | ? (...args: ParameterName) => ReturnType 31 | : () => ReturnType 32 | : ReturnType; 33 | 34 | export type inferGetters> = T extends ( 35 | state: any, 36 | getters?: any 37 | ) => infer R 38 | ? R 39 | : void; 40 | 41 | export interface RichActionContext< 42 | S, 43 | G extends ReturnedGetters, 44 | M extends ReturnedMutations 45 | > { 46 | dispatch: Dispatch; 47 | mutations: M; 48 | state: S; 49 | getters: G; 50 | } 51 | export type RichAction, M extends ReturnedMutations> = ( 52 | this: Store, 53 | injectee: RichActionContext, 54 | payload?: any 55 | ) => any; 56 | 57 | export interface RichActionTree< 58 | S, 59 | G extends ReturnedGetters, 60 | M extends ReturnedMutations 61 | > { 62 | [x: string]: RichAction; 63 | } 64 | 65 | export type ActionBush = Record>; 66 | 67 | export type ReturnedGetters> = { 68 | [K in keyof T]: inferGetters; 69 | }; 70 | export type ReturnedActions> = { 71 | [K in keyof T]: inferActions; 72 | }; 73 | export type ReturnedMutations> = { 74 | [K in keyof T]: inferMutations; 75 | }; 76 | 77 | export type StoreModuleType = { 78 | getters?: ReturnedGetters; 79 | actions?: ReturnedActions; 80 | mutations?: ReturnedMutations; 81 | state: any; 82 | } & SharedMutations; 83 | 84 | export type SharedMutations = { 85 | resetState: () => void; 86 | updateState: (callback: ((state: S) => Partial | void) | Partial) => void; 87 | }; 88 | -------------------------------------------------------------------------------- /src/modules/hooks.ts: -------------------------------------------------------------------------------- 1 | import { VuexModuleArgs } from './default'; 2 | import { MutationTree, Store, GetterTree } from 'vuex'; 3 | import { 4 | ReturnedGetters, 5 | ReturnedActions, 6 | ReturnedMutations, 7 | ActionBush, 8 | SharedMutations, 9 | } from '../types'; 10 | import { buildModifiers } from '../utils/modifiers'; 11 | import cloneDeep from 'lodash/cloneDeep'; 12 | import { getCurrentInstance, readonly, toRefs, ToRefs } from 'vue-demi'; 13 | 14 | export const useStore = (name: string): Store => { 15 | const vm = getCurrentInstance(); 16 | if (!vm) throw new Error(`${name} hook must be called within a setup function`); 17 | return vm.proxy.$store; 18 | }; 19 | 20 | export interface VuexModuleHookOptions { 21 | unwrap: TWrap; 22 | } 23 | 24 | export type VuexModuleHook< 25 | S extends Record, 26 | M extends MutationTree, 27 | G extends GetterTree, 28 | A extends ActionBush, 29 | TWrap extends boolean = false 30 | > = { 31 | state: TWrap extends true ? S : ToRefs; 32 | getters: ReturnedGetters; 33 | mutations: ReturnedMutations; 34 | actions: ReturnedActions; 35 | } & SharedMutations; 36 | 37 | export function createDefaultModuleHook< 38 | S extends Record, 39 | M extends MutationTree, 40 | G extends GetterTree, 41 | A extends ActionBush, 42 | TWrap extends boolean 43 | >({ 44 | name, 45 | state, 46 | actions, 47 | getters, 48 | mutations, 49 | hookOptions, 50 | }: VuexModuleArgs & { hookOptions?: VuexModuleHookOptions }): VuexModuleHook< 51 | S, 52 | M, 53 | G, 54 | A, 55 | TWrap 56 | > { 57 | const store = useStore(name); 58 | 59 | const initialState = readonly(cloneDeep(state)); 60 | 61 | function resetState(): void { 62 | store.commit(`${name}/resetState`, initialState); 63 | } 64 | function updateState(callback: ((state: S) => Partial | void) | Partial) { 65 | const storeState = store.state[name]; 66 | let updatedState: Partial | null = null; 67 | if (callback instanceof Function) { 68 | const returnedKeys = callback(storeState); 69 | if (returnedKeys) { 70 | updatedState = returnedKeys; 71 | } 72 | } else { 73 | updatedState = callback; 74 | } 75 | const stateToUpdate = updatedState ?? storeState; 76 | store.commit(`${name}/updateState`, stateToUpdate); 77 | } 78 | 79 | const { registerActions, registerGetters, registerMutations, reactiveState } = buildModifiers( 80 | store, 81 | name 82 | ); 83 | 84 | const _mutations = registerMutations(mutations); 85 | const _actions = registerActions(actions); 86 | const _getters = registerGetters(getters); 87 | const _state = hookOptions?.unwrap ? readonly(reactiveState()) : toRefs(reactiveState()); 88 | 89 | return { 90 | state: _state, 91 | actions: _actions, 92 | getters: _getters, 93 | mutations: _mutations, 94 | resetState, 95 | updateState, 96 | }; 97 | } 98 | 99 | export function createModuleHook< 100 | S extends Record, 101 | M extends MutationTree, 102 | G extends GetterTree, 103 | A extends ActionBush 104 | >(params: VuexModuleArgs) { 105 | return (hookOptions?: VuexModuleHookOptions) => 106 | createDefaultModuleHook({ ...params, hookOptions }); 107 | } 108 | -------------------------------------------------------------------------------- /src/modules/dynamic.ts: -------------------------------------------------------------------------------- 1 | import { ActionBush } from 'src/types'; 2 | import * as Vuex from 'vuex'; 3 | import { VuexModule, VuexModuleArgs } from './default'; 4 | import { createModuleHook, VuexModuleHook } from './hooks'; 5 | 6 | // function unWrapDynamicModule>(module: T) {} 7 | 8 | export type ModuleToInstance = TModule extends VuexDynamicModule< 9 | infer S, 10 | infer M, 11 | infer G, 12 | infer A 13 | > 14 | ? DynamicModuleInstance 15 | : TModule; 16 | 17 | export class VuexDynamicModule< 18 | S extends Record, 19 | M extends Vuex.MutationTree, 20 | G extends Vuex.GetterTree, 21 | A extends ActionBush 22 | > { 23 | private nestedName?: string; 24 | private namespaceName!: string; 25 | private module!: DynamicModuleInstance; 26 | private state!: S; 27 | private getters!: any; 28 | private mutations!: any; 29 | private actions!: any; 30 | private options?: Vuex.ModuleOptions; 31 | private store!: Vuex.Store; 32 | 33 | protected _logger: boolean; 34 | 35 | private get params() { 36 | return { 37 | state: this.state, 38 | getters: this.getters, 39 | mutations: this.mutations, 40 | actions: this.actions, 41 | options: this.options, 42 | }; 43 | } 44 | 45 | get name(): string { 46 | if (this.nestedName) { 47 | return `${this.namespaceName}-${this.nestedName}`; 48 | } 49 | 50 | return this.namespaceName; 51 | } 52 | 53 | constructor({ 54 | name, 55 | mutations, 56 | state, 57 | actions, 58 | getters, 59 | options, 60 | logger = true, 61 | }: VuexModuleArgs) { 62 | this.namespaceName = name; 63 | this.state = state; 64 | this.getters = getters; 65 | this.actions = actions; 66 | this.mutations = mutations; 67 | this.options = options; 68 | this._logger = logger; 69 | } 70 | 71 | public save(store: Vuex.Store) { 72 | this.store = store; 73 | } 74 | 75 | public instance( 76 | moduleKey?: string 77 | ): [DynamicModuleInstance, () => VuexModuleHook] { 78 | this.nestedName = moduleKey; 79 | let fullName = this.name; 80 | this.module = new DynamicModuleInstance({ name: fullName, ...this.params, store: this.store }); 81 | const dynamicHook = createModuleHook({ name: fullName, ...this.params }); 82 | return [this.module, dynamicHook]; 83 | } 84 | } 85 | 86 | export class DynamicModuleInstance< 87 | S extends Record, 88 | M extends Vuex.MutationTree, 89 | G extends Vuex.GetterTree, 90 | A extends Record> 91 | > extends VuexModule { 92 | private nestedName?: string; 93 | public isRegistered: boolean = false; 94 | 95 | constructor({ store, ...args }: VuexModuleArgs & { store: Vuex.Store }) { 96 | super(args); 97 | this.store = store; 98 | } 99 | 100 | public register() { 101 | this.activate(this.store); 102 | this.isRegistered = true; 103 | } 104 | 105 | public unregister(): void { 106 | this.store.unregisterModule( 107 | (this.nestedName ? [this.name, this.nestedName] : this.name) as any 108 | ); 109 | this.isRegistered = false; 110 | } 111 | } 112 | 113 | export const createVuexDynamicModule = < 114 | S extends Record, 115 | G extends Vuex.GetterTree, 116 | M extends Vuex.MutationTree, 117 | A extends Record> 118 | >( 119 | params: VuexModuleArgs 120 | ): VuexDynamicModule => { 121 | const defaultModule = new VuexDynamicModule(params); 122 | 123 | return defaultModule; 124 | }; 125 | 126 | // createVuexDynamicModule({ 127 | // name: 'zefez', 128 | // state: { 129 | // foo: 'bar', 130 | // }, 131 | // mutations: { 132 | // boo(state) { 133 | // state.foo; 134 | // }, 135 | // }, 136 | // actions: { 137 | // test({ state, commit, getters }, test: string | null) { 138 | // state.foo; 139 | // }, 140 | // }, 141 | // }); 142 | -------------------------------------------------------------------------------- /src/modules/default.ts: -------------------------------------------------------------------------------- 1 | import * as Vuex from 'vuex'; 2 | import { ReturnedGetters, ReturnedActions, ReturnedMutations, ActionBush } from '../types'; 3 | import { buildModifiers } from '../utils/modifiers'; 4 | import { setHelpers } from './helpers'; 5 | import cloneDeep from 'lodash/cloneDeep'; 6 | import { createModuleHook, VuexModuleHook, VuexModuleHookOptions } from './hooks'; 7 | 8 | export interface VuexModuleArgs< 9 | S extends Record, 10 | G extends Vuex.GetterTree = never, 11 | M extends Vuex.MutationTree = never, 12 | A extends ActionBush = never 13 | > { 14 | name: string; 15 | state: S; 16 | getters?: G; 17 | mutations?: M; 18 | actions?: A; 19 | options?: Vuex.ModuleOptions; 20 | logger?: boolean; 21 | } 22 | 23 | export class VuexModule< 24 | S extends Record, 25 | M extends Vuex.MutationTree, 26 | G extends Vuex.GetterTree, 27 | A extends ActionBush 28 | > { 29 | protected name!: string; 30 | protected initialState: S = {} as any; 31 | protected _getters?: Vuex.GetterTree; 32 | protected _mutations?: Vuex.MutationTree; 33 | protected _actions?: A; 34 | protected _options?: Vuex.ModuleOptions; 35 | protected _logger: boolean; 36 | protected _state!: S; 37 | 38 | protected store!: Vuex.Store; 39 | 40 | public getters!: ReturnedGetters; 41 | public actions!: ReturnedActions; 42 | public mutations!: ReturnedMutations; 43 | public state: S = {} as any; 44 | 45 | constructor({ 46 | name, 47 | state, 48 | actions, 49 | getters, 50 | mutations, 51 | options, 52 | logger = true, 53 | }: VuexModuleArgs) { 54 | Object.defineProperty(this, 'initialState', { 55 | enumerable: false, 56 | configurable: false, 57 | get() { 58 | return cloneDeep(state); 59 | }, 60 | set() {}, 61 | }); 62 | this.name = name; 63 | this._state = cloneDeep(state); 64 | this._getters = getters; 65 | this._actions = actions; 66 | this._mutations = mutations; 67 | this._options = options; 68 | this._logger = logger; 69 | } 70 | 71 | public resetState() { 72 | this.store.commit(`${this.name}/resetState`, this.initialState); 73 | } 74 | public updateState(callback: ((state: S) => Partial | void) | Partial) { 75 | const storeState = this.store.state[this.name]; 76 | let updatedState: Partial | null = null; 77 | if (callback instanceof Function) { 78 | const returnedKeys = callback(storeState); 79 | if (returnedKeys) { 80 | updatedState = returnedKeys; 81 | } 82 | } else { 83 | updatedState = callback; 84 | } 85 | const stateToUpdate = updatedState ?? storeState; 86 | this.store.commit(`${this.name}/updateState`, stateToUpdate); 87 | } 88 | 89 | public extract() { 90 | return { 91 | name: this.name, 92 | state: this._state, 93 | getters: this._getters, 94 | actions: this._actions as any, 95 | mutations: this._mutations, 96 | options: this._options, 97 | }; 98 | } 99 | protected activate(store: Vuex.Store): void { 100 | let { name, actions, getters, mutations, state, options } = this.extract(); 101 | this.store = store; 102 | 103 | if (store.hasModule(name)) { 104 | console.log(`%c Module "${name}" still active, skipping activation`, 'color: #4287f5'); 105 | return; 106 | } else { 107 | const moduleName = name; 108 | if (mutations == null && mutations === undefined) { 109 | mutations = {}; 110 | } 111 | mutations = setHelpers(mutations); 112 | store.registerModule( 113 | moduleName, 114 | { 115 | namespaced: true, 116 | actions, 117 | getters, 118 | mutations, 119 | state, 120 | }, 121 | options 122 | ); 123 | const { registerActions, registerGetters, registerMutations, reactiveState } = buildModifiers( 124 | store, 125 | this.name 126 | ); 127 | this.mutations = registerMutations(this._mutations); 128 | this.actions = registerActions(this._actions); 129 | this.getters = registerGetters(this._getters); 130 | Object.defineProperty(this, 'state', { 131 | enumerable: true, 132 | configurable: true, 133 | get() { 134 | return reactiveState(); 135 | }, 136 | }); 137 | } 138 | } 139 | 140 | public deploy(store: Vuex.Store) { 141 | this.activate(store); 142 | } 143 | } 144 | 145 | export const createVuexModule = < 146 | S extends Record, 147 | G extends Vuex.GetterTree, 148 | M extends Vuex.MutationTree, 149 | A extends ActionBush 150 | >( 151 | params: VuexModuleArgs 152 | ): [ 153 | VuexModule, 154 | ( 155 | hookOptions?: VuexModuleHookOptions 156 | ) => VuexModuleHook 157 | ] => { 158 | const defaultModule = new VuexModule(params); 159 | const moduleHook = createModuleHook(params); 160 | 161 | return [defaultModule, moduleHook]; 162 | }; 163 | 164 | // const test = new VuexModule({ 165 | // name: 'zefez', 166 | // state: { 167 | // foo: 'bar', 168 | // }, 169 | // mutations: { 170 | // boo(state) { 171 | // state.foo; 172 | // }, 173 | // }, 174 | // actions: { 175 | // test({ commit, state, getters }, test: string | null) { 176 | // state.foo; 177 | // }, 178 | // }, 179 | // }); 180 | 181 | // test.actions.test(); 182 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🧰 vuex-typed-modules 2 | 3 | [![npm version][npm-version-src]][npm-version-href] 4 | [![npm downloads][npm-downloads-src]][npm-downloads-href] 5 | [![npm downloads][npm-total-downloads-src]][npm-downloads-href] 6 | 7 | 8 | [npm-version-src]: https://img.shields.io/npm/v/vuex-typed-modules.svg 9 | [npm-version-href]: https://www.npmjs.com/package/vuex-typed-modules 10 | [npm-downloads-src]: https://img.shields.io/npm/dm/vuex-typed-modules.svg 11 | [npm-total-downloads-src]: https://img.shields.io/npm/dt/vuex-typed-modules.svg 12 | [npm-downloads-href]: https://www.npmjs.com/package/vuex-typed-modules 13 | 14 | A VueX 3 & 4 wrapper that provides type safe hooks and handlers to your Vuex Store modules with less code! 15 | 16 | > 4.x Support Vue 2 & 3, and Vuex 3 & 4 and added composition-api support (Thanks to `vue-demi`) 17 | 18 | > 3.x Working with Vue 2, and Vue 3 with Vuex4 (but not hooks) 19 | 20 | ## Installation 21 | 22 | ```bash 23 | npm i vuex-typed-modules 24 | #or 25 | yarn add vuex-typed-modules 26 | ``` 27 | 28 | # Usage for version `4.x` 29 | 30 | ## Define Module and hook 31 | 32 | ```typescript 33 | import { createVuexModule } from 'vuex-typed-modules'; 34 | 35 | export const [testModule, useTestModule] = createVuexModule({ 36 | name: 'testModule', 37 | state: { 38 | count: 1, 39 | }, 40 | mutations: { 41 | addCount(state, number: number) { 42 | state.count += number; 43 | }, 44 | }, 45 | actions: { 46 | async addCountAsync(_, count: number): Promise { 47 | await myAsyncFunction(count); 48 | // Calling mutation 49 | testModule.mutations.addCount(count); 50 | }, 51 | }, 52 | }); 53 | ``` 54 | 55 | ## Module declaration (For 4.x and 3.x) 56 | 57 | In your `main.ts` 58 | 59 | ```typescript 60 | import { Database } from "vuex-typed-modules"; 61 | import { testModule } from '~modules' 62 | 63 | const database = new Database({ logger: true }); 64 | const store = new Vuex.Store({ 65 | plugins: [database.deploy([testModule])]; 66 | }) 67 | 68 | // If you're using Vue 3: 69 | createApp(App).use(store).mount("#app"); 70 | 71 | // If you're using Vue 2: 72 | new Vue({ 73 | store, 74 | render: h => h(App) 75 | }).$mount("#app"); 76 | ``` 77 | 78 | ## For Nuxt.js 79 | 80 | ```typescript 81 | // store/index.ts 82 | import { Database } from 'vuex-typed-modules'; 83 | import { testModule } from '~modules'; 84 | 85 | const database = new Database({ logger: process.browser }); 86 | export const plugins = [database.deploy([testModule])]; 87 | 88 | export const state = () => ({}); 89 | ``` 90 | 91 | ## Usage in your components or in other modules! 92 | 93 | ```html 94 | 100 | ``` 101 | 102 | ```typescript 103 | import { defineComponent, onBeforeUnmount } from 'vue'; 104 | import { testModule } from '~/modules'; 105 | 106 | export default defineComponent({ 107 | name: 'Home', 108 | setup() { 109 | const { 110 | state: { count }, 111 | actions: { increment }, 112 | } = useChildStoreModule(); 113 | 114 | return { 115 | count, 116 | increment, 117 | }; 118 | }, 119 | }); 120 | ``` 121 | 122 | ## Note 123 | 124 | Store hooks return refs for the state. It can be overwridden by using the option `unwrap` 125 | 126 | With Refs 127 | 128 | ```ts 129 | // You can destructure state when using refs 130 | const { 131 | state: { count }, 132 | } = useTestModule(); // count is of type `Ref` 133 | console.log(count.value); 134 | ``` 135 | 136 | Without Refs 137 | 138 | ```ts 139 | // If you destructure the state, it will loses reactivity 140 | const { state } = useTestModule({ unwrap: true }); 141 | state.count; // count is of type `number` 142 | ``` 143 | 144 | ## Dynamic Modules 145 | 146 | For dynamic modules, simply use the class `VuexDynamicModule` instead 147 | 148 | ```typescript 149 | import { createVuexDynamicModule } from 'vuex-typed-modules'; 150 | 151 | export const dynamicModule = createVuexDynamicModule({ 152 | name: 'dynamicModule', 153 | logger: false, 154 | state: { 155 | count: 1, 156 | type: null, 157 | }, 158 | actions: { 159 | // Due to limitions of Typescript, I can't provide typings for infered mutations and getters inside the same object. 160 | // It would make an infinite loop (I tried). 161 | // For dynamic module you can fallback on "commit" "dispatch" and "getters" 162 | exemple({ state, commit, dispatch, getters }, param: string) { 163 | // ... 164 | }, 165 | }, 166 | }); 167 | ``` 168 | 169 | ### Usage 170 | 171 | ```vue 172 | 197 | ``` 198 | 199 | ## Default module helpers 200 | 201 | Vuex types modules also add helpers functions on top of your module to prevent from writing short mutations 202 | 203 | ```typescript 204 | testModule.resetState(); 205 | // Reset your module to the initial State 206 | ``` 207 | 208 | ```typescript 209 | // You can specify only the property you want to update 210 | testModule.updateState({ 211 | count: 3, 212 | }); 213 | 214 | // You can also give a callback function to have access to the current state 215 | testModule.updateState((state) => ({ 216 | count: state.count + 2, 217 | })); 218 | 219 | // And also mutate the state directly (A bit heavier on the update) 220 | testModule.updateState((state) => { 221 | state.count++; 222 | }); 223 | ``` 224 | 225 | # ------------------------------------------- 226 | 227 | # Usage for `3.x` 228 | 229 | ## Define Module 230 | 231 | Create a `test.module.ts` in your store folder 232 | 233 | ```typescript 234 | import { VuexModule } from 'vuex-typed-modules'; 235 | 236 | export const testModule = new VuexModule({ 237 | name: 'testModule', 238 | state: { 239 | count: 1, 240 | }, 241 | mutations: { 242 | addCount(state, number: number) { 243 | state.count += number; 244 | }, 245 | }, 246 | actions: { 247 | async addCountAsync(_, count: number): Promise { 248 | await myAsyncFunction(count); 249 | // Calling mutation 250 | testModule.mutations.addCount(count); 251 | }, 252 | }, 253 | }); 254 | ``` 255 | 256 | ## Usage in your components or in other modules! 257 | 258 | ```html 259 | 265 | ``` 266 | 267 | ```typescript 268 | import { Component, Prop, Vue } from 'vue-property-decorator'; 269 | import { testModule } from '~/modules'; 270 | 271 | @Component 272 | export default class Home extends Vue { 273 | get count() { 274 | return testModule.getters.count; 275 | } 276 | 277 | async increment() { 278 | await testModule.actions.addCountAsync(2); 279 | } 280 | } 281 | ``` 282 | 283 | # Tests 284 | 285 | ```typescript 286 | // user.spec.ts 287 | import { createTestStore } from 'vuex-typed-modules'; 288 | import { createLocalVue } from '@vue/test-utils'; 289 | // import state, actions, mutations and getters from some store module 290 | 291 | const configStore = { 292 | state, 293 | actions, 294 | mutations, 295 | getters, 296 | }; 297 | 298 | const localVue = createLocalVue(); 299 | localVue.use(Vuex); 300 | 301 | const store = createTestStore(configStore); 302 | 303 | describe('User Module', () => { 304 | it('name should be empty', () => { 305 | expect(store.state.name).toBe(''); 306 | }); 307 | it('name should change to Foo', () => { 308 | store.dispatch('CHANGE_NAME', 'Foo'); 309 | expect(store.state.name).toBe('Foo'); 310 | }); 311 | }); 312 | ``` 313 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@nuxtjs/composition-api@^0.24.7": 6 | version "0.24.7" 7 | resolved "https://registry.yarnpkg.com/@nuxtjs/composition-api/-/composition-api-0.24.7.tgz#76ec3660a03cd7bdb8b85fd31e8dc6a2b7194e8f" 8 | integrity sha512-q633RvsCi3veuGzTSkP/+a55Fn9EZS1APV2GJrdjajnBKKOMNPIXlAC8xAWGcsHE73/Cgf9DfGURQhcFvERRJA== 9 | dependencies: 10 | "@vue/composition-api" "1.0.0-rc.14" 11 | defu "^5.0.0" 12 | estree-walker "^2.0.2" 13 | fs-extra "^9.1.0" 14 | magic-string "^0.25.7" 15 | ufo "^0.7.7" 16 | upath "^2.0.1" 17 | 18 | "@types/lodash@^4.14.171": 19 | version "4.14.171" 20 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.171.tgz#f01b3a5fe3499e34b622c362a46a609fdb23573b" 21 | integrity sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg== 22 | 23 | "@types/node@^15.3.1": 24 | version "15.3.1" 25 | resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.1.tgz#23a06b87eedb524016616e886b116b8fdcb180af" 26 | integrity sha512-weaeiP4UF4XgF++3rpQhpIJWsCTS4QJw5gvBhQu6cFIxTwyxWIe3xbnrY/o2lTCQ0lsdb8YIUDUvLR4Vuz5rbw== 27 | 28 | "@types/webpack-env@^1.16.2": 29 | version "1.16.2" 30 | resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.2.tgz#8db514b059c1b2ae14ce9d7bb325296de6a9a0fa" 31 | integrity sha512-vKx7WNQNZDyJveYcHAm9ZxhqSGLYwoyLhrHjLBOkw3a7cT76sTdjgtwyijhk1MaHyRIuSztcVwrUOO/NEu68Dw== 32 | 33 | "@vue/composition-api@1.0.0-rc.14", "@vue/composition-api@^1.0.0-rc.14": 34 | version "1.0.0-rc.14" 35 | resolved "https://registry.yarnpkg.com/@vue/composition-api/-/composition-api-1.0.0-rc.14.tgz#4803fbccf3f3c770416e69095010c7bc0c4aa1c3" 36 | integrity sha512-WKbOiy1zk8loM7ma88fOH0yacOEfMIQb0IZJEq561A+4C8GvLSqVSLT5K1iBVkzzJ07Pha8ntbeWSUQlBhRDKg== 37 | dependencies: 38 | tslib "^2.3.0" 39 | 40 | at-least-node@^1.0.0: 41 | version "1.0.0" 42 | resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" 43 | integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== 44 | 45 | balanced-match@^1.0.0: 46 | version "1.0.0" 47 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 48 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 49 | 50 | brace-expansion@^1.1.7: 51 | version "1.1.11" 52 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 53 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 54 | dependencies: 55 | balanced-match "^1.0.0" 56 | concat-map "0.0.1" 57 | 58 | concat-map@0.0.1: 59 | version "0.0.1" 60 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 61 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 62 | 63 | defu@^5.0.0: 64 | version "5.0.0" 65 | resolved "https://registry.yarnpkg.com/defu/-/defu-5.0.0.tgz#5768f0d402a555bfc4c267246b20f82ce8b5a10b" 66 | integrity sha512-VHg73EDeRXlu7oYWRmmrNp/nl7QkdXUxkQQKig0Zk8daNmm84AbGoC8Be6/VVLJEKxn12hR0UBmz8O+xQiAPKQ== 67 | 68 | estree-walker@^2.0.2: 69 | version "2.0.2" 70 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 71 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== 72 | 73 | fs-extra@^9.1.0: 74 | version "9.1.0" 75 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" 76 | integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== 77 | dependencies: 78 | at-least-node "^1.0.0" 79 | graceful-fs "^4.2.0" 80 | jsonfile "^6.0.1" 81 | universalify "^2.0.0" 82 | 83 | fs.realpath@^1.0.0: 84 | version "1.0.0" 85 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 86 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 87 | 88 | glob@^7.1.3: 89 | version "7.1.4" 90 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" 91 | integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== 92 | dependencies: 93 | fs.realpath "^1.0.0" 94 | inflight "^1.0.4" 95 | inherits "2" 96 | minimatch "^3.0.4" 97 | once "^1.3.0" 98 | path-is-absolute "^1.0.0" 99 | 100 | graceful-fs@^4.1.6, graceful-fs@^4.2.0: 101 | version "4.2.6" 102 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" 103 | integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== 104 | 105 | inflight@^1.0.4: 106 | version "1.0.6" 107 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 108 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 109 | dependencies: 110 | once "^1.3.0" 111 | wrappy "1" 112 | 113 | inherits@2: 114 | version "2.0.4" 115 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 116 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 117 | 118 | jsonfile@^6.0.1: 119 | version "6.1.0" 120 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" 121 | integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== 122 | dependencies: 123 | universalify "^2.0.0" 124 | optionalDependencies: 125 | graceful-fs "^4.1.6" 126 | 127 | lodash@^4.17.21: 128 | version "4.17.21" 129 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 130 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 131 | 132 | magic-string@^0.25.7: 133 | version "0.25.7" 134 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" 135 | integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== 136 | dependencies: 137 | sourcemap-codec "^1.4.4" 138 | 139 | minimatch@^3.0.4: 140 | version "3.0.4" 141 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 142 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 143 | dependencies: 144 | brace-expansion "^1.1.7" 145 | 146 | once@^1.3.0: 147 | version "1.4.0" 148 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 149 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 150 | dependencies: 151 | wrappy "1" 152 | 153 | path-is-absolute@^1.0.0: 154 | version "1.0.1" 155 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 156 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 157 | 158 | rimraf@^3.0.2: 159 | version "3.0.2" 160 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 161 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 162 | dependencies: 163 | glob "^7.1.3" 164 | 165 | sourcemap-codec@^1.4.4: 166 | version "1.4.8" 167 | resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" 168 | integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== 169 | 170 | tslib@^2.3.0: 171 | version "2.3.0" 172 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" 173 | integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== 174 | 175 | typescript@^4.3.5: 176 | version "4.3.5" 177 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" 178 | integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== 179 | 180 | ufo@^0.7.7: 181 | version "0.7.7" 182 | resolved "https://registry.yarnpkg.com/ufo/-/ufo-0.7.7.tgz#0062f9e5e790819b0fb23ca24d7c63a4011c036a" 183 | integrity sha512-N25aY3HBkJBnahm+2l4JRBBrX5I+JPakF/tDHYDTjd3wUR7iFLdyiPhj8mBwBz21v728BKwM9L9tgBfCntgdlw== 184 | 185 | universalify@^2.0.0: 186 | version "2.0.0" 187 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" 188 | integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== 189 | 190 | upath@^2.0.1: 191 | version "2.0.1" 192 | resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" 193 | integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== 194 | 195 | vue-demi@^0.10.1: 196 | version "0.10.1" 197 | resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.10.1.tgz#229b81395510f02f4ee255344557a12cc0120930" 198 | integrity sha512-L6Oi+BvmMv6YXvqv5rJNCFHEKSVu7llpWWJczqmAQYOdmPPw5PNYoz1KKS//Fxhi+4QP64dsPjtmvnYGo1jemA== 199 | 200 | vue@^2.6.14: 201 | version "2.6.14" 202 | resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235" 203 | integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ== 204 | 205 | vuex@^3.6.2: 206 | version "3.6.2" 207 | resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71" 208 | integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw== 209 | 210 | wrappy@1: 211 | version "1.0.2" 212 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 213 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 214 | --------------------------------------------------------------------------------