redux-sacala 0.3.1 → 0.3.3

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andrey Monkin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -7,6 +7,7 @@ A library for creating composable Redux blocks with state, actions, and effects.
7
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
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
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.
10
+ - **Selector**: A pure function that takes the state and returns a derived value. Selectors are defined using `.selectors()` and can be accessed via `.select`. For memoization, it is recommended to use `createSelector` from `@reduxjs/toolkit`. In compositions, selectors from child blocks are automatically "lifted" and available under the block's name.
10
11
 
11
12
  ## Examples
12
13
 
@@ -79,6 +80,58 @@ const rootBlock = ReduxBlock.composition("root")
79
80
  // rootBlock.actions.logAndIncrement()
80
81
  ```
81
82
 
83
+ ### Selectors
84
+
85
+ Selectors allow you to extract and derive data from the state. They are defined using `.selectors()` and are available on the `.select` property of the built block.
86
+
87
+ ```typescript
88
+ const counterBlock = ReduxBlock.builder("counter", { count: 0 })
89
+ .action("inc", (state) => ({ count: state.count + 1 }))
90
+ .selectors({
91
+ count: (state) => state.count,
92
+ doubleCount: (state) => state.count * 2,
93
+ })
94
+ .build();
95
+
96
+ // Usage:
97
+ // counterBlock.select.count({ count: 5 }) -> 5
98
+ // counterBlock.select.doubleCount({ count: 5 }) -> 10
99
+ ```
100
+
101
+ For complex or expensive derivations, it is recommended to use `createSelector` from `@reduxjs/toolkit` (or `reselect`) to enable memoization:
102
+
103
+ ```typescript
104
+ import { createSelector } from '@reduxjs/toolkit';
105
+
106
+ const counterBlock = ReduxBlock.builder("counter", { count: 0 })
107
+ .selectors({
108
+ count: (state) => state.count,
109
+ // Memoized selector using createSelector
110
+ tripleCount: createSelector(
111
+ [(state: { count: number }) => state.count],
112
+ (count) => count * 3
113
+ ),
114
+ })
115
+ .build();
116
+ ```
117
+
118
+ When blocks are composed, their selectors are automatically "lifted" to work with the composition's state.
119
+
120
+ ```typescript
121
+ const rootBlock = ReduxBlock.composition("root")
122
+ .block("counter", counterBlock)
123
+ .selectors({
124
+ isPositive: (state) => state.counter.count > 0,
125
+ })
126
+ .build();
127
+
128
+ // Lifted selector from counterBlock:
129
+ // rootBlock.select.counter.count({ counter: { count: 5 } }) -> 5
130
+
131
+ // Composition selector:
132
+ // rootBlock.select.isPositive({ counter: { count: 5 } }) -> true
133
+ ```
134
+
82
135
  ### Context Mapping
83
136
 
84
137
  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.
@@ -132,3 +185,7 @@ const store = configureStore({
132
185
  ),
133
186
  });
134
187
  ```
