redux-sacala 0.3.5 → 0.3.7
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/README.md +48 -0
- package/build/redux-sacala.cjs +1 -1
- package/build/redux-sacala.cjs.map +1 -1
- package/build/redux-sacala.d.ts +11 -2
- package/build/redux-sacala.js +59 -50
- package/build/redux-sacala.js.map +1 -1
- package/package.json +20 -4
package/README.md
CHANGED
|
@@ -221,6 +221,54 @@ const store = configureStore({
|
|
|
221
221
|
});
|
|
222
222
|
```
|
|
223
223
|
|
|
224
|
+
### Dependency Injection with [di-sacala](https://github.com/monkin/di-sacala)
|
|
225
|
+
|
|
226
|
+
For larger applications, it is highly recommended to use `di-sacala` to manage and provide dependencies to your effects. It provides a clean way to define and resolve dependencies with full type safety.
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { configureStore } from '@reduxjs/toolkit';
|
|
230
|
+
import { ReduxBlock } from "redux-sacala";
|
|
231
|
+
import { DiContainer, DiService } from "di-sacala";
|
|
232
|
+
|
|
233
|
+
// 1. Define your services
|
|
234
|
+
class ApiService implements DiService<"api"> {
|
|
235
|
+
name = "api" as const;
|
|
236
|
+
async fetchUser(id: string) {
|
|
237
|
+
return { id, name: "User " + id };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
class LoggerService implements DiService<"logger"> {
|
|
242
|
+
name = "logger" as const;
|
|
243
|
+
log(msg: string) {
|
|
244
|
+
console.log(`[LOG]: ${msg}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
class DispatcherService implements DiService<"dispatch"> {
|
|
249
|
+
name = "dispatch" as const;
|
|
250
|
+
constructor() {
|
|
251
|
+
}
|
|
252
|
+
dispatch(action: Action) {
|
|
253
|
+
// Dispatch action using Redux store
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 2. Create and configure the container
|
|
258
|
+
const container = new DiContainer()
|
|
259
|
+
.inject(ApiService)
|
|
260
|
+
.inject(LoggerService)
|
|
261
|
+
.inject(DispatcherService);
|
|
262
|
+
|
|
263
|
+
const store = configureStore({
|
|
264
|
+
reducer: rootBlock.reducer,
|
|
265
|
+
middleware: (getDefaultMiddleware) =>
|
|
266
|
+
getDefaultMiddleware().concat(
|
|
267
|
+
ReduxBlock.middleware(rootBlock, container)
|
|
268
|
+
),
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
224
272
|
## License
|
|
225
273
|
|
|
226
274
|
MIT
|
package/build/redux-sacala.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function p(c,e){return typeof c=="object"&&c!==null&&Object.hasOwn(c,e)}const b=c=>new Proxy({},{get(e,t){return p(e,t)?e[t]:(...r)=>{const i=`${c}/${t}`;return r.length?{type:i,payload:r}:{type:i}}}});function h(c,e){return typeof c=="function"?(t=>c(e(t))):Object.fromEntries(Object.entries(c).map(([t,r])=>[t,h(r,e)]))}class f{constructor(e,t,r,i,n){this.name=e,this.initial=t,this.reducers=r,this.handlers=i,this.select=n}static init(e,t){return new f(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:b(this.name),effects:r=>this.handlers.reduce((i,n)=>Object.assign(i,Object.fromEntries(Object.entries(n(r)).map(([s,u])=>[`${t}/${s}`,u]))),{}),reducer:(r=e,i)=>{const n=this.reducers[i.type];if(!n)return r;const s="payload"in i?i.payload:void 0;return s&&s.length?n(r,...s):n(r)},select:this.select}}}class d{constructor(e){this.name=e,this.creators=b(e)}blocks={};handlers=[];creators;select={};static init(e){return new d(e)}block(e,t){return this.blocks[e]=t,this.creators[e]=t.actions,this.select[e]=h(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((n,s)=>Object.assign(n,Object.fromEntries(Object.entries(s(t)).map(([u,o])=>[`${r}/${u}`,o]))),{});return Object.values(this.blocks).forEach(n=>Object.assign(i,n.effects(t))),i},reducer:(t,r)=>{let i=t,n=!1;return e.forEach(([s,u])=>{const o=t?.[s],a=u(o,r);a!==o&&(n||(n=!0,i={...t}),i[s]=a)}),i},select:this.select}}}exports.ReduxBlock=void 0;(c=>{function e(s,u){return f.init(s,u)}c.builder=e;function t(s){return d.init(s)}c.composition=t;function r(s,u){const o=s.effects(u);return()=>a=>l=>{l&&typeof l=="object"&&"type"in l&&p(o,l.type)&&o[l.type](..."payload"in l?l.payload:[]),a(l)}}c.middleware=r;function i(s,u){return{actions:s.actions,reducer:s.reducer,effects:o=>s.effects(u(o)),select:s.select}}c.mapContext=i;function n(s,u){return{actions:s.actions,reducer:s.reducer,effects:s.effects,select:h(s.select,u)}}c.mapSelectors=n})(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\";\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
|
+
{"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 & { [action in 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 FindFunction<T> = T extends Function ? T : FindFunction<T[keyof T]>;\n type TakeFirst<T> = T extends [infer First, ...any] ? First : never;\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 export type TakeSelectorsState<Block extends AnyBlock> = TakeFirst<Parameters<FindFunction<TakeSelectors<Block>>>>;\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 (dependencies) 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 /**\n * Maps the selectors of a given block to a new state using a provided selector function.\n */\n export function mapSelectors<Block extends AnyBlock, NewState>(\n block: Block,\n selectState: (state: NewState) => TakeSelectorsState<Block>,\n ): ReduxBlock<\n TakeState<Block>,\n TakeCreators<Block>,\n TakeContext<Block>,\n LiftSelectors<TakeSelectors<Block>, NewState>\n > {\n return {\n actions: block.actions,\n reducer: block.reducer,\n effects: block.effects,\n select: lift(block.select, selectState),\n } as any;\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","mapSelectors"],"mappings":"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"}
|
package/build/redux-sacala.d.ts
CHANGED
|
@@ -20,7 +20,9 @@ declare class BlockBuilder<Name extends string, State, Creators extends Record<s
|
|
|
20
20
|
* Append an action handler to the block.
|
|
21
21
|
* Action is a pure function that takes the state + arguments and returns a new state.
|
|
22
22
|
*/
|
|
23
|
-
action<Action extends string, Payload extends unknown[] = []>(action: Action, handler: (state: State, ...payload: Payload) => State): BlockBuilder<Name, State, Creators &
|
|
23
|
+
action<Action extends string, Payload extends unknown[] = []>(action: Action, handler: (state: State, ...payload: Payload) => State): BlockBuilder<Name, State, Creators & {
|
|
24
|
+
[action in Action]: (...payload: Payload) => PayloadAction<`${Name}/${Action}`, Payload>;
|
|
25
|
+
}, Context, Selectors>;
|
|
24
26
|
/**
|
|
25
27
|
* Append effect handlers to the block.
|
|
26
28
|
* Effects can call any side effects provided from the context.
|
|
@@ -105,11 +107,14 @@ export declare interface ReduxBlock<State, Creators, Context, Selectors> {
|
|
|
105
107
|
}
|
|
106
108
|
|
|
107
109
|
export declare namespace ReduxBlock {
|
|
110
|
+
export type FindFunction<T> = T extends Function ? T : FindFunction<T[keyof T]>;
|
|
111
|
+
export type TakeFirst<T> = T extends [infer First, ...any] ? First : never;
|
|
108
112
|
export type AnyBlock = ReduxBlock<any, any, any, any>;
|
|
109
113
|
export type TakeState<Block extends AnyBlock> = Block extends ReduxBlock<infer State, any, any, any> ? State : never;
|
|
110
114
|
export type TakeCreators<Block extends AnyBlock> = Block extends ReduxBlock<any, infer Creators, any, any> ? Creators : never;
|
|
111
115
|
export type TakeContext<Block extends AnyBlock> = Block extends ReduxBlock<any, any, infer Context, any> ? Context : never;
|
|
112
116
|
export type TakeSelectors<Block extends AnyBlock> = Block extends ReduxBlock<any, any, any, infer Selectors> ? Selectors : never;
|
|
117
|
+
export type TakeSelectorsState<Block extends AnyBlock> = TakeFirst<Parameters<FindFunction<TakeSelectors<Block>>>>;
|
|
113
118
|
/**
|
|
114
119
|
* Create a block builder.
|
|
115
120
|
* It's a starting point for creating a block.
|
|
@@ -125,9 +130,13 @@ export declare namespace ReduxBlock {
|
|
|
125
130
|
*/
|
|
126
131
|
export function middleware<Block extends AnyBlock>(block: Block, context: TakeContext<Block>): Middleware;
|
|
127
132
|
/**
|
|
128
|
-
* Create a new block with a different context shape.
|
|
133
|
+
* Create a new block with a different context (dependencies) shape.
|
|
129
134
|
*/
|
|
130
135
|
export function mapContext<Block extends AnyBlock, NewContext>(block: Block, mapper: (context: NewContext) => TakeContext<Block>): ReduxBlock<TakeState<Block>, TakeCreators<Block>, NewContext, TakeSelectors<Block>>;
|
|
136
|
+
/**
|
|
137
|
+
* Maps the selectors of a given block to a new state using a provided selector function.
|
|
138
|
+
*/
|
|
139
|
+
export function mapSelectors<Block extends AnyBlock, NewState>(block: Block, selectState: (state: NewState) => TakeSelectorsState<Block>): ReduxBlock<TakeState<Block>, TakeCreators<Block>, TakeContext<Block>, LiftSelectors<TakeSelectors<Block>, NewState>>;
|
|
131
140
|
{};
|
|
132
141
|
}
|
|
133
142
|
|
package/build/redux-sacala.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
function
|
|
1
|
+
function b(c, e) {
|
|
2
2
|
return typeof c == "object" && c !== null && Object.hasOwn(c, e);
|
|
3
3
|
}
|
|
4
|
-
const
|
|
4
|
+
const m = (c) => new Proxy(
|
|
5
5
|
{},
|
|
6
6
|
{
|
|
7
7
|
get(e, t) {
|
|
8
|
-
return
|
|
9
|
-
const
|
|
10
|
-
return r.length ? { type:
|
|
8
|
+
return b(e, t) ? e[t] : (...r) => {
|
|
9
|
+
const n = `${c}/${t}`;
|
|
10
|
+
return r.length ? { type: n, payload: r } : { type: n };
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
);
|
|
15
|
-
function
|
|
16
|
-
return typeof c == "function" ? ((t) => c(e(t))) : Object.fromEntries(Object.entries(c).map(([t, r]) => [t,
|
|
15
|
+
function l(c, e) {
|
|
16
|
+
return typeof c == "function" ? ((t) => c(e(t))) : Object.fromEntries(Object.entries(c).map(([t, r]) => [t, l(r, e)]));
|
|
17
17
|
}
|
|
18
|
-
class
|
|
19
|
-
constructor(e, t, r,
|
|
20
|
-
this.name = e, this.initial = t, this.reducers = r, this.handlers =
|
|
18
|
+
class f {
|
|
19
|
+
constructor(e, t, r, n, i) {
|
|
20
|
+
this.name = e, this.initial = t, this.reducers = r, this.handlers = n, this.select = i;
|
|
21
21
|
}
|
|
22
22
|
static init(e, t) {
|
|
23
|
-
return new
|
|
23
|
+
return new f(e, t, {}, [], {});
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Append an action handler to the block.
|
|
@@ -42,42 +42,42 @@ class l {
|
|
|
42
42
|
build() {
|
|
43
43
|
const e = this.initial, t = this.name;
|
|
44
44
|
return {
|
|
45
|
-
actions:
|
|
45
|
+
actions: m(this.name),
|
|
46
46
|
effects: (r) => this.handlers.reduce(
|
|
47
|
-
(
|
|
48
|
-
|
|
47
|
+
(n, i) => Object.assign(
|
|
48
|
+
n,
|
|
49
49
|
Object.fromEntries(
|
|
50
|
-
Object.entries(
|
|
51
|
-
`${t}/${
|
|
52
|
-
|
|
50
|
+
Object.entries(i(r)).map(([s, u]) => [
|
|
51
|
+
`${t}/${s}`,
|
|
52
|
+
u
|
|
53
53
|
])
|
|
54
54
|
)
|
|
55
55
|
),
|
|
56
56
|
{}
|
|
57
57
|
),
|
|
58
|
-
reducer: (r = e,
|
|
59
|
-
const
|
|
60
|
-
if (!
|
|
61
|
-
const
|
|
62
|
-
return
|
|
58
|
+
reducer: (r = e, n) => {
|
|
59
|
+
const i = this.reducers[n.type];
|
|
60
|
+
if (!i) return r;
|
|
61
|
+
const s = "payload" in n ? n.payload : void 0;
|
|
62
|
+
return s && s.length ? i(r, ...s) : i(r);
|
|
63
63
|
},
|
|
64
64
|
select: this.select
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
class
|
|
68
|
+
class d {
|
|
69
69
|
constructor(e) {
|
|
70
|
-
this.name = e, this.creators =
|
|
70
|
+
this.name = e, this.creators = m(e);
|
|
71
71
|
}
|
|
72
72
|
blocks = {};
|
|
73
73
|
handlers = [];
|
|
74
74
|
creators;
|
|
75
75
|
select = {};
|
|
76
76
|
static init(e) {
|
|
77
|
-
return new
|
|
77
|
+
return new d(e);
|
|
78
78
|
}
|
|
79
79
|
block(e, t) {
|
|
80
|
-
return this.blocks[e] = t, this.creators[e] = t.actions, this.select[e] =
|
|
80
|
+
return this.blocks[e] = t, this.creators[e] = t.actions, this.select[e] = l(t.select, (r) => r[e]), this;
|
|
81
81
|
}
|
|
82
82
|
selectors(e) {
|
|
83
83
|
return Object.assign(this.select, e), this;
|
|
@@ -90,59 +90,68 @@ class a {
|
|
|
90
90
|
return {
|
|
91
91
|
actions: this.creators,
|
|
92
92
|
effects: (t) => {
|
|
93
|
-
const r = this.name,
|
|
94
|
-
(
|
|
95
|
-
|
|
93
|
+
const r = this.name, n = this.handlers.reduce(
|
|
94
|
+
(i, s) => Object.assign(
|
|
95
|
+
i,
|
|
96
96
|
Object.fromEntries(
|
|
97
|
-
Object.entries(
|
|
98
|
-
`${r}/${
|
|
97
|
+
Object.entries(s(t)).map(([u, o]) => [
|
|
98
|
+
`${r}/${u}`,
|
|
99
99
|
o
|
|
100
100
|
])
|
|
101
101
|
)
|
|
102
102
|
),
|
|
103
103
|
{}
|
|
104
104
|
);
|
|
105
|
-
return Object.values(this.blocks).forEach((
|
|
105
|
+
return Object.values(this.blocks).forEach((i) => Object.assign(n, i.effects(t))), n;
|
|
106
106
|
},
|
|
107
107
|
reducer: (t, r) => {
|
|
108
|
-
let
|
|
109
|
-
return e.forEach(([
|
|
110
|
-
const o = t?.[
|
|
111
|
-
|
|
112
|
-
}),
|
|
108
|
+
let n = t, i = !1;
|
|
109
|
+
return e.forEach(([s, u]) => {
|
|
110
|
+
const o = t?.[s], a = u(o, r);
|
|
111
|
+
a !== o && (i || (i = !0, n = { ...t }), n[s] = a);
|
|
112
|
+
}), n;
|
|
113
113
|
},
|
|
114
114
|
select: this.select
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
-
var
|
|
118
|
+
var p;
|
|
119
119
|
((c) => {
|
|
120
|
-
function e(s,
|
|
121
|
-
return
|
|
120
|
+
function e(s, u) {
|
|
121
|
+
return f.init(s, u);
|
|
122
122
|
}
|
|
123
123
|
c.builder = e;
|
|
124
124
|
function t(s) {
|
|
125
|
-
return
|
|
125
|
+
return d.init(s);
|
|
126
126
|
}
|
|
127
127
|
c.composition = t;
|
|
128
|
-
function r(s,
|
|
129
|
-
const
|
|
130
|
-
return () => (
|
|
131
|
-
|
|
128
|
+
function r(s, u) {
|
|
129
|
+
const o = s.effects(u);
|
|
130
|
+
return () => (a) => (h) => {
|
|
131
|
+
h && typeof h == "object" && "type" in h && b(o, h.type) && o[h.type](..."payload" in h ? h.payload : []), a(h);
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
134
|
c.middleware = r;
|
|
135
|
-
function
|
|
135
|
+
function n(s, u) {
|
|
136
136
|
return {
|
|
137
137
|
actions: s.actions,
|
|
138
138
|
reducer: s.reducer,
|
|
139
|
-
effects: (
|
|
139
|
+
effects: (o) => s.effects(u(o)),
|
|
140
140
|
select: s.select
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
|
-
c.mapContext =
|
|
144
|
-
|
|
143
|
+
c.mapContext = n;
|
|
144
|
+
function i(s, u) {
|
|
145
|
+
return {
|
|
146
|
+
actions: s.actions,
|
|
147
|
+
reducer: s.reducer,
|
|
148
|
+
effects: s.effects,
|
|
149
|
+
select: l(s.select, u)
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
c.mapSelectors = i;
|
|
153
|
+
})(p || (p = {}));
|
|
145
154
|
export {
|
|
146
|
-
|
|
155
|
+
p as ReduxBlock
|
|
147
156
|
};
|
|
148
157
|
//# 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\";\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
|
+
{"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 & { [action in 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 FindFunction<T> = T extends Function ? T : FindFunction<T[keyof T]>;\n type TakeFirst<T> = T extends [infer First, ...any] ? First : never;\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 export type TakeSelectorsState<Block extends AnyBlock> = TakeFirst<Parameters<FindFunction<TakeSelectors<Block>>>>;\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 (dependencies) 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 /**\n * Maps the selectors of a given block to a new state using a provided selector function.\n */\n export function mapSelectors<Block extends AnyBlock, NewState>(\n block: Block,\n selectState: (state: NewState) => TakeSelectorsState<Block>,\n ): ReduxBlock<\n TakeState<Block>,\n TakeCreators<Block>,\n TakeContext<Block>,\n LiftSelectors<TakeSelectors<Block>, NewState>\n > {\n return {\n actions: block.actions,\n reducer: block.reducer,\n effects: block.effects,\n select: lift(block.select, selectState),\n } as any;\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","mapSelectors"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "redux-sacala",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
|
+
"description": "A library for creating composable Redux blocks with state, actions, and effects",
|
|
4
5
|
"license": "MIT",
|
|
5
6
|
"repository": {
|
|
6
7
|
"type": "git",
|
|
@@ -11,10 +12,24 @@
|
|
|
11
12
|
},
|
|
12
13
|
"homepage": "https://github.com/monkin/redux-sacala#readme",
|
|
13
14
|
"type": "module",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"redux",
|
|
17
|
+
"state-management",
|
|
18
|
+
"composition",
|
|
19
|
+
"typescript",
|
|
20
|
+
"toolkit"
|
|
21
|
+
],
|
|
14
22
|
"author": {
|
|
15
23
|
"name": "Andrey Monkin",
|
|
16
24
|
"email": "monkin.andrey@gmail.com"
|
|
17
25
|
},
|
|
26
|
+
"files": [
|
|
27
|
+
"build"
|
|
28
|
+
],
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
},
|
|
18
33
|
"module": "build/redux-sacala.js",
|
|
19
34
|
"main": "build/redux-sacala.cjs",
|
|
20
35
|
"types": "build/redux-sacala.d.ts",
|
|
@@ -32,8 +47,8 @@
|
|
|
32
47
|
"devDependencies": {
|
|
33
48
|
"@eslint/js": "9.39.2",
|
|
34
49
|
"@reduxjs/toolkit": "2.11.2",
|
|
35
|
-
"@types/node": "25.0.
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
50
|
+
"@types/node": "25.0.9",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "8.53.0",
|
|
37
52
|
"@typescript-eslint/parser": "8.53.0",
|
|
38
53
|
"eslint": "9.39.2",
|
|
39
54
|
"eslint-config-prettier": "10.1.8",
|
|
@@ -46,9 +61,10 @@
|
|
|
46
61
|
},
|
|
47
62
|
"scripts": {
|
|
48
63
|
"build": "vite build",
|
|
49
|
-
"prepublishOnly": "npm test && npm run build",
|
|
64
|
+
"prepublishOnly": "npm run lint && npm test && npm run build",
|
|
50
65
|
"test": "vitest run",
|
|
51
66
|
"lint": "eslint .",
|
|
67
|
+
"lint:fix": "eslint . --fix",
|
|
52
68
|
"format": "prettier --write ."
|
|
53
69
|
}
|
|
54
70
|
}
|