diff --git a/src/Updux.ts b/src/Updux.ts index b9358a9..d35b81c 100644 --- a/src/Updux.ts +++ b/src/Updux.ts @@ -116,6 +116,7 @@ export default class Updux< this.initial, this.#localMutations, this.#defaultMutation, + this.#subduxes, ) as any as ( state: undefined | typeof this.initial, action: Action, diff --git a/src/buildUpreducer.todo b/src/buildUpreducer.todo deleted file mode 100644 index 39672ac..0000000 --- a/src/buildUpreducer.todo +++ /dev/null @@ -1,45 +0,0 @@ -import u from 'updeep'; -import { mapValues } from 'lodash-es'; - -export function buildUpreducer( - initial, - mutations, - subduxes = {}, - wrapper = undefined, -) { - const subReducers = - Object.keys(subduxes).length > 0 - ? mapValues(subduxes, ({ upreducer }) => upreducer) - : null; - - const upreducer = (action) => (state) => { - if (!action?.type) - throw new Error('upreducer called with a bad action'); - - let newState = state ?? initial; - - if (subReducers) { - if (subduxes['*']) { - newState = u.updateIn( - '*', - subduxes['*'].upreducer(action), - newState, - ); - } else { - const update = mapValues(subReducers, (upReducer) => - upReducer(action), - ); - - newState = u(update, newState); - } - } - - const a = mutations[action.type] || mutations['+']; - - if (!a) return newState; - - return a(action.payload, action)(newState); - }; - - return wrapper ? wrapper(upreducer) : upreducer; -} diff --git a/src/mutations.test.todo b/src/mutations.test.todo deleted file mode 100644 index 7e72b34..0000000 --- a/src/mutations.test.todo +++ /dev/null @@ -1,48 +0,0 @@ -import schema from 'json-schema-shorthand'; -import u from 'updeep'; - -import { action } from './actions.js'; - -import { Updux, dux } from './Updux.js'; - -test('mutation of a subdux', async () => { - const bar = dux({ - actions: { - baz: null, - }, - }); - bar.setMutation('baz', () => (state) => ({ ...state, x: 1 })); - - const foo = dux({ - subduxes: { bar }, - }); - - const store = foo.createStore(); - store.dispatch.baz(); - expect(store.getState()).toMatchObject({ bar: { x: 1 } }); -}); - -test('strings and generators', async () => { - const actionA = action('a'); - - const foo = dux({ - actions: { - b: null, - a: actionA, - }, - }); - - // as a string and defined - expect(() => foo.setMutation('a', () => {})).not.toThrow(); - - // as a generator and defined - expect(() => foo.setMutation(actionA, () => {})).not.toThrow(); - - // as a string, not defined - expect(() => foo.setMutation('c', () => {})).toThrow(); - - foo.setMutation(action('d'), () => {}); - - expect(foo.actions.d).toBeTypeOf('function'); -}); - diff --git a/src/mutations.test.ts b/src/mutations.test.ts index 09c3000..5858b63 100644 --- a/src/mutations.test.ts +++ b/src/mutations.test.ts @@ -1,6 +1,6 @@ import { test, expect } from 'vitest'; -import Updux from './index.js'; +import Updux, { createAction } from './index.js'; test('set a mutation', () => { const dux = new Updux({ @@ -53,3 +53,28 @@ test('default mutation', () => { expect(dux.reducer(undefined, { type: 'foo' })).toEqual('got it'); expect(dux.reducer(undefined, { type: 'bar' })).toEqual('bar'); }); + +test('mutation of a subdux', () => { + const baz = createAction('baz'); + const noop = createAction('noop'); + const stopit = createAction('stopit'); + + const bar = new Updux({ + initial: 0, + actions: { + baz, + stopit, + }, + }); + bar.addMutation(baz, () => () => 1); + bar.addMutation(stopit, () => () => 2); + + const foo = new Updux({ + subduxes: { bar }, + }); + foo.addMutation(stopit, () => (state) => state, true); + + expect(foo.reducer(undefined, noop())).toHaveProperty('bar', 0); + expect(foo.reducer(undefined, baz())).toHaveProperty('bar', 1); + expect(foo.reducer(undefined, stopit())).toHaveProperty('bar', 0); +}); diff --git a/src/reducer.ts b/src/reducer.ts index 12b431c..9ca2571 100644 --- a/src/reducer.ts +++ b/src/reducer.ts @@ -16,8 +16,7 @@ export function buildReducer( defaultMutation?: Omit, subduxes: Record = {}, ) { - // const subReducers = - // ? R.mapValues(subduxes, R.prop('reducer')); + const subReducers = R.mapValues(subduxes, R.prop('reducer')); // TODO matcherMutation // TODO defaultMutation @@ -48,6 +47,16 @@ export function buildReducer( )(state); } + if (!terminal && Object.keys(subduxes).length > 0) { + // subduxes + state = R.merge( + state, + R.mapValues(subReducers, (reducer, slice) => + (reducer as any)(state[slice], action), + ), + ); + } + return state; };