redux-sacala 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/test.yml +30 -0
- package/README.md +101 -101
- package/build/redux-sacala.cjs +1 -1
- package/build/redux-sacala.cjs.map +1 -1
- package/build/redux-sacala.d.ts +94 -36
- package/build/redux-sacala.js +123 -43
- package/build/redux-sacala.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- name: Use Node.js
|
|
15
|
+
uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: '20'
|
|
18
|
+
cache: 'npm'
|
|
19
|
+
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: npm ci
|
|
22
|
+
|
|
23
|
+
- name: Lint
|
|
24
|
+
run: npm run lint
|
|
25
|
+
|
|
26
|
+
- name: Build
|
|
27
|
+
run: npm run build
|
|
28
|
+
|
|
29
|
+
- name: Test
|
|
30
|
+
run: npm test
|
package/README.md
CHANGED
|
@@ -1,134 +1,134 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Redux Sacala
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A library for creating composable Redux blocks with state, actions, and effects.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Terms Definition
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **Ducks Pattern**: Encourages grouping related logic together.
|
|
11
|
-
- **Extra Arguments**: Inject dependencies into your effects via middleware.
|
|
7
|
+
- **ReduxBlock**: A composable unit of Redux logic that encapsulates state, action creators, and effect handlers. It provides a structured way to define how state changes and how side effects are handled.
|
|
8
|
+
- **Action**: A pure function that describes how the state changes in response to an event. In `redux-sacala`, actions are defined using `.action()` and they also serve as action creators.
|
|
9
|
+
- **Effect**: A non-pure handler that can perform side effects such as asynchronous API calls, logging, or dispatching other actions. Effects are defined using `.effects()` and have access to a context object providing necessary dependencies.
|
|
12
10
|
|
|
13
|
-
##
|
|
11
|
+
## Examples
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```
|
|
13
|
+
### Simple Block with Actions
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { ReduxBlock } from "redux-sacala";
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
const counterBlock = ReduxBlock.builder("counter", 0)
|
|
19
|
+
.action("inc", (state: number) => state + 1)
|
|
20
|
+
.action("add", (state: number, value: number) => state + value)
|
|
21
|
+
.build();
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
// Usage:
|
|
24
|
+
// counterBlock.actions.inc() -> { type: "counter/inc" }
|
|
25
|
+
// counterBlock.actions.add(5) -> { type: "counter/add", payload: [5] }
|
|
26
|
+
```
|
|
22
27
|
|
|
23
|
-
###
|
|
28
|
+
### Block with Effects
|
|
24
29
|
|
|
25
30
|
```typescript
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
interface CounterState {
|
|
29
|
-
count: number;
|
|
30
|
-
}
|
|
31
|
+
interface User { id: string; name: string; }
|
|
31
32
|
|
|
32
|
-
interface
|
|
33
|
-
|
|
33
|
+
interface UserContext {
|
|
34
|
+
fetchUser: (id: string) => Promise<User>;
|
|
35
|
+
dispatch: (action: any) => void;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
setCount(state, payload: number) {
|
|
49
|
-
return { count: payload };
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
effects: (dispatch, getState) => ({
|
|
53
|
-
asyncIncrement(payload: number, { logger }) {
|
|
54
|
-
logger('Starting async increment');
|
|
55
|
-
setTimeout(() => {
|
|
56
|
-
dispatch(actions.increment());
|
|
57
|
-
logger('Incremented');
|
|
58
|
-
}, payload);
|
|
59
|
-
}
|
|
60
|
-
})
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
export { actions, reducer, createMiddleware };
|
|
38
|
+
const userBlock = ReduxBlock.builder("user", { data: null as User | null, loading: false })
|
|
39
|
+
.action("setLoading", (state, loading: boolean) => ({ ...state, loading }))
|
|
40
|
+
.action("setData", (state, data: User) => ({ ...state, data, loading: false }))
|
|
41
|
+
.effects((ctx: UserContext) => ({
|
|
42
|
+
loadUser: async (id: string) => {
|
|
43
|
+
ctx.dispatch(userBlock.actions.setLoading(true));
|
|
44
|
+
const data = await ctx.fetchUser(id);
|
|
45
|
+
ctx.dispatch(userBlock.actions.setData(data));
|
|
46
|
+
}
|
|
47
|
+
}))
|
|
48
|
+
.build();
|
|
64
49
|
```
|
|
65
50
|
|
|
66
|
-
###
|
|
51
|
+
### Blocks Composition
|
|
67
52
|
|
|
68
53
|
```typescript
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
counter: reducer
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Create middleware with extra argument
|
|
77
|
-
const counterMiddleware = createMiddleware({
|
|
78
|
-
logger: (msg) => console.log(msg)
|
|
79
|
-
});
|
|
54
|
+
const rootBlock = ReduxBlock.composition("root")
|
|
55
|
+
.block("counter", counterBlock)
|
|
56
|
+
.block("user", userBlock)
|
|
57
|
+
.build();
|
|
80
58
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
applyMiddleware(counterMiddleware)
|
|
84
|
-
);
|
|
59
|
+
// rootBlock.actions.counter.inc()
|
|
60
|
+
// rootBlock.actions.user.loadUser("123")
|
|
85
61
|
```
|
|
86
62
|
|
|
87
|
-
###
|
|
63
|
+
### Blocks Composition with an Extra Effect
|
|
88
64
|
|
|
89
65
|
```typescript
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
66
|
+
const rootBlock = ReduxBlock.composition("root")
|
|
67
|
+
.block("counter", counterBlock)
|
|
68
|
+
.effects((ctx: { logger: (msg: string) => void, dispatch: (a: any) => void }) => ({
|
|
69
|
+
logAndIncrement: () => {
|
|
70
|
+
ctx.logger("Incrementing counter");
|
|
71
|
+
ctx.dispatch(rootBlock.actions.counter.inc());
|
|
72
|
+
}
|
|
73
|
+
}))
|
|
74
|
+
.build();
|
|
75
|
+
|
|
76
|
+
// Usage:
|
|
77
|
+
// rootBlock.actions.counter.inc()
|
|
78
|
+
// rootBlock.actions.counter.add(5)
|
|
79
|
+
// rootBlock.actions.logAndIncrement()
|
|
94
80
|
```
|
|
95
81
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
### `createReduxBlock<GlobalState, ExtraArgument = undefined>()(options)`
|
|
99
|
-
|
|
100
|
-
Creates a Redux block. The double-call pattern is used for better TypeScript type inference.
|
|
82
|
+
### Context Mapping
|
|
101
83
|
|
|
102
|
-
|
|
103
|
-
- `name`: `string`. The key under which the state is stored in the global state. Must match a key in `GlobalState`.
|
|
104
|
-
- `initial`: `GlobalState[name]`. The initial state of the block.
|
|
105
|
-
- `actions`: An object where each key is an action name and each value is a state handler: `(state: BlockState, payload: any) => BlockState`.
|
|
106
|
-
- `effects`: (Optional) A function `(dispatch, getState) => effectsMap`.
|
|
107
|
-
- `effectsMap` keys are action types.
|
|
108
|
-
- `effectsMap` values are effect handlers: `(payload: any, extraArgument: ExtraArgument) => void`.
|
|
84
|
+
You can change the context shape of a block using `ReduxBlock.mapContext`. This is useful when you want to adapt a block to a different environment or use a more convenient context structure.
|
|
109
85
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
86
|
+
```typescript
|
|
87
|
+
interface OldContext {
|
|
88
|
+
log: {
|
|
89
|
+
error: (msg: string) => void;
|
|
90
|
+
info: (msg: string) => void;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
117
93
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
94
|
+
const block = ReduxBlock.builder("test", { message: "" })
|
|
95
|
+
.effects((ctx: OldContext) => ({
|
|
96
|
+
logError: (msg: string) => ctx.log.error(msg),
|
|
97
|
+
}))
|
|
98
|
+
.build();
|
|
121
99
|
|
|
122
|
-
|
|
123
|
-
|
|
100
|
+
interface NewContext {
|
|
101
|
+
log: (level: "error" | "info", msg: string) => void;
|
|
102
|
+
}
|
|
124
103
|
|
|
125
|
-
|
|
126
|
-
|
|
104
|
+
const mappedBlock = ReduxBlock.mapContext(
|
|
105
|
+
block,
|
|
106
|
+
(ctx: NewContext): OldContext => ({
|
|
107
|
+
log: {
|
|
108
|
+
error: (msg) => ctx.log("error", msg),
|
|
109
|
+
info: (msg) => ctx.log("info", msg),
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
127
113
|
|
|
128
|
-
|
|
129
|
-
npm run lint
|
|
114
|
+
// Now mappedBlock expects NewContext
|
|
130
115
|
```
|
|
131
116
|
|
|
132
|
-
|
|
117
|
+
### Minimal Redux Toolkit Example
|
|
133
118
|
|
|
134
|
-
|
|
119
|
+
```typescript
|
|
120
|
+
import { configureStore } from '@reduxjs/toolkit';
|
|
121
|
+
import { ReduxBlock } from "redux-sacala";
|
|
122
|
+
|
|
123
|
+
const store = configureStore({
|
|
124
|
+
reducer: rootBlock.reducer,
|
|
125
|
+
middleware: (getDefaultMiddleware) =>
|
|
126
|
+
getDefaultMiddleware().concat(
|
|
127
|
+
ReduxBlock.middleware(rootBlock, {
|
|
128
|
+
dispatch: (action) => store.dispatch(action),
|
|
129
|
+
logger: console.log,
|
|
130
|
+
fetchUser: async (id) => ({ id, name: "John Doe" })
|
|
131
|
+
})
|
|
132
|
+
),
|
|
133
|
+
});
|
|
134
|
+
```
|
package/build/redux-sacala.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function d(o,e){return typeof o=="object"&&o!==null&&Object.hasOwn(o,e)}const f=o=>new Proxy({},{get(e,t){return d(e,t)?e[t]:(...r)=>{const s=`${o}/${t}`;return r.length?{type:s,payload:r}:{type:s}}}});class l{constructor(e,t,r,s){this.name=e,this.initial=t,this.reducers=r,this.handlers=s}static init(e,t){return new l(e,t,{},[])}action(e,t){return this.reducers[`${this.name}/${e}`]=t,this}effects(e){return this.handlers.push(e),this}build(){const e=this.initial,t=this.name;return{actions:f(this.name),effects:r=>this.handlers.reduce((s,i)=>Object.assign(s,Object.fromEntries(Object.entries(i(r)).map(([n,u])=>[`${t}/${n}`,u]))),{}),reducer:(r=e,s)=>{const i=this.reducers[s.type];if(!i)return r;const n="payload"in s?s.payload:void 0;return n&&n.length?i(r,...n):i(r)}}}}class a{constructor(e){this.name=e,this.creators=f(e)}blocks={};handlers=[];creators;static init(e){return new a(e)}block(e,t){return this.blocks[e]=t,this.creators[e]=t.actions,this}effects(e){return this.handlers.push(e),this}build(){const e=Object.entries(this.blocks).map(([t,r])=>[t,r.reducer]);return{actions:this.creators,effects:t=>{const r=this.name,s=this.handlers.reduce((i,n)=>Object.assign(i,Object.fromEntries(Object.entries(n(t)).map(([u,c])=>[`${r}/${u}`,c]))),{});return Object.values(this.blocks).forEach(i=>Object.assign(s,i.effects(t))),s},reducer:(t,r)=>{let s=t,i=!1;return e.forEach(([n,u])=>{const c=t?.[n],h=u(c,r);h!==c&&(i||(i=!0,s={...t}),s[n]=h)}),s}}}}exports.ReduxBlock=void 0;(o=>{function e(s,i){return l.init(s,i)}o.builder=e;function t(s){return a.init(s)}o.composition=t;function r(s,i){const n=s.effects(i);return()=>u=>c=>{c&&typeof c=="object"&&"type"in c&&d(n,c.type)&&n[c.type](..."payload"in c?c.payload:[]),u(c)}}o.middleware=r})(exports.ReduxBlock||(exports.ReduxBlock={}));
|
|
2
2
|
//# sourceMappingURL=redux-sacala.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redux-sacala.cjs","sources":["../src/redux-sacala.ts"],"sourcesContent":["import { Dispatch, Action, Reducer, Middleware, AnyAction, MiddlewareAPI } from \"redux\";\n\ntype UnknownToUndefined<T> = unknown extends T ? undefined : T;\n\ntype FirstArgument<F> = F extends (arg1: infer U, ...args: any[]) => any ? UnknownToUndefined<U> : undefined;\ntype SecondArgument<F> = F extends (arg1: any, arg2: infer U, ...args: any[]) => any\n ? UnknownToUndefined<U>\n : undefined;\n\nconst bindAll = <T extends { [key: string]: Function }>(map: T): T => {\n const result = {} as any as T;\n for (const i in map) {\n result[i] = map[i].bind(map);\n }\n return result;\n};\n\nconst appendPrefix = <T>(prefix: string, map: { [key: string]: T }) => {\n const r: { [key: string]: any } = {};\n for (const i in map) {\n r[prefix + i] = map[i];\n }\n return r;\n};\n\n// Input\ntype ActionHandler<BlockState, Payload> = (state: BlockState, payload: Payload) => BlockState;\ntype ActionMap<BlockState> = { [action: string]: ActionHandler<BlockState, any> };\ntype EffectsMap<GlobalState, ExtraArgument> = (\n dispatch: Dispatch,\n getState: () => GlobalState,\n) => { [effect: string]: (payload: any, extraArgument: ExtraArgument) => any };\n\n// Output\ntype ActionCreator<Handler extends ActionHandler<any, any>> =\n undefined extends SecondArgument<Handler>\n ? () => Action<string>\n : (payload: SecondArgument<Handler>) => Action<string> & { payload: SecondArgument<Handler> };\n\ntype ActionCreatorMap<Actions extends ActionMap<any>> = {\n [name in keyof Actions]: ActionCreator<Actions[name]>;\n};\n\ntype EffectsCreatorMap<GlobalState, ExtraArgument, Map extends EffectsMap<GlobalState, ExtraArgument>> = {\n [key in keyof ReturnType<Map>]: undefined extends FirstArgument<ReturnType<Map>[key]>\n ? () => Action\n : (payload: FirstArgument<ReturnType<Map>[key]>) => Action;\n};\n\n// Transformation\nconst createActionCreator = (type: string) => (payload?: any) => (payload === undefined ? { type } : { type, payload });\nconst createEffectCreator = (type: string) => (payload: any) => ({ type, payload });\n\nconst createReducer = <BlockState>(prefix: string, initial: BlockState, actionMap: ActionMap<BlockState>): Reducer => {\n const actions: ActionMap<BlockState> = appendPrefix(prefix + \"/\", bindAll(actionMap));\n return (state: BlockState = initial, action?: AnyAction) => {\n if (action && action.type) {\n const handler: (state: BlockState, payload?: any) => BlockState = actions[action.type];\n if (handler) {\n return handler(state, action.payload);\n } else {\n return state;\n }\n } else {\n return state;\n }\n };\n};\n\ntype MiddlewareCreator<T> = T extends undefined ? () => Middleware : (argument: T) => Middleware;\n\nconst createMiddlewareCreator = <GlobalState, ExtraArgument>(\n prefix: string,\n effectsMap: EffectsMap<GlobalState, ExtraArgument>,\n): MiddlewareCreator<ExtraArgument> =>\n ((argument: ExtraArgument) => (store: MiddlewareAPI) => {\n const effects = appendPrefix(prefix + \"/\", bindAll(effectsMap(store.dispatch, store.getState)));\n return (next: Dispatch) => (action: Action<string> & { payload: any[] }) => {\n if (action && Object.prototype.hasOwnProperty.call(effects, action.type)) {\n effects[action.type](action.payload, argument);\n } else {\n next(action);\n }\n };\n }) as MiddlewareCreator<ExtraArgument>;\n\nconst fail = (): never => {\n throw new Error(\"Can't have access to 'dispatch' and 'getState' during initialization\");\n};\n\nexport const createReduxBlock =\n <GlobalState, ExtraArgument = undefined>() =>\n <\n Name extends keyof GlobalState & string,\n Actions extends ActionMap<GlobalState[Name]>,\n Effects extends EffectsMap<GlobalState, ExtraArgument>,\n >({\n name,\n initial,\n actions,\n effects,\n }: {\n name: Name;\n initial: GlobalState[Name];\n actions: Actions;\n effects?: Effects;\n }): {\n name: Name;\n reducer: Reducer<GlobalState[Name]>;\n actions: ActionCreatorMap<Actions> & EffectsCreatorMap<GlobalState, ExtraArgument, Effects>;\n } & ({} extends ReturnType<Effects> ? {} : { createMiddleware: MiddlewareCreator<ExtraArgument> }) => {\n const actionCreators = Object.keys(actions).reduce((r, key) => {\n r[key] = createActionCreator(`${name}/${key}`);\n return r;\n }, {} as any);\n const effectCreators = Object.keys(effects ? effects(fail, fail) : {}).reduce((r, key) => {\n r[key] = createEffectCreator(`${name}/${key}`);\n return r;\n }, {} as any);\n\n return {\n name,\n reducer: createReducer(name as string, initial, actions),\n createMiddleware: effects\n ? createMiddlewareCreator<GlobalState, ExtraArgument>(name as string, effects)\n : ((() => (_: MiddlewareAPI) => (next: Dispatch) => next) as MiddlewareCreator<ExtraArgument>),\n actions: {\n ...actionCreators,\n ...effectCreators,\n },\n };\n };\n"],"names":["bindAll","map","result","i","appendPrefix","prefix","r","createActionCreator","type","payload","createEffectCreator","createReducer","initial","actionMap","actions","state","action","handler","createMiddlewareCreator","effectsMap","argument","store","effects","next","fail","createReduxBlock","name","actionCreators","key","effectCreators","_"],"mappings":"gFASA,MAAMA,EAAkDC,GAAc,CAClE,MAAMC,EAAS,CAAA,EACf,UAAWC,KAAKF,EACZC,EAAOC,CAAC,EAAIF,EAAIE,CAAC,EAAE,KAAKF,CAAG,EAE/B,OAAOC,CACX,EAEME,EAAe,CAAIC,EAAgBJ,IAA8B,CACnE,MAAMK,EAA4B,CAAA,EAClC,UAAWH,KAAKF,EACZK,EAAED,EAASF,CAAC,EAAIF,EAAIE,CAAC,EAEzB,OAAOG,CACX,EA2BMC,EAAuBC,GAAkBC,GAAmBA,IAAY,OAAY,CAAE,KAAAD,CAAA,EAAS,CAAE,KAAAA,EAAM,QAAAC,CAAA,EACvGC,EAAuBF,GAAkBC,IAAkB,CAAE,KAAAD,EAAM,QAAAC,IAEnEE,EAAgB,CAAaN,EAAgBO,EAAqBC,IAA8C,CAClH,MAAMC,EAAiCV,EAAaC,EAAS,IAAKL,EAAQa,CAAS,CAAC,EACpF,MAAO,CAACE,EAAoBH,EAASI,IAAuB,CACxD,GAAIA,GAAUA,EAAO,KAAM,CACvB,MAAMC,EAA4DH,EAAQE,EAAO,IAAI,EACrF,OAAIC,EACOA,EAAQF,EAAOC,EAAO,OAAO,EAE7BD,CAEf,KACI,QAAOA,CAEf,CACJ,EAIMG,EAA0B,CAC5Bb,EACAc,KAEEC,GAA6BC,GAAyB,CACpD,MAAMC,EAAUlB,EAAaC,EAAS,IAAKL,EAAQmB,EAAWE,EAAM,SAAUA,EAAM,QAAQ,CAAC,CAAC,EAC9F,OAAQE,GAAoBP,GAAgD,CACpEA,GAAU,OAAO,UAAU,eAAe,KAAKM,EAASN,EAAO,IAAI,EACnEM,EAAQN,EAAO,IAAI,EAAEA,EAAO,QAASI,CAAQ,EAE7CG,EAAKP,CAAM,CAEnB,CACJ,GAEEQ,EAAO,IAAa,CACtB,MAAM,IAAI,MAAM,sEAAsE,CAC1F,EAEaC,EACT,IACA,CAIE,CACE,KAAAC,EACA,QAAAd,EACA,QAAAE,EACA,QAAAQ,CACJ,IASsG,CAClG,MAAMK,EAAiB,OAAO,KAAKb,CAAO,EAAE,OAAO,CAACR,EAAGsB,KACnDtB,EAAEsB,CAAG,EAAIrB,EAAoB,GAAGmB,CAAI,IAAIE,CAAG,EAAE,EACtCtB,GACR,CAAA,CAAS,EACNuB,EAAiB,OAAO,KAAKP,EAAUA,EAAQE,EAAMA,CAAI,EAAI,CAAA,CAAE,EAAE,OAAO,CAAClB,EAAGsB,KAC9EtB,EAAEsB,CAAG,EAAIlB,EAAoB,GAAGgB,CAAI,IAAIE,CAAG,EAAE,EACtCtB,GACR,CAAA,CAAS,EAEZ,MAAO,CACH,KAAAoB,EACA,QAASf,EAAce,EAAgBd,EAASE,CAAO,EACvD,iBAAkBQ,EACZJ,EAAoDQ,EAAgBJ,CAAO,GACzE,IAAOQ,GAAsBP,GAAmBA,GACxD,QAAS,CACL,GAAGI,EACH,GAAGE,CAAA,CACP,CAER"}
|
|
1
|
+
{"version":3,"file":"redux-sacala.cjs","sources":["../src/redux-sacala.ts"],"sourcesContent":["import { Middleware, Reducer, UnknownAction } from \"redux\";\n\n/**\n * Composable Redux block with state description, action creators, and effects handlers.\n * Use `ReduxBlock.builder` to start building a new block.\n */\nexport interface ReduxBlock<State, Creators, Context> {\n /**\n * Action creators for this block.\n * When composed, action creators can form a folder tree structure.\n */\n actions: Creators;\n /**\n * Reducer that can be used directly in Redux store configuration.\n */\n reducer: Reducer<State, UnknownAction>;\n /**\n * Effects to be called on effects actions.\n * Use `ReduxBlock.middleware` to create middleware for effects processing.\n */\n effects: Effects<Context>;\n}\n\ntype PayloadAction<Type extends string, Payload extends unknown[]> = Payload extends never[]\n ? { type: Type }\n : { type: Type; payload: Payload };\n\n/**\n * Checks if the given key exists directly on the provided object.\n */\nfunction has<K extends string | symbol>(v: unknown, k: K): v is Record<K, unknown> {\n return typeof v === \"object\" && v !== null && Object.hasOwn(v, k);\n}\n\nconst creator = (scope: string) =>\n new Proxy(\n {},\n {\n get(target, property) {\n if (has(target, property)) {\n return target[property];\n }\n\n return (...payload: unknown[]) => {\n const type = `${scope}/${property as string}`;\n return payload.length ? { type, payload } : { type };\n };\n },\n },\n ) as Record<string, (...payload: unknown[]) => UnknownAction>;\n\n/**\n * Effects creator. It receives context with side effect APIs and returns non-pure handlers.\n */\ntype Effects<Context> = (context: Context) => Record<string, (...payload: any[]) => void>;\n\n/**\n * Convert effects type to action creators.\n */\ntype EffectsToCreators<Name extends string, E extends Effects<any>> = {\n [K in keyof ReturnType<E>]: (\n ...parameters: Parameters<ReturnType<E>[K]>\n ) => PayloadAction<`${Name}/${K extends string ? K : never}`, Parameters<ReturnType<E>[K]>>;\n};\n\nclass BlockBuilder<\n Name extends string,\n State,\n Creators extends Record<string, (...parameters: unknown[]) => PayloadAction<any, any>>,\n Context,\n> {\n private constructor(\n readonly name: Name,\n readonly initial: State,\n /**\n * Per-message action reducers for this block.\n */\n private readonly reducers: Record<string, (state: State, ...payload: unknown[]) => State>,\n /**\n * Effects handlers for this block.\n */\n private readonly handlers: Effects<Context>[],\n ) {}\n\n static init<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}> {\n return new BlockBuilder(name, initial, {}, []);\n }\n\n /**\n * Append an action handler to the block.\n * Action is a pure function that takes the state + arguments and returns a new state.\n */\n action<Action extends string, Payload extends unknown[] = []>(\n action: Action,\n handler: (state: State, ...payload: Payload) => State,\n ): BlockBuilder<\n Name,\n State,\n Creators & Record<Action, (...payload: Payload) => PayloadAction<`${Name}/${Action}`, Payload>>,\n Context\n > {\n this.reducers[`${this.name}/${action}`] = handler as (state: State, ...payload: unknown[]) => State;\n return this as any;\n }\n\n /**\n * Append effect handlers to the block.\n * Effects can call any side effects provided from the context.\n */\n effects<E extends Effects<any>>(\n effects: E,\n ): BlockBuilder<\n Name,\n State,\n Creators & EffectsToCreators<Name, E>,\n Context & (E extends Effects<infer C> ? C : never)\n > {\n this.handlers.push(effects);\n return this as any;\n }\n\n build(): ReduxBlock<State, Creators, Context> {\n const initialState = this.initial;\n const blockName = this.name;\n return {\n actions: creator(this.name),\n effects: (context: Context) =>\n this.handlers.reduce(\n (acc, effect) =>\n Object.assign(\n acc,\n Object.fromEntries(\n Object.entries(effect(context)).map(([effectName, handler]) => [\n `${blockName}/${effectName}`,\n handler,\n ]),\n ),\n ),\n {} as Record<string, (...payload: unknown[]) => void>,\n ),\n reducer: (state = initialState, action: UnknownAction) => {\n const handler = this.reducers[action.type];\n if (!handler) return state;\n const payload = \"payload\" in action ? (action.payload as unknown[]) : undefined;\n return payload && payload.length ? handler(state, ...payload) : handler(state);\n },\n } as any;\n }\n}\n\nclass CompositionBuilder<\n Name extends string,\n BlockMap extends Record<string, ReduxBlock<any, any, any>>,\n Creators,\n Context,\n> {\n private blocks: BlockMap = {} as BlockMap;\n private handlers: Effects<Context>[] = [];\n private creators: Creators;\n\n private constructor(private name: Name) {\n this.creators = creator(name) as Creators;\n }\n\n static init<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}> {\n return new CompositionBuilder(name);\n }\n\n block<Name extends string, Block extends ReduxBlock<any, any, any>>(\n name: Name,\n block: Block,\n ): CompositionBuilder<\n Name,\n BlockMap & Record<Name, Block>,\n Creators & Record<Name, ReduxBlock.TakeCreators<Block>>,\n Context & ReduxBlock.TakeContext<Block>\n > {\n (this.blocks as Record<string, ReduxBlock<any, any, any>>)[name] = block;\n (this.creators as Record<string, unknown>)[name] = block.actions;\n return this as any;\n }\n\n effects<E extends Effects<any>>(\n effects: E,\n ): CompositionBuilder<\n Name,\n BlockMap,\n Creators & EffectsToCreators<Name, E>,\n Context & (E extends Effects<infer ExtraContext> ? ExtraContext : never)\n > {\n (this.handlers as (Effects<Context> | E)[]).push(effects);\n return this as any;\n }\n\n build(): ReduxBlock<{ [K in keyof BlockMap]: ReduxBlock.TakeState<BlockMap[K]> }, Creators, Context> {\n const reducers = Object.entries(this.blocks).map(([name, block]) => [name, block.reducer] as const);\n return {\n actions: this.creators,\n effects: (context: Context) => {\n const blockName = this.name;\n const result = this.handlers.reduce(\n (acc, effect) =>\n Object.assign(\n acc,\n Object.fromEntries(\n Object.entries(effect(context)).map(([effectName, handler]) => [\n `${blockName}/${effectName}`,\n handler,\n ]),\n ),\n ),\n {} as Record<string, (...payload: unknown[]) => void>,\n );\n Object.values(this.blocks).forEach((block) => Object.assign(result, block.effects(context)));\n return result;\n },\n reducer: (state: any, action: UnknownAction) => {\n let result = state;\n let changed = false;\n reducers.forEach(([name, reducer]) => {\n const original = state?.[name];\n const updated = reducer(original, action);\n if (updated !== original) {\n if (!changed) {\n changed = true;\n result = { ...state };\n }\n result[name] = updated;\n }\n });\n return result;\n },\n } as any;\n }\n}\n\nexport namespace ReduxBlock {\n type AnyBlock = ReduxBlock<any, any, any>;\n\n export type TakeState<Block extends AnyBlock> = Block extends ReduxBlock<infer State, any, any> ? State : never;\n export type TakeCreators<Block extends AnyBlock> =\n Block extends ReduxBlock<any, infer Creators, any> ? Creators : never;\n export type TakeContext<Block extends AnyBlock> =\n Block extends ReduxBlock<any, any, infer Context> ? Context : never;\n\n /**\n * Create a block builder.\n * It's a starting point for creating a block.\n */\n export function builder<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}> {\n return BlockBuilder.init(name, initial);\n }\n\n /**\n * Create a composition builder.\n */\n export function composition<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}> {\n return CompositionBuilder.init(name);\n }\n\n /**\n * Create middleware for effects processing.\n * It expects to receive a context object that provides necessary dependencies for effect handlers.\n */\n export function middleware<Block extends AnyBlock>(block: Block, context: TakeContext<Block>): Middleware {\n const effects = block.effects(context);\n return () => (next) => (action) => {\n if (action && typeof action === \"object\" && \"type\" in action && has(effects, action.type as string)) {\n effects[action.type as string](...(\"payload\" in action ? (action.payload as unknown[]) : []));\n }\n next(action);\n };\n }\n}\n"],"names":["has","v","k","creator","scope","target","property","payload","type","BlockBuilder","name","initial","reducers","handlers","action","handler","effects","initialState","blockName","context","acc","effect","effectName","state","CompositionBuilder","block","result","changed","reducer","original","updated","ReduxBlock","builder","composition","middleware","next"],"mappings":"gFA8BA,SAASA,EAA+BC,EAAYC,EAA+B,CAC/E,OAAO,OAAOD,GAAM,UAAYA,IAAM,MAAQ,OAAO,OAAOA,EAAGC,CAAC,CACpE,CAEA,MAAMC,EAAWC,GACb,IAAI,MACA,CAAA,EACA,CACI,IAAIC,EAAQC,EAAU,CAClB,OAAIN,EAAIK,EAAQC,CAAQ,EACbD,EAAOC,CAAQ,EAGnB,IAAIC,IAAuB,CAC9B,MAAMC,EAAO,GAAGJ,CAAK,IAAIE,CAAkB,GAC3C,OAAOC,EAAQ,OAAS,CAAE,KAAAC,EAAM,QAAAD,CAAA,EAAY,CAAE,KAAAC,CAAA,CAClD,CACJ,CAAA,CAER,EAgBJ,MAAMC,CAKJ,CACU,YACKC,EACAC,EAIQC,EAIAC,EACnB,CAVW,KAAA,KAAAH,EACA,KAAA,QAAAC,EAIQ,KAAA,SAAAC,EAIA,KAAA,SAAAC,CAClB,CAEH,OAAO,KAAiCH,EAAYC,EAAmD,CACnG,OAAO,IAAIF,EAAaC,EAAMC,EAAS,CAAA,EAAI,CAAA,CAAE,CACjD,CAMA,OACIG,EACAC,EAMF,CACE,YAAK,SAAS,GAAG,KAAK,IAAI,IAAID,CAAM,EAAE,EAAIC,EACnC,IACX,CAMA,QACIC,EAMF,CACE,YAAK,SAAS,KAAKA,CAAO,EACnB,IACX,CAEA,OAA8C,CAC1C,MAAMC,EAAe,KAAK,QACpBC,EAAY,KAAK,KACvB,MAAO,CACH,QAASf,EAAQ,KAAK,IAAI,EAC1B,QAAUgB,GACN,KAAK,SAAS,OACV,CAACC,EAAKC,IACF,OAAO,OACHD,EACA,OAAO,YACH,OAAO,QAAQC,EAAOF,CAAO,CAAC,EAAE,IAAI,CAAC,CAACG,EAAYP,CAAO,IAAM,CAC3D,GAAGG,CAAS,IAAII,CAAU,GAC1BP,CAAA,CACH,CAAA,CACL,EAER,CAAA,CAAC,EAET,QAAS,CAACQ,EAAQN,EAAcH,IAA0B,CACtD,MAAMC,EAAU,KAAK,SAASD,EAAO,IAAI,EACzC,GAAI,CAACC,EAAS,OAAOQ,EACrB,MAAMhB,EAAU,YAAaO,EAAUA,EAAO,QAAwB,OACtE,OAAOP,GAAWA,EAAQ,OAASQ,EAAQQ,EAAO,GAAGhB,CAAO,EAAIQ,EAAQQ,CAAK,CACjF,CAAA,CAER,CACJ,CAEA,MAAMC,CAKJ,CAKU,YAAoBd,EAAY,CAAZ,KAAA,KAAAA,EACxB,KAAK,SAAWP,EAAQO,CAAI,CAChC,CANQ,OAAmB,CAAA,EACnB,SAA+B,CAAA,EAC/B,SAMR,OAAO,KAA0BA,EAAkD,CAC/E,OAAO,IAAIc,EAAmBd,CAAI,CACtC,CAEA,MACIA,EACAe,EAMF,CACG,YAAK,OAAqDf,CAAI,EAAIe,EAClE,KAAK,SAAqCf,CAAI,EAAIe,EAAM,QAClD,IACX,CAEA,QACIT,EAMF,CACG,YAAK,SAAsC,KAAKA,CAAO,EACjD,IACX,CAEA,OAAqG,CACjG,MAAMJ,EAAW,OAAO,QAAQ,KAAK,MAAM,EAAE,IAAI,CAAC,CAACF,EAAMe,CAAK,IAAM,CAACf,EAAMe,EAAM,OAAO,CAAU,EAClG,MAAO,CACH,QAAS,KAAK,SACd,QAAUN,GAAqB,CAC3B,MAAMD,EAAY,KAAK,KACjBQ,EAAS,KAAK,SAAS,OACzB,CAACN,EAAKC,IACF,OAAO,OACHD,EACA,OAAO,YACH,OAAO,QAAQC,EAAOF,CAAO,CAAC,EAAE,IAAI,CAAC,CAACG,EAAYP,CAAO,IAAM,CAC3D,GAAGG,CAAS,IAAII,CAAU,GAC1BP,CAAA,CACH,CAAA,CACL,EAER,CAAA,CAAC,EAEL,cAAO,OAAO,KAAK,MAAM,EAAE,QAASU,GAAU,OAAO,OAAOC,EAAQD,EAAM,QAAQN,CAAO,CAAC,CAAC,EACpFO,CACX,EACA,QAAS,CAACH,EAAYT,IAA0B,CAC5C,IAAIY,EAASH,EACTI,EAAU,GACd,OAAAf,EAAS,QAAQ,CAAC,CAACF,EAAMkB,CAAO,IAAM,CAClC,MAAMC,EAAWN,IAAQb,CAAI,EACvBoB,EAAUF,EAAQC,EAAUf,CAAM,EACpCgB,IAAYD,IACPF,IACDA,EAAU,GACVD,EAAS,CAAE,GAAGH,CAAA,GAElBG,EAAOhB,CAAI,EAAIoB,EAEvB,CAAC,EACMJ,CACX,CAAA,CAER,CACJ,CAEiBK,QAAAA,WAAAA,QAAAA,GAAV,CAaI,SAASC,EAAoCtB,EAAYC,EAAmD,CAC/G,OAAOF,EAAa,KAAKC,EAAMC,CAAO,CAC1C,CAFOoB,EAAS,QAAAC,EAOT,SAASC,EAAiCvB,EAAkD,CAC/F,OAAOc,EAAmB,KAAKd,CAAI,CACvC,CAFOqB,EAAS,YAAAE,EAQT,SAASC,EAAmCT,EAAcN,EAAyC,CACtG,MAAMH,EAAUS,EAAM,QAAQN,CAAO,EACrC,MAAO,IAAOgB,GAAUrB,GAAW,CAC3BA,GAAU,OAAOA,GAAW,UAAY,SAAUA,GAAUd,EAAIgB,EAASF,EAAO,IAAc,GAC9FE,EAAQF,EAAO,IAAc,EAAE,GAAI,YAAaA,EAAUA,EAAO,QAAwB,EAAG,EAEhGqB,EAAKrB,CAAM,CACf,CACJ,CAROiB,EAAS,WAAAG,CAAA,GA5BHH,QAAAA,aAAAA,mBAAA,CAAA,EAAA"}
|
package/build/redux-sacala.d.ts
CHANGED
|
@@ -1,49 +1,107 @@
|
|
|
1
|
-
import { Action } from 'redux';
|
|
2
|
-
import { Dispatch } from 'redux';
|
|
3
1
|
import { Middleware } from 'redux';
|
|
4
2
|
import { Reducer } from 'redux';
|
|
3
|
+
import { UnknownAction } from 'redux';
|
|
5
4
|
|
|
6
|
-
declare
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
declare class BlockBuilder<Name extends string, State, Creators extends Record<string, (...parameters: unknown[]) => PayloadAction<any, any>>, Context> {
|
|
6
|
+
readonly name: Name;
|
|
7
|
+
readonly initial: State;
|
|
8
|
+
/**
|
|
9
|
+
* Per-message action reducers for this block.
|
|
10
|
+
*/
|
|
11
|
+
private readonly reducers;
|
|
12
|
+
/**
|
|
13
|
+
* Effects handlers for this block.
|
|
14
|
+
*/
|
|
15
|
+
private readonly handlers;
|
|
16
|
+
private constructor();
|
|
17
|
+
static init<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}>;
|
|
18
|
+
/**
|
|
19
|
+
* Append an action handler to the block.
|
|
20
|
+
* Action is a pure function that takes the state + arguments and returns a new state.
|
|
21
|
+
*/
|
|
22
|
+
action<Action extends string, Payload extends unknown[] = []>(action: Action, handler: (state: State, ...payload: Payload) => State): BlockBuilder<Name, State, Creators & Record<Action, (...payload: Payload) => PayloadAction<`${Name}/${Action}`, Payload>>, Context>;
|
|
23
|
+
/**
|
|
24
|
+
* Append effect handlers to the block.
|
|
25
|
+
* Effects can call any side effects provided from the context.
|
|
26
|
+
*/
|
|
27
|
+
effects<E extends Effects<any>>(effects: E): BlockBuilder<Name, State, Creators & EffectsToCreators<Name, E>, Context & (E extends Effects<infer C> ? C : never)>;
|
|
28
|
+
build(): ReduxBlock<State, Creators, Context>;
|
|
29
|
+
}
|
|
13
30
|
|
|
14
|
-
declare
|
|
31
|
+
declare class CompositionBuilder<Name extends string, BlockMap extends Record<string, ReduxBlock<any, any, any>>, Creators, Context> {
|
|
32
|
+
private name;
|
|
33
|
+
private blocks;
|
|
34
|
+
private handlers;
|
|
35
|
+
private creators;
|
|
36
|
+
private constructor();
|
|
37
|
+
static init<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}>;
|
|
38
|
+
block<Name extends string, Block extends ReduxBlock<any, any, any>>(name: Name, block: Block): CompositionBuilder<Name, BlockMap & Record<Name, Block>, Creators & Record<Name, ReduxBlock.TakeCreators<Block>>, Context & ReduxBlock.TakeContext<Block>>;
|
|
39
|
+
effects<E extends Effects<any>>(effects: E): CompositionBuilder<Name, BlockMap, Creators & EffectsToCreators<Name, E>, Context & (E extends Effects<infer ExtraContext> ? ExtraContext : never)>;
|
|
40
|
+
build(): ReduxBlock<{
|
|
41
|
+
[K in keyof BlockMap]: ReduxBlock.TakeState<BlockMap[K]>;
|
|
42
|
+
}, Creators, Context>;
|
|
43
|
+
}
|
|
15
44
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Effects creator. It receives context with side effect APIs and returns non-pure handlers.
|
|
47
|
+
*/
|
|
48
|
+
declare type Effects<Context> = (context: Context) => Record<string, (...payload: any[]) => void>;
|
|
19
49
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}) => {
|
|
26
|
-
name: Name;
|
|
27
|
-
reducer: Reducer<GlobalState[Name]>;
|
|
28
|
-
actions: ActionCreatorMap<Actions> & EffectsCreatorMap<GlobalState, ExtraArgument, Effects>;
|
|
29
|
-
} & ({} extends ReturnType<Effects> ? {} : {
|
|
30
|
-
createMiddleware: MiddlewareCreator<ExtraArgument>;
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
declare type EffectsCreatorMap<GlobalState, ExtraArgument, Map extends EffectsMap<GlobalState, ExtraArgument>> = {
|
|
34
|
-
[key in keyof ReturnType<Map>]: undefined extends FirstArgument<ReturnType<Map>[key]> ? () => Action : (payload: FirstArgument<ReturnType<Map>[key]>) => Action;
|
|
50
|
+
/**
|
|
51
|
+
* Convert effects type to action creators.
|
|
52
|
+
*/
|
|
53
|
+
declare type EffectsToCreators<Name extends string, E extends Effects<any>> = {
|
|
54
|
+
[K in keyof ReturnType<E>]: (...parameters: Parameters<ReturnType<E>[K]>) => PayloadAction<`${Name}/${K extends string ? K : never}`, Parameters<ReturnType<E>[K]>>;
|
|
35
55
|
};
|
|
36
56
|
|
|
37
|
-
declare type
|
|
38
|
-
|
|
57
|
+
declare type PayloadAction<Type extends string, Payload extends unknown[]> = Payload extends never[] ? {
|
|
58
|
+
type: Type;
|
|
59
|
+
} : {
|
|
60
|
+
type: Type;
|
|
61
|
+
payload: Payload;
|
|
39
62
|
};
|
|
40
63
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
declare
|
|
64
|
+
/**
|
|
65
|
+
* Composable Redux block with state description, action creators, and effects handlers.
|
|
66
|
+
* Use `ReduxBlock.builder` to start building a new block.
|
|
67
|
+
*/
|
|
68
|
+
export declare interface ReduxBlock<State, Creators, Context> {
|
|
69
|
+
/**
|
|
70
|
+
* Action creators for this block.
|
|
71
|
+
* When composed, action creators can form a folder tree structure.
|
|
72
|
+
*/
|
|
73
|
+
actions: Creators;
|
|
74
|
+
/**
|
|
75
|
+
* Reducer that can be used directly in Redux store configuration.
|
|
76
|
+
*/
|
|
77
|
+
reducer: Reducer<State, UnknownAction>;
|
|
78
|
+
/**
|
|
79
|
+
* Effects to be called on effects actions.
|
|
80
|
+
* Use `ReduxBlock.middleware` to create middleware for effects processing.
|
|
81
|
+
*/
|
|
82
|
+
effects: Effects<Context>;
|
|
83
|
+
}
|
|
46
84
|
|
|
47
|
-
declare
|
|
85
|
+
export declare namespace ReduxBlock {
|
|
86
|
+
export type AnyBlock = ReduxBlock<any, any, any>;
|
|
87
|
+
export type TakeState<Block extends AnyBlock> = Block extends ReduxBlock<infer State, any, any> ? State : never;
|
|
88
|
+
export type TakeCreators<Block extends AnyBlock> = Block extends ReduxBlock<any, infer Creators, any> ? Creators : never;
|
|
89
|
+
export type TakeContext<Block extends AnyBlock> = Block extends ReduxBlock<any, any, infer Context> ? Context : never;
|
|
90
|
+
/**
|
|
91
|
+
* Create a block builder.
|
|
92
|
+
* It's a starting point for creating a block.
|
|
93
|
+
*/
|
|
94
|
+
export function builder<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}>;
|
|
95
|
+
/**
|
|
96
|
+
* Create a composition builder.
|
|
97
|
+
*/
|
|
98
|
+
export function composition<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}>;
|
|
99
|
+
/**
|
|
100
|
+
* Create middleware for effects processing.
|
|
101
|
+
* It expects to receive a context object that provides necessary dependencies for effect handlers.
|
|
102
|
+
*/
|
|
103
|
+
export function middleware<Block extends AnyBlock>(block: Block, context: TakeContext<Block>): Middleware;
|
|
104
|
+
{};
|
|
105
|
+
}
|
|
48
106
|
|
|
49
107
|
export { }
|
package/build/redux-sacala.js
CHANGED
|
@@ -1,47 +1,127 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
const n = a(e + "/", u(c));
|
|
13
|
-
return (o = r, s) => {
|
|
14
|
-
if (s && s.type) {
|
|
15
|
-
const t = n[s.type];
|
|
16
|
-
return t ? t(o, s.payload) : o;
|
|
17
|
-
} else
|
|
18
|
-
return o;
|
|
19
|
-
};
|
|
20
|
-
}, h = (e, r) => ((c) => (n) => {
|
|
21
|
-
const o = a(e + "/", u(r(n.dispatch, n.getState)));
|
|
22
|
-
return (s) => (t) => {
|
|
23
|
-
t && Object.prototype.hasOwnProperty.call(o, t.type) ? o[t.type](t.payload, c) : s(t);
|
|
24
|
-
};
|
|
25
|
-
}), i = () => {
|
|
26
|
-
throw new Error("Can't have access to 'dispatch' and 'getState' during initialization");
|
|
27
|
-
}, y = () => ({
|
|
28
|
-
name: e,
|
|
29
|
-
initial: r,
|
|
30
|
-
actions: c,
|
|
31
|
-
effects: n
|
|
32
|
-
}) => {
|
|
33
|
-
const o = Object.keys(c).reduce((t, d) => (t[d] = l(`${e}/${d}`), t), {}), s = Object.keys(n ? n(i, i) : {}).reduce((t, d) => (t[d] = p(`${e}/${d}`), t), {});
|
|
34
|
-
return {
|
|
35
|
-
name: e,
|
|
36
|
-
reducer: f(e, r, c),
|
|
37
|
-
createMiddleware: n ? h(e, n) : (() => (t) => (d) => d),
|
|
38
|
-
actions: {
|
|
39
|
-
...o,
|
|
40
|
-
...s
|
|
1
|
+
function f(u, e) {
|
|
2
|
+
return typeof u == "object" && u !== null && Object.hasOwn(u, e);
|
|
3
|
+
}
|
|
4
|
+
const b = (u) => new Proxy(
|
|
5
|
+
{},
|
|
6
|
+
{
|
|
7
|
+
get(e, t) {
|
|
8
|
+
return f(e, t) ? e[t] : (...r) => {
|
|
9
|
+
const s = `${u}/${t}`;
|
|
10
|
+
return r.length ? { type: s, payload: r } : { type: s };
|
|
11
|
+
};
|
|
41
12
|
}
|
|
42
|
-
}
|
|
43
|
-
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
class h {
|
|
16
|
+
constructor(e, t, r, s) {
|
|
17
|
+
this.name = e, this.initial = t, this.reducers = r, this.handlers = s;
|
|
18
|
+
}
|
|
19
|
+
static init(e, t) {
|
|
20
|
+
return new h(e, t, {}, []);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Append an action handler to the block.
|
|
24
|
+
* Action is a pure function that takes the state + arguments and returns a new state.
|
|
25
|
+
*/
|
|
26
|
+
action(e, t) {
|
|
27
|
+
return this.reducers[`${this.name}/${e}`] = t, this;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Append effect handlers to the block.
|
|
31
|
+
* Effects can call any side effects provided from the context.
|
|
32
|
+
*/
|
|
33
|
+
effects(e) {
|
|
34
|
+
return this.handlers.push(e), this;
|
|
35
|
+
}
|
|
36
|
+
build() {
|
|
37
|
+
const e = this.initial, t = this.name;
|
|
38
|
+
return {
|
|
39
|
+
actions: b(this.name),
|
|
40
|
+
effects: (r) => this.handlers.reduce(
|
|
41
|
+
(s, n) => Object.assign(
|
|
42
|
+
s,
|
|
43
|
+
Object.fromEntries(
|
|
44
|
+
Object.entries(n(r)).map(([i, o]) => [
|
|
45
|
+
`${t}/${i}`,
|
|
46
|
+
o
|
|
47
|
+
])
|
|
48
|
+
)
|
|
49
|
+
),
|
|
50
|
+
{}
|
|
51
|
+
),
|
|
52
|
+
reducer: (r = e, s) => {
|
|
53
|
+
const n = this.reducers[s.type];
|
|
54
|
+
if (!n) return r;
|
|
55
|
+
const i = "payload" in s ? s.payload : void 0;
|
|
56
|
+
return i && i.length ? n(r, ...i) : n(r);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
class a {
|
|
62
|
+
constructor(e) {
|
|
63
|
+
this.name = e, this.creators = b(e);
|
|
64
|
+
}
|
|
65
|
+
blocks = {};
|
|
66
|
+
handlers = [];
|
|
67
|
+
creators;
|
|
68
|
+
static init(e) {
|
|
69
|
+
return new a(e);
|
|
70
|
+
}
|
|
71
|
+
block(e, t) {
|
|
72
|
+
return this.blocks[e] = t, this.creators[e] = t.actions, this;
|
|
73
|
+
}
|
|
74
|
+
effects(e) {
|
|
75
|
+
return this.handlers.push(e), this;
|
|
76
|
+
}
|
|
77
|
+
build() {
|
|
78
|
+
const e = Object.entries(this.blocks).map(([t, r]) => [t, r.reducer]);
|
|
79
|
+
return {
|
|
80
|
+
actions: this.creators,
|
|
81
|
+
effects: (t) => {
|
|
82
|
+
const r = this.name, s = this.handlers.reduce(
|
|
83
|
+
(n, i) => Object.assign(
|
|
84
|
+
n,
|
|
85
|
+
Object.fromEntries(
|
|
86
|
+
Object.entries(i(t)).map(([o, c]) => [
|
|
87
|
+
`${r}/${o}`,
|
|
88
|
+
c
|
|
89
|
+
])
|
|
90
|
+
)
|
|
91
|
+
),
|
|
92
|
+
{}
|
|
93
|
+
);
|
|
94
|
+
return Object.values(this.blocks).forEach((n) => Object.assign(s, n.effects(t))), s;
|
|
95
|
+
},
|
|
96
|
+
reducer: (t, r) => {
|
|
97
|
+
let s = t, n = !1;
|
|
98
|
+
return e.forEach(([i, o]) => {
|
|
99
|
+
const c = t?.[i], l = o(c, r);
|
|
100
|
+
l !== c && (n || (n = !0, s = { ...t }), s[i] = l);
|
|
101
|
+
}), s;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
var d;
|
|
107
|
+
((u) => {
|
|
108
|
+
function e(s, n) {
|
|
109
|
+
return h.init(s, n);
|
|
110
|
+
}
|
|
111
|
+
u.builder = e;
|
|
112
|
+
function t(s) {
|
|
113
|
+
return a.init(s);
|
|
114
|
+
}
|
|
115
|
+
u.composition = t;
|
|
116
|
+
function r(s, n) {
|
|
117
|
+
const i = s.effects(n);
|
|
118
|
+
return () => (o) => (c) => {
|
|
119
|
+
c && typeof c == "object" && "type" in c && f(i, c.type) && i[c.type](..."payload" in c ? c.payload : []), o(c);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
u.middleware = r;
|
|
123
|
+
})(d || (d = {}));
|
|
44
124
|
export {
|
|
45
|
-
|
|
125
|
+
d as ReduxBlock
|
|
46
126
|
};
|
|
47
127
|
//# sourceMappingURL=redux-sacala.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redux-sacala.js","sources":["../src/redux-sacala.ts"],"sourcesContent":["import { Dispatch, Action, Reducer, Middleware, AnyAction, MiddlewareAPI } from \"redux\";\n\ntype UnknownToUndefined<T> = unknown extends T ? undefined : T;\n\ntype FirstArgument<F> = F extends (arg1: infer U, ...args: any[]) => any ? UnknownToUndefined<U> : undefined;\ntype SecondArgument<F> = F extends (arg1: any, arg2: infer U, ...args: any[]) => any\n ? UnknownToUndefined<U>\n : undefined;\n\nconst bindAll = <T extends { [key: string]: Function }>(map: T): T => {\n const result = {} as any as T;\n for (const i in map) {\n result[i] = map[i].bind(map);\n }\n return result;\n};\n\nconst appendPrefix = <T>(prefix: string, map: { [key: string]: T }) => {\n const r: { [key: string]: any } = {};\n for (const i in map) {\n r[prefix + i] = map[i];\n }\n return r;\n};\n\n// Input\ntype ActionHandler<BlockState, Payload> = (state: BlockState, payload: Payload) => BlockState;\ntype ActionMap<BlockState> = { [action: string]: ActionHandler<BlockState, any> };\ntype EffectsMap<GlobalState, ExtraArgument> = (\n dispatch: Dispatch,\n getState: () => GlobalState,\n) => { [effect: string]: (payload: any, extraArgument: ExtraArgument) => any };\n\n// Output\ntype ActionCreator<Handler extends ActionHandler<any, any>> =\n undefined extends SecondArgument<Handler>\n ? () => Action<string>\n : (payload: SecondArgument<Handler>) => Action<string> & { payload: SecondArgument<Handler> };\n\ntype ActionCreatorMap<Actions extends ActionMap<any>> = {\n [name in keyof Actions]: ActionCreator<Actions[name]>;\n};\n\ntype EffectsCreatorMap<GlobalState, ExtraArgument, Map extends EffectsMap<GlobalState, ExtraArgument>> = {\n [key in keyof ReturnType<Map>]: undefined extends FirstArgument<ReturnType<Map>[key]>\n ? () => Action\n : (payload: FirstArgument<ReturnType<Map>[key]>) => Action;\n};\n\n// Transformation\nconst createActionCreator = (type: string) => (payload?: any) => (payload === undefined ? { type } : { type, payload });\nconst createEffectCreator = (type: string) => (payload: any) => ({ type, payload });\n\nconst createReducer = <BlockState>(prefix: string, initial: BlockState, actionMap: ActionMap<BlockState>): Reducer => {\n const actions: ActionMap<BlockState> = appendPrefix(prefix + \"/\", bindAll(actionMap));\n return (state: BlockState = initial, action?: AnyAction) => {\n if (action && action.type) {\n const handler: (state: BlockState, payload?: any) => BlockState = actions[action.type];\n if (handler) {\n return handler(state, action.payload);\n } else {\n return state;\n }\n } else {\n return state;\n }\n };\n};\n\ntype MiddlewareCreator<T> = T extends undefined ? () => Middleware : (argument: T) => Middleware;\n\nconst createMiddlewareCreator = <GlobalState, ExtraArgument>(\n prefix: string,\n effectsMap: EffectsMap<GlobalState, ExtraArgument>,\n): MiddlewareCreator<ExtraArgument> =>\n ((argument: ExtraArgument) => (store: MiddlewareAPI) => {\n const effects = appendPrefix(prefix + \"/\", bindAll(effectsMap(store.dispatch, store.getState)));\n return (next: Dispatch) => (action: Action<string> & { payload: any[] }) => {\n if (action && Object.prototype.hasOwnProperty.call(effects, action.type)) {\n effects[action.type](action.payload, argument);\n } else {\n next(action);\n }\n };\n }) as MiddlewareCreator<ExtraArgument>;\n\nconst fail = (): never => {\n throw new Error(\"Can't have access to 'dispatch' and 'getState' during initialization\");\n};\n\nexport const createReduxBlock =\n <GlobalState, ExtraArgument = undefined>() =>\n <\n Name extends keyof GlobalState & string,\n Actions extends ActionMap<GlobalState[Name]>,\n Effects extends EffectsMap<GlobalState, ExtraArgument>,\n >({\n name,\n initial,\n actions,\n effects,\n }: {\n name: Name;\n initial: GlobalState[Name];\n actions: Actions;\n effects?: Effects;\n }): {\n name: Name;\n reducer: Reducer<GlobalState[Name]>;\n actions: ActionCreatorMap<Actions> & EffectsCreatorMap<GlobalState, ExtraArgument, Effects>;\n } & ({} extends ReturnType<Effects> ? {} : { createMiddleware: MiddlewareCreator<ExtraArgument> }) => {\n const actionCreators = Object.keys(actions).reduce((r, key) => {\n r[key] = createActionCreator(`${name}/${key}`);\n return r;\n }, {} as any);\n const effectCreators = Object.keys(effects ? effects(fail, fail) : {}).reduce((r, key) => {\n r[key] = createEffectCreator(`${name}/${key}`);\n return r;\n }, {} as any);\n\n return {\n name,\n reducer: createReducer(name as string, initial, actions),\n createMiddleware: effects\n ? createMiddlewareCreator<GlobalState, ExtraArgument>(name as string, effects)\n : ((() => (_: MiddlewareAPI) => (next: Dispatch) => next) as MiddlewareCreator<ExtraArgument>),\n actions: {\n ...actionCreators,\n ...effectCreators,\n },\n };\n };\n"],"names":["bindAll","map","result","i","appendPrefix","prefix","r","createActionCreator","type","payload","createEffectCreator","createReducer","initial","actionMap","actions","state","action","handler","createMiddlewareCreator","effectsMap","argument","store","effects","next","fail","createReduxBlock","name","actionCreators","key","effectCreators","_"],"mappings":"AASA,MAAMA,IAAU,CAAwCC,MAAc;AAClE,QAAMC,IAAS,CAAA;AACf,aAAWC,KAAKF;AACZ,IAAAC,EAAOC,CAAC,IAAIF,EAAIE,CAAC,EAAE,KAAKF,CAAG;AAE/B,SAAOC;AACX,GAEME,IAAe,CAAIC,GAAgBJ,MAA8B;AACnE,QAAMK,IAA4B,CAAA;AAClC,aAAWH,KAAKF;AACZ,IAAAK,EAAED,IAASF,CAAC,IAAIF,EAAIE,CAAC;AAEzB,SAAOG;AACX,GA2BMC,IAAsB,CAACC,MAAiB,CAACC,MAAmBA,MAAY,SAAY,EAAE,MAAAD,EAAA,IAAS,EAAE,MAAAA,GAAM,SAAAC,EAAA,GACvGC,IAAsB,CAACF,MAAiB,CAACC,OAAkB,EAAE,MAAAD,GAAM,SAAAC,MAEnEE,IAAgB,CAAaN,GAAgBO,GAAqBC,MAA8C;AAClH,QAAMC,IAAiCV,EAAaC,IAAS,KAAKL,EAAQa,CAAS,CAAC;AACpF,SAAO,CAACE,IAAoBH,GAASI,MAAuB;AACxD,QAAIA,KAAUA,EAAO,MAAM;AACvB,YAAMC,IAA4DH,EAAQE,EAAO,IAAI;AACrF,aAAIC,IACOA,EAAQF,GAAOC,EAAO,OAAO,IAE7BD;AAAA,IAEf;AACI,aAAOA;AAAA,EAEf;AACJ,GAIMG,IAA0B,CAC5Bb,GACAc,OAEC,CAACC,MAA4B,CAACC,MAAyB;AACpD,QAAMC,IAAUlB,EAAaC,IAAS,KAAKL,EAAQmB,EAAWE,EAAM,UAAUA,EAAM,QAAQ,CAAC,CAAC;AAC9F,SAAO,CAACE,MAAmB,CAACP,MAAgD;AACxE,IAAIA,KAAU,OAAO,UAAU,eAAe,KAAKM,GAASN,EAAO,IAAI,IACnEM,EAAQN,EAAO,IAAI,EAAEA,EAAO,SAASI,CAAQ,IAE7CG,EAAKP,CAAM;AAAA,EAEnB;AACJ,IAEEQ,IAAO,MAAa;AACtB,QAAM,IAAI,MAAM,sEAAsE;AAC1F,GAEaC,IACT,MACA,CAIE;AAAA,EACE,MAAAC;AAAA,EACA,SAAAd;AAAA,EACA,SAAAE;AAAA,EACA,SAAAQ;AACJ,MASsG;AAClG,QAAMK,IAAiB,OAAO,KAAKb,CAAO,EAAE,OAAO,CAACR,GAAGsB,OACnDtB,EAAEsB,CAAG,IAAIrB,EAAoB,GAAGmB,CAAI,IAAIE,CAAG,EAAE,GACtCtB,IACR,CAAA,CAAS,GACNuB,IAAiB,OAAO,KAAKP,IAAUA,EAAQE,GAAMA,CAAI,IAAI,CAAA,CAAE,EAAE,OAAO,CAAClB,GAAGsB,OAC9EtB,EAAEsB,CAAG,IAAIlB,EAAoB,GAAGgB,CAAI,IAAIE,CAAG,EAAE,GACtCtB,IACR,CAAA,CAAS;AAEZ,SAAO;AAAA,IACH,MAAAoB;AAAA,IACA,SAASf,EAAce,GAAgBd,GAASE,CAAO;AAAA,IACvD,kBAAkBQ,IACZJ,EAAoDQ,GAAgBJ,CAAO,KACzE,MAAM,CAACQ,MAAqB,CAACP,MAAmBA;AAAA,IACxD,SAAS;AAAA,MACL,GAAGI;AAAA,MACH,GAAGE;AAAA,IAAA;AAAA,EACP;AAER;"}
|
|
1
|
+
{"version":3,"file":"redux-sacala.js","sources":["../src/redux-sacala.ts"],"sourcesContent":["import { Middleware, Reducer, UnknownAction } from \"redux\";\n\n/**\n * Composable Redux block with state description, action creators, and effects handlers.\n * Use `ReduxBlock.builder` to start building a new block.\n */\nexport interface ReduxBlock<State, Creators, Context> {\n /**\n * Action creators for this block.\n * When composed, action creators can form a folder tree structure.\n */\n actions: Creators;\n /**\n * Reducer that can be used directly in Redux store configuration.\n */\n reducer: Reducer<State, UnknownAction>;\n /**\n * Effects to be called on effects actions.\n * Use `ReduxBlock.middleware` to create middleware for effects processing.\n */\n effects: Effects<Context>;\n}\n\ntype PayloadAction<Type extends string, Payload extends unknown[]> = Payload extends never[]\n ? { type: Type }\n : { type: Type; payload: Payload };\n\n/**\n * Checks if the given key exists directly on the provided object.\n */\nfunction has<K extends string | symbol>(v: unknown, k: K): v is Record<K, unknown> {\n return typeof v === \"object\" && v !== null && Object.hasOwn(v, k);\n}\n\nconst creator = (scope: string) =>\n new Proxy(\n {},\n {\n get(target, property) {\n if (has(target, property)) {\n return target[property];\n }\n\n return (...payload: unknown[]) => {\n const type = `${scope}/${property as string}`;\n return payload.length ? { type, payload } : { type };\n };\n },\n },\n ) as Record<string, (...payload: unknown[]) => UnknownAction>;\n\n/**\n * Effects creator. It receives context with side effect APIs and returns non-pure handlers.\n */\ntype Effects<Context> = (context: Context) => Record<string, (...payload: any[]) => void>;\n\n/**\n * Convert effects type to action creators.\n */\ntype EffectsToCreators<Name extends string, E extends Effects<any>> = {\n [K in keyof ReturnType<E>]: (\n ...parameters: Parameters<ReturnType<E>[K]>\n ) => PayloadAction<`${Name}/${K extends string ? K : never}`, Parameters<ReturnType<E>[K]>>;\n};\n\nclass BlockBuilder<\n Name extends string,\n State,\n Creators extends Record<string, (...parameters: unknown[]) => PayloadAction<any, any>>,\n Context,\n> {\n private constructor(\n readonly name: Name,\n readonly initial: State,\n /**\n * Per-message action reducers for this block.\n */\n private readonly reducers: Record<string, (state: State, ...payload: unknown[]) => State>,\n /**\n * Effects handlers for this block.\n */\n private readonly handlers: Effects<Context>[],\n ) {}\n\n static init<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}> {\n return new BlockBuilder(name, initial, {}, []);\n }\n\n /**\n * Append an action handler to the block.\n * Action is a pure function that takes the state + arguments and returns a new state.\n */\n action<Action extends string, Payload extends unknown[] = []>(\n action: Action,\n handler: (state: State, ...payload: Payload) => State,\n ): BlockBuilder<\n Name,\n State,\n Creators & Record<Action, (...payload: Payload) => PayloadAction<`${Name}/${Action}`, Payload>>,\n Context\n > {\n this.reducers[`${this.name}/${action}`] = handler as (state: State, ...payload: unknown[]) => State;\n return this as any;\n }\n\n /**\n * Append effect handlers to the block.\n * Effects can call any side effects provided from the context.\n */\n effects<E extends Effects<any>>(\n effects: E,\n ): BlockBuilder<\n Name,\n State,\n Creators & EffectsToCreators<Name, E>,\n Context & (E extends Effects<infer C> ? C : never)\n > {\n this.handlers.push(effects);\n return this as any;\n }\n\n build(): ReduxBlock<State, Creators, Context> {\n const initialState = this.initial;\n const blockName = this.name;\n return {\n actions: creator(this.name),\n effects: (context: Context) =>\n this.handlers.reduce(\n (acc, effect) =>\n Object.assign(\n acc,\n Object.fromEntries(\n Object.entries(effect(context)).map(([effectName, handler]) => [\n `${blockName}/${effectName}`,\n handler,\n ]),\n ),\n ),\n {} as Record<string, (...payload: unknown[]) => void>,\n ),\n reducer: (state = initialState, action: UnknownAction) => {\n const handler = this.reducers[action.type];\n if (!handler) return state;\n const payload = \"payload\" in action ? (action.payload as unknown[]) : undefined;\n return payload && payload.length ? handler(state, ...payload) : handler(state);\n },\n } as any;\n }\n}\n\nclass CompositionBuilder<\n Name extends string,\n BlockMap extends Record<string, ReduxBlock<any, any, any>>,\n Creators,\n Context,\n> {\n private blocks: BlockMap = {} as BlockMap;\n private handlers: Effects<Context>[] = [];\n private creators: Creators;\n\n private constructor(private name: Name) {\n this.creators = creator(name) as Creators;\n }\n\n static init<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}> {\n return new CompositionBuilder(name);\n }\n\n block<Name extends string, Block extends ReduxBlock<any, any, any>>(\n name: Name,\n block: Block,\n ): CompositionBuilder<\n Name,\n BlockMap & Record<Name, Block>,\n Creators & Record<Name, ReduxBlock.TakeCreators<Block>>,\n Context & ReduxBlock.TakeContext<Block>\n > {\n (this.blocks as Record<string, ReduxBlock<any, any, any>>)[name] = block;\n (this.creators as Record<string, unknown>)[name] = block.actions;\n return this as any;\n }\n\n effects<E extends Effects<any>>(\n effects: E,\n ): CompositionBuilder<\n Name,\n BlockMap,\n Creators & EffectsToCreators<Name, E>,\n Context & (E extends Effects<infer ExtraContext> ? ExtraContext : never)\n > {\n (this.handlers as (Effects<Context> | E)[]).push(effects);\n return this as any;\n }\n\n build(): ReduxBlock<{ [K in keyof BlockMap]: ReduxBlock.TakeState<BlockMap[K]> }, Creators, Context> {\n const reducers = Object.entries(this.blocks).map(([name, block]) => [name, block.reducer] as const);\n return {\n actions: this.creators,\n effects: (context: Context) => {\n const blockName = this.name;\n const result = this.handlers.reduce(\n (acc, effect) =>\n Object.assign(\n acc,\n Object.fromEntries(\n Object.entries(effect(context)).map(([effectName, handler]) => [\n `${blockName}/${effectName}`,\n handler,\n ]),\n ),\n ),\n {} as Record<string, (...payload: unknown[]) => void>,\n );\n Object.values(this.blocks).forEach((block) => Object.assign(result, block.effects(context)));\n return result;\n },\n reducer: (state: any, action: UnknownAction) => {\n let result = state;\n let changed = false;\n reducers.forEach(([name, reducer]) => {\n const original = state?.[name];\n const updated = reducer(original, action);\n if (updated !== original) {\n if (!changed) {\n changed = true;\n result = { ...state };\n }\n result[name] = updated;\n }\n });\n return result;\n },\n } as any;\n }\n}\n\nexport namespace ReduxBlock {\n type AnyBlock = ReduxBlock<any, any, any>;\n\n export type TakeState<Block extends AnyBlock> = Block extends ReduxBlock<infer State, any, any> ? State : never;\n export type TakeCreators<Block extends AnyBlock> =\n Block extends ReduxBlock<any, infer Creators, any> ? Creators : never;\n export type TakeContext<Block extends AnyBlock> =\n Block extends ReduxBlock<any, any, infer Context> ? Context : never;\n\n /**\n * Create a block builder.\n * It's a starting point for creating a block.\n */\n export function builder<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}> {\n return BlockBuilder.init(name, initial);\n }\n\n /**\n * Create a composition builder.\n */\n export function composition<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}> {\n return CompositionBuilder.init(name);\n }\n\n /**\n * Create middleware for effects processing.\n * It expects to receive a context object that provides necessary dependencies for effect handlers.\n */\n export function middleware<Block extends AnyBlock>(block: Block, context: TakeContext<Block>): Middleware {\n const effects = block.effects(context);\n return () => (next) => (action) => {\n if (action && typeof action === \"object\" && \"type\" in action && has(effects, action.type as string)) {\n effects[action.type as string](...(\"payload\" in action ? (action.payload as unknown[]) : []));\n }\n next(action);\n };\n }\n}\n"],"names":["has","v","k","creator","scope","target","property","payload","type","BlockBuilder","name","initial","reducers","handlers","action","handler","effects","initialState","blockName","context","acc","effect","effectName","state","CompositionBuilder","block","result","changed","reducer","original","updated","ReduxBlock","builder","composition","middleware","next"],"mappings":"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"}
|