danholibraryjs 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Classes/Events/EventEmitter.d.ts +24 -0
- package/dist/Classes/Events/EventEmitter.js +24 -0
- package/dist/Classes/store.d.ts +79 -0
- package/dist/Classes/store.js +85 -0
- package/docs/Classes.md +33 -0
- package/docs/Types.md +8 -0
- package/package.json +1 -1
- package/src/Classes/Events/EventEmitter.ts +24 -0
- package/src/Classes/store.ts +95 -0
|
@@ -4,6 +4,30 @@ import { BaseEvent, EventHandler } from '../../Types';
|
|
|
4
4
|
* @borrows EventCollection
|
|
5
5
|
* @borrows BaseEvent
|
|
6
6
|
* @borrows EventHandler
|
|
7
|
+
*
|
|
8
|
+
* @example ```ts
|
|
9
|
+
* import { EventEmitter } from 'danholibraryjs';
|
|
10
|
+
*
|
|
11
|
+
* type EventTypes = {
|
|
12
|
+
* create: [username: string, password: string],
|
|
13
|
+
* update: [id: string, user: User],
|
|
14
|
+
* delete: [id: string, reason?: string],
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* const emitter = new EventEmitter<EventTypes>(new Map([
|
|
18
|
+
* ['create', (username, password) => {
|
|
19
|
+
* return { username, password };
|
|
20
|
+
* }],
|
|
21
|
+
* ['update', (id, user) => {
|
|
22
|
+
* return { id, ...user };
|
|
23
|
+
* }]
|
|
24
|
+
* ]));
|
|
25
|
+
*
|
|
26
|
+
* const onDelete = (id: string, reason?: string) => console.log(`User ${id} was deleted because ${reason}`);
|
|
27
|
+
* emitter.on('delete', onDelete);
|
|
28
|
+
* emitter.emit('delete', '1', 'No longer needed');
|
|
29
|
+
* emitter.off('delete', onDelete);
|
|
30
|
+
* ```
|
|
7
31
|
*/
|
|
8
32
|
export declare class EventEmitter<Events extends BaseEvent<string, Array<any>>> {
|
|
9
33
|
/**@param events Map<name: string, handlers: EventHandler[]>*/
|
|
@@ -10,6 +10,30 @@ const EventCollection_1 = __importDefault(require("./EventCollection"));
|
|
|
10
10
|
* @borrows EventCollection
|
|
11
11
|
* @borrows BaseEvent
|
|
12
12
|
* @borrows EventHandler
|
|
13
|
+
*
|
|
14
|
+
* @example ```ts
|
|
15
|
+
* import { EventEmitter } from 'danholibraryjs';
|
|
16
|
+
*
|
|
17
|
+
* type EventTypes = {
|
|
18
|
+
* create: [username: string, password: string],
|
|
19
|
+
* update: [id: string, user: User],
|
|
20
|
+
* delete: [id: string, reason?: string],
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* const emitter = new EventEmitter<EventTypes>(new Map([
|
|
24
|
+
* ['create', (username, password) => {
|
|
25
|
+
* return { username, password };
|
|
26
|
+
* }],
|
|
27
|
+
* ['update', (id, user) => {
|
|
28
|
+
* return { id, ...user };
|
|
29
|
+
* }]
|
|
30
|
+
* ]));
|
|
31
|
+
*
|
|
32
|
+
* const onDelete = (id: string, reason?: string) => console.log(`User ${id} was deleted because ${reason}`);
|
|
33
|
+
* emitter.on('delete', onDelete);
|
|
34
|
+
* emitter.emit('delete', '1', 'No longer needed');
|
|
35
|
+
* emitter.off('delete', onDelete);
|
|
36
|
+
* ```
|
|
13
37
|
*/
|
|
14
38
|
class EventEmitter {
|
|
15
39
|
/**@param events Map<name: string, handlers: EventHandler[]>*/
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Arrayable } from "../Types";
|
|
2
|
+
import { EventEmitter } from "./Events";
|
|
3
|
+
export declare type Reducer<State, Types extends Record<string, any[]>, Action extends keyof Types> = (state: State, ...args: Types[Action]) => State;
|
|
4
|
+
/**
|
|
5
|
+
* EventEmitter, but it stores state and handles state change with reducers
|
|
6
|
+
*
|
|
7
|
+
* @Initialization Actions & initial state must be defined in type parameters. InitialState must be provided in constructor, whereas reducer is optional.
|
|
8
|
+
* The ActionType must have properties as strings and values as arrays.
|
|
9
|
+
*
|
|
10
|
+
* @HandlingActions Reducers can be added through constructor or using Store.on('action', reducer) or Store.once('action', reducer).
|
|
11
|
+
* Every state change must return the next state, apart from 'stateChange', which returns void/any
|
|
12
|
+
* Emit/Dispatch an action using Store.dispatch('action', ...args), ...args being the parameters from the ActionType.
|
|
13
|
+
* Store.emit should NOT be used, as it doesn't update the Store's state.
|
|
14
|
+
*
|
|
15
|
+
* Reducer functions can be removed using Store.off('action', reducer);
|
|
16
|
+
*
|
|
17
|
+
* @borrows EventEmitter
|
|
18
|
+
* @borrows Arrayable
|
|
19
|
+
*
|
|
20
|
+
* @example ```ts
|
|
21
|
+
* import { Store } from 'danholibraryjs';
|
|
22
|
+
*
|
|
23
|
+
* type Todo = {
|
|
24
|
+
* id: string,
|
|
25
|
+
* text: string,
|
|
26
|
+
* completed: boolean
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* type TodoActions = {
|
|
30
|
+
* create: [text: string],
|
|
31
|
+
* update: [id: string, text: string],
|
|
32
|
+
* toggleComplete: [id: string, force?: boolean],
|
|
33
|
+
* delete: [id: string],
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* const store = new Store<Array<Todo>, TodoActions>(new Array<Todo>(), new Map([
|
|
37
|
+
* create: (state, text) => {
|
|
38
|
+
* return [...state, {
|
|
39
|
+
* id: Math.random().toString(),
|
|
40
|
+
* text,
|
|
41
|
+
* completed: false
|
|
42
|
+
* }];
|
|
43
|
+
* },
|
|
44
|
+
* toggleComplete: (state, id, force) => {
|
|
45
|
+
* const todo = state.find(todo => todo.id === id);
|
|
46
|
+
* if (!todo) return state;
|
|
47
|
+
*
|
|
48
|
+
* return state.map(todo => (
|
|
49
|
+
* todo.id === id ? {
|
|
50
|
+
* ...todo,
|
|
51
|
+
* completed: force === undefined ? !todo.completed : force
|
|
52
|
+
* } : todo
|
|
53
|
+
* ));
|
|
54
|
+
* }
|
|
55
|
+
* ]));
|
|
56
|
+
*
|
|
57
|
+
* store.on('delete', (state, id) => {
|
|
58
|
+
* return state.filter(todo => todo.id !== id);
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* store.on('stateChange', (prevState, currentState) => console.log('State change', prevState, currentState));
|
|
62
|
+
*
|
|
63
|
+
* store.dispatch('create', 'Make store!');
|
|
64
|
+
*
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare class Store<State extends object, ActionTypes extends Record<string, any[]>, Actions extends {
|
|
68
|
+
[Action in keyof ActionTypes]: Array<Reducer<State, ActionTypes, Action>>;
|
|
69
|
+
} = {
|
|
70
|
+
[Action in keyof ActionTypes]: Array<Reducer<State, ActionTypes, Action>>;
|
|
71
|
+
}> extends EventEmitter<Record<keyof Actions, ActionTypes[keyof ActionTypes]> & Record<'stateChange', [previous: State, current: State]>> {
|
|
72
|
+
constructor(state: State, actions?: {
|
|
73
|
+
[Action in keyof ActionTypes]?: Arrayable<Reducer<State, ActionTypes, Action>>;
|
|
74
|
+
});
|
|
75
|
+
private _state;
|
|
76
|
+
get state(): State;
|
|
77
|
+
dispatch<Action extends keyof ActionTypes>(action: Action, ...args: ActionTypes[Action]): State;
|
|
78
|
+
}
|
|
79
|
+
export default Store;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Store = void 0;
|
|
4
|
+
const Events_1 = require("./Events");
|
|
5
|
+
/**
|
|
6
|
+
* EventEmitter, but it stores state and handles state change with reducers
|
|
7
|
+
*
|
|
8
|
+
* @Initialization Actions & initial state must be defined in type parameters. InitialState must be provided in constructor, whereas reducer is optional.
|
|
9
|
+
* The ActionType must have properties as strings and values as arrays.
|
|
10
|
+
*
|
|
11
|
+
* @HandlingActions Reducers can be added through constructor or using Store.on('action', reducer) or Store.once('action', reducer).
|
|
12
|
+
* Every state change must return the next state, apart from 'stateChange', which returns void/any
|
|
13
|
+
* Emit/Dispatch an action using Store.dispatch('action', ...args), ...args being the parameters from the ActionType.
|
|
14
|
+
* Store.emit should NOT be used, as it doesn't update the Store's state.
|
|
15
|
+
*
|
|
16
|
+
* Reducer functions can be removed using Store.off('action', reducer);
|
|
17
|
+
*
|
|
18
|
+
* @borrows EventEmitter
|
|
19
|
+
* @borrows Arrayable
|
|
20
|
+
*
|
|
21
|
+
* @example ```ts
|
|
22
|
+
* import { Store } from 'danholibraryjs';
|
|
23
|
+
*
|
|
24
|
+
* type Todo = {
|
|
25
|
+
* id: string,
|
|
26
|
+
* text: string,
|
|
27
|
+
* completed: boolean
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* type TodoActions = {
|
|
31
|
+
* create: [text: string],
|
|
32
|
+
* update: [id: string, text: string],
|
|
33
|
+
* toggleComplete: [id: string, force?: boolean],
|
|
34
|
+
* delete: [id: string],
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* const store = new Store<Array<Todo>, TodoActions>(new Array<Todo>(), new Map([
|
|
38
|
+
* create: (state, text) => {
|
|
39
|
+
* return [...state, {
|
|
40
|
+
* id: Math.random().toString(),
|
|
41
|
+
* text,
|
|
42
|
+
* completed: false
|
|
43
|
+
* }];
|
|
44
|
+
* },
|
|
45
|
+
* toggleComplete: (state, id, force) => {
|
|
46
|
+
* const todo = state.find(todo => todo.id === id);
|
|
47
|
+
* if (!todo) return state;
|
|
48
|
+
*
|
|
49
|
+
* return state.map(todo => (
|
|
50
|
+
* todo.id === id ? {
|
|
51
|
+
* ...todo,
|
|
52
|
+
* completed: force === undefined ? !todo.completed : force
|
|
53
|
+
* } : todo
|
|
54
|
+
* ));
|
|
55
|
+
* }
|
|
56
|
+
* ]));
|
|
57
|
+
*
|
|
58
|
+
* store.on('delete', (state, id) => {
|
|
59
|
+
* return state.filter(todo => todo.id !== id);
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* store.on('stateChange', (prevState, currentState) => console.log('State change', prevState, currentState));
|
|
63
|
+
*
|
|
64
|
+
* store.dispatch('create', 'Make store!');
|
|
65
|
+
*
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
class Store extends Events_1.EventEmitter {
|
|
69
|
+
constructor(state, actions = {}) {
|
|
70
|
+
super(new Map(...Object.entries(actions).map(([action, reducers]) => [action, reducers])));
|
|
71
|
+
this._state = state;
|
|
72
|
+
}
|
|
73
|
+
_state;
|
|
74
|
+
get state() {
|
|
75
|
+
return this._state;
|
|
76
|
+
}
|
|
77
|
+
dispatch(action, ...args) {
|
|
78
|
+
const previous = { ...this._state };
|
|
79
|
+
this._state = super.emit(action, ...args).reduce((state, returned) => ({ ...state, ...returned }), this.state);
|
|
80
|
+
super.emit('stateChange', ...[previous, this.state]);
|
|
81
|
+
return this.state;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.Store = Store;
|
|
85
|
+
exports.default = Store;
|
package/docs/Classes.md
CHANGED
|
@@ -2,6 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
## Classes
|
|
4
4
|
|
|
5
|
+
```ts
|
|
6
|
+
/**
|
|
7
|
+
* EventEmitter, but it stores state and handles state change with reducers
|
|
8
|
+
*
|
|
9
|
+
* @Initialization Actions & initial state must be defined in type parameters. InitialState must be provided in constructor, whereas reducer is optional.
|
|
10
|
+
* The ActionType must have properties as strings and values as arrays.
|
|
11
|
+
*
|
|
12
|
+
* @HandlingActions Reducers can be added through constructor or using Store.on('action', reducer) or Store.once('action', reducer).
|
|
13
|
+
* Every state change must return the next state, apart from 'stateChange', which returns void/any
|
|
14
|
+
* Emit/Dispatch an action using Store.dispatch('action', ...args), ...args being the parameters from the ActionType.
|
|
15
|
+
* Store.emit should NOT be used, as it doesn't update the Store's state.
|
|
16
|
+
*
|
|
17
|
+
* Reducer functions can be removed using Store.off('action', reducer);
|
|
18
|
+
*
|
|
19
|
+
* @borrows EventEmitter
|
|
20
|
+
* @borrows Arrayable
|
|
21
|
+
*/
|
|
22
|
+
class Store<
|
|
23
|
+
State extends object,
|
|
24
|
+
ActionTypes extends Record<string, any[]>,
|
|
25
|
+
Actions extends
|
|
26
|
+
{ [Action in keyof ActionTypes]: Array<Reducer<State, ActionTypes, Action>> } =
|
|
27
|
+
{ [Action in keyof ActionTypes]: Array<Reducer<State, ActionTypes, Action>> }
|
|
28
|
+
> extends EventEmitter<Record<keyof Actions, ActionTypes[keyof ActionTypes]> & Record<'stateChange', [previous: State, current: State]>> {
|
|
29
|
+
constructor(state: State, actions: { [Action in keyof ActionTypes]?: Arrayable<Reducer<State, ActionTypes, Action>> } = {});
|
|
30
|
+
|
|
31
|
+
private _state: State;
|
|
32
|
+
public get state(): State;
|
|
33
|
+
|
|
34
|
+
public dispatch<Action extends keyof ActionTypes>(action: Action, ...args: ActionTypes[Action]): State;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
5
38
|
### Events
|
|
6
39
|
|
|
7
40
|
```ts
|
package/docs/Types.md
CHANGED
|
@@ -127,3 +127,11 @@ export type TransformTypes<From, BaseType, NewType> = Record<keyof {
|
|
|
127
127
|
[Key in keyof From as From[Key] extends BaseType ? Key : never]: Key
|
|
128
128
|
}, NewType>
|
|
129
129
|
```
|
|
130
|
+
|
|
131
|
+
### Store
|
|
132
|
+
```ts
|
|
133
|
+
/**
|
|
134
|
+
* Reducer function to map wanted parameters when using @see Store.on(action, reducer);
|
|
135
|
+
*/
|
|
136
|
+
export type Reducer<State, Types extends Record<string, any[]>, Action extends keyof Types> = (state: State, ...args: Types[Action]) => State
|
|
137
|
+
```
|
package/package.json
CHANGED
|
@@ -6,6 +6,30 @@ import { BaseEvent, EventHandler } from '../../Types';
|
|
|
6
6
|
* @borrows EventCollection
|
|
7
7
|
* @borrows BaseEvent
|
|
8
8
|
* @borrows EventHandler
|
|
9
|
+
*
|
|
10
|
+
* @example ```ts
|
|
11
|
+
* import { EventEmitter } from 'danholibraryjs';
|
|
12
|
+
*
|
|
13
|
+
* type EventTypes = {
|
|
14
|
+
* create: [username: string, password: string],
|
|
15
|
+
* update: [id: string, user: User],
|
|
16
|
+
* delete: [id: string, reason?: string],
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* const emitter = new EventEmitter<EventTypes>(new Map([
|
|
20
|
+
* ['create', (username, password) => {
|
|
21
|
+
* return { username, password };
|
|
22
|
+
* }],
|
|
23
|
+
* ['update', (id, user) => {
|
|
24
|
+
* return { id, ...user };
|
|
25
|
+
* }]
|
|
26
|
+
* ]));
|
|
27
|
+
*
|
|
28
|
+
* const onDelete = (id: string, reason?: string) => console.log(`User ${id} was deleted because ${reason}`);
|
|
29
|
+
* emitter.on('delete', onDelete);
|
|
30
|
+
* emitter.emit('delete', '1', 'No longer needed');
|
|
31
|
+
* emitter.off('delete', onDelete);
|
|
32
|
+
* ```
|
|
9
33
|
*/
|
|
10
34
|
export class EventEmitter<Events extends BaseEvent<string, Array<any>>> {
|
|
11
35
|
/**@param events Map<name: string, handlers: EventHandler[]>*/
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Arrayable } from "../Types";
|
|
2
|
+
import { EventEmitter } from "./Events";
|
|
3
|
+
|
|
4
|
+
export type Reducer<State, Types extends Record<string, any[]>, Action extends keyof Types> = (state: State, ...args: Types[Action]) => State
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* EventEmitter, but it stores state and handles state change with reducers
|
|
8
|
+
*
|
|
9
|
+
* @Initialization Actions & initial state must be defined in type parameters. InitialState must be provided in constructor, whereas reducer is optional.
|
|
10
|
+
* The ActionType must have properties as strings and values as arrays.
|
|
11
|
+
*
|
|
12
|
+
* @HandlingActions Reducers can be added through constructor or using Store.on('action', reducer) or Store.once('action', reducer).
|
|
13
|
+
* Every state change must return the next state, apart from 'stateChange', which returns void/any
|
|
14
|
+
* Emit/Dispatch an action using Store.dispatch('action', ...args), ...args being the parameters from the ActionType.
|
|
15
|
+
* Store.emit should NOT be used, as it doesn't update the Store's state.
|
|
16
|
+
*
|
|
17
|
+
* Reducer functions can be removed using Store.off('action', reducer);
|
|
18
|
+
*
|
|
19
|
+
* @borrows EventEmitter
|
|
20
|
+
* @borrows Arrayable
|
|
21
|
+
*
|
|
22
|
+
* @example ```ts
|
|
23
|
+
* import { Store } from 'danholibraryjs';
|
|
24
|
+
*
|
|
25
|
+
* type Todo = {
|
|
26
|
+
* id: string,
|
|
27
|
+
* text: string,
|
|
28
|
+
* completed: boolean
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* type TodoActions = {
|
|
32
|
+
* create: [text: string],
|
|
33
|
+
* update: [id: string, text: string],
|
|
34
|
+
* toggleComplete: [id: string, force?: boolean],
|
|
35
|
+
* delete: [id: string],
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* const store = new Store<Array<Todo>, TodoActions>(new Array<Todo>(), new Map([
|
|
39
|
+
* create: (state, text) => {
|
|
40
|
+
* return [...state, {
|
|
41
|
+
* id: Math.random().toString(),
|
|
42
|
+
* text,
|
|
43
|
+
* completed: false
|
|
44
|
+
* }];
|
|
45
|
+
* },
|
|
46
|
+
* toggleComplete: (state, id, force) => {
|
|
47
|
+
* const todo = state.find(todo => todo.id === id);
|
|
48
|
+
* if (!todo) return state;
|
|
49
|
+
*
|
|
50
|
+
* return state.map(todo => (
|
|
51
|
+
* todo.id === id ? {
|
|
52
|
+
* ...todo,
|
|
53
|
+
* completed: force === undefined ? !todo.completed : force
|
|
54
|
+
* } : todo
|
|
55
|
+
* ));
|
|
56
|
+
* }
|
|
57
|
+
* ]));
|
|
58
|
+
*
|
|
59
|
+
* store.on('delete', (state, id) => {
|
|
60
|
+
* return state.filter(todo => todo.id !== id);
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* store.on('stateChange', (prevState, currentState) => console.log('State change', prevState, currentState));
|
|
64
|
+
*
|
|
65
|
+
* store.dispatch('create', 'Make store!');
|
|
66
|
+
*
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export class Store<
|
|
70
|
+
State extends object,
|
|
71
|
+
ActionTypes extends Record<string, any[]>,
|
|
72
|
+
Actions extends
|
|
73
|
+
{ [Action in keyof ActionTypes]: Array<Reducer<State, ActionTypes, Action>> } =
|
|
74
|
+
{ [Action in keyof ActionTypes]: Array<Reducer<State, ActionTypes, Action>> }
|
|
75
|
+
> extends EventEmitter<Record<keyof Actions, ActionTypes[keyof ActionTypes]> & Record<'stateChange', [previous: State, current: State]>> {
|
|
76
|
+
constructor(state: State, actions: { [Action in keyof ActionTypes]?: Arrayable<Reducer<State, ActionTypes, Action>> } = {}) {
|
|
77
|
+
super(new Map(...Object.entries(actions).map(([action, reducers]) => [action, reducers as any])));
|
|
78
|
+
|
|
79
|
+
this._state = state;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private _state: State;
|
|
83
|
+
public get state(): State {
|
|
84
|
+
return this._state;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public dispatch<Action extends keyof ActionTypes>(action: Action, ...args: ActionTypes[Action]): State {
|
|
88
|
+
const previous = { ...this._state };
|
|
89
|
+
this._state = super.emit<State, Action>(action, ...args as any).reduce((state, returned) => ({ ...state, ...returned }), this.state);
|
|
90
|
+
|
|
91
|
+
super.emit<void, 'stateChange'>('stateChange', ...[previous, this.state] as any);
|
|
92
|
+
return this.state;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export default Store;
|