@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 CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * @cyysummer/projector v0.0.11
2
+ * @cyysummer/projector v0.0.12
3
3
  * (c) 2021-PRESENT Chris Liu
4
4
  * @license MIT
5
5
  **/
6
- import k from"on-change";import{cloneDeep as v,debounce as F,set as E}from"lodash-es";import{withEvents as j}from"@cyysummer/core";var f=class extends j(){constructor(t){super();this._paused=!1;this._shadow=v(t)}sendTo(t){this._projectorFactory=typeof t=="function"?t:()=>t}pause(){this._paused=!0}resume(){this._paused=!1}},i=class extends f{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})}},d=class extends f{constructor(t,r=500){super(t);this._wait=r;this._buffer=new Map;this.receiveCore=F(()=>{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 P from"on-change";var y=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}},p=class extends y{constructor(e,t){super(e,t)}},S=class extends y{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 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:o}=t,c=r(this.ensureStrategy(),o);c instanceof Promise&&await c}}},h=class extends g{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)}},_=class extends g{async flushCore(){this.ensureStrategy().reset(),this.run([...this._queue.values()])}};import{debounce as C}from"lodash-es";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 S(this._schema);return this._scheduler&&e.withScheduler(this._scheduler),this._recorder.sendTo(e),{tracked:this._tracked,recorder:this._recorder,projector:e,scheduler:this._scheduler}}buildStatic(){if(!this._strategy&&!this._strategyFactory)throw new Error("Builder: no strategy was provided. Call `withStrategy()` to provide.");this._scheduler||(this._scheduler=new h),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._strategy??this._strategyFactory);let t=new p(this._schema,this._scheduler);return this._recorder.sendTo(t),this._recorder.on("record",this._waitTime?C(e,this._waitTime):e),{tracked:this._tracked,recorder:this._recorder,scheduler:this._scheduler}}onFlush(e){return this._flushCallback=e,this}withLazyScheduler(e=500){return this._scheduler=new h(void 0,e),this}withTotalScheduler(){return this._scheduler=new _,this}withStrategy(e){return typeof e=="function"?this._strategyFactory=e:this._strategy=e,this}track(){this._recorder&&this._tracked||(this._recorder=this._waitTime>0?new d(this._initial,this._waitTime):new i(this._initial),this._tracked=P(this._initial,(e,t)=>this._recorder.receive(e,t),{pathAsArray:!0}))}};import{get as m,keys as w}from"lodash-es";var I=u=>{},x=class{at(e){return(t,r)=>{let o=T(r);return t.execute(e,o)}}atWith(e,t){return(o,c)=>{let a=T(c),s=t(a);return o.execute(e,s)}}arrayAt(e,t){return(r,o)=>{let c=o.path?m(o.source,o.path):o.value;if(c&&Array.isArray(c)&&c.length>0){let a={keys:typeof c[0]=="object"?w(c[0]):[],resolveHeader:(s,n)=>String(s),...t};return r.executeArray(e,c,a)}}}arrayAtWith(e,t,r){return(o,c)=>{let a=c.path?m(c.source,c.path):c.value;if(a&&Array.isArray(a)&&a.length>0){let s=a.map(t),n={keys:typeof a[0]=="object"?w(a[0]):[],resolveHeader:(l,A)=>String(l),...r};return o.executeArray(e,s,n)}}}loop(e){return async(t,r)=>{let o=T(r);if(Array.isArray(o)){let c=o;for(let a=0;a<c.length;a++){let s=c[a],l=e(s,a)(t,{value:s});l instanceof Promise&&await l}}else throw new Error(`Effect: Value at path '${r.path}' is not an array.`)}}sourceWith(e,t){return(r,o)=>{let c=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=T(r);for(let c of e)await c(t,{value:o})}}sequenceWith(e,t){return async(o,c)=>{let a=T(c),s=t(a);for(let n of e)await n(o,{value:s})}}when(e,t,r=I){return(o,c)=>{let a=T(c);return(e(a)?t:r)(o,{value:a})}}whenFromSource(e,t,r=I){return(o,c)=>(e(c.source)?t:r)(o,c)}},T=u=>u.source&&u.path?m(u.source,u.path):u.value;function X(u){let e=new i(u);return[k(u,(r,o)=>e.receive(r,o),{pathAsArray:!0}),e]}export{b as Builder,S as DynamicProjector,x as EffectFactory,d as LazyRecorder,h as LazyScheduler,p as Projector,y as ProjectorBase,i as Recorder,f as RecorderBase,g as Scheduler,_ as TotalScheduler,X as track};
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyysummer/projector",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "A powerful state projection library for creating anything.",
5
5
  "license": "MIT",
6
6
  "author": "Chris Liu",
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: RecorderBase<TSource>;
136
+ recorder: IRecorder<TSource>;
183
137
  projector: DynamicProjector<TSource>;
184
138
  scheduler: IScheduler<TTarget> | undefined;
185
139
  };
186
- buildStatic(): {
140
+ build(): {
187
141
  tracked: TSource;
188
- recorder: RecorderBase<TSource>;
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(wait?: number): Builder<TSource, TTarget, TLocation>;
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, Recorder<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
  */