Skip to content

Commit 09b525c

Browse files
committed
implemented new flow
1 parent af84b98 commit 09b525c

File tree

15 files changed

+633
-189
lines changed

15 files changed

+633
-189
lines changed

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
.vscode/
2-
test-js/
3-
test-ts/
41
node_modules/

.vscode/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"files.exclude": {
3+
"node_modules": true,
4+
"test-js/node_modules": true,
5+
"test-ts/node_modules": true
6+
}
7+
}

src/actions.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { ActionDescriptor, ActionOption, VuexModule, VuexModuleInternalsPrototype } from "./interfaces";
2+
import { ActionContext } from 'vuex';
3+
import { LegacyVuexModule } from './module.legacy';
4+
5+
/*
6+
* We need a Vuex action to always be present so we can
7+
* guarantee access to the context object always exist when creating a
8+
* proxy.
9+
*/
10+
export const internalAction = ( state :any, context :any ) => undefined;
11+
12+
13+
export function action(options? :ActionOption ): (target:any, key:string, descriptor:ActionDescriptor) => any
14+
export function action(target:any, key:string, descriptor:ActionDescriptor):any
15+
export function action(...params:any[]) {
16+
17+
const firstParam = params[0] as VuexModule | ActionOption | undefined;
18+
19+
if( firstParam === undefined ) return handleMutateActionMode;
20+
21+
if( firstParam instanceof VuexModule || firstParam instanceof LegacyVuexModule ) {
22+
return handleMutateActionMode( firstParam, params[ 1 ], params[ 2 ] )
23+
}
24+
25+
switch( firstParam.mode ) {
26+
case "raw": return handleRawActionMode;
27+
case "mutate": return handleMutateActionMode;
28+
default: return handleMutateActionMode;
29+
}
30+
31+
}
32+
33+
export function getRawActionContext<T extends VuexModule, R>( thisArg:ThisType<T> ) {
34+
return thisArg as ActionContext<T, R>
35+
}
36+
37+
function handleMutateActionMode(target:VuexModule, key:string, descriptor:ActionDescriptor) {
38+
39+
40+
initializeActionsCache( target );
41+
42+
(target as VuexModuleInternalsPrototype).__actions__.push({
43+
__name__: key,
44+
__type__: "mutate",
45+
})
46+
47+
}
48+
49+
function handleRawActionMode(target:any, key:string, descriptor:ActionDescriptor) {
50+
51+
initializeActionsCache( target );
52+
53+
(target as VuexModuleInternalsPrototype).__actions__.push({
54+
__name__: key,
55+
__type__: "raw",
56+
});
57+
}
58+
59+
function initializeActionsCache(target :any) {
60+
if( ( target as VuexModuleInternalsPrototype).__actions__ === undefined ) {
61+
(target as VuexModuleInternalsPrototype).__actions__ = [];
62+
}
63+
}

src/getters.legacy.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
/*
3+
* The getter decorator exists just for backward compatibility.
4+
* Not doing anything.
5+
*/
6+
export const getter = (target:any, propertyKey:string) => undefined

src/getters.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
export const internalGetter = ( state :any, context :any ) => ( field :string ) => {
2+
const fields = field.split( "." );
3+
switch( fields.length ) {
4+
case 1:
5+
return state[ fields[0] ];
6+
case 2:
7+
return state[ fields[0] ][ fields[1] ];
8+
case 3:
9+
return state[ fields[0] ][ fields[1] ][ fields[2] ];
10+
case 4:
11+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ];
12+
case 5:
13+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ][ fields[4] ];
14+
case 6:
15+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ][ fields[4] ][ fields[ 5] ];
16+
case 7:
17+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ][ fields[4] ][ fields[ 5] ][ fields[6] ];
18+
case 8:
19+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ][ fields[4] ][ fields[ 5] ][ fields[6] ][ fields[7] ];
20+
case 9:
21+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ][ fields[4] ][ fields[ 5] ][ fields[6] ][ fields[7] ][ fields[8] ];
22+
case 10:
23+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ][ fields[4] ][ fields[ 5] ][ fields[6] ][ fields[7] ][ fields[8] ][ fields[9] ];
24+
case 11:
25+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ][ fields[4] ][ fields[ 5] ][ fields[6] ][ fields[7] ][ fields[8] ][ fields[9] ][ fields[10] ];
26+
case 12:
27+
return state[ fields[0] ][ fields[1] ][ fields[2] ][ fields[3] ][ fields[4] ][ fields[ 5] ][ fields[6] ][ fields[7] ][ fields[8] ][ fields[9] ][ fields[10] ][ fields[11] ];
28+
}
29+
}
30+

src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export { extractVuexModule, createModule } from "./module";
2+
export { createSubModule } from "./submodule";
3+
export { createProxy } from "./proxy"
4+
export { action, getRawActionContext } from "./actions";
5+
export { mutation } from "./mutations";
6+
7+
export { Module, LegacyVuexModule as VuexModule } from "./module.legacy";
8+
export { getter } from "./getters.legacy";

src/interfaces.ts

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,45 @@
11
export interface VuexModuleOptions {
2-
namespaced ?:boolean;
3-
target ?:"nuxt"
2+
/*
3+
* Takes a boolean or a namespacedPath.
4+
* Defines wether the module should be namespaced or not.
5+
* If true, then the module will be namespaced.
6+
* If false, then the module will not be namespaced.
7+
* If it is a string the module will be namespaced and the value will be the namespaced path
8+
*/
9+
namespaced ?:boolean | string;
10+
target ?:"nuxt";
11+
enableLocalWatchers ?:boolean | string;
12+
enableLocalSubscriptions ?:boolean | string;
13+
enableLocalActionSubscriptions ?:boolean | string;
414
}
515

