|
1 | | -import { Overmind, EventType } from 'overmind' |
2 | | -import { BehaviorSubject, Observable } from 'rxjs' |
3 | | -import { map } from 'rxjs/operators' |
4 | | -import { IS_PROXY } from 'proxy-state-tree' |
5 | | - |
6 | | -class ServiceBase {} |
7 | | - |
8 | 1 | // @ts-ignore |
9 | | -const IS_PRODUCTION = process.env.NODE_ENV === 'production' |
10 | | - |
11 | | -let nextComponentId = 0 |
12 | | - |
13 | | -const Track = (Component) => { |
14 | | - const componentId = nextComponentId++ |
15 | | - let componentInstanceId = 0 |
16 | | - |
17 | | - function findService(target) { |
18 | | - return Object.keys(target).find((key) => target[key] instanceof ServiceBase) |
19 | | - } |
20 | | - |
21 | | - if (!IS_PRODUCTION) { |
22 | | - const targetNgOnInit = Component.prototype.ngOnInit |
23 | | - Component.prototype.ngOnInit = function() { |
24 | | - if ( |
25 | | - !Component['__annotations__'][0] || |
26 | | - Component['__annotations__'][0].changeDetection !== 0 |
27 | | - ) { |
28 | | - throw new Error( |
29 | | - 'OVERMIND: You have to add ChangeDetectionStrategy.OnPush on component ' + |
30 | | - Component.name |
31 | | - ) |
32 | | - } |
33 | | - targetNgOnInit && targetNgOnInit.call(this) |
34 | | - } |
35 | | - const targetNgAfterViewInit = Component.prototype.ngAfterViewInit |
36 | | - Component.prototype.ngAfterViewInit = function() { |
37 | | - const service = this[findService(this)] |
38 | | - |
39 | | - if (!service) { |
40 | | - throw new Error( |
41 | | - 'OVERMIND - You have not added the Overmind service to component ' + |
42 | | - Component.name |
43 | | - ) |
44 | | - } |
45 | | - |
46 | | - service.addComponent({ |
47 | | - componentId, |
48 | | - componentInstanceId: componentInstanceId++, |
49 | | - name: Component.name, |
50 | | - }) |
51 | | - |
52 | | - targetNgAfterViewInit && targetNgAfterViewInit.call(this) |
53 | | - } |
54 | | - } |
55 | | - |
56 | | - const targetNgOnChanges = Component.prototype.ngOnChanges |
57 | | - Component.prototype.ngOnChanges = function(changes) { |
58 | | - const service = this[findService(this)] |
59 | | - |
60 | | - for (let key in changes) { |
61 | | - if (changes[key].currentValue[IS_PROXY]) { |
62 | | - this[key] = service.tree.master.rescope( |
63 | | - changes[key].currentValue, |
64 | | - service.tree |
65 | | - ) |
66 | | - } |
67 | | - } |
68 | | - targetNgOnChanges && targetNgOnChanges.call(this, changes) |
69 | | - } |
70 | | -} |
71 | | - |
72 | | -interface IService<App extends Overmind<any>> { |
73 | | - new (): { |
74 | | - actions: App['actions'] |
75 | | - effects: App['effects'] |
76 | | - addMutationListener: App['addMutationListener'] |
77 | | - select<T>(expr: (state: App['state']) => T): Observable<T> |
78 | | - select(): Observable<App['state']> |
79 | | - } |
80 | | - Track |
81 | | -} |
82 | | - |
83 | | -export function createService<App extends Overmind<any>>( |
84 | | - overmind: App |
85 | | -): IService<App> { |
86 | | - return class Service extends ServiceBase { |
87 | | - static Track = Track |
88 | | - private tree: any |
89 | | - private state$: Observable<any> |
90 | | - private subject: BehaviorSubject<any> |
91 | | - private overmind: App |
92 | | - private componentDetails: any |
93 | | - actions: App['actions'] |
94 | | - effects: App['effects'] |
95 | | - addMutationListener: App['addMutationListener'] |
96 | | - constructor() { |
97 | | - super() |
98 | | - this.tree = (overmind as any).proxyStateTree.getTrackStateTreeWithProxifier() |
99 | | - this.subject = new BehaviorSubject(this.tree.state) |
100 | | - this.state$ = this.subject.asObservable() |
101 | | - this.overmind = overmind |
102 | | - |
103 | | - this.actions = this.overmind.actions |
104 | | - this.addMutationListener = this.overmind.addMutationListener |
105 | | - |
106 | | - this.tree.track(this.onUpdate) |
107 | | - |
108 | | - if (!IS_PRODUCTION) { |
109 | | - ;(window['__zone_symbol__setTimeout'] || setTimeout)(() => { |
110 | | - if (!this.componentDetails) { |
111 | | - throw new Error( |
112 | | - 'OVERMIND - You have added a service without adding the Track decorator' |
113 | | - ) |
114 | | - } |
115 | | - }) |
116 | | - } |
117 | | - } |
118 | | - private addComponent(componentDetails) { |
119 | | - if (this.componentDetails) { |
120 | | - throw new Error( |
121 | | - 'OVERMIND - This service is already instantiated, you have to provide it as well with providers: [OvermindService] on ' + |
122 | | - this.componentDetails.name |
123 | | - ) |
124 | | - } |
125 | | - this.componentDetails = componentDetails |
126 | | - this.overmind.eventHub.emitAsync(EventType.COMPONENT_ADD, { |
127 | | - componentId: componentDetails.componentId, |
128 | | - componentInstanceId: componentDetails.componentInstanceId, |
129 | | - name: componentDetails.name, |
130 | | - paths: Array.from(this.tree.pathDependencies) as any, |
131 | | - }) |
132 | | - } |
133 | | - private onUpdate = (mutations, paths, flushId) => { |
134 | | - this.tree.track(this.onUpdate) |
135 | | - this.subject.next(this.tree.state) |
136 | | - if (this.componentDetails) { |
137 | | - ;(window['__zone_symbol__setTimeout'] || setTimeout)(() => { |
138 | | - this.overmind.eventHub.emitAsync(EventType.COMPONENT_UPDATE, { |
139 | | - componentId: this.componentDetails.componentId, |
140 | | - componentInstanceId: this.componentDetails.componentInstanceId, |
141 | | - name: this.componentDetails.name, |
142 | | - paths: Array.from(this.tree.pathDependencies) as any, |
143 | | - flushId, |
144 | | - }) |
145 | | - }) |
146 | | - } |
147 | | - } |
148 | | - private ngOnDestroy() { |
149 | | - ;(this.overmind as any).proxyStateTree.disposeTree(this.tree) |
150 | | - if (this.componentDetails) { |
151 | | - this.overmind.eventHub.emitAsync(EventType.COMPONENT_REMOVE, { |
152 | | - componentId: this.componentDetails.componentId, |
153 | | - componentInstanceId: this.componentDetails.componentInstanceId, |
154 | | - name: this.componentDetails.name, |
155 | | - }) |
156 | | - } |
157 | | - } |
158 | | - select<T>(expr: (state: App['state']) => T): Observable<T> |
159 | | - select(): Observable<App['state']> |
160 | | - select() { |
161 | | - const args = arguments |
162 | | - return this.state$.pipe( |
163 | | - map((value) => (args[0] ? args[0](value) : value)) |
164 | | - ) |
165 | | - } |
166 | | - } |
167 | | -} |
| 2 | +import { NgModule } from '@angular/core' |
| 3 | +import { OvermindTrackDirective, OVERMIND_INSTANCE } from './directive' |
| 4 | +import { OvermindService } from './service' |
| 5 | + |
| 6 | +export { OVERMIND_INSTANCE } |
| 7 | + |
| 8 | +@NgModule({ |
| 9 | + declarations: [OvermindTrackDirective], |
| 10 | + exports: [OvermindTrackDirective], |
| 11 | + imports: [], |
| 12 | + providers: [ |
| 13 | + { |
| 14 | + provide: OvermindService, |
| 15 | + useFactory: (overmind) => new OvermindService(overmind), |
| 16 | + deps: [OVERMIND_INSTANCE], |
| 17 | + }, |
| 18 | + ], |
| 19 | +}) |
| 20 | +export class OvermindModule {} |
0 commit comments