This repository was archived by the owner on Apr 3, 2022. It is now read-only.
forked from ngrx/example-app
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathreducer-enum.ts
73 lines (63 loc) · 2.47 KB
/
reducer-enum.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import {Enum, EnumValue} from 'ts-enums';
import {ActionEnumValue, TypedAction} from '../actions/action-enum';
import {isArray} from 'rxjs/util/isArray';
import {ActionReducer} from '@ngrx/store';
export type ReducerFunction<S, T> = (state: S, action: TypedAction<T>) => S;
function extractDescriptions<T>(action: ActionEnumValue<T> | ActionEnumValue<T>[]): string {
if (isArray(action)) {
return action.map((value: ActionEnumValue<T>) => value.fullName).join(';');
} else {
return action.fullName;
}
}
export abstract class ReducerEnumValue<S, T> extends EnumValue {
readonly actions: ActionEnumValue<T>[];
constructor(action: ActionEnumValue<T> | ActionEnumValue<T>[],
private _reduce: ReducerFunction<S, T>) {
// if there's only one action value, use its fullName. Otherwise, concat
// the fullName of all the action values.
super(extractDescriptions(action));
// accumulate the action types to check against when reducing
this.actions = isArray(action) ? action : [action];
}
get reduce(): ReducerFunction<S, T> {
return this._reduce;
}
}
export abstract class ReducerEnum<V extends ReducerEnumValue<S, any>, S> extends Enum<V> {
constructor(private initialState: S) {
super();
}
protected initEnum(name: string): void {
super.initEnum(name);
// ensure that each enum is used at most once per reducer
const allActions: Set<ActionEnumValue<any>> = new Set();
this.values.forEach((value: V) => {
value.actions.forEach((action: ActionEnumValue<any>) => {
if (allActions.has(action)) {
const message =
`Action ${action.fullName} is used multiple times in ${name} - this is not allowed`;
throw new Error(message);
} else {
allActions.add(action);
}
});
});
}
reducer<T>(): ActionReducer<S> {
// Find the appropriate enum instance for the action, if any, and return
// its reducer.
return (state: S = this.initialState, action: TypedAction<T>): S => {
const reducerInstance: V = this.fromAction(action);
return reducerInstance ? reducerInstance.reduce(state, action) : state;
};
}
private fromAction(action: TypedAction<any>): V {
// look through all of the reducer enum instances to find one that has the
// current action in its array of actions
return this.values.find((value: V) => {
return value.actions.some((type: ActionEnumValue<any>) =>
type.description === action.type);
});
}
}