Skip to content

Commit 85d57d4

Browse files
committed
Added store and middleware meta
1 parent 938d7c5 commit 85d57d4

File tree

7 files changed

+147
-50
lines changed

7 files changed

+147
-50
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ node_modules
22
dist
33
coverage
44
*.lock
5-
*.log
5+
*.log
6+
.vscode

src/createStoreContext.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react'
22

3-
import { Contexts, Store, Middleware, InitActions, MiddlewareCreator } from './types'
3+
import { Contexts, Store, Middleware, InitActions, MiddlewareCreator, Meta } from './types'
44
import { mapActionsToDefault, mapActionsToDispatch } from './mapActions'
55
import { resolveStores, resolveMiddleware } from './resolvers'
66

@@ -59,16 +59,20 @@ export default function createStoreContext<
5959
TState,
6060
TMiddlewareContexts extends Contexts = Contexts,
6161
TContexts extends Contexts = Contexts,
62-
TInitActions extends InitActions<TState, TContexts> = InitActions<TState, TContexts>,
62+
TMeta extends Meta = Meta,
63+
TInitActions extends InitActions<TState, TContexts, TMeta> = InitActions<TState, TContexts, TMeta>,
6364
>(
6465
initialState: TState,
6566
actions: TInitActions = {} as TInitActions,
6667
options: {
6768
contexts?: TContexts,
68-
middleware?: (Middleware | MiddlewareCreator<TMiddlewareContexts>)[]
69+
middleware?: (Middleware | MiddlewareCreator<TMiddlewareContexts>)[],
70+
meta?: TMeta
6971
} = {}
70-
): [React.Context<Store<TState, TContexts, TInitActions>>, React.FC] {
71-
const store = { ...initialState, ...mapActionsToDefault(initialState, actions) } as Store<TState, TContexts, TInitActions>
72+
): [React.Context<Store<TState, TContexts, TMeta, TInitActions>>, React.FC] {
73+
const _meta = options.meta || {} as TMeta
74+
75+
const store = { ...initialState, ...mapActionsToDefault(initialState, _meta, actions) } as Store<TState, TContexts, TMeta, TInitActions>
7276
const context = React.createContext(store)
7377

7478
const provider: React.FC = props => {
@@ -82,10 +86,11 @@ export default function createStoreContext<
8286
const _actions = mapActionsToDispatch({
8387
state: _state,
8488
setState,
85-
stores: _stores
89+
stores: _stores,
90+
meta: _meta
8691
}, actions, _middleware)
8792

88-
const _store = { ..._state, ..._actions } as Store<TState, TContexts, TInitActions>
93+
const _store = { ..._state, ..._actions } as Store<TState, TContexts, TMeta, TInitActions>
8994
return (<context.Provider value={_store}>
9095
{props.children}
9196
</context.Provider>)

src/mapActions.tsx

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Contexts, InferStores, ContextReference, MappedActions, Middleware, InitActions } from './types'
1+
import { Contexts, InferStores, ContextReference, MappedActions, Middleware, InitActions, Meta } from './types'
22
import { runWithMiddleware } from './middleware'
33

44
/**
@@ -7,45 +7,49 @@ import { runWithMiddleware } from './middleware'
77
export function mapActionsToDispatch<
88
TState,
99
TContexts extends Contexts,
10-
TInitActions extends InitActions<TState, TContexts>
10+
TMeta extends Meta,
11+
TInitActions extends InitActions<TState, TContexts, TMeta>
1112
>(
12-
contextReference: ContextReference<TState, TContexts>,
13+
contextReference: ContextReference<TState, TContexts, TMeta>,
1314
actions?: TInitActions,
14-
middleware: Middleware[] = []
15-
): MappedActions<TState, TContexts, TInitActions> {
15+
middleware: Middleware[] = [],
16+
): MappedActions<TState, TContexts, TMeta, TInitActions> {
1617
if (actions === undefined || typeof actions !== 'function')
17-
return {} as MappedActions<TState, TContexts, TInitActions>
18+
return {} as MappedActions<TState, TContexts, TMeta, TInitActions>
1819
const initActions = actions(contextReference)
1920
return Object.keys(initActions).reduce((obj, key) => {
2021
return {
2122
...obj,
22-
[key]: (...args: []) => runWithMiddleware(middleware, initActions, key, args)
23+
[key]: (...args: []) => runWithMiddleware(middleware, initActions, args, { actionName: key, ...contextReference.meta })
2324
}
24-
}, {} as MappedActions<TState, TContexts, TInitActions>)
25+
}, {} as MappedActions<TState, TContexts, TMeta, TInitActions>)
2526
}
2627
/**
2728
* @hidden Internal function to map action creators to store actions when there are no Providers available
2829
*/
2930
export function mapActionsToDefault<
3031
TState,
31-
TInitActions extends InitActions<TState, TContexts>,
32-
TContexts extends Contexts
32+
TContexts extends Contexts,
33+
TMeta extends Meta,
34+
TInitActions extends InitActions<TState, TContexts, TMeta>
3335
>(
3436
initialState: TState,
35-
actions?: TInitActions
36-
): MappedActions<TState, TContexts, TInitActions> {
37+
meta: TMeta,
38+
actions?: TInitActions,
39+
): MappedActions<TState, TContexts, TMeta, TInitActions> {
3740
if (actions === undefined || typeof actions !== 'function')
38-
return {} as MappedActions<TState, TContexts, TInitActions>
39-
const contextReference: ContextReference<TState, TContexts> = {
41+
return {} as MappedActions<TState, TContexts, TMeta, TInitActions>
42+
const contextReference: ContextReference<TState, TContexts, TMeta> = {
4043
state: initialState,
4144
stores: {} as InferStores<TContexts>,
42-
setState: (value) => { throw new Error(`Can't invoke 'setState' with ${value} because provider does not exist`) }
45+
setState: (value) => { throw new Error(`Can't invoke 'setState' with ${value} because provider does not exist`) },
46+
meta
4347
}
4448
const initActions = actions(contextReference)
4549
return Object.keys(initActions).reduce((obj, key) => {
4650
return {
4751
...obj,
4852
[key]: (...args: never[]) => initActions[key](...args)
4953
}
50-
}, {} as MappedActions<TState, TContexts, TInitActions>)
54+
}, {} as MappedActions<TState, TContexts, TMeta, TInitActions>)
5155
}