188
+
189
+ ## License
190
+
191
+ MIT
@@ -1,2 +1,2 @@
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={}));
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function f(c,e){return typeof c=="object"&&c!==null&&Object.hasOwn(c,e)}const d=c=>new Proxy({},{get(e,t){return f(e,t)?e[t]:(...r)=>{const i=`${c}/${t}`;return r.length?{type:i,payload:r}:{type:i}}}});function b(c,e){return typeof c=="function"?(t=>c(e(t))):Object.fromEntries(Object.entries(c).map(([t,r])=>[t,b(r,e)]))}class h{constructor(e,t,r,i,s){this.name=e,this.initial=t,this.reducers=r,this.handlers=i,this.select=s}static init(e,t){return new h(e,t,{},[],{})}action(e,t){return this.reducers[`${this.name}/${e}`]=t,this}effects(e){return this.handlers.push(e),this}selectors(e){return Object.assign(this.select,e),this}build(){const e=this.initial,t=this.name;return{actions:d(this.name),effects:r=>this.handlers.reduce((i,s)=>Object.assign(i,Object.fromEntries(Object.entries(s(r)).map(([n,o])=>[`${t}/${n}`,o]))),{}),reducer:(r=e,i)=>{const s=this.reducers[i.type];if(!s)return r;const n="payload"in i?i.payload:void 0;return n&&n.length?s(r,...n):s(r)},select:this.select}}}class a{constructor(e){this.name=e,this.creators=d(e)}blocks={};handlers=[];creators;select={};static init(e){return new a(e)}block(e,t){return this.blocks[e]=t,this.creators[e]=t.actions,this.select[e]=b(t.select,r=>r[e]),this}selectors(e){return Object.assign(this.select,e),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,i=this.handlers.reduce((s,n)=>Object.assign(s,Object.fromEntries(Object.entries(n(t)).map(([o,l])=>[`${r}/${o}`,l]))),{});return Object.values(this.blocks).forEach(s=>Object.assign(i,s.effects(t))),i},reducer:(t,r)=>{let i=t,s=!1;return e.forEach(([n,o])=>{const l=t?.[n],u=o(l,r);u!==l&&(s||(s=!0,i={...t}),i[n]=u)}),i},select:this.select}}}exports.ReduxBlock=void 0;(c=>{function e(s,n){return h.init(s,n)}c.builder=e;function t(s){return a.init(s)}c.composition=t;function r(s,n){const o=s.effects(n);return()=>l=>u=>{u&&typeof u=="object"&&"type"in u&&f(o,u.type)&&o[u.type](..."payload"in u?u.payload:[]),l(u)}}c.middleware=r;function i(s,n){return{actions:s.actions,reducer:s.reducer,effects:o=>s.effects(n(o)),select:s.select}}c.mapContext=i})(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 { 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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"}
1
+ {"version":3,"file":"redux-sacala.cjs","sources":["../src/redux-sacala.ts"],"sourcesContent":["import { Middleware, Reducer, UnknownAction } from \"redux\";\nimport { Selector } from \"@reduxjs/toolkit\";\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, Selectors> {\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>;\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 * Selectors for derived state properties.\n */\n select: Selectors;\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\ntype LiftSelectors<Tree, NewState> = Tree extends (...args: any) => infer Value\n ? Selector<NewState, Value>\n : {\n [K in keyof Tree]: LiftSelectors<Tree[K], NewState>;\n };\n\nfunction lift<Tree, RootState, State>(\n tree: Tree,\n selectState: (root: RootState) => State,\n): LiftSelectors<Tree, RootState> {\n if (typeof tree === \"function\") {\n return ((state: RootState) => tree(selectState(state))) as any;\n } else {\n return Object.fromEntries(Object.entries(tree as any).map(([k, v]) => [k, lift(v, selectState)])) as any;\n }\n}\n\nclass BlockBuilder<\n Name extends string,\n State,\n Creators extends Record<string, (...parameters: unknown[]) => PayloadAction<any, any>>,\n Context,\n Selectors extends Record<string, Selector<State>>,\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 private readonly select: Selectors,\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 Selectors\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 Selectors\n > {\n this.handlers.push(effects);\n return this as any;\n }\n\n selectors<SelectorsToAdd extends Record<string, Selector<State>>>(\n selectors: SelectorsToAdd,\n ): BlockBuilder<Name, State, Creators, Context, Selectors & SelectorsToAdd> {\n Object.assign(this.select as any, selectors);\n return this as any;\n }\n\n build(): ReduxBlock<State, Creators, Context, Selectors> {\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 select: this.select,\n } as any;\n }\n}\n\nclass CompositionBuilder<\n Name extends string,\n BlockMap extends Record<string, ReduxBlock<any, any, any, any>>,\n Creators,\n Context,\n Selectors,\n> {\n private readonly blocks: BlockMap = {} as BlockMap;\n private readonly handlers: Effects<Context>[] = [];\n private readonly creators: Creators;\n private readonly select: Selectors = {} as Selectors;\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, any>>(\n name: Name,\n block: Block,\n ): CompositionBuilder<\n Name,\n BlockMap & { [name in Name]: Block },\n Creators & { [name in Name]: ReduxBlock.TakeCreators<Block> },\n Context & ReduxBlock.TakeContext<Block>,\n Selectors & {\n [key in Name]: LiftSelectors<\n ReduxBlock.TakeSelectors<Block>,\n { [name in Name]: ReduxBlock.TakeState<Block> }\n >;\n }\n > {\n (this.blocks as Record<string, ReduxBlock<any, any, any, any>>)[name] = block;\n (this.creators as Record<string, unknown>)[name] = block.actions;\n (this.select as Record<string, unknown>)[name] = lift(block.select, (rootState: any) => rootState[name]);\n return this as any;\n }\n\n selectors<\n SelectorsToAdd extends Record<string, Selector<{ [K in keyof BlockMap]: ReduxBlock.TakeState<BlockMap[K]> }>>,\n >(selectors: SelectorsToAdd): CompositionBuilder<Name, BlockMap, Creators, Context, Selectors & SelectorsToAdd> {\n Object.assign(this.select as any, selectors);\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 Selectors\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, Selectors> {\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 select: this.select,\n } as any;\n }\n}\n\nexport namespace ReduxBlock {\n type AnyBlock = ReduxBlock<any, any, any, any>;\n\n export type TakeState<Block extends AnyBlock> =\n Block extends ReduxBlock<infer State, any, any, any> ? State : never;\n export type TakeCreators<Block extends AnyBlock> =\n Block extends ReduxBlock<any, infer Creators, any, any> ? Creators : never;\n export type TakeContext<Block extends AnyBlock> =\n Block extends ReduxBlock<any, any, infer Context, any> ? Context : never;\n export type TakeSelectors<Block extends AnyBlock> =\n Block extends ReduxBlock<any, any, any, infer Selectors> ? Selectors : 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>(\n name: Name,\n initial: State,\n ): 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 /**\n * Create a new block with a different context shape.\n */\n export function mapContext<Block extends AnyBlock, NewContext>(\n block: Block,\n mapper: (context: NewContext) => TakeContext<Block>,\n ): ReduxBlock<TakeState<Block>, TakeCreators<Block>, NewContext, TakeSelectors<Block>> {\n return {\n actions: block.actions,\n reducer: block.reducer,\n effects: (ctx) => block.effects(mapper(ctx)),\n select: block.select,\n };\n }\n}\n"],"names":["has","v","k","creator","scope","target","property","payload","type","lift","tree","selectState","state","BlockBuilder","name","initial","reducers","handlers","select","action","handler","effects","selectors","initialState","blockName","context","acc","effect","effectName","CompositionBuilder","block","rootState","result","changed","reducer","original","updated","ReduxBlock","builder","composition","middleware","next","mapContext","mapper","ctx"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { Middleware } from 'redux';
2
2
  import { Reducer } from 'redux';
3
- import { UnknownAction } from 'redux';
3
+ import { Selector } from '@reduxjs/toolkit';
4
4
 
5
- declare class BlockBuilder<Name extends string, State, Creators extends Record<string, (...parameters: unknown[]) => PayloadAction<any, any>>, Context> {
5
+ declare class BlockBuilder<Name extends string, State, Creators extends Record<string, (...parameters: unknown[]) => PayloadAction<any, any>>, Context, Selectors extends Record<string, Selector<State>>> {
6
6
  readonly name: Name;
7
7
  readonly initial: State;
8
8
  /**
@@ -13,33 +13,47 @@ declare class BlockBuilder<Name extends string, State, Creators extends Record<s
13
13
  * Effects handlers for this block.
14
14
  */
15
15
  private readonly handlers;
16
+ private readonly select;
16
17
  private constructor();
17
- static init<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}>;
18
+ static init<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}, {}>;
18
19
  /**
19
20
  * Append an action handler to the block.
20
21
  * Action is a pure function that takes the state + arguments and returns a new state.
21
22
  */
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
+ 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, Selectors>;
23
24
  /**
24
25
  * Append effect handlers to the block.
25
26
  * Effects can call any side effects provided from the context.
26
27
  */
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>;
28
+ effects<E extends Effects<any>>(effects: E): BlockBuilder<Name, State, Creators & EffectsToCreators<Name, E>, Context & (E extends Effects<infer C> ? C : never), Selectors>;
29
+ selectors<SelectorsToAdd extends Record<string, Selector<State>>>(selectors: SelectorsToAdd): BlockBuilder<Name, State, Creators, Context, Selectors & SelectorsToAdd>;
30
+ build(): ReduxBlock<State, Creators, Context, Selectors>;
29
31
  }
30
32
 
31
- declare class CompositionBuilder<Name extends string, BlockMap extends Record<string, ReduxBlock<any, any, any>>, Creators, Context> {
33
+ declare class CompositionBuilder<Name extends string, BlockMap extends Record<string, ReduxBlock<any, any, any, any>>, Creators, Context, Selectors> {
32
34
  private name;
33
- private blocks;
34
- private handlers;
35
- private creators;
35
+ private readonly blocks;
36
+ private readonly handlers;
37
+ private readonly creators;
38
+ private readonly select;
36
39
  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
+ static init<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}, {}>;
41
+ block<Name extends string, Block extends ReduxBlock<any, any, any, any>>(name: Name, block: Block): CompositionBuilder<Name, BlockMap & {
42
+ [name in Name]: Block;
43
+ }, Creators & {
44
+ [name in Name]: ReduxBlock.TakeCreators<Block>;
45
+ }, Context & ReduxBlock.TakeContext<Block>, Selectors & {
46
+ [key in Name]: LiftSelectors<ReduxBlock.TakeSelectors<Block>, {
47
+ [name in Name]: ReduxBlock.TakeState<Block>;
48
+ }>;
49
+ }>;
50
+ selectors<SelectorsToAdd extends Record<string, Selector<{
51
+ [K in keyof BlockMap]: ReduxBlock.TakeState<BlockMap[K]>;
52
+ }>>>(selectors: SelectorsToAdd): CompositionBuilder<Name, BlockMap, Creators, Context, Selectors & SelectorsToAdd>;
53
+ effects<E extends Effects<any>>(effects: E): CompositionBuilder<Name, BlockMap, Creators & EffectsToCreators<Name, E>, Context & (E extends Effects<infer ExtraContext> ? ExtraContext : never), Selectors>;
40
54
  build(): ReduxBlock<{
41
55
  [K in keyof BlockMap]: ReduxBlock.TakeState<BlockMap[K]>;
42
- }, Creators, Context>;
56
+ }, Creators, Context, Selectors>;
43
57
  }
44
58
 
45
59
  /**
@@ -54,6 +68,10 @@ declare type EffectsToCreators<Name extends string, E extends Effects<any>> = {
54
68
  [K in keyof ReturnType<E>]: (...parameters: Parameters<ReturnType<E>[K]>) => PayloadAction<`${Name}/${K extends string ? K : never}`, Parameters<ReturnType<E>[K]>>;
55
69
  };
56
70
 
71
+ declare type LiftSelectors<Tree, NewState> = Tree extends (...args: any) => infer Value ? Selector<NewState, Value> : {
72
+ [K in keyof Tree]: LiftSelectors<Tree[K], NewState>;
73
+ };
74
+
57
75
  declare type PayloadAction<Type extends string, Payload extends unknown[]> = Payload extends never[] ? {
58
76
  type: Type;
59
77
  } : {
@@ -65,7 +83,7 @@ declare type PayloadAction<Type extends string, Payload extends unknown[]> = Pay
65
83
  * Composable Redux block with state description, action creators, and effects handlers.
66
84
  * Use `ReduxBlock.builder` to start building a new block.
67
85
  */
68
- export declare interface ReduxBlock<State, Creators, Context> {
86
+ export declare interface ReduxBlock<State, Creators, Context, Selectors> {
69
87
  /**
70
88
  * Action creators for this block.
71
89
  * When composed, action creators can form a folder tree structure.
@@ -74,33 +92,42 @@ export declare interface ReduxBlock<State, Creators, Context> {
74
92
  /**
75
93
  * Reducer that can be used directly in Redux store configuration.
76
94
  */
77
- reducer: Reducer<State, UnknownAction>;
95
+ reducer: Reducer<State>;
78
96
  /**
79
97
  * Effects to be called on effects actions.
80
98
  * Use `ReduxBlock.middleware` to create middleware for effects processing.
81
99
  */
82
100
  effects: Effects<Context>;
101
+ /**
102
+ * Selectors for derived state properties.
103
+ */
104
+ select: Selectors;
83
105
  }
84
106
 
85
107
  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;
108
+ export type AnyBlock = ReduxBlock<any, any, any, any>;
109
+ export type TakeState<Block extends AnyBlock> = Block extends ReduxBlock<infer State, any, any, any> ? State : never;
110
+ export type TakeCreators<Block extends AnyBlock> = Block extends ReduxBlock<any, infer Creators, any, any> ? Creators : never;
111
+ export type TakeContext<Block extends AnyBlock> = Block extends ReduxBlock<any, any, infer Context, any> ? Context : never;
112
+ export type TakeSelectors<Block extends AnyBlock> = Block extends ReduxBlock<any, any, any, infer Selectors> ? Selectors : never;
90
113
  /**
91
114
  * Create a block builder.
92
115
  * It's a starting point for creating a block.
93
116
  */
94
- export function builder<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}>;
117
+ export function builder<Name extends string, State>(name: Name, initial: State): BlockBuilder<Name, State, {}, {}, {}>;
95
118
  /**
96
119
  * Create a composition builder.
97
120
  */
98
- export function composition<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}>;
121
+ export function composition<Name extends string>(name: Name): CompositionBuilder<Name, {}, {}, {}, {}>;
99
122
  /**
100
123
  * Create middleware for effects processing.
101
124
  * It expects to receive a context object that provides necessary dependencies for effect handlers.
102
125
  */
103
126
  export function middleware<Block extends AnyBlock>(block: Block, context: TakeContext<Block>): Middleware;
127
+ /**
128
+ * Create a new block with a different context shape.
129
+ */
130
+ export function mapContext<Block extends AnyBlock, NewContext>(block: Block, mapper: (context: NewContext) => TakeContext<Block>): ReduxBlock<TakeState<Block>, TakeCreators<Block>, NewContext, TakeSelectors<Block>>;
104
131
  {};
105
132
  }
