initial reducer
This commit is contained in:
parent
93533a739f
commit
4c28a9ad05
@ -41,11 +41,13 @@ type ResolveActions<
|
|||||||
: never;
|
: never;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Mutation<A extends ActionCreator<any> = ActionCreator<any>, S = any> = (
|
export type Mutation<
|
||||||
state: S,
|
A extends ActionCreator<any> = ActionCreator<any>,
|
||||||
|
S = any,
|
||||||
|
> = (
|
||||||
payload: ReturnType<A>['payload'],
|
payload: ReturnType<A>['payload'],
|
||||||
action: ReturnType<A>,
|
action: ReturnType<A>,
|
||||||
) => S | void;
|
) => (state: S) => S | void;
|
||||||
|
|
||||||
export default class Updux<
|
export default class Updux<
|
||||||
T_LocalState = Record<any, any>,
|
T_LocalState = Record<any, any>,
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import { test, expect } from 'vitest';
|
|
||||||
|
|
||||||
import { Updux } from './Updux.js';
|
|
||||||
|
|
||||||
test('basic reducer', () => {
|
|
||||||
const dux = new Updux({ initial: { a: 3 } });
|
|
||||||
|
|
||||||
expect(dux.reducer).toBeTypeOf('function');
|
|
||||||
|
|
||||||
expect(dux.reducer({ a: 1 }, { type: 'foo' })).toMatchObject({ a: 1 }); // noop
|
|
||||||
});
|
|
||||||
|
|
||||||
test('basic upreducer', () => {
|
|
||||||
const dux = new Updux({ initial: { a: 3 } });
|
|
||||||
|
|
||||||
expect(dux.upreducer).toBeTypeOf('function');
|
|
||||||
|
|
||||||
expect(dux.upreducer({ type: 'foo' })({ a: 1 })).toMatchObject({ a: 1 }); // noop
|
|
||||||
});
|
|
31
src/reducer.test.ts
Normal file
31
src/reducer.test.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { test, expect } from 'vitest';
|
||||||
|
|
||||||
|
import { buildReducer } from './reducer.js';
|
||||||
|
import Updux from './Updux.js';
|
||||||
|
|
||||||
|
test('buildReducer, initial state', () => {
|
||||||
|
const reducer = buildReducer({ a: 1 });
|
||||||
|
|
||||||
|
expect(reducer(undefined, { type: 'foo' })).toEqual({ a: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('buildReducer, mutation', () => {
|
||||||
|
const reducer = buildReducer(1, [
|
||||||
|
{
|
||||||
|
matcher: ({ type }) => type === 'inc',
|
||||||
|
mutation: () => (state) => state + 1,
|
||||||
|
terminal: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(reducer(undefined, { type: 'foo' })).toEqual(1);
|
||||||
|
expect(reducer(undefined, { type: 'inc' })).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.todo('basic reducer', () => {
|
||||||
|
const dux = new Updux({ initial: { a: 3 } });
|
||||||
|
|
||||||
|
expect(dux.reducer).toBeTypeOf('function');
|
||||||
|
|
||||||
|
expect(dux.reducer({ a: 1 }, { type: 'foo' })).toMatchObject({ a: 1 }); // noop
|
||||||
|
});
|
79
src/reducer.ts
Normal file
79
src/reducer.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { Action, ActionCreator, createAction } from '@reduxjs/toolkit';
|
||||||
|
import { BaseActionCreator } from '@reduxjs/toolkit/dist/createAction.js';
|
||||||
|
import * as R from 'remeda';
|
||||||
|
import { Dux } from './types.js';
|
||||||
|
import { Mutation } from './Updux.js';
|
||||||
|
|
||||||
|
type MutationCase = {
|
||||||
|
matcher: (action: Action) => boolean;
|
||||||
|
mutation: Mutation;
|
||||||
|
terminal: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildReducer(
|
||||||
|
initialState: any,
|
||||||
|
mutations: MutationCase[] = [],
|
||||||
|
subduxes: Record<string, Dux> = {},
|
||||||
|
) {
|
||||||
|
// const subReducers =
|
||||||
|
// ? R.mapValues(subduxes, R.prop('reducer'));
|
||||||
|
|
||||||
|
// TODO matcherMutation
|
||||||
|
// TODO defaultMutation
|
||||||
|
|
||||||
|
const reducer = (state = initialState, action: Action) => {
|
||||||
|
if (!action?.type)
|
||||||
|
throw new Error('upreducer called with a bad action');
|
||||||
|
|
||||||
|
let terminal = false;
|
||||||
|
let didSomething = false;
|
||||||
|
|
||||||
|
const foo = createAction('foo');
|
||||||
|
|
||||||
|
const localMutation = mutations.find(({ matcher }) => matcher(action));
|
||||||
|
|
||||||
|
if (localMutation) {
|
||||||
|
didSomething = true;
|
||||||
|
if (localMutation.terminal) terminal = true;
|
||||||
|
|
||||||
|
// TODO wrap mutations in immer
|
||||||
|
state = localMutation.mutation(
|
||||||
|
(action as any).payload,
|
||||||
|
action,
|
||||||
|
)(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO defaultMutation
|
||||||
|
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
|
||||||
|
return reducer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
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;
|
||||||
|
*/
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user