6-
export class VuexModule {
7-
}
8-
9-
type VuexStashTypes = "state" | "explicit-mutation" | "getter" | "action" | "submodule";
10-
11-
export interface VuexStash<T extends VuexStashTypes> {
12-
[ field :string ]: {
13-
type :T,
14-
value:
15-
T extends "state" ? boolean | number | string | object | any :
16-
T extends "explicit-mutation" ? ( state :any, payload :any ) => void :
17-
T extends "getter" ? { getter :( state :any, context :any ) => any, mutation? :( state :any, payload :any ) => void } :
18-
T extends "action" ? ( context :any, payload :any ) => Promise<any> :
19-
T extends "submodule" ? Map :
20-
never
21-
}
22-
}
16+
export class VuexModule {}
2317

2418
export type VuexModuleConstructor = typeof VuexModule & VuexModuleInternals;
2519

2620
export interface VuexModuleInternals {
27-
prototype :{
28-
__options__ :VuexModuleOptions | undefined;
29-
__vuex_module_cache__ :undefined | VuexObject;
30-
__vuex_module_tree_stash__: VuexStash<VuexStashTypes>;
31-
__vuex_proxy_cache__ :{} | undefined;
32-
__vuex_local_proxy_cache__ :{} | undefined;
33-
__submodules_cache__: Map;
34-
__mutations_cache__: {
35-
__explicit_mutations__: {},
36-
__setter_mutations__: {},
37-
};
38-
__context_store__: Map | undefined;
39-
}
21+
prototype :VuexModuleInternalsPrototype
22+
}
23+
24+
export interface VuexModuleInternalsPrototype {
25+
__options__ :VuexModuleOptions | undefined;
26+
__namespacedPath__ :string;
27+
__vuex_module_cache__ :undefined | VuexObject;
28+
__vuex_proxy_cache__ :{} | undefined;
29+
__vuex_local_proxy_cache__ :{} | undefined;
30+
__submodules_cache__: Map;
31+
__context_store__: Map | undefined;
32+
__mutations_cache__: {
33+
__explicit_mutations__: {},
34+
__setter_mutations__: {},
35+
};
36+
__explicit_getter_names__ :string[];
37+
__explicit_mutations_names__: string[],
38+
__actions__: {
39+
__name__ :string,
40+
__type__ :ActionType,
41+
}[],
42+
__watch__ :Map;
4043
}
4144

4245
export interface SubModuleType<T> {
@@ -60,4 +63,37 @@ export type Map = Record<DictionaryField, any>
6063
export interface FieldPayload {
6164
field :string;
6265
payload :any;
66+
}
67+
68+
export type MutationDescriptor = TypedPropertyDescriptor<(payload?:any) => void>
69+
70+
export type ActionType = "raw" | "mutate";
71+
72+
export type ActionOption = {
73+
mode? :ActionType
74+
}
75+
76+
export type ActionDescriptor = TypedPropertyDescriptor<(payload?:any) => Promise<any>>
77+
78+
export interface ProxyWatchers {
79+
80+
$watch (
81+
getterField :string,
82+
callback :(( newVal :string, oldVal :string) => void) | object,
83+
options? :{ deep :boolean, immediate :boolean }
84+
) :() => void
85+
86+
$subscribe (
87+
mutationfield :string,
88+
callback :( payload :any ) => void,
89+
) :void
90+
91+
$subscribeAction (
92+
actionField :string,
93+
callbackOrObj :( payload :any ) => void | ({
94+
before: ( payload :any ) => void,
95+
after: ( payload :any ) => void,
96+
})
97+
) :void
98+
6399
}

src/module.legacy.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { VuexModuleConstructor, VuexModule, Map } from "./interfaces";
2+
import { createModule, extractVuexModule } from "./module";
3+
import { createProxy } from './proxy';
4+
import { createSubModule } from './submodule';
5+
6+
export function Module({ namespacedPath = "", target = "core" as VuexModuleTarget } = defaultModuleOptions ) {
7+
8+
return function( module :VuexModule ) :void {
9+
10+
const VuexClass = module as VuexModuleConstructor;
11+
12+
const mod = createModule({
13+
target: VuexClass.prototype.__options__ && VuexClass.prototype.__options__.target,
14+
namespaced: VuexClass.prototype.__options__ && VuexClass.prototype.__options__.namespaced || false,
15+
});
16+
17+
// Add all fields in mod prototype without replacing
18+
for( let field in mod.prototype ) {
19+
//@ts-ignore
20+
if( VuexClass.prototype[ field ] ) continue;
21+
//@ts-ignore
22+
VuexClass.prototype[ field ] = mod.prototype[ field ]
23+
}
24+
25+
26+
}
27+
28+
}
29+
30+
export class LegacyVuexModule {
31+
32+
static ExtractVuexModule( cls :typeof VuexModule ) {
33+
const vxmodule = extractVuexModule( cls );
34+
//@ts-ignore
35+
return vxmodule[ cls.prototype.__namespacedPath__ ]
36+
}
37+
38+
static CreateProxy( cls :typeof VuexModule, $store :Map ) {
39+
return createProxy( cls, $store )
40+
}
41+
42+
static CreateSubModule( cls :typeof VuexModule ) {
43+
return createSubModule( cls );
44+
}
45+
}
46+
47+
export type VuexModuleTarget = "core" | "nuxt";
48+
49+
interface ModuleOptions {
50+
namespacedPath?: string,
51+
target?: VuexModuleTarget
52+
}
53+
54+
const defaultModuleOptions :ModuleOptions = {
55+
namespacedPath: "",
56+
target: "core",
57+
}

0 commit comments

Comments
 (0)