diff --git a/src/buildMutations/index.ts b/src/buildMutations/index.ts index 472a1a0..c1b6420 100644 --- a/src/buildMutations/index.ts +++ b/src/buildMutations/index.ts @@ -12,7 +12,7 @@ type SubMutations = { } function buildMutations( - mutations :Dictionary = {}, + mutations :Dictionary = {}, subduxes = {} ) { // we have to differentiate the subduxes with '*' than those @@ -49,15 +49,26 @@ function buildMutations( nonGlobby.forEach(([slice, {mutations = {}, reducer = {}}]:any[]) => { Object.entries(mutations).forEach(([type, mutation]) => { - const localized = (payload = null, action :Action) => - u.updateIn(slice)((mutation as Mutation)(payload, action)); + const localized = (payload = null, action :Action) => { + console.log(slice); + + return u.updateIn(slice)((mutation as Mutation)(payload, action)); + } mergedMutations[type].push(localized); }); }); Object.entries(mutations).forEach(([type, mutation]) => { - mergedMutations[type].push(mutation); + if ( Array.isArray(mutation) ) { + if( mutation[1] ) { + mergedMutations[type] = [ + mutation[0] + ] + } + else mergedMutations[type].push( mutation[0] ); + } + else mergedMutations[type].push(mutation); }); return fp.mapValues(composeMutations)(mergedMutations); diff --git a/src/sink.test.ts b/src/sink.test.ts new file mode 100644 index 0000000..96ebe38 --- /dev/null +++ b/src/sink.test.ts @@ -0,0 +1,39 @@ +import Updux from './updux'; + +const foo = new Updux({ + initial: 0, + mutations: { + doIt: () => (state: number) => { + console.log(state); + return state + 1; + }, + }, +}); + +const bar = new Updux<{foo: number}>({ + subduxes: {foo}, + mutations: { + doIt: () => (state: any) => state, + }, +}); + +bar.addMutation( + foo.actions.doIt, + () => (state: any) => ({...state, bar: 'yay'}), + true, +); + +test('initial', () => { + expect(bar.initial).toEqual({foo: 0}); +}); + +test('foo alone', () => { + expect(foo.reducer(undefined, foo.actions.doIt())).toEqual(1); +}); + +test('sink mutations', () => { + expect(bar.reducer(undefined, bar.actions.doIt())).toEqual({ + foo: 0, + bar: 'yay', + }); +}); diff --git a/src/updux.ts b/src/updux.ts index a159b50..76a268a 100644 --- a/src/updux.ts +++ b/src/updux.ts @@ -42,12 +42,12 @@ export type Dux = Pick< >; /** - * `Updux` is a way to minimize and simplify the boilerplate associated with the - * creation of a `Redux` store. It takes a shorthand configuration - * object, and generates the appropriate reducer, actions, middleware, etc. - * In true `Redux`-like fashion, upduxes can be made of sub-upduxes (`subduxes` for short) for different slices of the root state. - * @typeparam S Store's state type. Defaults to `any`. - */ + * `Updux` is a way to minimize and simplify the boilerplate associated with the + * creation of a `Redux` store. It takes a shorthand configuration + * object, and generates the appropriate reducer, actions, middleware, etc. + * In true `Redux`-like fashion, upduxes can be made of sub-upduxes (`subduxes` for short) for different slices of the root state. + * @typeparam S Store's state type. Defaults to `any`. + */ export class Updux { subduxes: Dictionary; @@ -60,41 +60,41 @@ export class Updux { */ initial: S; -/** - * Function that can be provided to alter all local mutations of the updux - * (the mutations of subduxes are left untouched). - * - * Can be used, for example, for Immer integration: - * - * ``` - * import Updux from 'updux'; - * import { produce } from 'Immer'; - * - * const updux = new Updux({ - * initial: { counter: 0 }, - * groomMutations: mutation => (...args) => produce( mutation(...args) ), - * mutations: { - * add: (inc=1) => draft => draft.counter += inc - * } - * }); - * - * ``` - * - * Or perhaps for debugging: - * - * ``` - * import Updux from 'updux'; - * - * const updux = new Updux({ - * initial: { counter: 0 }, - * groomMutations: mutation => (...args) => state => { - * console.log( "got action ", args[1] ); - * return mutation(...args)(state); - * } - * }); - * - * ``` - */ + /** + * Function that can be provided to alter all local mutations of the updux + * (the mutations of subduxes are left untouched). + * + * Can be used, for example, for Immer integration: + * + * ``` + * import Updux from 'updux'; + * import { produce } from 'Immer'; + * + * const updux = new Updux({ + * initial: { counter: 0 }, + * groomMutations: mutation => (...args) => produce( mutation(...args) ), + * mutations: { + * add: (inc=1) => draft => draft.counter += inc + * } + * }); + * + * ``` + * + * Or perhaps for debugging: + * + * ``` + * import Updux from 'updux'; + * + * const updux = new Updux({ + * initial: { counter: 0 }, + * groomMutations: mutation => (...args) => state => { + * console.log( "got action ", args[1] ); + * return mutation(...args)(state); + * } + * }); + * + * ``` + */ groomMutations: (mutation: Mutation) => Mutation; @observable private localEffects: Dictionary< @@ -103,7 +103,9 @@ export class Updux { @observable private localActions: Dictionary; - @observable private localMutations: Dictionary>; + @observable private localMutations: Dictionary< + Mutation | [Mutation, boolean | undefined] + >; constructor(config: UpduxConfig = {}) { this.groomMutations = config.groomMutations || ((x: Mutation) => x); @@ -245,6 +247,8 @@ export class Updux { * Adds a mutation and its associated action to the updux. * If a local mutation was already associated to the action, * it will be replaced by the new one. + * @param isSink + * If `true`, disables the subduxes mutations for this action. * @example * ``` * updux.addMutation( add, inc => state => state + inc ); @@ -253,11 +257,13 @@ export class Updux { addMutation( creator: A, mutation: Mutation infer R ? R : never>, + isSink?: boolean, ) { this.localActions[creator.type] = creator; - this.localMutations[creator.type] = this.groomMutations( - mutation as any, - ) as Mutation; + this.localMutations[creator.type] = [ + this.groomMutations(mutation as any) as Mutation, + isSink, + ]; } }