@cyysummer/projector 0.0.12 → 0.0.13
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 +47 -12
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @cyysummer/projector v0.0.
|
|
2
|
+
* @cyysummer/projector v0.0.13
|
|
3
3
|
* (c) 2021-PRESENT Chris Liu
|
|
4
4
|
* @license MIT
|
|
5
5
|
**/
|
|
6
|
-
|
|
6
|
+
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:o}=t,c=this._resolveEffect(r);c&&(this._ensureScheduler(),this._scheduler.enqueue({path:r.join("."),effect:c,ctx:{source:e,path:r,value:o}}))}_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{debounce as L}from"lodash-es";var T=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:o}=t,c=r(this.ensureStrategy(),o);c instanceof Promise&&await c}}},y=class extends T{async flushCore(){let e=[...this._queue.values()];this._queue.clear(),this.run(e)}},h=class extends T{constructor(t,r=500){super(t);this.wait=r;this.flushCore=L(async()=>{let t=[...this._queue.values()];this._queue.clear(),this.run(t)},this.wait)}},p=class extends T{async flushCore(){this.ensureStrategy().reset(),this.run([...this._queue.values()])}};import{debounce as k}from"lodash-es";import A from"on-change";import{cloneDeep as j,debounce as P,set as b}from"lodash-es";import{withEvents as C}from"@cyysummer/core";var S=class extends C(){constructor(t){super();this._paused=!1;this._shadow=j(t)}sendTo(t){this._projectorFactory=typeof t=="function"?t:()=>t}pause(){this._paused=!0}resume(){this._paused=!1}},g=class extends S{receive(e,t){if(this._paused)return;b(this._shadow,e,t);let r=[{path:e,value:t}];this._projectorFactory?.()?.project(this._shadow,...r),this.emit("record",{next:this._shadow,patches:r})}},_=class extends S{constructor(t,r=500){super(t);this._wait=r;this._buffer=new Map;this.receiveCore=P(()=>{let t=[...this._buffer.values()];log.trace("LazyRecorder.receiveCore,",t),this._buffer.clear();for(let r of t)b(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())}};function w(a,e=500){let t=e>0?new _(a,e):new g(a);return[A(a,(o,c)=>t.receive(o,c),{pathAsArray:!0}),t]}var I=class{constructor(e){this._initial=e;this._waitTime=500;if(!e)throw new Error("Builder: initial object is required.")}buildDynamic(){if(!this._schema)throw new Error("Builder: no schema. Call `loadSchema()` before build.");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._schema)throw new Error("Builder: no schema. Call `loadSchema()` before build.");if(!this._strategyFactory)throw new Error("Builder: no strategy. Call `withStrategy()` before build.");this._scheduler||(this._scheduler=new h);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}}lazy(e=500){if(Number(e)<0)throw new Error("Builder: wait time must be >= 0.");return this._waitTime=e,this}loadSchema(e){return this._schema=e,this}onFlush(e){return this._flushCallback=e,this}withLazyScheduler(){return this._scheduler=new h(void 0,this._waitTime),this}withScheduler(){return this._scheduler=new y(void 0),this}withTotalScheduler(){return this._scheduler=new p,this}withStrategy(e){return this._strategyFactory=typeof e=="function"?e:()=>e,this}track(){this._recorder&&this._tracked||([this._tracked,this._recorder]=w(this._initial,this._waitTime))}};import{get as E,keys as R}from"lodash-es";var x=a=>{},v=class{at(e){return(t,r)=>{let o=i(r);return t.execute(e,o)}}atWith(e,t){return async(o,c)=>{let u=i(c),n=await t(u);return o.execute(e,n)}}arrayAt(e,t){return(r,o)=>{let c=o.path?E(o.source,o.path):o.value;if(c&&Array.isArray(c)&&c.length>0){let u=m(c,t);return r.executeArray(e,c,u)}}}arrayFrom(e,t,r){return async(c,u)=>{let n=i(u),s=await t(n),F=m(s,r);return c.executeArray(e,s,F)}}arrayAtWith(e,t,r){return(o,c)=>{let u=c.path?E(c.source,c.path):c.value;if(u&&Array.isArray(u)&&u.length>0){let n=u.map(t),s=m(u,r);return o.executeArray(e,n,s)}}}loop(e){return async(t,r)=>{let o=i(r);if(Array.isArray(o)){let c=o;for(let u=0;u<c.length;u++){let n=c[u];await e(n,u)(t,{value:n})}}else throw new Error(`Effect: Value at path '${r.path}' is not an array.`)}}sourceWith(e,t){return async(r,o)=>{let c=await t(o.source);return r.execute(e,c)}}raw(e,t){return(r,o)=>r.execute(e,t)}sequence(...e){return async(t,r)=>{let o=i(r);for(let c of e)await c(t,{value:o})}}sequenceFromSource(e,...t){return async(r,o)=>{let c=await e(o.source);for(let u of t)await u(r,{value:c})}}sequenceWith(e,...t){return async(o,c)=>{let u=i(c),n=await e(u);for(let s of t)await s(o,{value:n})}}when(e,t,r=x){return(o,c)=>{let u=i(c);return(e(u)?t:r)(o,{value:u})}}whenFromSource(e,t,r=x){return(o,c)=>(e(c.source)?t:r)(o,c)}},m=(a,e)=>({keys:typeof a[0]=="object"?R(a[0]):[],resolveHeader:(t,r)=>String(t),...e}),i=a=>a.source&&a.path?E(a.source,a.path):a.value;export{I as Builder,d as DynamicProjector,v as EffectFactory,_ as LazyRecorder,h as LazyScheduler,f as Projector,l as ProjectorBase,g as Recorder,S as RecorderBase,y as Scheduler,T as SchedulerBase,p as TotalScheduler,w as track};
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
package/types/lib.d.ts
CHANGED
|
@@ -121,16 +121,22 @@ declare class DynamicProjector<TSource> extends ProjectorBase<TSource> {
|
|
|
121
121
|
protected _ensureScheduler(): void;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Builder pattern for projector.
|
|
126
|
+
* @template TSource Source object structure.
|
|
127
|
+
* @template TTarget Projection target.
|
|
128
|
+
* @template TLocation A descriptor of location in `TTarget` where projection effects are executed.
|
|
129
|
+
*/
|
|
124
130
|
declare class Builder<TSource extends object, TTarget, TLocation> {
|
|
125
131
|
private _initial;
|
|
126
|
-
private _schema;
|
|
127
|
-
private _waitTime;
|
|
128
132
|
private _flushCallback?;
|
|
129
133
|
private _recorder?;
|
|
134
|
+
private _schema?;
|
|
130
135
|
private _scheduler?;
|
|
131
136
|
private _strategyFactory?;
|
|
132
137
|
private _tracked?;
|
|
133
|
-
|
|
138
|
+
private _waitTime;
|
|
139
|
+
constructor(_initial: TSource);
|
|
134
140
|
buildDynamic(): {
|
|
135
141
|
tracked: TSource;
|
|
136
142
|
recorder: IRecorder<TSource>;
|
|
@@ -142,6 +148,13 @@ declare class Builder<TSource extends object, TTarget, TLocation> {
|
|
|
142
148
|
recorder: IRecorder<TSource>;
|
|
143
149
|
scheduler: IScheduler<TTarget>;
|
|
144
150
|
};
|
|
151
|
+
/**
|
|
152
|
+
* Use debounced Recorder/Scheduler.
|
|
153
|
+
* @param wait Debounce time in milliseconds. Default: 500.
|
|
154
|
+
* @returns
|
|
155
|
+
*/
|
|
156
|
+
lazy(wait?: number): Builder<TSource, TTarget, TLocation>;
|
|
157
|
+
loadSchema(schema: Schema<TSource>): Builder<TSource, TTarget, TLocation>;
|
|
145
158
|
/**
|
|
146
159
|
* Provide a callback to execute after scheduler flushed.
|
|
147
160
|
* @param callback
|
|
@@ -149,6 +162,7 @@ declare class Builder<TSource extends object, TTarget, TLocation> {
|
|
|
149
162
|
*/
|
|
150
163
|
onFlush(callback: Action): Builder<TSource, TTarget, TLocation>;
|
|
151
164
|
withLazyScheduler(): Builder<TSource, TTarget, TLocation>;
|
|
165
|
+
withScheduler(): Builder<TSource, TTarget, TLocation>;
|
|
152
166
|
withTotalScheduler(): Builder<TSource, TTarget, TLocation>;
|
|
153
167
|
withStrategy(strategy: ITargetExecutionStrategy<TTarget, TLocation>): Builder<TSource, TTarget, TLocation>;
|
|
154
168
|
withStrategy(factory: Func<ITargetExecutionStrategy<TTarget, TLocation>>): Builder<TSource, TTarget, TLocation>;
|
|
@@ -180,6 +194,14 @@ declare class EffectFactory<TSource extends object, TLocation = any> {
|
|
|
180
194
|
* @returns
|
|
181
195
|
*/
|
|
182
196
|
arrayAt<T, U = UnwrapArray<T>>(location: TLocation, options?: Partial<ArrayEffectOptions>): Effect<TSource, T>;
|
|
197
|
+
/**
|
|
198
|
+
* Create an effect bound to a specific location on the target. Source value is converted to array using mapper.
|
|
199
|
+
* @param location Identifies the location on the effect target where this effect will be executed.
|
|
200
|
+
* @param mapper Function to transform the element of the array.
|
|
201
|
+
* @param options
|
|
202
|
+
* @returns
|
|
203
|
+
*/
|
|
204
|
+
arrayFrom<T, U extends any[]>(location: TLocation, mapper: Func1<T, U>, options?: Partial<ArrayEffectOptions>): Effect<TSource, U>;
|
|
183
205
|
/**
|
|
184
206
|
* Create an effect bound to a specific location on the target. When it executs, source value will be transformed with `mapper`. Source value should be an array.
|
|
185
207
|
* @param location Identifies the location on the effect target where this effect will be executed.
|
|
@@ -209,18 +231,25 @@ declare class EffectFactory<TSource extends object, TLocation = any> {
|
|
|
209
231
|
*/
|
|
210
232
|
raw<T>(location: TLocation, rawValue: T): Effect<TSource, T>;
|
|
211
233
|
/**
|
|
212
|
-
*
|
|
234
|
+
* Execute multiple effects in sequence.
|
|
213
235
|
* @param effects Effects to call.
|
|
214
236
|
* @returns
|
|
215
237
|
*/
|
|
216
|
-
sequence<T>(effects: Effect<TSource, T>[]): Effect<TSource, T>;
|
|
238
|
+
sequence<T>(...effects: Effect<TSource, T>[]): Effect<TSource, T>;
|
|
217
239
|
/**
|
|
218
|
-
*
|
|
240
|
+
* Execute multiple effects in sequence. When it executs, `TSource` object will be transformed with `mapper` first, then pass to `effects`.
|
|
241
|
+
* @param mapper Function to transform the value.
|
|
219
242
|
* @param effects Effects to call.
|
|
243
|
+
* @returns
|
|
244
|
+
*/
|
|
245
|
+
sequenceFromSource<R>(mapper: Func1<TSource, R>, ...effects: Effect<TSource, R>[]): Effect<TSource, R>;
|
|
246
|
+
/**
|
|
247
|
+
* Execute multiple effects in sequence. When it executs, source value will be transformed with `mapper` first, then pass to `effects`.
|
|
220
248
|
* @param mapper Function to transform the value.
|
|
249
|
+
* @param effects Effects to call.
|
|
221
250
|
* @returns
|
|
222
251
|
*/
|
|
223
|
-
sequenceWith<T, R>(
|
|
252
|
+
sequenceWith<T, R>(mapper: Func1<T, R>, ...effects: Effect<TSource, any>[]): Effect<TSource, R>;
|
|
224
253
|
/**
|
|
225
254
|
* Execute effect based on condition. The condition is based on the value of the current property path.
|
|
226
255
|
* @param condition Condition delegate that takes the value of the property and returns true or false.
|
|
@@ -294,7 +323,7 @@ declare class LazyRecorder<TSource extends object> extends RecorderBase<TSource>
|
|
|
294
323
|
/**
|
|
295
324
|
* Scheduler abstract class, used to schedule projector effects.
|
|
296
325
|
*/
|
|
297
|
-
declare abstract class
|
|
326
|
+
declare abstract class SchedulerBase<TTarget> implements IScheduler<TTarget> {
|
|
298
327
|
protected readonly _queue: Map<string, IScheduleItem<any, any>>;
|
|
299
328
|
protected _strategyFactory?: Func<ITargetExecutionStrategy<TTarget, any>>;
|
|
300
329
|
constructor(strategy?: ITargetExecutionStrategy<TTarget, any>);
|
|
@@ -307,6 +336,12 @@ declare abstract class Scheduler<TTarget> implements IScheduler<TTarget> {
|
|
|
307
336
|
protected abstract flushCore(): MaybePromise<void>;
|
|
308
337
|
protected run(list: IScheduleItem<any, any>[]): Promise<void>;
|
|
309
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* Run all queued effects at once.
|
|
341
|
+
*/
|
|
342
|
+
declare class Scheduler<TTarget> extends SchedulerBase<TTarget> {
|
|
343
|
+
protected flushCore(): Promise<void>;
|
|
344
|
+
}
|
|
310
345
|
/**
|
|
311
346
|
* A scheduler that **delays and batches** effect executions using debounce.
|
|
312
347
|
*
|
|
@@ -319,15 +354,15 @@ declare abstract class Scheduler<TTarget> implements IScheduler<TTarget> {
|
|
|
319
354
|
* `LazyScheduler` is more conservative: it waits for a quiet period before flushing the accumulated
|
|
320
355
|
* effects in batch.
|
|
321
356
|
*/
|
|
322
|
-
declare class LazyScheduler<TTarget> extends
|
|
357
|
+
declare class LazyScheduler<TTarget> extends SchedulerBase<TTarget> {
|
|
323
358
|
protected wait: number;
|
|
324
359
|
constructor(strategy?: ITargetExecutionStrategy<TTarget, any>, wait?: number);
|
|
325
360
|
protected readonly flushCore: lodash_es.DebouncedFunc<() => Promise<void>>;
|
|
326
361
|
}
|
|
327
362
|
/**
|
|
328
|
-
* Run all queued effects at once. The queue will NOT be cleared. The strategy will `reset()` before running any effects.
|
|
363
|
+
* Run all queued effects at once. The queue will NOT be cleared. The strategy will `reset()` before running any effects, in order to make sure strategy is in initial state.
|
|
329
364
|
*/
|
|
330
|
-
declare class TotalScheduler<TTarget> extends
|
|
365
|
+
declare class TotalScheduler<TTarget> extends SchedulerBase<TTarget> {
|
|
331
366
|
protected flushCore(): Promise<void>;
|
|
332
367
|
}
|
|
333
368
|
|
|
@@ -339,4 +374,4 @@ declare class TotalScheduler<TTarget> extends Scheduler<TTarget> {
|
|
|
339
374
|
*/
|
|
340
375
|
declare function track<TSource extends object>(initial: TSource, wait?: number): [TSource, IRecorder<TSource>];
|
|
341
376
|
|
|
342
|
-
export { Builder, DynamicProjector, EffectFactory, LazyRecorder, LazyScheduler, Projector, ProjectorBase, Recorder, RecorderBase, Scheduler, TotalScheduler, track };
|
|
377
|
+
export { Builder, DynamicProjector, EffectFactory, LazyRecorder, LazyScheduler, Projector, ProjectorBase, Recorder, RecorderBase, Scheduler, SchedulerBase, TotalScheduler, track };
|