@cyysummer/projector 0.0.11 → 0.0.12
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/index.js +2 -2
- package/package.json +1 -1
- package/types/lib.d.ts +71 -64
- package/types/types.d.ts +13 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @cyysummer/projector v0.0.
|
|
2
|
+
* @cyysummer/projector v0.0.12
|
|
3
3
|
* (c) 2021-PRESENT Chris Liu
|
|
4
4
|
* @license MIT
|
|
5
5
|
**/
|
|
6
|
-
import
|
|
6
|
+
import"on-change";var l=class{constructor(e,t){this._schema=e;this._scheduler=t;if(!e)throw new Error("Projector: Schema is required.")}project(e,...t){for(let r of t)this._dispatch(e,r)}_dispatch(e,t){let{path:r,value:c}=t,o=this._resolveEffect(r);o&&(this._ensureScheduler(),this._scheduler.enqueue({path:r.join("."),effect:o,ctx:{source:e,path:r,value:c}}))}_ensureScheduler(){if(!this._scheduler)throw new Error("Projector: no scheduler.")}_resolveEffect(e){let t=this._schema;for(let r of e){if(!t)return null;t=t[r]}return typeof t=="function"?t:null}},f=class extends l{constructor(e,t){super(e,t)}},d=class extends l{withScheduler(e){return typeof e=="function"?this._schedulerFactory=e:this._scheduler=e,this}_ensureScheduler(){if(!this._scheduler&&this._schedulerFactory&&(this._scheduler=this._schedulerFactory()),!this._scheduler)throw new Error("Projector: no scheduler.")}};import{cloneDeep as F,debounce as j,set as E}from"lodash-es";import{withEvents as L}from"@cyysummer/core";var p=class extends L(){constructor(t){super();this._paused=!1;this._shadow=F(t)}sendTo(t){this._projectorFactory=typeof t=="function"?t:()=>t}pause(){this._paused=!0}resume(){this._paused=!1}},y=class extends p{receive(e,t){if(this._paused)return;E(this._shadow,e,t);let r=[{path:e,value:t}];this._projectorFactory?.()?.project(this._shadow,...r),this.emit("record",{next:this._shadow,patches:r})}},S=class extends p{constructor(t,r=500){super(t);this._wait=r;this._buffer=new Map;this.receiveCore=j(()=>{let t=[...this._buffer.values()];log.trace("LazyRecorder.receiveCore,",t),this._buffer.clear();for(let r of t)E(this._shadow,r.path,r.value);this._projectorFactory?.()?.project(this._shadow,...t),this.emit("record",{next:this._shadow,patches:t})},this._wait,{trailing:!0})}receive(t,r){this._paused||(this._buffer.set(t.join("."),{path:t,value:r}),this.receiveCore())}};import{debounce as P}from"lodash-es";var g=class{constructor(e){this._queue=new Map;e&&(this._strategyFactory=()=>e)}enqueue(e){return this._queue.set(e.path,e),this}flush(){return log.trace("Scheduler.flush()",[...this._queue.keys()]),this.flushCore()}reset(){this._queue.clear()}withStrategy(e){return this._strategyFactory=typeof e=="function"?e:()=>e,this}ensureStrategy(){let e=this._strategyFactory?.();if(!e)throw new Error("Scheduler: no strategy.");return e}async run(e){for(let t of e){let{effect:r,ctx:c}=t,o=r(this.ensureStrategy(),c);o instanceof Promise&&await o}}},T=class extends g{constructor(t,r=500){super(t);this.wait=r;this.flushCore=P(async()=>{let t=[...this._queue.values()];this._queue.clear(),this.run(t)},this.wait)}},_=class extends g{async flushCore(){this.ensureStrategy().reset(),this.run([...this._queue.values()])}};import{debounce as k}from"lodash-es";import C from"on-change";function I(a,e=500){let t=e>0?new S(a,e):new y(a);return[C(a,(c,o)=>t.receive(c,o),{pathAsArray:!0}),t]}var b=class{constructor(e,t,r=500){this._initial=e;this._schema=t;this._waitTime=r;if(!e||!t||!r)throw new Error("Builder: all params are required.");if(Number(r)<0)throw new Error("Builder: wait time must be >= 0.")}buildDynamic(){this.track();let e=new d(this._schema);return this._scheduler&&e.withScheduler(this._scheduler),this._recorder.sendTo(e),{tracked:this._tracked,recorder:this._recorder,projector:e,scheduler:this._scheduler}}build(){if(!this._strategyFactory)throw new Error("Builder: no strategy was provided. Call `withStrategy()` to provide.");this._scheduler||(this._scheduler=new T),this._flushCallback||log.warn("Builder: no flush callback was provided.");let e=async()=>{await this._scheduler.flush(),this._flushCallback?.()};this.track(),this._scheduler.withStrategy(this._strategyFactory);let t=new f(this._schema,this._scheduler);return this._recorder.sendTo(t),this._recorder.on("record",this._waitTime?k(e,this._waitTime):e),{tracked:this._tracked,recorder:this._recorder,scheduler:this._scheduler}}onFlush(e){return this._flushCallback=e,this}withLazyScheduler(){return this._scheduler=new T(void 0,this._waitTime),this}withTotalScheduler(){return this._scheduler=new _,this}withStrategy(e){return this._strategyFactory=typeof e=="function"?e:()=>e,this}track(){this._recorder&&this._tracked||([this._tracked,this._recorder]=I(this._initial,this._waitTime))}};import{get as m,keys as w}from"lodash-es";var x=a=>{},v=class{at(e){return(t,r)=>{let c=i(r);return t.execute(e,c)}}atWith(e,t){return(c,o)=>{let u=i(o),n=t(u);return c.execute(e,n)}}arrayAt(e,t){return(r,c)=>{let o=c.path?m(c.source,c.path):c.value;if(o&&Array.isArray(o)&&o.length>0){let u={keys:typeof o[0]=="object"?w(o[0]):[],resolveHeader:(n,s)=>String(n),...t};return r.executeArray(e,o,u)}}}arrayAtWith(e,t,r){return(c,o)=>{let u=o.path?m(o.source,o.path):o.value;if(u&&Array.isArray(u)&&u.length>0){let n=u.map(t),s={keys:typeof u[0]=="object"?w(u[0]):[],resolveHeader:(h,R)=>String(h),...r};return c.executeArray(e,n,s)}}}loop(e){return async(t,r)=>{let c=i(r);if(Array.isArray(c)){let o=c;for(let u=0;u<o.length;u++){let n=o[u],h=e(n,u)(t,{value:n});h instanceof Promise&&await h}}else throw new Error(`Effect: Value at path '${r.path}' is not an array.`)}}sourceWith(e,t){return(r,c)=>{let o=t(c.source);return r.execute(e,o)}}raw(e,t){return(r,c)=>r.execute(e,t)}sequence(e){return async(t,r)=>{let c=i(r);for(let o of e)await o(t,{value:c})}}sequenceWith(e,t){return async(c,o)=>{let u=i(o),n=t(u);for(let s of e)await s(c,{value:n})}}when(e,t,r=x){return(c,o)=>{let u=i(o);return(e(u)?t:r)(c,{value:u})}}whenFromSource(e,t,r=x){return(c,o)=>(e(o.source)?t:r)(c,o)}},i=a=>a.source&&a.path?m(a.source,a.path):a.value;export{b as Builder,d as DynamicProjector,v as EffectFactory,S as LazyRecorder,T as LazyScheduler,f as Projector,l as ProjectorBase,y as Recorder,p as RecorderBase,g as Scheduler,_ as TotalScheduler,I as track};
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
package/types/lib.d.ts
CHANGED
|
@@ -56,6 +56,19 @@ type ArrayEffectOptions = {
|
|
|
56
56
|
resolveHeader: (key: string | symbol, index?: number) => string;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
|
|
60
|
+
type RecorderEvents = {
|
|
61
|
+
record: { next: any; patches: Patch[]; };
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
interface IRecorder<TSource extends object> extends IEventful<RecorderEvents> {
|
|
65
|
+
pause(): void;
|
|
66
|
+
receive(path: any[], value: any): void;
|
|
67
|
+
resume(): void;
|
|
68
|
+
sendTo(projector: IProjector<TSource>): void;
|
|
69
|
+
sendTo(factory: Func<IProjector<TSource>>): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
59
72
|
/**
|
|
60
73
|
* Strategy defines actual execution methods for projecting values to target.
|
|
61
74
|
*/
|
|
@@ -89,64 +102,6 @@ interface Patch {
|
|
|
89
102
|
value: any;
|
|
90
103
|
}
|
|
91
104
|
|
|
92
|
-
type RecorderEvents = {
|
|
93
|
-
record: {
|
|
94
|
-
next: any;
|
|
95
|
-
patches: Patch[];
|
|
96
|
-
};
|
|
97
|
-
};
|
|
98
|
-
declare const RecorderBase_base: Constructor<object> & (new (...args: any[]) => object & IEventful<RecorderEvents>);
|
|
99
|
-
/**
|
|
100
|
-
* Record changes to an object.
|
|
101
|
-
*/
|
|
102
|
-
declare abstract class RecorderBase<TSource extends object> extends RecorderBase_base {
|
|
103
|
-
protected _paused: boolean;
|
|
104
|
-
protected _projectorFactory?: Func<IProjector<TSource>>;
|
|
105
|
-
protected _shadow: TSource;
|
|
106
|
-
constructor(initial: TSource);
|
|
107
|
-
/**
|
|
108
|
-
* Receive changes from the tracked object.
|
|
109
|
-
* @param path
|
|
110
|
-
* @param value
|
|
111
|
-
* @returns
|
|
112
|
-
*/
|
|
113
|
-
abstract receive(path: any[], value: any): void;
|
|
114
|
-
/**
|
|
115
|
-
* Send changes to a projector.
|
|
116
|
-
* @param projector
|
|
117
|
-
*/
|
|
118
|
-
sendTo(projector: IProjector<TSource>): void;
|
|
119
|
-
/**
|
|
120
|
-
* Send changes to a projector.
|
|
121
|
-
* @param factory
|
|
122
|
-
*/
|
|
123
|
-
sendTo(factory: Func<IProjector<TSource>>): void;
|
|
124
|
-
pause(): void;
|
|
125
|
-
resume(): void;
|
|
126
|
-
}
|
|
127
|
-
declare class Recorder<TSource extends object> extends RecorderBase<TSource> {
|
|
128
|
-
/**
|
|
129
|
-
* Receive changes from the tracked object.
|
|
130
|
-
* @param path
|
|
131
|
-
* @param value
|
|
132
|
-
* @returns
|
|
133
|
-
*/
|
|
134
|
-
receive(path: any[], value: any): void;
|
|
135
|
-
}
|
|
136
|
-
declare class LazyRecorder<TSource extends object> extends RecorderBase<TSource> {
|
|
137
|
-
protected _wait: number;
|
|
138
|
-
protected _buffer: Map<string, Patch>;
|
|
139
|
-
constructor(initial: TSource, _wait?: number);
|
|
140
|
-
/**
|
|
141
|
-
* Receive changes from the tracked object.
|
|
142
|
-
* @param path
|
|
143
|
-
* @param value
|
|
144
|
-
* @returns
|
|
145
|
-
*/
|
|
146
|
-
receive(path: any[], value: any): void;
|
|
147
|
-
protected readonly receiveCore: lodash_es.DebouncedFunc<() => void>;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
105
|
declare abstract class ProjectorBase<TSource> implements IProjector<TSource> {
|
|
151
106
|
protected _schema: Schema<TSource>;
|
|
152
107
|
protected _scheduler?: IScheduler<any> | undefined;
|
|
@@ -173,19 +128,18 @@ declare class Builder<TSource extends object, TTarget, TLocation> {
|
|
|
173
128
|
private _flushCallback?;
|
|
174
129
|
private _recorder?;
|
|
175
130
|
private _scheduler?;
|
|
176
|
-
private _strategy?;
|
|
177
131
|
private _strategyFactory?;
|
|
178
132
|
private _tracked?;
|
|
179
133
|
constructor(_initial: TSource, _schema: Schema<TSource>, _waitTime?: number);
|
|
180
134
|
buildDynamic(): {
|
|
181
135
|
tracked: TSource;
|
|
182
|
-
recorder:
|
|
136
|
+
recorder: IRecorder<TSource>;
|
|
183
137
|
projector: DynamicProjector<TSource>;
|
|
184
138
|
scheduler: IScheduler<TTarget> | undefined;
|
|
185
139
|
};
|
|
186
|
-
|
|
140
|
+
build(): {
|
|
187
141
|
tracked: TSource;
|
|
188
|
-
recorder:
|
|
142
|
+
recorder: IRecorder<TSource>;
|
|
189
143
|
scheduler: IScheduler<TTarget>;
|
|
190
144
|
};
|
|
191
145
|
/**
|
|
@@ -194,7 +148,7 @@ declare class Builder<TSource extends object, TTarget, TLocation> {
|
|
|
194
148
|
* @returns
|
|
195
149
|
*/
|
|
196
150
|
onFlush(callback: Action): Builder<TSource, TTarget, TLocation>;
|
|
197
|
-
withLazyScheduler(
|
|
151
|
+
withLazyScheduler(): Builder<TSource, TTarget, TLocation>;
|
|
198
152
|
withTotalScheduler(): Builder<TSource, TTarget, TLocation>;
|
|
199
153
|
withStrategy(strategy: ITargetExecutionStrategy<TTarget, TLocation>): Builder<TSource, TTarget, TLocation>;
|
|
200
154
|
withStrategy(factory: Func<ITargetExecutionStrategy<TTarget, TLocation>>): Builder<TSource, TTarget, TLocation>;
|
|
@@ -285,6 +239,58 @@ declare class EffectFactory<TSource extends object, TLocation = any> {
|
|
|
285
239
|
whenFromSource<T>(condition: Predicate<TSource>, ifTrue: Effect<TSource, any>, ifFalse?: Effect<TSource, any>): Effect<TSource, T>;
|
|
286
240
|
}
|
|
287
241
|
|
|
242
|
+
declare const RecorderBase_base: Constructor<object> & (new (...args: any[]) => object & IEventful<RecorderEvents>);
|
|
243
|
+
/**
|
|
244
|
+
* Record changes to an object.
|
|
245
|
+
*/
|
|
246
|
+
declare abstract class RecorderBase<TSource extends object> extends RecorderBase_base implements IRecorder<TSource> {
|
|
247
|
+
protected _paused: boolean;
|
|
248
|
+
protected _projectorFactory?: Func<IProjector<TSource>>;
|
|
249
|
+
protected _shadow: TSource;
|
|
250
|
+
constructor(initial: TSource);
|
|
251
|
+
/**
|
|
252
|
+
* Receive changes from the tracked object.
|
|
253
|
+
* @param path
|
|
254
|
+
* @param value
|
|
255
|
+
* @returns
|
|
256
|
+
*/
|
|
257
|
+
abstract receive(path: any[], value: any): void;
|
|
258
|
+
/**
|
|
259
|
+
* Send changes to a projector.
|
|
260
|
+
* @param projector
|
|
261
|
+
*/
|
|
262
|
+
sendTo(projector: IProjector<TSource>): void;
|
|
263
|
+
/**
|
|
264
|
+
* Send changes to a projector.
|
|
265
|
+
* @param factory
|
|
266
|
+
*/
|
|
267
|
+
sendTo(factory: Func<IProjector<TSource>>): void;
|
|
268
|
+
pause(): void;
|
|
269
|
+
resume(): void;
|
|
270
|
+
}
|
|
271
|
+
declare class Recorder<TSource extends object> extends RecorderBase<TSource> {
|
|
272
|
+
/**
|
|
273
|
+
* Receive changes from the tracked object.
|
|
274
|
+
* @param path
|
|
275
|
+
* @param value
|
|
276
|
+
* @returns
|
|
277
|
+
*/
|
|
278
|
+
receive(path: any[], value: any): void;
|
|
279
|
+
}
|
|
280
|
+
declare class LazyRecorder<TSource extends object> extends RecorderBase<TSource> {
|
|
281
|
+
protected _wait: number;
|
|
282
|
+
protected _buffer: Map<string, Patch>;
|
|
283
|
+
constructor(initial: TSource, _wait?: number);
|
|
284
|
+
/**
|
|
285
|
+
* Receive changes from the tracked object.
|
|
286
|
+
* @param path
|
|
287
|
+
* @param value
|
|
288
|
+
* @returns
|
|
289
|
+
*/
|
|
290
|
+
receive(path: any[], value: any): void;
|
|
291
|
+
protected readonly receiveCore: lodash_es.DebouncedFunc<() => void>;
|
|
292
|
+
}
|
|
293
|
+
|
|
288
294
|
/**
|
|
289
295
|
* Scheduler abstract class, used to schedule projector effects.
|
|
290
296
|
*/
|
|
@@ -328,8 +334,9 @@ declare class TotalScheduler<TTarget> extends Scheduler<TTarget> {
|
|
|
328
334
|
/**
|
|
329
335
|
* Track changes to an object.
|
|
330
336
|
* @param initial Source object to track. This must the raw object, not reactive-enabled object.
|
|
337
|
+
* @param [wait=500] Wait before change notification. Useful when the object changes at high frequency.
|
|
331
338
|
* @returns A tuple of the tracked object and a recorder.
|
|
332
339
|
*/
|
|
333
|
-
declare function track<TSource extends object>(initial: TSource): [TSource,
|
|
340
|
+
declare function track<TSource extends object>(initial: TSource, wait?: number): [TSource, IRecorder<TSource>];
|
|
334
341
|
|
|
335
342
|
export { Builder, DynamicProjector, EffectFactory, LazyRecorder, LazyScheduler, Projector, ProjectorBase, Recorder, RecorderBase, Scheduler, TotalScheduler, track };
|
package/types/types.d.ts
CHANGED
|
@@ -54,6 +54,19 @@ export type ArrayEffectOptions = {
|
|
|
54
54
|
resolveHeader: (key: string | symbol, index?: number) => string;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
|
|
58
|
+
export type RecorderEvents = {
|
|
59
|
+
record: { next: any; patches: Patch[]; };
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export interface IRecorder<TSource extends object> extends IEventful<RecorderEvents> {
|
|
63
|
+
pause(): void;
|
|
64
|
+
receive(path: any[], value: any): void;
|
|
65
|
+
resume(): void;
|
|
66
|
+
sendTo(projector: IProjector<TSource>): void;
|
|
67
|
+
sendTo(factory: Func<IProjector<TSource>>): void;
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
/**
|
|
58
71
|
* Strategy defines actual execution methods for projecting values to target.
|
|
59
72
|
*/
|