src/middleware.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Action, Middleware, Contexts, InitActions, RetType, MiddlewareCreator, InitMiddleware } from './types'
1+
import { Action, Middleware, Contexts, InitActions, RetType, MiddlewareCreator, InitMiddleware, MiddlewareMeta, Meta } from './types'
22

33
/**
44
* Helper method to create custom middleware. It makes possible to create middleware using user stores, so that it could call other actions.
@@ -24,23 +24,23 @@ export function runWithMiddleware<
2424
TMiddleware extends Middleware<TArgs, TReturn>
2525
>(
2626
middleware: TMiddleware[],
27-
actions: RetType<InitActions<TState, TContexts>>,
28-
actionKey: string,
29-
args: TArgs
27+
actions: RetType<InitActions<TState, TContexts, Meta>>,
28+
args: TArgs,
29+
meta: MiddlewareMeta
3030
): TReturn | Promise<TReturn> {
3131
const [first, ...rest] = middleware
3232

33-
const action = actions[actionKey]
33+
const action = actions[meta.actionName]
3434

3535
if (first === undefined)
3636
return actionCaller(action, actions)(args)
3737

38-
return first((nextArgs) => runWithMiddleware(rest, actions, actionKey, nextArgs), actionKey, args)
38+
return first((nextArgs) => runWithMiddleware(rest, actions, nextArgs, meta), args, meta)
3939
}
4040

4141
const actionCaller = <
4242
TState,
4343
TContexts extends Contexts,
4444
TArgs extends [],
4545
TAction extends Action<TArgs> = Action<TArgs>
46-
>(action: TAction, actions: RetType<InitActions<TState, TContexts>>) => (args: TArgs) => action.call(actions, ...args)
46+
>(action: TAction, actions: RetType<InitActions<TState, TContexts, Meta>>) => (args: TArgs) => action.call(actions, ...args)

src/resolvers.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react'
22

3-
import { Contexts, InferStores, Middleware, MiddlewareCreator } from './types'
3+
import { Contexts, InferStores, Middleware, MiddlewareCreator, MiddlewareMeta, MiddlewareContextReference } from './types'
44

55
/**
66
* @hidden Internal method which resolves all given contexts to corresponding stores
@@ -16,12 +16,14 @@ export const resolveStores = <TContexts extends Contexts>(contexts: TContexts =
1616
/**
1717
* @hidden Internal method which resolves all given middlewares, provides injected stores
1818
*/
19-
export const resolveMiddleware = <TMiddlewareContexts extends Contexts>(middlewareList?: (Middleware | MiddlewareCreator<TMiddlewareContexts>)[]) =>
19+
export const resolveMiddleware = <TMiddlewareContexts extends Contexts>(
20+
middlewareList?: (Middleware | MiddlewareCreator<TMiddlewareContexts>)[]
21+
) =>
2022
middlewareList !== undefined
2123
? middlewareList.map(middleware => {
2224
if (isMiddlewareCreator(middleware)) {
2325
const _stores = resolveStores(middleware.contexts)
24-
const _middleware: Middleware = (next, actionKey, args) => middleware.initMiddleware({ stores: _stores }, next, actionKey, args)
26+
const _middleware: Middleware = (next, args, meta) => middleware.initMiddleware(next, args, { ...meta, stores: _stores })
2527
return _middleware
2628
} else {
2729
return middleware

src/types.tsx

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ export type DropFirst<T extends any[]> = ((...args: T) => any) extends (arg: any
3131
/**
3232
* Special context reference object which will be provided to the actions
3333
*/
34-
export type ContextReference<TState, TContexts extends Contexts> = {
34+
export type ContextReference<TState, TContexts extends Contexts, TMeta extends Meta> = {
3535
state: TState
3636
setState: React.Dispatch<React.SetStateAction<TState>>
3737
stores: InferStores<TContexts>
38+
meta: TMeta
3839
}
3940

4041
/**
@@ -49,22 +50,29 @@ export type Action<TArgs extends any[] = any[], TReturn = any> =
4950
*
5051
* Every entry will be mapped to a store action [[MappedActions]]
5152
*/
52-
export type InitActions<TState, TContexts extends Contexts> = (contextReference: ContextReference<TState, TContexts>) => {
53+
export type InitActions<TState, TContexts extends Contexts, TMeta extends Meta> = (contextReference: ContextReference<TState, TContexts, TMeta>) => {
5354
[key: string]: Action
5455
}
5556

5657
/**
5758
* Dictionary of store actions in the form { key: action }
5859
*/
59-
export type MappedActions<TState, TContexts extends Contexts, TInitActions extends InitActions<TState, TContexts>> = {
60+
export type MappedActions<TState, TContexts extends Contexts, TMeta extends Meta, TInitActions extends InitActions<TState, TContexts, TMeta>> = {
6061
[P in keyof RetType<TInitActions>]: (...args: Params<RetType<TInitActions>[P]>) => RetType<RetType<TInitActions>[P]>
6162
}
6263

64+
/**
65+
* Object which contains user-defined meta information for the store
66+
*/
67+
export type Meta = {
68+
readonly [key: string]: any
69+
}
70+
6371
/**
6472
* Store as an intersection of TState and [[MappedActions]]
6573
*/
66-
export type Store<TState, TContexts extends Contexts, TInitActions extends InitActions<TState, TContexts>> =
67-
TInitActions extends undefined ? TState : TState & MappedActions<TState, TContexts, TInitActions>
74+
export type Store<TState, TContexts extends Contexts, TMeta extends Meta, TInitActions extends InitActions<TState, TContexts, TMeta>> =
75+
TInitActions extends undefined ? TState : TState & MappedActions<TState, TContexts, TMeta, TInitActions>
6876

6977
/**
7078
* React.Context wrapper to predefault context type to any.
@@ -110,16 +118,26 @@ export type InferStores<TContexts extends Contexts> = {
110118
export type MiddlewareAction<TArgs extends [] = [], TReturn = any> =
111119
(args: TArgs) => TReturn | void
112120

121+
/**
122+
* Meta information about current store and action which is being executed
123+
*/
124+
export type MiddlewareMeta = {
125+
/**
126+
* Name of the action which is currently being executed
127+
*/
128+
readonly actionName: string
129+
} & Meta
130+
113131
/**
114132
* Middleware function, which will be executed after store action is called and before it executes
115133
* @typeparam TArgs Type of the arguments of the action
116134
* @typeparam TMiddlewareAction Next action in the chain. Could be either [[Action]] or [[MiddlewareAction]]
117135
* @param next Callable next action. Middleware must call it with `args` argument to continue the chain of calls. If `next` is not called, store action won't be executed
118-
* @param actionKey String name of the called action
119136
* @param args Array of action arguments, which action was originally called with
137+
* @param meta [[MiddlewareMeta]] Object which contains useful meta information about current store and action which is being executed
120138
*/
121139
export type Middleware<TArgs extends [] = [], TReturn extends any = any, TMiddlewareAction extends MiddlewareAction<TArgs> = MiddlewareAction<TArgs>> =
122-
(next: TMiddlewareAction, actionKey: string, args: TArgs) => Promise<TReturn> | TReturn
140+
(next: TMiddlewareAction, args: TArgs, meta: MiddlewareMeta) => Promise<TReturn> | TReturn
123141

124142
/**
125143
* Special middleware context reference object which will be provided to the middleware
@@ -130,17 +148,16 @@ export type MiddlewareContextReference<TContexts extends Contexts> = {
130148

131149
/**
132150
* Resolves correct middlewareContextReference with all the types correctly mapped
133-
* [[MiddlewareContextReference]] is passed to a middleware function [[Middleware]] in the form (reference) => middleware
151+
* [[MiddlewareMeta]] and [[MiddlewareContextReference]] is passed to a middleware function [[Middleware]] in the form (meta && reference) => middleware
134152
*/
135153
export type InitMiddleware<
136154
TContexts extends Contexts = Contexts,
137155
TArgs extends [] = [],
138156
TMiddlewareAction extends MiddlewareAction<TArgs> = MiddlewareAction<TArgs>
139157
> = (
140-
reference: MiddlewareContextReference<TContexts>,
141158
next: TMiddlewareAction,
142-
actionKey: string,
143-
args: TArgs
159+
args: TArgs,
160+
meta: MiddlewareContextReference<TContexts> & MiddlewareMeta,
144161
) => Promise<void> | void
145162

146163
/**

0 commit comments

Comments
 (0)