@microphi/store 1.1.3 → 1.1.5
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/LICENSE +21 -0
- package/README.md +57 -9
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/lib/effect/effect.d.ts +2 -1
- package/lib/lib/effect/effect.d.ts.map +1 -0
- package/lib/lib/effect/effect.js.map +1 -1
- package/lib/lib/list/list.d.ts +5 -2
- package/lib/lib/list/list.d.ts.map +1 -0
- package/lib/lib/list/list.js +20 -12
- package/lib/lib/list/list.js.map +1 -1
- package/lib/lib/reduce/reduce.d.ts +1 -0
- package/lib/lib/reduce/reduce.d.ts.map +1 -0
- package/lib/lib/reduce/reduce.js +1 -1
- package/lib/lib/reduce/reduce.js.map +1 -1
- package/lib/lib/store/store-3.experiment.d.ts +55 -0
- package/lib/lib/store/store-3.experiment.d.ts.map +1 -0
- package/lib/lib/store/store-3.experiment.js +107 -0
- package/lib/lib/store/store-3.experiment.js.map +1 -0
- package/lib/lib/store/store.d.ts +5 -4
- package/lib/lib/store/store.d.ts.map +1 -0
- package/lib/lib/store/store.js +10 -7
- package/lib/lib/store/store.js.map +1 -1
- package/lib/lib/utilities/capitalise.d.ts +1 -0
- package/lib/lib/utilities/capitalise.d.ts.map +1 -0
- package/lib/lib/utilities/scan-instance.d.ts +1 -0
- package/lib/lib/utilities/scan-instance.d.ts.map +1 -0
- package/package.json +10 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Davide Cavaliere
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,17 +1,65 @@
|
|
|
1
1
|
# @microphi/store
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A different way of doing state management with RxJS.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Install
|
|
6
|
+
With your favourite package manager install
|
|
7
|
+
```
|
|
8
|
+
@microphi/store
|
|
9
|
+
```
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
### Define the state
|
|
12
|
+
```typescript
|
|
13
|
+
interface ItemsState {
|
|
14
|
+
users: string[];
|
|
15
|
+
selected?: [number, string];
|
|
16
|
+
}
|
|
17
|
+
```
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
### Define the actions
|
|
20
|
+
```typescript
|
|
21
|
+
interface ItemsActions {
|
|
22
|
+
// An action MUST always return an Observable
|
|
23
|
+
findAll: () => Observable<string[]>;
|
|
24
|
+
// select: (name: string) => Observable<[number, string]>;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
### Implement effects and reducers in the store
|
|
10
28
|
|
|
11
|
-
|
|
29
|
+
```typescript
|
|
30
|
+
import { Store, Effect, Reduce } from '@microphi/store';
|
|
12
31
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
32
|
+
// -> Create a class that extends `Store` such as
|
|
33
|
+
class MyStore extends Store<ItemsState, ItemsActions>
|
|
34
|
+
implements makeStore<ItemsState, ItemsActions> {
|
|
35
|
+
// -> optionally implement `makeStore` to add extra type checking
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
// -> Set the initial state
|
|
39
|
+
super({
|
|
40
|
+
users: ['alice', 'bob'],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@Effect()
|
|
45
|
+
// -> Implement `findAll` method
|
|
46
|
+
findAll(): Observable<string[]> {
|
|
47
|
+
// - Simulate an async call
|
|
48
|
+
return of(['alice', 'bob', 'carl', 'denise']);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Reduce() // - Decorate with `@Reduce` so the `Store` knows this is a reducer
|
|
52
|
+
// -> Method name MUST be `on` + capitalized `actionName`
|
|
53
|
+
// its first argument is always the current state
|
|
54
|
+
// its second argument is the output of its action without the Observable.
|
|
55
|
+
public onFindAll(state: ItemsState, payload: string[]) {
|
|
56
|
+
// -> add state transition logic here
|
|
57
|
+
|
|
58
|
+
// -> Return the new state
|
|
59
|
+
return {
|
|
60
|
+
users: [...state.users, ...payload]
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
17
65
|
```
|
package/lib/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type EffectStrategy = 'switchMap' | 'mergeMap' | 'concatMap';
|
|
2
2
|
export interface Effect {
|
|
3
3
|
action: string;
|
|
4
4
|
strategy: EffectStrategy;
|
|
@@ -59,3 +59,4 @@ export declare const EffectSymbol: unique symbol;
|
|
|
59
59
|
export declare function Effect(strategy?: EffectStrategy): MethodDecorator;
|
|
60
60
|
export declare function getEffectMetadata(klass: object, key: string): any;
|
|
61
61
|
export declare function getEffects<T extends object>(instance: T): Effect[];
|
|
62
|
+
//# sourceMappingURL=effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../../../src/lib/effect/effect.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,CAAC;AAEpE,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,eAAO,MAAM,YAAY,eAAwB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAgB,MAAM,CAAC,QAAQ,GAAE,cAA4B,GAAG,eAAe,CAM9E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,OAE3D;AAED,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,EAAE,CAclE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../../../src/lib/effect/effect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../../../src/lib/effect/effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAS1D,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,MAAM,UAAU,MAAM,CAAC,WAA2B,WAAW;IAC3D,mDAAmD;IACnD,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QAC7B,wEAAwE;QACxE,OAAO,OAAO,CAAC,cAAc,CAAC,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC7E,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,GAAW;IAC1D,OAAO,OAAO,CAAC,WAAW,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,UAAU,CAAmB,QAAW;IAEtD,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAEpC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/C,IAAI,QAAQ,EAAE;YACZ,OAAO,CAAC,IAAI,CAAC,EAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAE,CAAC,CAAC;SACxC;IAEH,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["import { scanInstance } from '../utilities/scan-instance';\n\nexport type EffectStrategy = 'switchMap' | 'mergeMap' | 'concatMap';\n\nexport interface Effect {\n action: string;\n strategy: EffectStrategy;\n}\n\nexport const EffectSymbol = Symbol.for('@Effect');\n\n/**\n * Tags a method as an effect <br>\n *\n * Strategy is one of the following rxjs pipe-able operators:\n * - `mergeMap`\n * - `concatMap`\n * - `switchMap`\n *\n * As an example consider the following:\n * suppose there's an effect that takes 10 ms to return and then a reducer is called.<br>\n * Suppose we dispatch its event, the following diagram demonstrate what happens<br>\n * <code>\n * `D -> E -> (10) -> R`<br>\n * </code>\n * Event is dispatched `D`, event is executed `E`, takes 10ms and finally reducer is called with result from `E`\n *\n * Now let's suppose we dispatch again the same while `E` is still pending (executing) and suppose we call it with a different argument.\n *\n *\n * `D(a) -> E -> D(b)`\n *\n *\n * what happens next depends on the strategy used.<br>\n *\n *\n * If `switchMap` is used (default)\n *\n * `D(a) -> E(a) -> D(b) -> E(b) -> R(b)`\n *\n * the second dispatch cancels the first and so only `R(b)` is executed\n *\n *\n * If `mergeMap` is used\n *\n * `D(a) -> E(a) -> D(b) -> E(b) -> R(a) -> R(b)\n *\n * effects are executed in parallel and the first to come is the first served\n *\n * i.e.: lets say E(a) takes longer to respond then\n *\n * `D(a) -> D(b) -> E(b) -> R(b) -> E(a) -> -> R(a)`\n *\n *\n * If `concatMap` is used then the order of calls is respected.\n *\n * in the case above we'll have whatever the timings are on the effects\n *\n * `D(a) -> D(b) -> E(a) -> R(a) -> E(b) -> -> R(b)`\n *\n * @param strategy\n * @constructor\n */\nexport function Effect(strategy: EffectStrategy = 'switchMap'): MethodDecorator {\n // return Reflect.metadata(EffectSymbol, strategy);\n return (target, propertyKey) => {\n // return Reflect.metadata(EffectSymbol, strategy)(target, propertyKey);\n return Reflect.defineMetadata(EffectSymbol, strategy, target, propertyKey);\n };\n}\n\nexport function getEffectMetadata(klass: object, key: string) {\n return Reflect.getMetadata(EffectSymbol, klass, key);\n}\n\nexport function getEffects<T extends object>(instance: T): Effect[] {\n\n const effects: Effect[] = [];\n\n scanInstance(instance, (proto, key) => {\n\n const strategy = getEffectMetadata(proto, key);\n if (strategy) {\n effects.push({action: key, strategy,});\n }\n\n });\n\n return effects;\n}\n"]}
|
package/lib/lib/list/list.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $Keys } from 'utility-types';
|
|
2
|
-
export declare class List<EntityType extends
|
|
2
|
+
export declare class List<EntityType extends object> implements Iterable<EntityType> {
|
|
3
3
|
private IDField;
|
|
4
4
|
readonly entities: Map<any, EntityType>;
|
|
5
5
|
/**
|
|
@@ -7,12 +7,15 @@ export declare class List<EntityType extends {}> implements Iterable<EntityType>
|
|
|
7
7
|
*/
|
|
8
8
|
private readonly ids;
|
|
9
9
|
get size(): number;
|
|
10
|
-
|
|
10
|
+
has(id: any): boolean;
|
|
11
|
+
get(id: any): EntityType | undefined;
|
|
11
12
|
private getId;
|
|
12
13
|
constructor(IDField: $Keys<EntityType>, entities?: EntityType[]);
|
|
13
14
|
[Symbol.iterator](): IterableIterator<EntityType>;
|
|
14
15
|
upsert(...entities: EntityType[]): void;
|
|
15
16
|
prepend(...entities: EntityType[]): void;
|
|
17
|
+
clear(): void;
|
|
16
18
|
delete(...entities: EntityType[]): void;
|
|
17
19
|
append(...entities: EntityType[]): void;
|
|
18
20
|
}
|
|
21
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/lib/list/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,qBAAa,IAAI,CAAC,UAAU,SAAS,MAAM,CAAE,YAAW,QAAQ,CAAC,UAAU,CAAC;IA8B9D,OAAO,CAAC,OAAO;IA3B3B,SAAgB,QAAQ,uBAA8B;IAEtD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IAEjC,IAAW,IAAI,WAOd;IAEM,GAAG,CAAC,EAAE,EAAE,GAAG;IAIX,GAAG,CAAC,EAAE,EAAE,GAAG;IAGlB,OAAO,CAAC,KAAK;gBAIO,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,QAAQ,GAAE,UAAU,EAAO;IAW1E,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAS3C,MAAM,CAAC,GAAG,QAAQ,EAAE,UAAU,EAAE;IAYhC,OAAO,CAAC,GAAG,QAAQ,EAAE,UAAU,EAAE;IAejC,KAAK;IAOL,MAAM,CAAC,GAAG,QAAQ,EAAE,UAAU,EAAE;IAchC,MAAM,CAAC,GAAG,QAAQ,EAAE,UAAU,EAAE;CAYxC"}
|
package/lib/lib/list/list.js
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
export class List {
|
|
2
|
+
get size() {
|
|
3
|
+
if (this.ids.length !== this.entities.size) {
|
|
4
|
+
throw new Error(`Size Mismatch ${this.ids.length} !== ${this.entities.size}`);
|
|
5
|
+
}
|
|
6
|
+
return this.entities.size;
|
|
7
|
+
}
|
|
8
|
+
has(id) {
|
|
9
|
+
return this.entities.has(id);
|
|
10
|
+
}
|
|
11
|
+
get(id) {
|
|
12
|
+
return this.entities.get(id);
|
|
13
|
+
}
|
|
14
|
+
getId(entity) {
|
|
15
|
+
return entity[this.IDField];
|
|
16
|
+
}
|
|
2
17
|
constructor(IDField, entities = []) {
|
|
3
18
|
this.IDField = IDField;
|
|
4
19
|
this.entities = new Map();
|
|
@@ -13,22 +28,11 @@ export class List {
|
|
|
13
28
|
this.entities.set(id, item);
|
|
14
29
|
});
|
|
15
30
|
}
|
|
16
|
-
get size() {
|
|
17
|
-
if (this.ids.length !== this.entities.size) {
|
|
18
|
-
throw new Error(`Size Mismatch ${this.ids.length} !== ${this.entities.size}`);
|
|
19
|
-
}
|
|
20
|
-
return this.entities.size;
|
|
21
|
-
}
|
|
22
|
-
get(id) {
|
|
23
|
-
return this.entities.get(id);
|
|
24
|
-
}
|
|
25
|
-
getId(entity) {
|
|
26
|
-
return entity[this.IDField];
|
|
27
|
-
}
|
|
28
31
|
*[Symbol.iterator]() {
|
|
29
32
|
// tslint:disable-next-line:forin
|
|
30
33
|
for (const idx in this.ids) {
|
|
31
34
|
const id = this.ids[idx];
|
|
35
|
+
// @ts-ignore
|
|
32
36
|
yield this.entities.get(id);
|
|
33
37
|
}
|
|
34
38
|
}
|
|
@@ -51,6 +55,10 @@ export class List {
|
|
|
51
55
|
this.entities.set(id, e);
|
|
52
56
|
});
|
|
53
57
|
}
|
|
58
|
+
clear() {
|
|
59
|
+
this.ids.length = 0;
|
|
60
|
+
this.entities.clear();
|
|
61
|
+
}
|
|
54
62
|
delete(...entities) {
|
|
55
63
|
entities.forEach((e) => {
|
|
56
64
|
const id = this.getId(e);
|
package/lib/lib/list/list.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/lib/list/list.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,IAAI;
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/lib/list/list.ts"],"names":[],"mappings":"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","sourcesContent":["import { $Keys } from 'utility-types';\n\nexport class List<EntityType extends object> implements Iterable<EntityType> {\n\n\n public readonly entities = new Map<any, EntityType>();\n\n /**\n * maps entities position from the original array to their ids\n */\n private readonly ids: any[] = [];\n\n public get size() {\n if (this.ids.length !== this.entities.size) {\n\n throw new Error(`Size Mismatch ${this.ids.length} !== ${this.entities.size}`);\n }\n\n return this.entities.size;\n }\n\n public has(id: any) {\n return this.entities.has(id);\n }\n\n public get(id: any) {\n return this.entities.get(id);\n }\n private getId(entity: EntityType) {\n return entity[this.IDField];\n }\n\n constructor(private IDField: $Keys<EntityType>, entities: EntityType[] = []) {\n\n this.ids = entities.map((e) => this.getId(e));\n\n entities\n .forEach((item, idx) => {\n const id = item[IDField];\n this.entities.set(id, item);\n });\n }\n\n *[Symbol.iterator](): IterableIterator<EntityType> {\n // tslint:disable-next-line:forin\n for (const idx in this.ids) {\n const id = this.ids[idx];\n // @ts-ignore\n yield this.entities.get(id);\n }\n }\n\n public upsert(...entities: EntityType[]) {\n entities.forEach((e) => {\n const id = this.getId(e);\n\n if (!this.entities.has(id)) {\n this.ids.push(id);\n }\n\n this.entities.set(id, e);\n });\n }\n\n public prepend(...entities: EntityType[]) {\n entities.reverse().forEach((e) => {\n const id = this.getId(e);\n\n if (this.entities.has(id)) {\n this.delete(e);\n }\n\n this.ids.unshift(id);\n\n this.entities.set(id, e);\n\n });\n }\n\n public clear() {\n\n this.ids.length = 0;\n this.entities.clear();\n\n }\n\n public delete(...entities: EntityType[]) {\n\n entities.forEach((e) => {\n const id = this.getId(e);\n const indexOfId = this.ids.findIndex((_id) => _id === id);\n\n if (indexOfId >= 0) {\n this.ids.splice(indexOfId, 1);\n this.entities.delete(id);\n }\n });\n\n }\n\n public append(...entities: EntityType[]) {\n entities.forEach((e) => {\n const id = this.getId(e);\n\n if (this.entities.has(id)) {\n this.delete(e);\n }\n\n this.ids.push(id);\n this.entities.set(id, e);\n });\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reduce.d.ts","sourceRoot":"","sources":["../../../src/lib/reduce/reduce.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,eAAO,MAAM,YAAY,eAAoB,CAAC;AAE9C,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,MAAM,IAAI,eAAe,CASxC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,OAE/D;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAC,MAAM,EAAE,MAAM,CAAC;CAAC,EAAE,CAcjE"}
|
package/lib/lib/reduce/reduce.js
CHANGED
|
@@ -2,7 +2,7 @@ import 'reflect-metadata';
|
|
|
2
2
|
import { scanInstance } from '../utilities/scan-instance';
|
|
3
3
|
export const ReduceSymbol = Symbol('@Reduce');
|
|
4
4
|
export function Reduce() {
|
|
5
|
-
return (target, propertyKey) => {
|
|
5
|
+
return (target, propertyKey, descriptor) => {
|
|
6
6
|
// by convention a reducer have name such as onFindAll
|
|
7
7
|
// where findAll is the associated action
|
|
8
8
|
// with the following we extract the action's name
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reduce.js","sourceRoot":"","sources":["../../../src/lib/reduce/reduce.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAM9C,MAAM,UAAU,MAAM;IACpB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"reduce.js","sourceRoot":"","sources":["../../../src/lib/reduce/reduce.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAM9C,MAAM,UAAU,MAAM;IACpB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE;QACzC,sDAAsD;QACtD,yCAAyC;QACzC,kDAAkD;QAClD,MAAM,MAAM,GAAI,WAAsB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,GAAI,WAAsB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAEpG,OAAO,OAAO,CAAC,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3E,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAiB,EAAE,GAAW;IAC9D,OAAO,OAAO,CAAC,WAAW,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAE1C,MAAM,QAAQ,GAAwB,EAAE,CAAC;IAEzC,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAEpC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/C,IAAI,QAAQ,EAAE;YACZ,QAAQ,CAAC,IAAI,CAAC,EAAC,MAAM,EAAE,QAAQ,EAAC,CAAC,CAAC;SACnC;IAEH,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import 'reflect-metadata';\nimport { scanInstance } from '../utilities/scan-instance';\nimport { Class } from 'utility-types';\n\nexport const ReduceSymbol = Symbol('@Reduce');\n\nexport interface Reducer {\n action: string;\n}\n\nexport function Reduce(): MethodDecorator {\n return (target, propertyKey, descriptor) => {\n // by convention a reducer have name such as onFindAll\n // where findAll is the associated action\n // with the following we extract the action's name\n const action = (propertyKey as string).slice(2, 3).toLowerCase() + (propertyKey as string).slice(3);\n\n return Reflect.defineMetadata(ReduceSymbol, action, target, propertyKey);\n };\n}\n\nexport function getReduceMetadata(klass: Class<any>, key: string) {\n return Reflect.getMetadata(ReduceSymbol, klass, key);\n}\n\nexport function getReducers(instance: object): {action: string;}[] {\n\n const reducers: {action: string;}[] = [];\n\n scanInstance(instance, (proto, key) => {\n\n const metadata = getReduceMetadata(proto, key);\n if (metadata) {\n reducers.push({action: metadata});\n }\n\n });\n\n return reducers;\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
|
2
|
+
import { getPayloadFromActionType } from './store';
|
|
3
|
+
export type Class = new (...args: any[]) => {};
|
|
4
|
+
export type makeEffects<A> = {
|
|
5
|
+
[k in keyof A]: A[k] extends (...args: infer I) => infer O ? (...args: I) => Observable<O> : void;
|
|
6
|
+
};
|
|
7
|
+
export type returnType<T> = T extends (...args: any[]) => infer O ? O : string[];
|
|
8
|
+
export type makeReducers<A, S> = {
|
|
9
|
+
[k in keyof A]: (state: S, payload: returnType<A[k]>) => S;
|
|
10
|
+
};
|
|
11
|
+
export interface LoadingState {
|
|
12
|
+
status: boolean;
|
|
13
|
+
action: string;
|
|
14
|
+
payload: any;
|
|
15
|
+
}
|
|
16
|
+
export declare function StoreFactory<E extends Class, R extends Class, S, IE = InstanceType<E>, IR = InstanceType<R>>(effects: E, reducers: R, state: S): {
|
|
17
|
+
new (e: IE, r: IR): {
|
|
18
|
+
loading$: Subject<LoadingState>;
|
|
19
|
+
actions: Map<keyof (IE & IR), Subject<any>>;
|
|
20
|
+
_state$: BehaviorSubject<S>;
|
|
21
|
+
e: IE;
|
|
22
|
+
r: IR;
|
|
23
|
+
/**
|
|
24
|
+
* Select a state field using a mapping function
|
|
25
|
+
* @param fn mapping function
|
|
26
|
+
* @example
|
|
27
|
+
* store.select(({items}) => items);
|
|
28
|
+
*/
|
|
29
|
+
select(fn: (s: S) => any): Observable<any>;
|
|
30
|
+
/**
|
|
31
|
+
* Get the loading$ observable of a given action
|
|
32
|
+
* @param a the action
|
|
33
|
+
* @example
|
|
34
|
+
* store.getLoadingFor('findAll')
|
|
35
|
+
*/
|
|
36
|
+
getLoadingFor<K extends keyof IE>(a: K): Observable<LoadingState>;
|
|
37
|
+
/**
|
|
38
|
+
* Dispatch an action with the given payload.
|
|
39
|
+
* @param action action to dispatch
|
|
40
|
+
* @param payload payload to pass to the action
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
*
|
|
44
|
+
* interface IActions {
|
|
45
|
+
* findAll: () => string[];
|
|
46
|
+
* findOne: (name: string) => string;
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* store.dispatch('findAll');
|
|
50
|
+
* store.dispatch('findOne', 'alice');
|
|
51
|
+
*/
|
|
52
|
+
dispatch<K_1 extends keyof IE>(action: K_1, ...payload: getPayloadFromActionType<IE, K_1>): void;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=store-3.experiment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-3.experiment.d.ts","sourceRoot":"","sources":["../../../src/lib/store/store-3.experiment.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,OAAO,EAAkB,MAAM,MAAM,CAAC;AAG5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAOnD,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;AAE/C,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;KAC1B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI;CAClG,CAAA;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC;AAEjF,MAAM,MAAM,YAAY,CAAC,CAAC,EAAE,CAAC,IAAI;KAC9B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;CAC3D,CAAA;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,GAAG,CAAC;CACd;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,KAAK,EAC1C,CAAC,SAAS,KAAK,EACf,CAAC,EACD,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,EACpB,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,EACpB,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;YA4BT,EAAE,KAAY,EAAE;kBAN5B,QAAQ,YAAY,CAAC;iBAEtB,IAAI,MAAM,CAAC,EAAE,GAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC;iBAEhC,gBAAgB,CAAC,CAAC;WAEL,EAAE;WAAY,EAAE;QAuDtC;;;;;WAKG;uBACY,CAAC,KAAK,GAAG;QAMxB;;;;;WAKG;;QASH;;;;;;;;;;;;;;WAcG;;;EAMN"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { BehaviorSubject, Subject, switchMap, tap } from 'rxjs';
|
|
2
|
+
import { filter, map, withLatestFrom } from 'rxjs/operators';
|
|
3
|
+
import { getDebugger } from '@microphi/debug';
|
|
4
|
+
const d = getDebugger('store-3');
|
|
5
|
+
export function StoreFactory(effects, reducers, state) {
|
|
6
|
+
const effectNames = (Object.getOwnPropertyNames(effects.prototype))
|
|
7
|
+
.filter((m) => typeof effects.prototype[m] === 'function')
|
|
8
|
+
.filter((m) => m !== 'constructor');
|
|
9
|
+
d({ effectNames });
|
|
10
|
+
const reducerNames = Object.getOwnPropertyNames(reducers.prototype)
|
|
11
|
+
.filter((m) => typeof reducers.prototype[m] === 'function')
|
|
12
|
+
.filter((m) => m !== 'constructor');
|
|
13
|
+
d({ reducerNames });
|
|
14
|
+
// this will be common to all instances
|
|
15
|
+
const actions = new Set(effectNames.concat(reducerNames));
|
|
16
|
+
d({ actions });
|
|
17
|
+
return class {
|
|
18
|
+
constructor(e, r) {
|
|
19
|
+
this.e = e;
|
|
20
|
+
this.r = r;
|
|
21
|
+
this.loading$ = new Subject();
|
|
22
|
+
this.actions = new Map();
|
|
23
|
+
this._state$ = new BehaviorSubject(state);
|
|
24
|
+
d('initial state is', state);
|
|
25
|
+
actions.forEach((action) => {
|
|
26
|
+
d('creating Subject for action', action);
|
|
27
|
+
const actionSubject = new Subject();
|
|
28
|
+
actionSubject.pipe(withLatestFrom(this._state$), tap(([payload]) => {
|
|
29
|
+
d('action dispatched with payload', payload);
|
|
30
|
+
d('loading will start now!');
|
|
31
|
+
this.loading$.next({
|
|
32
|
+
action: action,
|
|
33
|
+
payload,
|
|
34
|
+
status: true
|
|
35
|
+
});
|
|
36
|
+
}), switchMap(([payload, state]) => {
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
38
|
+
return this.e[action].apply(this.e, payload).pipe(map((response) => {
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
40
|
+
return this.r[action].apply(this.r, [state, response]);
|
|
41
|
+
}),
|
|
42
|
+
// this tap needs to be here because we need the `payload`
|
|
43
|
+
tap(() => {
|
|
44
|
+
d('loading stops now');
|
|
45
|
+
this.loading$.next({
|
|
46
|
+
action: action,
|
|
47
|
+
status: false,
|
|
48
|
+
payload
|
|
49
|
+
});
|
|
50
|
+
}, () => {
|
|
51
|
+
d('loading stops now');
|
|
52
|
+
this.loading$.next({
|
|
53
|
+
action: action,
|
|
54
|
+
status: false,
|
|
55
|
+
payload
|
|
56
|
+
});
|
|
57
|
+
}));
|
|
58
|
+
})).subscribe((state) => {
|
|
59
|
+
d('new state is', state);
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
this._state$.next(state);
|
|
62
|
+
});
|
|
63
|
+
this.actions.set(action, actionSubject);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Select a state field using a mapping function
|
|
68
|
+
* @param fn mapping function
|
|
69
|
+
* @example
|
|
70
|
+
* store.select(({items}) => items);
|
|
71
|
+
*/
|
|
72
|
+
select(fn) {
|
|
73
|
+
return this._state$.pipe(map(fn));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get the loading$ observable of a given action
|
|
77
|
+
* @param a the action
|
|
78
|
+
* @example
|
|
79
|
+
* store.getLoadingFor('findAll')
|
|
80
|
+
*/
|
|
81
|
+
getLoadingFor(a) {
|
|
82
|
+
return this.loading$.pipe(filter(({ action }) => {
|
|
83
|
+
return action === a;
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Dispatch an action with the given payload.
|
|
88
|
+
* @param action action to dispatch
|
|
89
|
+
* @param payload payload to pass to the action
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
*
|
|
93
|
+
* interface IActions {
|
|
94
|
+
* findAll: () => string[];
|
|
95
|
+
* findOne: (name: string) => string;
|
|
96
|
+
* }
|
|
97
|
+
*
|
|
98
|
+
* store.dispatch('findAll');
|
|
99
|
+
* store.dispatch('findOne', 'alice');
|
|
100
|
+
*/
|
|
101
|
+
dispatch(action, ...payload) {
|
|
102
|
+
d('dispatching action', action, 'with payload', payload);
|
|
103
|
+
this.actions.get(action)?.next(payload);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=store-3.experiment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-3.experiment.js","sourceRoot":"","sources":["../../../src/lib/store/store-3.experiment.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAc,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,MAAM,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;AAuBjC,MAAM,UAAU,YAAY,CAK1B,OAAU,EAAE,QAAW,EAAE,KAAQ;IAEjC,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;SAChE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC;SACzD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,aAAa,CAAyB,CAAC;IAC9D,CAAC,CAAC,EAAC,WAAW,EAAC,CAAC,CAAC;IAEjB,MAAM,YAAY,GAAI,MAAM,CAAC,mBAAmB,CAAC,QAAQ,CAAC,SAAS,CAA0B;SAC1F,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC;SAC1D,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC;IACtC,CAAC,CAAC,EAAC,YAAY,EAAC,CAAC,CAAC;IAGlB,uCAAuC;IACvC,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CACjC,CAAC;IAEF,CAAC,CAAC,EAAC,OAAO,EAAC,CAAC,CAAC;IAEb,OAAO;QAQL,YAAmB,CAAK,EAAS,CAAK;YAAnB,MAAC,GAAD,CAAC,CAAI;YAAS,MAAC,GAAD,CAAC,CAAI;YANtC,aAAQ,GAA0B,IAAI,OAAO,EAAgB,CAAC;YAE9D,YAAO,GAAqC,IAAI,GAAG,EAAE,CAAC;YAEtD,YAAO,GAAuB,IAAI,eAAe,CAAI,KAAK,CAAC,CAAC;YAG1D,CAAC,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;YAE7B,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;gBACzB,CAAC,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;gBACzC,MAAM,aAAa,GAAG,IAAI,OAAO,EAAyC,CAAC;gBAE3E,aAAa,CAAC,IAAI,CAChB,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAC5B,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE;oBAChB,CAAC,CAAC,gCAAgC,EAAE,OAAO,CAAC,CAAC;oBAC7C,CAAC,CAAC,yBAAyB,CAAC,CAAC;oBAC7B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;wBACjB,MAAM,EAAE,MAAgB;wBACxB,OAAO;wBACP,MAAM,EAAE,IAAI;qBACb,CAAC,CAAC;gBACL,CAAC,CAAC,EACF,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE;oBAC7B,wDAAwD;oBACxD,OAAQ,IAAI,CAAC,CAAC,CAAC,MAAkB,CAAyB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CACpF,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;wBACf,wDAAwD;wBACxD,OAAQ,IAAI,CAAC,CAAC,CAAC,MAAkB,CAAyB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;oBAC9F,CAAC,CAAC;oBACF,0DAA0D;oBAC1D,GAAG,CAAC,GAAG,EAAE;wBACP,CAAC,CAAC,mBAAmB,CAAC,CAAC;wBACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;4BACjB,MAAM,EAAE,MAAgB;4BACxB,MAAM,EAAE,KAAK;4BACb,OAAO;yBACR,CAAC,CAAC;oBACL,CAAC,EAAE,GAAG,EAAE;wBACN,CAAC,CAAC,mBAAmB,CAAC,CAAC;wBACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;4BACjB,MAAM,EAAE,MAAgB;4BACxB,MAAM,EAAE,KAAK;4BACb,OAAO;yBACR,CAAC,CAAC;oBACL,CAAC,CAAC,CACH,CAAC;gBACJ,CAAC,CAAC,CACH,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;oBACpB,CAAC,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;oBACzB,aAAa;oBACb,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC,CAAC,CAAC;gBAEH,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;YAC1C,CAAC,CAAC,CAAC;QAEL,CAAC;QAGD;;;;;WAKG;QACH,MAAM,CAAC,EAAiB;YACtB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CACtB,GAAG,CAAC,EAAE,CAAC,CACR,CAAC;QACJ,CAAC;QAED;;;;;WAKG;QACH,aAAa,CAAqB,CAAI;YACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CACvB,MAAM,CAAC,CAAC,EAAC,MAAM,EAAC,EAAE,EAAE;gBAClB,OAAO,MAAM,KAAK,CAAC,CAAC;YACtB,CAAC,CAAC,CACH,CAAC;QACJ,CAAC;QAED;;;;;;;;;;;;;;WAcG;QACH,QAAQ,CAAqB,MAAS,EAAE,GAAG,OAAwC;YACjF,CAAC,CAAC,oBAAoB,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;YACzD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { $Keys } from 'utility-types';\nimport { BehaviorSubject, Observable, Subject, switchMap, tap } from 'rxjs';\nimport { filter, map, withLatestFrom } from 'rxjs/operators';\nimport { getDebugger } from '@microphi/debug';\nimport { getPayloadFromActionType } from './store';\n\nconst d = getDebugger('store-3');\n\n\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport type Class = new (...args: any[]) => {};\n\nexport type makeEffects<A> = {\n [k in keyof A]: A[k] extends (...args: infer I) => infer O ? (...args: I) => Observable<O> : void;\n}\n\nexport type returnType<T> = T extends (...args: any[]) => infer O ? O : string[];\n\nexport type makeReducers<A, S> = {\n [k in keyof A]: (state: S, payload: returnType<A[k]>) => S;\n}\n\nexport interface LoadingState {\n status: boolean;\n action: string;\n payload: any;\n}\n\nexport function StoreFactory<E extends Class,\n R extends Class,\n S,\n IE = InstanceType<E>,\n IR = InstanceType<R>,\n>(effects: E, reducers: R, state: S) {\n\n const effectNames = (Object.getOwnPropertyNames(effects.prototype))\n .filter((m) => typeof effects.prototype[m] === 'function')\n .filter((m) => m !== 'constructor') as $Keys<IE & object>[];\n d({effectNames});\n\n const reducerNames = (Object.getOwnPropertyNames(reducers.prototype) as $Keys<IE & object>[])\n .filter((m) => typeof reducers.prototype[m] === 'function')\n .filter((m) => m !== 'constructor');\n d({reducerNames});\n\n\n // this will be common to all instances\n const actions = new Set<keyof (IE&IR)>(\n effectNames.concat(reducerNames)\n );\n\n d({actions});\n\n return class {\n\n loading$: Subject<LoadingState> = new Subject<LoadingState>();\n\n actions: Map<keyof (IE&IR), Subject<any>> = new Map();\n\n _state$: BehaviorSubject<S> = new BehaviorSubject<S>(state);\n\n constructor(public e: IE, public r: IR) {\n d('initial state is', state);\n\n actions.forEach((action) => {\n d('creating Subject for action', action);\n const actionSubject = new Subject<{ action: string; payload: unknown; }>();\n\n actionSubject.pipe(\n withLatestFrom(this._state$),\n tap(([payload]) => {\n d('action dispatched with payload', payload);\n d('loading will start now!');\n this.loading$.next({\n action: action as string,\n payload,\n status: true\n });\n }),\n switchMap(([payload, state]) => {\n // eslint-disable-next-line @typescript-eslint/ban-types\n return (this.e[action as keyof IE] as unknown as Function).apply(this.e, payload).pipe(\n map((response) => {\n // eslint-disable-next-line @typescript-eslint/ban-types\n return (this.r[action as keyof IR] as unknown as Function).apply(this.r, [state, response]);\n }),\n // this tap needs to be here because we need the `payload`\n tap(() => {\n d('loading stops now');\n this.loading$.next({\n action: action as string,\n status: false,\n payload\n });\n }, () => {\n d('loading stops now');\n this.loading$.next({\n action: action as string,\n status: false,\n payload\n });\n })\n );\n })\n ).subscribe((state) => {\n d('new state is', state);\n // @ts-ignore\n this._state$.next(state);\n });\n\n this.actions.set(action, actionSubject);\n });\n\n }\n\n\n /**\n * Select a state field using a mapping function\n * @param fn mapping function\n * @example\n * store.select(({items}) => items);\n */\n select(fn: (s: S) => any) {\n return this._state$.pipe(\n map(fn)\n );\n }\n\n /**\n * Get the loading$ observable of a given action\n * @param a the action\n * @example\n * store.getLoadingFor('findAll')\n */\n getLoadingFor<K extends keyof IE>(a: K) {\n return this.loading$.pipe(\n filter(({action}) => {\n return action === a;\n })\n );\n }\n\n /**\n * Dispatch an action with the given payload.\n * @param action action to dispatch\n * @param payload payload to pass to the action\n *\n * @example\n *\n * interface IActions {\n * findAll: () => string[];\n * findOne: (name: string) => string;\n * }\n *\n * store.dispatch('findAll');\n * store.dispatch('findOne', 'alice');\n */\n dispatch<K extends keyof IE>(action: K, ...payload: getPayloadFromActionType<IE, K>) {\n d('dispatching action', action, 'with payload', payload);\n this.actions.get(action)?.next(payload);\n }\n };\n}\n"]}
|
package/lib/lib/store/store.d.ts
CHANGED
|
@@ -2,12 +2,12 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
|
|
2
2
|
import { Reducer } from '../reduce/reduce';
|
|
3
3
|
import { Effect } from '../effect/effect';
|
|
4
4
|
import { Brand, Primitive } from 'utility-types';
|
|
5
|
-
export
|
|
6
|
-
export
|
|
7
|
-
export
|
|
5
|
+
export type getPayloadFromActionType<A, C extends keyof A> = A[C] extends Function ? A[C] extends () => any ? never[] : A[C] extends (...args: infer T) => any ? T : never[] : A[C][];
|
|
6
|
+
export type PureReducer<T extends Primitive> = Brand<T, 'reducer'>;
|
|
7
|
+
export type makeEffects<Actions> = {
|
|
8
8
|
[k in keyof Actions]: Actions[k] extends PureReducer<Primitive> ? never : Actions[k];
|
|
9
9
|
};
|
|
10
|
-
export
|
|
10
|
+
export type makeStore<State, Actions> = {
|
|
11
11
|
[k in keyof makeEffects<Actions>]: makeEffects<Actions>[k];
|
|
12
12
|
} & {
|
|
13
13
|
[k in keyof Actions as `on${Capitalize<string & k>}`]: Actions[k] extends (...args: any) => Observable<infer O> ? (state: State, payload: O) => State : Actions[k] extends PureReducer<infer O> ? (state?: State, payload?: O) => State : (state?: State) => State;
|
|
@@ -36,3 +36,4 @@ export declare abstract class Store<State, A> {
|
|
|
36
36
|
private static getOperator;
|
|
37
37
|
private swallowError;
|
|
38
38
|
}
|
|
39
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/lib/store/store.ts"],"names":[],"mappings":"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"}
|
package/lib/lib/store/store.js
CHANGED
|
@@ -3,6 +3,12 @@ import { getReducers } from '../reduce/reduce';
|
|
|
3
3
|
import { catchError, concatMap, filter, map, mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
|
4
4
|
import { getEffects } from '../effect/effect';
|
|
5
5
|
export class Store {
|
|
6
|
+
get loading$() {
|
|
7
|
+
return this._loading$.asObservable();
|
|
8
|
+
}
|
|
9
|
+
get state$() {
|
|
10
|
+
return this._store$.asObservable();
|
|
11
|
+
}
|
|
6
12
|
constructor(initialState) {
|
|
7
13
|
this.initialState = initialState;
|
|
8
14
|
this.actions = new Map();
|
|
@@ -12,13 +18,15 @@ export class Store {
|
|
|
12
18
|
JSON.parse(JSON.stringify(this.initialState)));
|
|
13
19
|
this.effects = getEffects(this);
|
|
14
20
|
this.reducers = getReducers(this);
|
|
21
|
+
// @ts-ignore
|
|
15
22
|
const actions = [].concat(this.effects, this.reducers);
|
|
16
23
|
const actionsSet = new Set();
|
|
17
24
|
actions.forEach(({ action }) => actionsSet.add(action));
|
|
18
25
|
actionsSet.forEach((key) => {
|
|
19
26
|
this.actions.set(key, new Subject());
|
|
20
27
|
const effect = this.effects.find((e) => e.action === key);
|
|
21
|
-
const operator = Store.getOperator(effect
|
|
28
|
+
const operator = Store.getOperator(effect.strategy);
|
|
29
|
+
// @ts-ignore
|
|
22
30
|
this.actions.get(key).pipe(withLatestFrom(this._store$), tap(([{ payload }]) => {
|
|
23
31
|
this._loading$.next({
|
|
24
32
|
payload: payload,
|
|
@@ -26,6 +34,7 @@ export class Store {
|
|
|
26
34
|
code: key,
|
|
27
35
|
});
|
|
28
36
|
}), operator(([{ name, payload }]) => {
|
|
37
|
+
// @ts-ignore
|
|
29
38
|
return this[name](...payload).pipe(tap((response) => {
|
|
30
39
|
this._loading$.next({
|
|
31
40
|
payload,
|
|
@@ -50,12 +59,6 @@ export class Store {
|
|
|
50
59
|
})).subscribe(this._store$);
|
|
51
60
|
});
|
|
52
61
|
}
|
|
53
|
-
get loading$() {
|
|
54
|
-
return this._loading$.asObservable();
|
|
55
|
-
}
|
|
56
|
-
get state$() {
|
|
57
|
-
return this._store$.asObservable();
|
|
58
|
-
}
|
|
59
62
|
select(projection) {
|
|
60
63
|
return this.state$.pipe(map(projection));
|
|
61
64
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/lib/store/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,EAAc,EAAE,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACvE,OAAO,EAAE,WAAW,EAAW,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAA0B,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/lib/store/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,EAAc,EAAE,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACvE,OAAO,EAAE,WAAW,EAAW,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAA0B,UAAU,EAAE,MAAM,kBAAkB,CAAC;AA2CtE,MAAM,OAAgB,KAAK;IAWzB,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;IACvC,CAAC;IAOD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;IACrC,CAAC;IAED,YAAoB,YAAmB;QAAnB,iBAAY,GAAZ,YAAY,CAAO;QAtBtB,YAAO,GAA0D,IAAI,GAAG,EAAE,CAAC;QAOpF,cAAS,GAAG,IAAI,OAAO,EAAmB,CAAC;QAMhC,YAAO,GAA2B,IAAI,eAAe;QACtE,oEAAoE;QACpE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAC9C,CAAC;QAQA,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAElC,aAAa;QACb,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEvD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;QAErC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAC,MAAM,EAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAEtD,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAEzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,OAAO,EAAE,CAAC,CAAC;YAErC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC;YAE1D,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,MAAO,CAAC,QAAQ,CAAC,CAAC;YAErD,aAAa;YACb,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CACxB,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAC5B,GAAG,CAAC,CAAC,CAAC,EAAC,OAAO,EAAC,CAAC,EAAE,EAAE;gBAClB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;oBAClB,OAAO,EAAE,OAAO;oBAChB,MAAM,EAAE,IAAI;oBACZ,IAAI,EAAE,GAAc;iBACrB,CAAC,CAAC;YACL,CAAC,CAAC,EACF,QAAQ,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,OAAO,EAAC,CAAC,EAAE,EAAE;gBAE7B,aAAa;gBACb,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAChC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACf,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;wBAClB,OAAO;wBACP,QAAQ;wBACR,MAAM,EAAE,KAAK;wBACb,6DAA6D;wBAC7D,+DAA+D;wBAC/D,IAAI,EAAE,GAAc;qBACrB,CAAC,CAAC;gBACL,CAAC,CAAC;gBACF,eAAe;gBACf,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACf,qCAAqC;oBACrC,cAAc;oBACd,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAI,IAAe,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;oBAE/E,aAAa;oBACb,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,CAAC,CAAC;gBAC9D,CAAC,CAAC;gBACF,oFAAoF;gBACpF,+EAA+E;gBAC/E,UAAU,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAC9D,CAAC;YACJ,CAAC,CAAC,CAEH,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAI,UAA2B;QACnC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CACrB,GAAG,CAAC,UAAU,CAAC,CAChB,CAAC;IACJ,CAAC;IAED,aAAa,CAAoB,MAAS;QACxC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CACvB,MAAM,CAAC,CAAC,EAAC,IAAI,EAAC,EAAE,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC,EACnC,GAAG,CAAC,CAAC,EAAC,MAAM,EAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAC1B,CAAC;IACJ,CAAC;IAED,QAAQ,CACN,MAAS,EACT,GAAG,OAAuC;QAG1C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAgB,CAAC,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;SACzD;QAED,MAAM,IAAI,GAAW,CAAC,OAAQ,IAAqB,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAW,CAAC;QAG9G,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAgB,CAAC,EAAE,IAAI,CAAC,EAAC,IAAI,EAAE,OAAO,EAAC,CAAC,CAAC;IAC5D,CAAC;IAED,8DAA8D;IACtD,MAAM,CAAC,UAAU,CAAC,OAAY;QACpC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;IAED,8DAA8D;IACtD,MAAM,CAAC,WAAW,CAAC,UAA0B;QACnD,IAAI,UAAU,KAAK,UAAU,EAAE;YAC7B,OAAO,QAAQ,CAAC;SACjB;aAAM,IAAI,UAAU,KAAK,WAAW,EAAE;YACrC,OAAO,SAAS,CAAC;SAClB;aAAM;YACL,OAAO,SAAS,CAAC;SAClB;IACH,CAAC;IAEO,YAAY,CAAC,GAAW,EAAE,KAAY,EAAE,OAAY;QAC1D,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,GAAG,EAAE,KAAK,CAAC,CAAC;QAErD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAClB,OAAO;YACP,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,GAAc;SACrB,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC;IACf,CAAC;CAEF","sourcesContent":["import { BehaviorSubject, EMPTY, Observable, of, Subject } from 'rxjs';\nimport { getReducers, Reducer } from '../reduce/reduce';\nimport { catchError, concatMap, filter, map, mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators';\nimport { Effect, EffectStrategy, getEffects } from '../effect/effect';\nimport { Brand, Primitive } from 'utility-types';\n\nexport type getPayloadFromActionType<A, C extends keyof A> =\n// eslint-disable-next-line @typescript-eslint/ban-types\n A[C] extends Function ? A[C] extends () => any\n ? never[] : A[C] extends (...args: infer T) => any\n ? T : never[] : A[C][];\n\nexport type PureReducer<T extends Primitive> = Brand<T, 'reducer'>;\n\nexport type makeEffects<Actions> = {\n // Effects\n [k in keyof Actions]: Actions[k] extends PureReducer<Primitive>\n ? never\n : Actions[k]\n}\n\nexport type makeStore<State, Actions> =\n {\n [k in keyof makeEffects<Actions>]: makeEffects<Actions>[k]\n }\n // &\n // Actions\n &\n {\n // Reducers\n [k in keyof Actions as `on${Capitalize<string & k>}`]: Actions[k] extends (...args: any) => Observable<infer O>\n ? (state: State, payload: O) => State\n : Actions[k] extends PureReducer<infer O>\n ? (state?: State, payload?: O) => State\n : (state?: State) => State\n\n };\n\nexport interface LoadingState<A> {\n code: keyof A;\n payload?: any;\n response?: any;\n error?: any;\n status: boolean;\n}\n\nexport abstract class Store<State, A> {\n\n private readonly actions: Map<string, Subject<{ name: string, payload?: any }>> = new Map();\n\n readonly effects: Effect[];\n\n readonly reducers: Reducer[];\n\n\n private _loading$ = new Subject<LoadingState<A>>();\n\n public get loading$(): Observable<LoadingState<A>> {\n return this._loading$.asObservable();\n }\n\n protected readonly _store$: BehaviorSubject<State> = new BehaviorSubject<State>(\n // we need this in order to decouple initial state between instances\n JSON.parse(JSON.stringify(this.initialState))\n );\n\n public get state$(): Observable<State> {\n return this._store$.asObservable();\n }\n\n constructor(private initialState: State) {\n\n this.effects = getEffects(this);\n this.reducers = getReducers(this);\n\n // @ts-ignore\n const actions = [].concat(this.effects, this.reducers);\n\n const actionsSet = new Set<string>();\n\n actions.forEach(({action}) => actionsSet.add(action));\n\n actionsSet.forEach((key) => {\n\n this.actions.set(key, new Subject());\n\n const effect = this.effects.find((e) => e.action === key);\n\n const operator = Store.getOperator(effect!.strategy);\n\n // @ts-ignore\n this.actions.get(key).pipe(\n withLatestFrom(this._store$),\n tap(([{payload}]) => {\n this._loading$.next({\n payload: payload,\n status: true,\n code: key as keyof A,\n });\n }),\n operator(([{name, payload}]) => {\n\n // @ts-ignore\n return this[name](...payload).pipe(\n tap((response) => {\n this._loading$.next({\n payload,\n response,\n status: false,\n // here the action is done. The action is the only async call\n // we can assume the loading is done as the effect is not async\n code: key as keyof A,\n });\n }),\n // the above is\n map((response) => {\n // by convention reducer name must be\n // on + Action\n const reducerName = `on${(name[0]).toUpperCase()}${(name as string).slice(1)}`;\n\n // @ts-ignore\n return this[reducerName](this._store$.getValue(), response);\n }),\n // error need to be swallowed here too otherwise the observable chain will be broken\n // meaning that once an action goes into an error it cannot be dispatched again\n catchError((error) => this.swallowError(key, error, payload)),\n );\n }),\n // @ts-ignore\n ).subscribe(this._store$);\n });\n }\n\n select<R>(projection: (s: State) => R) {\n return this.state$.pipe(\n map(projection)\n );\n }\n\n getLoadingFor<C extends keyof A>(action: C): Observable<boolean> {\n return this.loading$.pipe(\n filter(({code}) => code === action),\n map(({status}) => status),\n );\n }\n\n dispatch<C extends keyof A>(\n action: C,\n ...payload: getPayloadFromActionType<A, C>\n ) {\n\n if (!this.actions.has(action as string)) {\n throw new Error(`Cannot find action ${String(action)}`);\n }\n\n const name: string = (typeof (this as unknown as A)[action] === 'function' ? action : 'noopEffect') as string;\n\n\n this.actions.get(action as string)?.next({name, payload});\n }\n\n // eslint-disable-next-line @typescript-eslint/member-ordering\n private static noopEffect(payload: any) {\n return of(payload);\n }\n\n // eslint-disable-next-line @typescript-eslint/member-ordering\n private static getOperator(strategyFn: EffectStrategy) {\n if (strategyFn === 'mergeMap') {\n return mergeMap;\n } else if (strategyFn === 'concatMap') {\n return concatMap;\n } else {\n return switchMap;\n }\n }\n\n private swallowError(key: string, error: Error, payload: any) {\n console.log(`Error handling action \"${key}\"`, error);\n\n this._loading$.next({\n payload,\n error: error,\n status: false,\n code: key as keyof A,\n });\n\n return EMPTY;\n }\n\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capitalise.d.ts","sourceRoot":"","sources":["../../../src/lib/utilities/capitalise.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,UAInC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan-instance.d.ts","sourceRoot":"","sources":["../../../src/lib/utilities/scan-instance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAItC,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,QAqBrG"}
|
package/package.json
CHANGED
|
@@ -22,19 +22,24 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"lib"
|
|
24
24
|
],
|
|
25
|
-
"version": "1.1.
|
|
25
|
+
"version": "1.1.5",
|
|
26
26
|
"dependencies": {
|
|
27
|
+
"@microphi/debug": "^1.1.5",
|
|
27
28
|
"reflect-metadata": "^0.1.13",
|
|
28
29
|
"tslib": "^2.5.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"@microphi/test": "^1.1.0",
|
|
32
32
|
"utility-types": "^3.10.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"rxjs": "
|
|
35
|
+
"rxjs": "~7.8.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
|
-
"build": "tsc -
|
|
39
|
-
|
|
38
|
+
"build": "tsc -b tsconfig.build.json",
|
|
39
|
+
"build:ci": "yarn build",
|
|
40
|
+
"test:ci": "jest --coverage --ci",
|
|
41
|
+
"prepack": "yarn build",
|
|
42
|
+
"lint": "eslint ./src"
|
|
43
|
+
},
|
|
44
|
+
"gitHead": "82e5091939c81ad825089316a5ddf66638e8c32f"
|
|
40
45
|
}
|