duplicate actions

This commit is contained in:
Yanick Champoux 2023-03-06 15:07:24 -05:00
parent d1ed23de2c
commit 000ca9871a
5 changed files with 79 additions and 26 deletions

View File

@ -8,6 +8,7 @@ import {
import { configureStore, Reducer, createAction } from '@reduxjs/toolkit'; import { configureStore, Reducer, createAction } from '@reduxjs/toolkit';
import { withPayload } from './actions.js'; import { withPayload } from './actions.js';
import { AggregateActions, Dux, UnionToIntersection } from './types.js'; import { AggregateActions, Dux, UnionToIntersection } from './types.js';
import { buildActions } from './buildActions.js';
type ActionCreator = ReturnType<typeof createAction>; type ActionCreator = ReturnType<typeof createAction>;
@ -32,7 +33,9 @@ export default class Updux<
> = {}; > = {};
#subduxes: SUBDUXES; #subduxes: SUBDUXES;
#actions: Record<string, ActionCreator>; #name: string;
#actions: AggregateActions<T_LocalActions, SUBDUXES>;
constructor( constructor(
config: Partial<{ config: Partial<{
@ -45,13 +48,12 @@ export default class Updux<
this.#localInitial = config.initial ?? ({} as T_LocalState); this.#localInitial = config.initial ?? ({} as T_LocalState);
this.#localActions = config.actions ?? ({} as T_LocalActions); this.#localActions = config.actions ?? ({} as T_LocalActions);
this.#subduxes = config.subduxes ?? ({} as SUBDUXES); this.#subduxes = config.subduxes ?? ({} as SUBDUXES);
this.#actions = buildActions(this.#localActions, this.#subduxes);
} }
get actions(): AggregateActions<T_LocalActions, SUBDUXES> { get actions() {
return R.mergeAll([ return this.#actions;
this.#localActions,
...Object.values(this.#subduxes).map(R.pathOr(['actions'], {})),
]) as any;
} }
// TODO memoize? // TODO memoize?

View File

@ -7,24 +7,6 @@ import { Updux } from './Updux.js';
test('throw if double action', () => {
expect(
() =>
new Updux({
actions: {
foo: action('foo'),
},
subduxes: {
beta: {
actions: {
foo: action('foo'),
},
},
},
}),
).toThrow(/action 'foo' already defined/);
});
test('action definition shortcut', () => { test('action definition shortcut', () => {
const foo = new Updux({ const foo = new Updux({
actions: { actions: {

View File

@ -64,3 +64,39 @@ test('Updux config accepts actions', () => {
}, },
}); });
}); });
test('throw if double action', () => {
expect(
() =>
new Updux({
actions: {
foo: createAction('foo'),
},
subduxes: {
beta: {
actions: {
foo: createAction('foo'),
},
},
},
}),
).toThrow(/action 'foo' defined both locally and in subdux 'beta'/);
expect(
() =>
new Updux({
subduxes: {
gamma: {
actions: {
foo: createAction('foo'),
},
},
beta: {
actions: {
foo: createAction('foo'),
},
},
},
}),
).toThrow(/action 'foo' defined both in subduxes 'gamma' and 'beta'/);
});

View File

@ -3,7 +3,7 @@ import { createAction } from '@reduxjs/toolkit';
export { createAction } from '@reduxjs/toolkit'; export { createAction } from '@reduxjs/toolkit';
interface WithPayload { interface WithPayload {
(): <P>(input: P) => { payload: P }; <P>(): (input: P) => { payload: P };
<P, A extends any[]>(prepare: (...args: A) => P): (...input: A) => { <P, A extends any[]>(prepare: (...args: A) => P): (...input: A) => {
payload: P; payload: P;
}; };
@ -11,5 +11,5 @@ interface WithPayload {
export const withPayload: WithPayload = ((prepare) => export const withPayload: WithPayload = ((prepare) =>
(...input) => ({ (...input) => ({
payload: prepare ? prepare(...input) : input, payload: prepare ? prepare(...input) : input[0],
})) as any; })) as any;

33
src/buildActions.ts Normal file
View File

@ -0,0 +1,33 @@
import * as R from 'remeda';
export function buildActions(localActions, subduxes) {
let actions: Record<string, string> = {};
for (const slice in subduxes) {
const subdux = subduxes[slice].actions;
if (!subdux) continue;
for (const a in subdux) {
if (actions[a]) {
throw new Error(
`action '${a}' defined both in subduxes '${actions[a]}' and '${slice}'`,
);
}
actions[a] = slice;
}
}
for (const a in localActions) {
if (actions[a]) {
throw new Error(
`action '${a}' defined both locally and in subdux '${actions[a]}'`,
);
}
}
return R.mergeAll([
localActions,
...Object.values(subduxes).map(R.pathOr<any, any>(['actions'], {})),
]) as any;
}