@push.rocks/smartstate 2.0.6

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.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * autocreated commitinfo by @pushrocks/commitinfo
3
+ */
4
+ export declare const commitinfo: {
5
+ name: string;
6
+ version: string;
7
+ description: string;
8
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * autocreated commitinfo by @pushrocks/commitinfo
3
+ */
4
+ export const commitinfo = {
5
+ name: '@pushrocks/smartstate',
6
+ version: '2.0.6',
7
+ description: 'a package that handles state in a good way'
8
+ };
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDRDQUE0QztDQUMxRCxDQUFBIn0=
@@ -0,0 +1,3 @@
1
+ export * from './smartstate.classes.smartstate.js';
2
+ export * from './smartstate.classes.statepart.js';
3
+ export * from './smartstate.classes.stateaction.js';
@@ -0,0 +1,4 @@
1
+ export * from './smartstate.classes.smartstate.js';
2
+ export * from './smartstate.classes.statepart.js';
3
+ export * from './smartstate.classes.stateaction.js';
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLG9DQUFvQyxDQUFDO0FBQ25ELGNBQWMsbUNBQW1DLENBQUM7QUFDbEQsY0FBYyxxQ0FBcUMsQ0FBQyJ9
@@ -0,0 +1,26 @@
1
+ import { StatePart } from './smartstate.classes.statepart.js';
2
+ /**
3
+ * Smartstate takes care of providing state
4
+ */
5
+ export declare class Smartstate<StatePartNameType> {
6
+ statePartMap: {
7
+ [key: string]: StatePart<StatePartNameType, any>;
8
+ };
9
+ constructor();
10
+ /**
11
+ * Allows getting and initializing a new statepart
12
+ * initMode === 'soft' it will allow existing stateparts
13
+ * initMode === 'mandatory' will fail if there is an exiting statepart
14
+ * initMode === 'force' will overwrite any existing statepart
15
+ * @param statePartNameArg
16
+ * @param initialArg
17
+ * @param initMode
18
+ */
19
+ getStatePart<PayloadType>(statePartNameArg: string & StatePartNameType, initialArg?: PayloadType, initMode?: 'soft' | 'mandatory' | 'force'): StatePart<StatePartNameType, PayloadType>;
20
+ /**
21
+ * creates a statepart
22
+ * @param statePartName
23
+ * @param initialPayloadArg
24
+ */
25
+ private createStatePart;
26
+ }
@@ -0,0 +1,45 @@
1
+ import './smartstate.plugins.js';
2
+ import { StatePart } from './smartstate.classes.statepart.js';
3
+ /**
4
+ * Smartstate takes care of providing state
5
+ */
6
+ export class Smartstate {
7
+ constructor() {
8
+ this.statePartMap = {};
9
+ }
10
+ /**
11
+ * Allows getting and initializing a new statepart
12
+ * initMode === 'soft' it will allow existing stateparts
13
+ * initMode === 'mandatory' will fail if there is an exiting statepart
14
+ * initMode === 'force' will overwrite any existing statepart
15
+ * @param statePartNameArg
16
+ * @param initialArg
17
+ * @param initMode
18
+ */
19
+ getStatePart(statePartNameArg, initialArg, initMode) {
20
+ if (this.statePartMap[statePartNameArg]) {
21
+ if (initialArg && (!initMode || initMode !== 'soft')) {
22
+ throw new Error(`${statePartNameArg} already exists, yet you try to set an initial state again`);
23
+ }
24
+ return this.statePartMap[statePartNameArg];
25
+ }
26
+ else {
27
+ if (!initialArg) {
28
+ throw new Error(`${statePartNameArg} does not yet exist, yet you don't provide an initial state`);
29
+ }
30
+ return this.createStatePart(statePartNameArg, initialArg);
31
+ }
32
+ }
33
+ /**
34
+ * creates a statepart
35
+ * @param statePartName
36
+ * @param initialPayloadArg
37
+ */
38
+ createStatePart(statePartName, initialPayloadArg) {
39
+ const newState = new StatePart(statePartName);
40
+ newState.setState(initialPayloadArg);
41
+ this.statePartMap[statePartName] = newState;
42
+ return newState;
43
+ }
44
+ }
45
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdGF0ZS5jbGFzc2VzLnNtYXJ0c3RhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHN0YXRlLmNsYXNzZXMuc21hcnRzdGF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUF5Qix5QkFBeUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFFOUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sVUFBVTtJQUdyQjtRQUZPLGlCQUFZLEdBQXlELEVBQUUsQ0FBQztJQUVoRSxDQUFDO0lBRWhCOzs7Ozs7OztPQVFHO0lBQ0ksWUFBWSxDQUNqQixnQkFBNEMsRUFDNUMsVUFBd0IsRUFDeEIsUUFBeUM7UUFFekMsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLGdCQUF1QixDQUFDLEVBQUU7WUFDOUMsSUFBSSxVQUFVLElBQUksQ0FBQyxDQUFDLFFBQVEsSUFBSSxRQUFRLEtBQUssTUFBTSxDQUFDLEVBQUU7Z0JBQ3BELE1BQU0sSUFBSSxLQUFLLENBQ2IsR0FBRyxnQkFBZ0IsNERBQTRELENBQ2hGLENBQUM7YUFDSDtZQUNELE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsQ0FBOEMsQ0FBQztTQUN6RjthQUFNO1lBQ0wsSUFBSSxDQUFDLFVBQVUsRUFBRTtnQkFDZixNQUFNLElBQUksS0FBSyxDQUNiLEdBQUcsZ0JBQWdCLDZEQUE2RCxDQUNqRixDQUFDO2FBQ0g7WUFDRCxPQUFPLElBQUksQ0FBQyxlQUFlLENBQWMsZ0JBQWdCLEVBQUUsVUFBVSxDQUFDLENBQUM7U0FDeEU7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLGVBQWUsQ0FDckIsYUFBZ0MsRUFDaEMsaUJBQThCO1FBRTlCLE1BQU0sUUFBUSxHQUFHLElBQUksU0FBUyxDQUFpQyxhQUFhLENBQUMsQ0FBQztRQUM5RSxRQUFRLENBQUMsUUFBUSxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDckMsSUFBSSxDQUFDLFlBQVksQ0FBQyxhQUFvQixDQUFDLEdBQUcsUUFBUSxDQUFDO1FBQ25ELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7Q0FDRiJ9
@@ -0,0 +1,13 @@
1
+ import { StatePart } from './smartstate.classes.statepart.js';
2
+ export interface IActionDef<TStateType, TActionPayloadType> {
3
+ (stateArg: StatePart<any, TStateType>, actionPayload: TActionPayloadType): Promise<TStateType>;
4
+ }
5
+ /**
6
+ * an actionmodifier for the state
7
+ */
8
+ export declare class StateAction<TStateType, TActionPayloadType> {
9
+ statePartRef: StatePart<any, any>;
10
+ actionDef: IActionDef<TStateType, TActionPayloadType>;
11
+ constructor(statePartRef: StatePart<any, any>, actionDef: IActionDef<TStateType, TActionPayloadType>);
12
+ trigger(payload: TActionPayloadType): void;
13
+ }
@@ -0,0 +1,15 @@
1
+ import './smartstate.plugins.js';
2
+ import './smartstate.classes.statepart.js';
3
+ /**
4
+ * an actionmodifier for the state
5
+ */
6
+ export class StateAction {
7
+ constructor(statePartRef, actionDef) {
8
+ this.statePartRef = statePartRef;
9
+ this.actionDef = actionDef;
10
+ }
11
+ trigger(payload) {
12
+ this.statePartRef.dispatchAction(this, payload);
13
+ }
14
+ }
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdGF0ZS5jbGFzc2VzLnN0YXRlYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRzdGF0ZS5jbGFzc2VzLnN0YXRlYWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQXlCLHlCQUF5QixDQUFDO0FBQ25ELE9BQTBCLG1DQUFtQyxDQUFDO0FBTTlEOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFDdEIsWUFDUyxZQUFpQyxFQUNqQyxTQUFxRDtRQURyRCxpQkFBWSxHQUFaLFlBQVksQ0FBcUI7UUFDakMsY0FBUyxHQUFULFNBQVMsQ0FBNEM7SUFDM0QsQ0FBQztJQUVHLE9BQU8sQ0FBQyxPQUEyQjtRQUN4QyxJQUFJLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDbEQsQ0FBQztDQUNGIn0=
@@ -0,0 +1,48 @@
1
+ import * as plugins from './smartstate.plugins.js';
2
+ import { StateAction, IActionDef } from './smartstate.classes.stateaction.js';
3
+ export declare class StatePart<TStatePartName, TStatePayload> {
4
+ name: TStatePartName;
5
+ state: plugins.smartrx.rxjs.Subject<TStatePayload>;
6
+ stateStore: TStatePayload;
7
+ private cumulativeDeferred;
8
+ constructor(nameArg: TStatePartName);
9
+ /**
10
+ * gets the state from the state store
11
+ */
12
+ getState(): TStatePayload;
13
+ /**
14
+ * sets the stateStore to the new state
15
+ * @param newStateArg
16
+ */
17
+ setState(newStateArg: TStatePayload): void;
18
+ /**
19
+ * notifies of a change on the state
20
+ */
21
+ notifyChange(): void;
22
+ private lastStateNotificationPayloadHash;
23
+ /**
24
+ * creates a cumulative notification by adding a change notification at the end of the call stack;
25
+ */
26
+ notifyChangeCumulative(): void;
27
+ /**
28
+ * selects a state or a substate
29
+ */
30
+ select<T = TStatePayload>(selectorFn?: (state: TStatePayload) => T): plugins.smartrx.rxjs.Observable<T>;
31
+ /**
32
+ * creates an action capable of modifying the state
33
+ */
34
+ createAction<TActionPayload>(actionDef: IActionDef<TStatePayload, TActionPayload>): StateAction<TStatePayload, TActionPayload>;
35
+ /**
36
+ * dispatches an action on the statepart level
37
+ */
38
+ dispatchAction<T>(stateAction: StateAction<TStatePayload, T>, actionPayload: T): Promise<void>;
39
+ /**
40
+ * waits until a certain part of the state becomes available
41
+ * @param selectorFn
42
+ */
43
+ waitUntilPresent<T = TStatePayload>(selectorFn?: (state: TStatePayload) => T): Promise<T>;
44
+ /**
45
+ * is executed
46
+ */
47
+ stateSetup(funcArg: (statePartArg?: StatePart<any, TStatePayload>) => Promise<TStatePayload>): Promise<void>;
48
+ }
@@ -0,0 +1,103 @@
1
+ import * as plugins from './smartstate.plugins.js';
2
+ import { StateAction } from './smartstate.classes.stateaction.js';
3
+ export class StatePart {
4
+ constructor(nameArg) {
5
+ this.state = new plugins.smartrx.rxjs.Subject();
6
+ this.cumulativeDeferred = plugins.smartpromise.cumulativeDefer();
7
+ this.name = nameArg;
8
+ }
9
+ /**
10
+ * gets the state from the state store
11
+ */
12
+ getState() {
13
+ return this.stateStore;
14
+ }
15
+ /**
16
+ * sets the stateStore to the new state
17
+ * @param newStateArg
18
+ */
19
+ setState(newStateArg) {
20
+ this.stateStore = newStateArg;
21
+ this.notifyChange();
22
+ }
23
+ /**
24
+ * notifies of a change on the state
25
+ */
26
+ notifyChange() {
27
+ const createStateHash = (stateArg) => {
28
+ return plugins.isohash.sha256FromString(plugins.smartjson.stringify(stateArg));
29
+ };
30
+ if (this.stateStore &&
31
+ this.lastStateNotificationPayloadHash &&
32
+ createStateHash(this.stateStore) === this.lastStateNotificationPayloadHash) {
33
+ return;
34
+ }
35
+ else {
36
+ this.lastStateNotificationPayloadHash = this.stateStore;
37
+ }
38
+ this.state.next(this.stateStore);
39
+ }
40
+ /**
41
+ * creates a cumulative notification by adding a change notification at the end of the call stack;
42
+ */
43
+ notifyChangeCumulative() {
44
+ // TODO: check viability
45
+ setTimeout(() => this.state.next(this.stateStore), 0);
46
+ }
47
+ /**
48
+ * selects a state or a substate
49
+ */
50
+ select(selectorFn) {
51
+ if (!selectorFn) {
52
+ selectorFn = (state) => state;
53
+ }
54
+ const mapped = this.state.pipe(plugins.smartrx.rxjs.ops.startWith(this.getState()), plugins.smartrx.rxjs.ops.map((stateArg) => {
55
+ try {
56
+ return selectorFn(stateArg);
57
+ }
58
+ catch (e) {
59
+ // Nothing here
60
+ }
61
+ }));
62
+ return mapped;
63
+ }
64
+ /**
65
+ * creates an action capable of modifying the state
66
+ */
67
+ createAction(actionDef) {
68
+ return new StateAction(this, actionDef);
69
+ }
70
+ /**
71
+ * dispatches an action on the statepart level
72
+ */
73
+ async dispatchAction(stateAction, actionPayload) {
74
+ await this.cumulativeDeferred.promise;
75
+ const newState = await stateAction.actionDef(this, actionPayload);
76
+ this.setState(newState);
77
+ }
78
+ /**
79
+ * waits until a certain part of the state becomes available
80
+ * @param selectorFn
81
+ */
82
+ async waitUntilPresent(selectorFn) {
83
+ const done = plugins.smartpromise.defer();
84
+ const selectedObservable = this.select(selectorFn);
85
+ const subscription = selectedObservable.subscribe(async (value) => {
86
+ if (value) {
87
+ done.resolve(value);
88
+ }
89
+ });
90
+ const result = await done.promise;
91
+ subscription.unsubscribe();
92
+ return result;
93
+ }
94
+ /**
95
+ * is executed
96
+ */
97
+ async stateSetup(funcArg) {
98
+ const resultPromise = funcArg(this);
99
+ this.cumulativeDeferred.addPromise(resultPromise);
100
+ this.setState(await resultPromise);
101
+ }
102
+ }
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdGF0ZS5jbGFzc2VzLnN0YXRlcGFydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0c3RhdGUuY2xhc3Nlcy5zdGF0ZXBhcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSx5QkFBeUIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsV0FBVyxFQUFjLE1BQU0scUNBQXFDLENBQUM7QUFFOUUsTUFBTSxPQUFPLFNBQVM7SUFNcEIsWUFBWSxPQUF1QjtRQUo1QixVQUFLLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQWlCLENBQUM7UUFFekQsdUJBQWtCLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUdsRSxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQztJQUN0QixDQUFDO0lBRUQ7O09BRUc7SUFDSSxRQUFRO1FBQ2IsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxRQUFRLENBQUMsV0FBMEI7UUFDeEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxXQUFXLENBQUM7UUFDOUIsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFRDs7T0FFRztJQUNJLFlBQVk7UUFDakIsTUFBTSxlQUFlLEdBQUcsQ0FBQyxRQUFhLEVBQUUsRUFBRTtZQUN4QyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUNqRixDQUFDLENBQUM7UUFDRixJQUNFLElBQUksQ0FBQyxVQUFVO1lBQ2YsSUFBSSxDQUFDLGdDQUFnQztZQUNyQyxlQUFlLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLElBQUksQ0FBQyxnQ0FBZ0MsRUFDMUU7WUFDQSxPQUFPO1NBQ1I7YUFBTTtZQUNMLElBQUksQ0FBQyxnQ0FBZ0MsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1NBQ3pEO1FBQ0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ25DLENBQUM7SUFHRDs7T0FFRztJQUNJLHNCQUFzQjtRQUMzQix3QkFBd0I7UUFDeEIsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxNQUFNLENBQ1gsVUFBd0M7UUFFeEMsSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUNmLFVBQVUsR0FBRyxDQUFDLEtBQW9CLEVBQUUsRUFBRSxDQUFVLEtBQU0sQ0FBQztTQUN4RDtRQUNELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUM1QixPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxFQUNuRCxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7WUFDeEMsSUFBSTtnQkFDRixPQUFPLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQzthQUM3QjtZQUFDLE9BQU8sQ0FBQyxFQUFFO2dCQUNWLGVBQWU7YUFDaEI7UUFDSCxDQUFDLENBQUMsQ0FDSCxDQUFDO1FBQ0YsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksWUFBWSxDQUNqQixTQUFvRDtRQUVwRCxPQUFPLElBQUksV0FBVyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsY0FBYyxDQUFJLFdBQTBDLEVBQUUsYUFBZ0I7UUFDekYsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDO1FBQ3RDLE1BQU0sUUFBUSxHQUFHLE1BQU0sV0FBVyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFDbEUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSyxDQUFDLGdCQUFnQixDQUMzQixVQUF3QztRQUV4QyxNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBSyxDQUFDO1FBQzdDLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNuRCxNQUFNLFlBQVksR0FBRyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQ2hFLElBQUksS0FBSyxFQUFFO2dCQUNULElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDckI7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQztRQUNsQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDM0IsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFVBQVUsQ0FDckIsT0FBaUY7UUFFakYsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3BDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDbEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLGFBQWEsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7Q0FDRiJ9
@@ -0,0 +1,5 @@
1
+ import * as isohash from '@pushrocks/isohash';
2
+ import * as smartjson from '@pushrocks/smartjson';
3
+ import * as smartpromise from '@pushrocks/smartpromise';
4
+ import * as smartrx from '@pushrocks/smartrx';
5
+ export { isohash, smartjson, smartpromise, smartrx };
@@ -0,0 +1,6 @@
1
+ import * as isohash from '@pushrocks/isohash';
2
+ import * as smartjson from '@pushrocks/smartjson';
3
+ import * as smartpromise from '@pushrocks/smartpromise';
4
+ import * as smartrx from '@pushrocks/smartrx';
5
+ export { isohash, smartjson, smartpromise, smartrx };
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRzdGF0ZS5wbHVnaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRzdGF0ZS5wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sb0JBQW9CLENBQUM7QUFDOUMsT0FBTyxLQUFLLFNBQVMsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEtBQUssWUFBWSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sS0FBSyxPQUFPLE1BQU0sb0JBQW9CLENBQUM7QUFFOUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxDQUFDIn0=
package/license ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2019 Task Venture Capital GmbH (hello@task.vc)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/npmextra.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "npmci": {
3
+ "npmGlobalTools": [],
4
+ "npmAccessLevel": "public"
5
+ },
6
+ "gitzone": {
7
+ "projectType": "npm",
8
+ "module": {
9
+ "githost": "gitlab.com",
10
+ "gitscope": "pushrocks",
11
+ "gitrepo": "smartstate",
12
+ "description": "a package that handles state in a good way",
13
+ "npmPackagename": "@pushrocks/smartstate",
14
+ "license": "MIT"
15
+ }
16
+ }
17
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@push.rocks/smartstate",
3
+ "version": "2.0.6",
4
+ "private": false,
5
+ "description": "a package that handles state in a good way",
6
+ "main": "dist_ts/index.js",
7
+ "typings": "dist_ts/index.d.ts",
8
+ "type": "module",
9
+ "author": "Lossless GmbH",
10
+ "license": "MIT",
11
+ "scripts": {
12
+ "test": "(tstest test/)",
13
+ "build": "(tsbuild --web --allowimplicitany && tsbundle npm)",
14
+ "buildDocs": "tsdoc"
15
+ },
16
+ "devDependencies": {
17
+ "@gitzone/tsbuild": "^2.1.65",
18
+ "@gitzone/tsbundle": "^2.0.7",
19
+ "@gitzone/tsrun": "^1.2.39",
20
+ "@gitzone/tstest": "^1.0.74",
21
+ "@pushrocks/tapbundle": "^5.0.4",
22
+ "@types/node": "^18.15.11"
23
+ },
24
+ "dependencies": {
25
+ "@pushrocks/isohash": "^2.0.0",
26
+ "@pushrocks/lik": "^6.0.2",
27
+ "@pushrocks/smartjson": "^5.0.5",
28
+ "@pushrocks/smartpromise": "^4.0.0",
29
+ "@pushrocks/smartrx": "^3.0.0"
30
+ },
31
+ "files": [
32
+ "ts/**/*",
33
+ "ts_web/**/*",
34
+ "dist/**/*",
35
+ "dist_*/**/*",
36
+ "dist_ts/**/*",
37
+ "dist_ts_web/**/*",
38
+ "assets/**/*",
39
+ "cli.js",
40
+ "npmextra.json",
41
+ "readme.md"
42
+ ],
43
+ "browserslist": [
44
+ "last 1 chrome versions"
45
+ ]
46
+ }
package/readme.md ADDED
@@ -0,0 +1,37 @@
1
+ # @pushrocks/smartstate
2
+ a package that handles state in a good way
3
+
4
+ ## Availabililty and Links
5
+ * [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartstate)
6
+ * [gitlab.com (source)](https://gitlab.com/pushrocks/smartstate)
7
+ * [github.com (source mirror)](https://github.com/pushrocks/smartstate)
8
+ * [docs (typedoc)](https://pushrocks.gitlab.io/smartstate/)
9
+
10
+ ## Status for master
11
+
12
+ Status Category | Status Badge
13
+ -- | --
14
+ GitLab Pipelines | [![pipeline status](https://gitlab.com/pushrocks/smartstate/badges/master/pipeline.svg)](https://lossless.cloud)
15
+ GitLab Pipline Test Coverage | [![coverage report](https://gitlab.com/pushrocks/smartstate/badges/master/coverage.svg)](https://lossless.cloud)
16
+ npm | [![npm downloads per month](https://badgen.net/npm/dy/@pushrocks/smartstate)](https://lossless.cloud)
17
+ Snyk | [![Known Vulnerabilities](https://badgen.net/snyk/pushrocks/smartstate)](https://lossless.cloud)
18
+ TypeScript Support | [![TypeScript](https://badgen.net/badge/TypeScript/>=%203.x/blue?icon=typescript)](https://lossless.cloud)
19
+ node Support | [![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
20
+ Code Style | [![Code Style](https://badgen.net/badge/style/prettier/purple)](https://lossless.cloud)
21
+ PackagePhobia (total standalone install weight) | [![PackagePhobia](https://badgen.net/packagephobia/install/@pushrocks/smartstate)](https://lossless.cloud)
22
+ PackagePhobia (package size on registry) | [![PackagePhobia](https://badgen.net/packagephobia/publish/@pushrocks/smartstate)](https://lossless.cloud)
23
+ BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bundlephobia/minzip/@pushrocks/smartstate)](https://lossless.cloud)
24
+
25
+ ## Usage
26
+
27
+ Use TypeScript for best in class intellisense.
28
+
29
+ ## Contribution
30
+
31
+ We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
32
+
33
+ For further information read the linked docs at the top of this readme.
34
+
35
+ ## Legal
36
+ > MIT licensed | **&copy;** [Task Venture Capital GmbH](https://task.vc)
37
+ | By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
@@ -0,0 +1,8 @@
1
+ /**
2
+ * autocreated commitinfo by @pushrocks/commitinfo
3
+ */
4
+ export const commitinfo = {
5
+ name: '@pushrocks/smartstate',
6
+ version: '2.0.6',
7
+ description: 'a package that handles state in a good way'
8
+ }
package/ts/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './smartstate.classes.smartstate.js';
2
+ export * from './smartstate.classes.statepart.js';
3
+ export * from './smartstate.classes.stateaction.js';
@@ -0,0 +1,57 @@
1
+ import * as plugins from './smartstate.plugins.js';
2
+ import { StatePart } from './smartstate.classes.statepart.js';
3
+
4
+ /**
5
+ * Smartstate takes care of providing state
6
+ */
7
+ export class Smartstate<StatePartNameType> {
8
+ public statePartMap: { [key: string]: StatePart<StatePartNameType, any> } = {};
9
+
10
+ constructor() {}
11
+
12
+ /**
13
+ * Allows getting and initializing a new statepart
14
+ * initMode === 'soft' it will allow existing stateparts
15
+ * initMode === 'mandatory' will fail if there is an exiting statepart
16
+ * initMode === 'force' will overwrite any existing statepart
17
+ * @param statePartNameArg
18
+ * @param initialArg
19
+ * @param initMode
20
+ */
21
+ public getStatePart<PayloadType>(
22
+ statePartNameArg: string & StatePartNameType,
23
+ initialArg?: PayloadType,
24
+ initMode?: 'soft' | 'mandatory' | 'force'
25
+ ): StatePart<StatePartNameType, PayloadType> {
26
+ if (this.statePartMap[statePartNameArg as any]) {
27
+ if (initialArg && (!initMode || initMode !== 'soft')) {
28
+ throw new Error(
29
+ `${statePartNameArg} already exists, yet you try to set an initial state again`
30
+ );
31
+ }
32
+ return this.statePartMap[statePartNameArg] as StatePart<StatePartNameType, PayloadType>;
33
+ } else {
34
+ if (!initialArg) {
35
+ throw new Error(
36
+ `${statePartNameArg} does not yet exist, yet you don't provide an initial state`
37
+ );
38
+ }
39
+ return this.createStatePart<PayloadType>(statePartNameArg, initialArg);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * creates a statepart
45
+ * @param statePartName
46
+ * @param initialPayloadArg
47
+ */
48
+ private createStatePart<PayloadType>(
49
+ statePartName: StatePartNameType,
50
+ initialPayloadArg: PayloadType
51
+ ): StatePart<StatePartNameType, PayloadType> {
52
+ const newState = new StatePart<StatePartNameType, PayloadType>(statePartName);
53
+ newState.setState(initialPayloadArg);
54
+ this.statePartMap[statePartName as any] = newState;
55
+ return newState;
56
+ }
57
+ }
@@ -0,0 +1,20 @@
1
+ import * as plugins from './smartstate.plugins.js';
2
+ import { StatePart } from './smartstate.classes.statepart.js';
3
+
4
+ export interface IActionDef<TStateType, TActionPayloadType> {
5
+ (stateArg: StatePart<any, TStateType>, actionPayload: TActionPayloadType): Promise<TStateType>;
6
+ }
7
+
8
+ /**
9
+ * an actionmodifier for the state
10
+ */
11
+ export class StateAction<TStateType, TActionPayloadType> {
12
+ constructor(
13
+ public statePartRef: StatePart<any, any>,
14
+ public actionDef: IActionDef<TStateType, TActionPayloadType>
15
+ ) {}
16
+
17
+ public trigger(payload: TActionPayloadType) {
18
+ this.statePartRef.dispatchAction(this, payload);
19
+ }
20
+ }
@@ -0,0 +1,127 @@
1
+ import * as plugins from './smartstate.plugins.js';
2
+ import { StateAction, IActionDef } from './smartstate.classes.stateaction.js';
3
+
4
+ export class StatePart<TStatePartName, TStatePayload> {
5
+ public name: TStatePartName;
6
+ public state = new plugins.smartrx.rxjs.Subject<TStatePayload>();
7
+ public stateStore: TStatePayload;
8
+ private cumulativeDeferred = plugins.smartpromise.cumulativeDefer();
9
+
10
+ constructor(nameArg: TStatePartName) {
11
+ this.name = nameArg;
12
+ }
13
+
14
+ /**
15
+ * gets the state from the state store
16
+ */
17
+ public getState(): TStatePayload {
18
+ return this.stateStore;
19
+ }
20
+
21
+ /**
22
+ * sets the stateStore to the new state
23
+ * @param newStateArg
24
+ */
25
+ public setState(newStateArg: TStatePayload) {
26
+ this.stateStore = newStateArg;
27
+ this.notifyChange();
28
+ }
29
+
30
+ /**
31
+ * notifies of a change on the state
32
+ */
33
+ public notifyChange() {
34
+ const createStateHash = (stateArg: any) => {
35
+ return plugins.isohash.sha256FromString(plugins.smartjson.stringify(stateArg));
36
+ };
37
+ if (
38
+ this.stateStore &&
39
+ this.lastStateNotificationPayloadHash &&
40
+ createStateHash(this.stateStore) === this.lastStateNotificationPayloadHash
41
+ ) {
42
+ return;
43
+ } else {
44
+ this.lastStateNotificationPayloadHash = this.stateStore;
45
+ }
46
+ this.state.next(this.stateStore);
47
+ }
48
+ private lastStateNotificationPayloadHash: any;
49
+
50
+ /**
51
+ * creates a cumulative notification by adding a change notification at the end of the call stack;
52
+ */
53
+ public notifyChangeCumulative() {
54
+ // TODO: check viability
55
+ setTimeout(() => this.state.next(this.stateStore), 0);
56
+ }
57
+
58
+ /**
59
+ * selects a state or a substate
60
+ */
61
+ public select<T = TStatePayload>(
62
+ selectorFn?: (state: TStatePayload) => T
63
+ ): plugins.smartrx.rxjs.Observable<T> {
64
+ if (!selectorFn) {
65
+ selectorFn = (state: TStatePayload) => <T>(<any>state);
66
+ }
67
+ const mapped = this.state.pipe(
68
+ plugins.smartrx.rxjs.ops.startWith(this.getState()),
69
+ plugins.smartrx.rxjs.ops.map((stateArg) => {
70
+ try {
71
+ return selectorFn(stateArg);
72
+ } catch (e) {
73
+ // Nothing here
74
+ }
75
+ })
76
+ );
77
+ return mapped;
78
+ }
79
+
80
+ /**
81
+ * creates an action capable of modifying the state
82
+ */
83
+ public createAction<TActionPayload>(
84
+ actionDef: IActionDef<TStatePayload, TActionPayload>
85
+ ): StateAction<TStatePayload, TActionPayload> {
86
+ return new StateAction(this, actionDef);
87
+ }
88
+
89
+ /**
90
+ * dispatches an action on the statepart level
91
+ */
92
+ public async dispatchAction<T>(stateAction: StateAction<TStatePayload, T>, actionPayload: T) {
93
+ await this.cumulativeDeferred.promise;
94
+ const newState = await stateAction.actionDef(this, actionPayload);
95
+ this.setState(newState);
96
+ }
97
+
98
+ /**
99
+ * waits until a certain part of the state becomes available
100
+ * @param selectorFn
101
+ */
102
+ public async waitUntilPresent<T = TStatePayload>(
103
+ selectorFn?: (state: TStatePayload) => T
104
+ ): Promise<T> {
105
+ const done = plugins.smartpromise.defer<T>();
106
+ const selectedObservable = this.select(selectorFn);
107
+ const subscription = selectedObservable.subscribe(async (value) => {
108
+ if (value) {
109
+ done.resolve(value);
110
+ }
111
+ });
112
+ const result = await done.promise;
113
+ subscription.unsubscribe();
114
+ return result;
115
+ }
116
+
117
+ /**
118
+ * is executed
119
+ */
120
+ public async stateSetup(
121
+ funcArg: (statePartArg?: StatePart<any, TStatePayload>) => Promise<TStatePayload>
122
+ ) {
123
+ const resultPromise = funcArg(this);
124
+ this.cumulativeDeferred.addPromise(resultPromise);
125
+ this.setState(await resultPromise);
126
+ }
127
+ }
@@ -0,0 +1,6 @@
1
+ import * as isohash from '@pushrocks/isohash';
2
+ import * as smartjson from '@pushrocks/smartjson';
3
+ import * as smartpromise from '@pushrocks/smartpromise';
4
+ import * as smartrx from '@pushrocks/smartrx';
5
+
6
+ export { isohash, smartjson, smartpromise, smartrx };