106
133
 
@@ -1,23 +1,26 @@
1
- function f(u, e) {
2
- return typeof u == "object" && u !== null && Object.hasOwn(u, e);
1
+ function d(c, e) {
2
+ return typeof c == "object" && c !== null && Object.hasOwn(c, e);
3
3
  }
4
- const b = (u) => new Proxy(
4
+ const b = (c) => new Proxy(
5
5
  {},
6
6
  {
7
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 };
8
+ return d(e, t) ? e[t] : (...r) => {
9
+ const i = `${c}/${t}`;
10
+ return r.length ? { type: i, payload: r } : { type: i };
11
11
  };
12
12
  }
13
13
  }
14
14
  );
15
- class h {
16
- constructor(e, t, r, s) {
17
- this.name = e, this.initial = t, this.reducers = r, this.handlers = s;
15
+ function p(c, e) {
16
+ return typeof c == "function" ? ((t) => c(e(t))) : Object.fromEntries(Object.entries(c).map(([t, r]) => [t, p(r, e)]));
17
+ }
18
+ class l {
19
+ constructor(e, t, r, i, s) {
20
+ this.name = e, this.initial = t, this.reducers = r, this.handlers = i, this.select = s;
18
21
  }
19
22
  static init(e, t) {
20
- return new h(e, t, {}, []);
23
+ return new l(e, t, {}, [], {});
21
24
  }
22
25
  /**
23
26
  * Append an action handler to the block.
@@ -33,28 +36,32 @@ class h {
33
36
  effects(e) {
34
37
  return this.handlers.push(e), this;
35
38
  }
39
+ selectors(e) {
40
+ return Object.assign(this.select, e), this;
41
+ }
36
42
  build() {
37
43
  const e = this.initial, t = this.name;
38
44
  return {
39
45
  actions: b(this.name),
40
46
  effects: (r) => this.handlers.reduce(
41
- (s, n) => Object.assign(
42
- s,
47
+ (i, s) => Object.assign(
48
+ i,
43
49
  Object.fromEntries(
44
- Object.entries(n(r)).map(([i, o]) => [
45
- `${t}/${i}`,
46
- o
50
+ Object.entries(s(r)).map(([n, h]) => [
51
+ `${t}/${n}`,
52
+ h
47
53
  ])
48
54
  )
49
55
  ),
50
56
  {}
51
57
  ),
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
+ reducer: (r = e, i) => {
59
+ const s = this.reducers[i.type];
60
+ if (!s) return r;
61
+ const n = "payload" in i ? i.payload : void 0;
62
+ return n && n.length ? s(r, ...n) : s(r);
63
+ },
64
+ select: this.select
58
65
  };
59
66
  }
60
67
  }
@@ -65,11 +72,15 @@ class a {
65
72
  blocks = {};
66
73
  handlers = [];
67
74
  creators;
75
+ select = {};
68
76
  static init(e) {
69
77
  return new a(e);
70
78
  }
71
79
  block(e, t) {
72
- return this.blocks[e] = t, this.creators[e] = t.actions, this;
80
+ return this.blocks[e] = t, this.creators[e] = t.actions, this.select[e] = p(t.select, (r) => r[e]), this;
81
+ }
82
+ selectors(e) {
83
+ return Object.assign(this.select, e), this;
73
84
  }
74
85
  effects(e) {
75
86
  return this.handlers.push(e), this;
@@ -79,49 +90,59 @@ class a {
79
90
  return {
80
91
  actions: this.creators,
81
92
  effects: (t) => {
82
- const r = this.name, s = this.handlers.reduce(
83
- (n, i) => Object.assign(
84
- n,
93
+ const r = this.name, i = this.handlers.reduce(
94
+ (s, n) => Object.assign(
95
+ s,
85
96
  Object.fromEntries(
86
- Object.entries(i(t)).map(([o, c]) => [
87
- `${r}/${o}`,
88
- c
97
+ Object.entries(n(t)).map(([h, o]) => [
98
+ `${r}/${h}`,
99
+ o
89
100
  ])
90
101
  )
91
102
  ),
92
103
  {}
93
104
  );
94
- return Object.values(this.blocks).forEach((n) => Object.assign(s, n.effects(t))), s;
105
+ return Object.values(this.blocks).forEach((s) => Object.assign(i, s.effects(t))), i;
95
106
  },
96
107
  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
- }
108
+ let i = t, s = !1;
109
+ return e.forEach(([n, h]) => {
110
+ const o = t?.[n], u = h(o, r);
111
+ u !== o && (s || (s = !0, i = { ...t }), i[n] = u);
112
+ }), i;
113
+ },
114
+ select: this.select
103
115
  };
104
116
  }
105
117
  }
106
- var d;
107
- ((u) => {
118
+ var f;
119
+ ((c) => {
108
120
  function e(s, n) {
109
- return h.init(s, n);
121
+ return l.init(s, n);
110
122
  }
111
- u.builder = e;
123
+ c.builder = e;
112
124
  function t(s) {
113
125
  return a.init(s);
114
126
  }
115
- u.composition = t;
127
+ c.composition = t;
116
128
  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);
129
+ const h = s.effects(n);
130
+ return () => (o) => (u) => {
131
+ u && typeof u == "object" && "type" in u && d(h, u.type) && h[u.type](..."payload" in u ? u.payload : []), o(u);
132
+ };
133
+ }
134
+ c.middleware = r;
135
+ function i(s, n) {
136
+ return {
137
+ actions: s.actions,
138
+ reducer: s.reducer,
139
+ effects: (h) => s.effects(n(h)),
140
+ select: s.select
120
141
  };
121
142
  }
122
- u.middleware = r;
123
- })(d || (d = {}));
143
+ c.mapContext = i;
144
+ })(f || (f = {}));
124
145
  export {
125
- d as ReduxBlock
146
+ f as ReduxBlock
126
147
  };
127
148
  //# sourceMappingURL=redux-sacala.js.map
@@ -1 +1 @@
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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"}
1
+ {"version":3,"file":"redux-sacala.js","sources":["../src/redux-sacala.ts"],"sourcesContent":["import { Middleware, Reducer, UnknownAction } from \"redux\";\nimport { Selector } from \"@reduxjs/toolkit\";\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, Selectors> {\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>;\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 * Selectors for derived state properties.\n */\n select: Selectors;\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\ntype LiftSelectors<Tree, NewState> = Tree extends (...args: any) => infer Value\n ? Selector<NewState, Value>\n : {\n [K in keyof Tree]: LiftSelectors<Tree[K], NewState>;\n };\n\nfunction lift<Tree, RootState, State>(\n tree: Tree,\n selectState: (root: RootState) => State,\n): LiftSelectors<Tree, RootState> {\n if (typeof tree === \"function\") {\n return ((state: RootState) => tree(selectState(state))) as any;\n } else {\n return Object.fromEntries(Object.entries(tree as any).map(([k, v]) => [k, lift(v, selectState)])) as any;\n }\n}\n\nclass BlockBuilder<\n Name extends string,\n State,\n Creators extends Record<string, (...parameters: unknown[]) => PayloadAction<any, any>>,\n Context,\n Selectors extends Record<string, Selector<State>>,\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 private readonly select: Selectors,\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 Selectors\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 Selectors\n > {\n this.handlers.push(effects);\n return this as any;\n }\n\n selectors<SelectorsToAdd extends Record<string, Selector<State>>>(\n selectors: SelectorsToAdd,\n ): BlockBuilder<Name, State, Creators, Context, Selectors & SelectorsToAdd> {\n Object.assign(this.select as any, selectors);\n return this as any;\n }\n\n build(): ReduxBlock<State, Creators, Context, Selectors> {\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 select: this.select,\n } as any;\n }\n}\n\nclass CompositionBuilder<\n Name extends string,\n BlockMap extends Record<string, ReduxBlock<any, any, any, any>>,\n Creators,\n Context,\n Selectors,\n> {\n private readonly blocks: BlockMap = {} as BlockMap;\n private readonly handlers: Effects<Context>[] = [];\n private readonly creators: Creators;\n private readonly select: Selectors = {} as Selectors;\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, any>>(\n name: Name,\n block: Block,\n ): CompositionBuilder<\n Name,\n BlockMap & { [name in Name]: Block },\n Creators & { [name in Name]: ReduxBlock.TakeCreators<Block> },\n Context & ReduxBlock.TakeContext<Block>,\n Selectors & {\n [key in Name]: LiftSelectors<\n ReduxBlock.TakeSelectors<Block>,\n { [name in Name]: ReduxBlock.TakeState<Block> }\n >;\n }\n > {\n (this.blocks as Record<string, ReduxBlock<any, any, any, any>>)[name] = block;\n (this.creators as Record<string, unknown>)[name] = block.actions;\n (this.select as Record<string, unknown>)[name] = lift(block.select, (rootState: any) => rootState[name]);\n return this as any;\n }\n\n selectors<\n SelectorsToAdd extends Record<string, Selector<{ [K in keyof BlockMap]: ReduxBlock.TakeState<BlockMap[K]> }>>,\n >(selectors: SelectorsToAdd): CompositionBuilder<Name, BlockMap, Creators, Context, Selectors & SelectorsToAdd> {\n Object.assign(this.select as any, selectors);\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 Selectors\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, Selectors> {\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 select: this.select,\n } as any;\n }\n}\n\nexport namespace ReduxBlock {\n type AnyBlock = ReduxBlock<any, any, any, any>;\n\n export type TakeState<Block extends AnyBlock> =\n Block extends ReduxBlock<infer State, any, any, any> ? State : never;\n export type TakeCreators<Block extends AnyBlock> =\n Block extends ReduxBlock<any, infer Creators, any, any> ? Creators : never;\n export type TakeContext<Block extends AnyBlock> =\n Block extends ReduxBlock<any, any, infer Context, any> ? Context : never;\n export type TakeSelectors<Block extends AnyBlock> =\n Block extends ReduxBlock<any, any, any, infer Selectors> ? Selectors : 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>(\n name: Name,\n initial: State,\n ): 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 /**\n * Create a new block with a different context shape.\n */\n export function mapContext<Block extends AnyBlock, NewContext>(\n block: Block,\n mapper: (context: NewContext) => TakeContext<Block>,\n ): ReduxBlock<TakeState<Block>, TakeCreators<Block>, NewContext, TakeSelectors<Block>> {\n return {\n actions: block.actions,\n reducer: block.reducer,\n effects: (ctx) => block.effects(mapper(ctx)),\n select: block.select,\n };\n }\n}\n"],"names":["has","v","k","creator","scope","target","property","payload","type","lift","tree","selectState","state","BlockBuilder","name","initial","reducers","handlers","select","action","handler","effects","selectors","initialState","blockName","context","acc","effect","effectName","CompositionBuilder","block","rootState","result","changed","reducer","original","updated","ReduxBlock","builder","composition","middleware","next","mapContext","mapper","ctx"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "redux-sacala",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
+ "license": "MIT",
4
5
  "type": "module",
5
6
  "author": {
6
7
  "name": "Andrey Monkin",
@@ -17,21 +18,23 @@
17
18
  }
18
19
  },
19
20
  "peerDependencies": {
20
- "redux": "^5.0.1"
21
+ "@reduxjs/toolkit": "^2.0.0",
22
+ "redux": "^5.0.0"
21
23
  },
22
24
  "devDependencies": {
23
25
  "@eslint/js": "9.39.2",
24
- "@types/node": "25.0.3",
26
+ "@reduxjs/toolkit": "2.11.2",
27
+ "@types/node": "25.0.8",
25
28
  "@typescript-eslint/eslint-plugin": "8.51.0",
26
- "@typescript-eslint/parser": "8.51.0",
29
+ "@typescript-eslint/parser": "8.53.0",
27
30
  "eslint": "9.39.2",
28
31
  "eslint-config-prettier": "10.1.8",
29
32
  "prettier": "3.7.4",
30
33
  "typescript": "5.9.3",
31
- "typescript-eslint": "8.51.0",
32
- "vite": "7.3.0",
34
+ "typescript-eslint": "8.53.0",
35
+ "vite": "7.3.1",
33
36
  "vite-plugin-dts": "4.5.4",
34
- "vitest": "4.0.16"
37
+ "vitest": "4.0.17"
35
38
  },
36
39
  "scripts": {
37
40
  "build": "vite build",
@@ -1,30 +0,0 @@
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