@cyysummer/projector 0.0.8 → 0.0.10

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.8
2
+ * @cyysummer/projector v0.0.10
3
3
  * (c) 2021-PRESENT Chris Liu
4
4
  * @license MIT
5
5
  **/
6
- import b from"on-change";import{set as m}from"lodash-es";import{withEvents as I}from"@cyysummer/core";var T=class extends I(){constructor(e){super();this._paused=!1;this._shadow=structuredClone(e)}receive(e,r){if(this._paused)return;m(this._shadow,e,r);let o=[{path:e,value:r}];this.emit("record",{next:this._shadow,patches:o}),this._ensureProjector(),this._projector?.project(this._shadow,...o)}sendTo(e){typeof e=="function"?this._projectorFactory=e:this._projector=e}pause(){this._paused=!0}resume(){this._paused=!1}_ensureProjector(){!this._projector&&this._projectorFactory&&(this._projector=this._projectorFactory())}};import{get as l,keys as d}from"lodash-es";var y=s=>{},S=class{constructor(t){this._strategy=t}at(t){return(e,r)=>{let o=i(r);return this._strategy.execute(e,t,o)}}atWith(t,e){return(o,c)=>{let u=i(c),a=e(u);return this._strategy.execute(o,t,a)}}arrayAt(t,e){return(r,o)=>{let c=o.path?l(o.source,o.path):o.value;if(c&&Array.isArray(c)&&c.length>0){let u={keys:typeof c[0]=="object"?d(c[0]):[],resolveHeader:(a,n)=>String(a),...e};return this._strategy.executeArray(r,t,c,u)}}}arrayAtWith(t,e,r){return(o,c)=>{let u=c.path?l(c.source,c.path):c.value;if(u&&Array.isArray(u)&&u.length>0){let a=u.map(e),n={keys:typeof u[0]=="object"?d(u[0]):[],resolveHeader:(f,v)=>String(f),...r};return this._strategy.executeArray(o,t,a,n)}}}loop(t){return async(e,r)=>{let o=i(r);if(Array.isArray(o)){let c=o;for(let u=0;u<c.length;u++){let a=c[u],f=t(a,u)(e,{value:a});f instanceof Promise&&await f}}else throw new Error(`Effect: Value at path '${r.path}' is not an array.`)}}sourceWith(t,e){return(r,o)=>{let c=e(o.source);return this._strategy.execute(r,t,c)}}raw(t,e){return(r,o)=>this._strategy.execute(r,t,e)}sequence(t){return async(e,r)=>{let o=i(r);for(let c of t)await c(e,{value:o})}}sequenceWith(t,e){return async(o,c)=>{let u=i(c),a=e(u);for(let n of t)await n(o,{value:a})}}when(t,e,r=y){return(o,c)=>{let u=i(c);return(t(u)?e:r)(o,{value:u})}}whenFromSource(t,e,r=y){return(o,c)=>(t(c.source)?e:r)(o,c)}},i=s=>s.source&&s.path?l(s.source,s.path):s.value;var h=class{constructor(t){this._schema=t;if(!t)throw new Error("Projector: Schema is required.")}project(t,...e){for(let r of e)this._dispatch(t,r)}_dispatch(t,e){let{path:r,value:o}=e,c=this._resolveEffect(r);c&&(this._ensureScheduler(),this._scheduler.enqueue({path:r.join("."),effect:c,ctx:{source:t,path:r,value:o}}))}_ensureScheduler(){if(!this._scheduler)throw new Error("Projector: no scheduler.")}_resolveEffect(t){let e=this._schema;for(let r of t){if(!e)return null;e=e[r]}return typeof e=="function"?e:null}},_=class extends h{constructor(t,e){super(t),this._scheduler=e}},g=class extends h{scheduleWith(t){return typeof t=="function"?this._schedulerFactory=t:this._scheduler=t,this}_ensureScheduler(){if(!this._scheduler&&this._schedulerFactory&&(this._scheduler=this._schedulerFactory()),!this._scheduler)throw new Error("Projector: no scheduler.")}};var p=class{constructor(t){this._target=t}withTarget(t){return typeof t=="function"?this._targetFactory=t:this._target=t,this}checkTarget(){if(!this._target&&this._targetFactory&&(this._target=this._targetFactory()),!this._target)throw new Error("Scheduler: target is not set")}},E=class extends p{constructor(){super(...arguments);this._queue=new Map}enqueue(e){return this._queue.set(e.path,e),this}async flush(){this.checkTarget(),log.trace("BufferedScheduler: flushing",[...this._queue.keys()]);let e=[...this._queue.values()];this._queue.clear();for(let r of e){let{effect:o,ctx:c}=r,u=o(this._target,c);u instanceof Promise&&await u}}};function k(s){let t=new T(s);return[b(s,t.receive.bind(t),{pathAsArray:!0}),t]}export{E as BufferedScheduler,g as DynamicProjector,S as EffectFactory,_ as Projector,h as ProjectorBase,T as Recorder,p as Scheduler,k as track};
6
+ import L from"on-change";import{cloneDeep as x,set as w}from"lodash-es";import{withEvents as v}from"@cyysummer/core";var i=class extends v(){constructor(t){super();this._paused=!1;this._shadow=x(t)}receive(t,r){if(this._paused)return;w(this._shadow,t,r);let o=[{path:t,value:r}];this.emit("record",{next:this._shadow,patches:o}),this._ensureProjector(),this._projector?.project(this._shadow,...o)}sendTo(t){typeof t=="function"?this._projectorFactory=t:this._projector=t}pause(){this._paused=!0}resume(){this._paused=!1}_ensureProjector(){!this._projector&&this._projectorFactory&&(this._projector=this._projectorFactory())}};import F from"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: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)}},y=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 b}from"lodash-es";var d=class{constructor(e){this._strategy=e;this._queue=new Map}enqueue(e){return this._queue.set(e.path,e),this}flush(){return this.checkStrategy(),log.trace("Scheduler.flush()",[...this._queue.keys()]),this.flushCore()}withStrategy(e){return typeof e=="function"?this._strategyFactory=e:this._strategy=e,this}checkStrategy(){if(!this._strategy&&this._strategyFactory&&(this._strategy=this._strategyFactory()),!this._strategy)throw new Error("Scheduler: no strategy.")}async run(e){for(let t of e){let{effect:r,ctx:o}=t,c=r(this._strategy,o);c instanceof Promise&&await c}}},p=class extends d{constructor(t,r=500){super(t);this.wait=r;this.flushCore=b(async()=>{let t=[...this._queue.values()];this._queue.clear(),this.run(t)},this.wait)}},S=class extends d{async flushCore(){this._strategy.reset(),this.run([...this._queue.values()])}};import{debounce as j}from"lodash-es";var _=class{constructor(e,t){this._initial=e;this._schema=t;this._flushWait=0}buildDynamic(){this.track();let e=new y(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._scheduler)throw new Error("Builder: no scheduler was provided. Call `withLazyScheduler()` or `withTotalScheduler()` to provide.");if(!this._strategy&&!this._strategyFactory)throw new Error("Builder: no strategy was provided. Call `withStrategy()` to provide.");if(!this._onFlush)throw new Error("Builder: no flush handler was provided. Call `onFlush()` to provide.");let e=async()=>{await this._scheduler.flush(),this._onFlush()};this.track(),this._scheduler.withStrategy(this._strategy??this._strategyFactory);let t=new f(this._schema,this._scheduler);return this._recorder.sendTo(t),this._recorder.on("record",this._flushWait?j(e,this._flushWait):e),{tracked:this._tracked,recorder:this._recorder,scheduler:this._scheduler}}onFlush(e,t=500){return this._onFlush=e,this._flushWait=t,this}withLazyScheduler(e=500){return this._scheduler=new p(void 0,e),this}withTotalScheduler(){return this._scheduler=new S,this}withStrategy(e){return typeof e=="function"?this._strategyFactory=e:this._strategy=e,this}track(){this._recorder&&this._tracked||(this._recorder=new i(this._initial),this._tracked=F(this._initial,(e,t)=>this._recorder.receive(e,t),{pathAsArray:!0}))}};import{get as g,keys as E}from"lodash-es";var m=u=>{},I=class{at(e){return(t,r)=>{let o=h(r);return t.execute(e,o)}}atWith(e,t){return(o,c)=>{let a=h(c),s=t(a);return o.execute(e,s)}}arrayAt(e,t){return(r,o)=>{let c=o.path?g(o.source,o.path):o.value;if(c&&Array.isArray(c)&&c.length>0){let a={keys:typeof c[0]=="object"?E(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?g(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"?E(a[0]):[],resolveHeader:(T,P)=>String(T),...r};return o.executeArray(e,s,n)}}}loop(e){return async(t,r)=>{let o=h(r);if(Array.isArray(o)){let c=o;for(let a=0;a<c.length;a++){let s=c[a],T=e(s,a)(t,{value:s});T instanceof Promise&&await T}}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=h(r);for(let c of e)await c(t,{value:o})}}sequenceWith(e,t){return async(o,c)=>{let a=h(c),s=t(a);for(let n of e)await n(o,{value:s})}}when(e,t,r=m){return(o,c)=>{let a=h(c);return(e(a)?t:r)(o,{value:a})}}whenFromSource(e,t,r=m){return(o,c)=>(e(c.source)?t:r)(o,c)}},h=u=>u.source&&u.path?g(u.source,u.path):u.value;function G(u){let e=new i(u);return[L(u,(r,o)=>e.receive(r,o),{pathAsArray:!0}),e]}export{_ as Builder,y as DynamicProjector,I as EffectFactory,p as LazyScheduler,f as Projector,l as ProjectorBase,i as Recorder,d as Scheduler,S as TotalScheduler,G 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.8",
3
+ "version": "0.0.10",
4
4
  "description": "A powerful state projection library for creating anything.",
5
5
  "license": "MIT",
6
6
  "author": "Chris Liu",
@@ -18,7 +18,7 @@
18
18
  }
19
19
  },
20
20
  "dependencies": {
21
- "lodash-es": "^4.17.22",
21
+ "lodash-es": "4.17.22",
22
22
  "on-change": "^6.0.1",
23
23
  "@cyysummer/core": "^0.0.12"
24
24
  },
@@ -26,11 +26,11 @@
26
26
  "@cyysummer/core": "^0.0.12"
27
27
  },
28
28
  "devDependencies": {
29
- "@types/lodash-es": "^4.17.12",
30
- "tsup": "^8.5.0",
31
- "typescript": "^5.9.2",
32
- "vite": "^7.1.5",
33
- "vitest": "^3.2.4"
29
+ "@types/lodash-es": "4.17.12",
30
+ "tsup": "^8.5.1",
31
+ "typescript": "^5.9.3",
32
+ "vite": "^7.3.1",
33
+ "vitest": "^4.0.17"
34
34
  },
35
35
  "publishConfig": {
36
36
  "access": "public"
package/types/lib.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import * as lodash_es from 'lodash-es';
2
+
1
3
  /**
2
4
  * A Schema defines how to project changes from a source object to a target object.
3
5
  */
@@ -16,8 +18,8 @@ type Schema<TSource, T = TSource> = {
16
18
  /**
17
19
  * An effect defines how to project a value from source to target.
18
20
  */
19
- // todo: Solve this `any`
20
- type Effect<TSource, TValue> = (target: any, ctx: IEffectContext<TSource, TValue>) => MaybePromise<void>;
21
+ // todo: Solve ITargetExecutionStrategy<any, any>. How to obtain TTarget and TLocation?
22
+ type Effect<TSource, TValue> = (strategy: ITargetExecutionStrategy<any, any>, ctx: IEffectContext<TSource, TValue>) => MaybePromise<void>;
21
23
 
22
24
  /**
23
25
  * The context for an effect. It contains information about changes.
@@ -57,9 +59,10 @@ type ArrayEffectOptions = {
57
59
  /**
58
60
  * Strategy defines actual execution methods for projecting values to target.
59
61
  */
60
- interface ITargetExecutionStrategy<TTarget, TLocation = any> {
61
- execute<T extends any>(target: TTarget, location: TLocation, value: T): MaybePromise<void>;
62
- executeArray<T extends any>(target: TTarget, location: TLocation, rows: T[], options: ArrayEffectOptions): MaybePromise<void>;
62
+ interface ITargetExecutionStrategy<TTarget, TLocation> {
63
+ execute<T extends any>(location: TLocation, value: T): MaybePromise<void>;
64
+ executeArray<T extends any>(location: TLocation, rows: T[], options: ArrayEffectOptions): MaybePromise<void>;
65
+ reset(): void;
63
66
  }
64
67
 
65
68
  interface IProjector<TSource> {
@@ -69,8 +72,8 @@ interface IProjector<TSource> {
69
72
  interface IScheduler<TTarget> {
70
73
  enqueue(effect: IScheduleItem): void;
71
74
  flush(): MaybePromise<void>;
72
- withTarget(target: TTarget): IScheduler<TTarget>;
73
- withTarget(target: Func<TTarget>): IScheduler<TTarget>;
75
+ withStrategy(strategy: ITargetExecutionStrategy<TTarget, any>): IScheduler<TTarget>;
76
+ withStrategy(factory: Func<ITargetExecutionStrategy<TTarget, any>>): IScheduler<TTarget>;
74
77
  }
75
78
 
76
79
  interface IScheduleItem<TSource, TValue> {
@@ -122,34 +125,83 @@ declare class Recorder<TSource extends object> extends Recorder_base {
122
125
  private _ensureProjector;
123
126
  }
124
127
 
128
+ declare abstract class ProjectorBase<TSource> implements IProjector<TSource> {
129
+ protected _schema: Schema<TSource>;
130
+ protected _scheduler?: IScheduler<any> | undefined;
131
+ constructor(_schema: Schema<TSource>, _scheduler?: IScheduler<any> | undefined);
132
+ project(next: TSource, ...patches: Patch[]): void;
133
+ protected _dispatch(next: TSource, patch: Patch): void;
134
+ protected _ensureScheduler(): void;
135
+ protected _resolveEffect(path: (string | symbol)[]): Effect<TSource, any> | null;
136
+ }
137
+ declare class Projector<TSource> extends ProjectorBase<TSource> {
138
+ constructor(_schema: Schema<TSource>, _scheduler: IScheduler<any>);
139
+ }
140
+ declare class DynamicProjector<TSource> extends ProjectorBase<TSource> {
141
+ private _schedulerFactory?;
142
+ withScheduler(scheduler: IScheduler<any>): IProjector<TSource>;
143
+ withScheduler(factory: Func<IScheduler<any>>): IProjector<TSource>;
144
+ protected _ensureScheduler(): void;
145
+ }
146
+
147
+ declare class Builder<TSource extends object, TTarget, TLocation> {
148
+ private _initial;
149
+ private _schema;
150
+ private _flushWait;
151
+ private _onFlush?;
152
+ private _recorder?;
153
+ private _scheduler?;
154
+ private _strategy?;
155
+ private _strategyFactory?;
156
+ private _tracked?;
157
+ constructor(_initial: TSource, _schema: Schema<TSource>);
158
+ buildDynamic(): {
159
+ tracked: TSource;
160
+ recorder: Recorder<TSource>;
161
+ projector: DynamicProjector<TSource>;
162
+ scheduler: IScheduler<TTarget> | undefined;
163
+ };
164
+ buildStatic(): {
165
+ tracked: TSource;
166
+ recorder: Recorder<TSource>;
167
+ scheduler: IScheduler<TTarget>;
168
+ };
169
+ onFlush(callback: Action, wait?: number): Builder<TSource, TTarget, TLocation>;
170
+ withLazyScheduler(wait?: number): Builder<TSource, TTarget, TLocation>;
171
+ withTotalScheduler(): Builder<TSource, TTarget, TLocation>;
172
+ withStrategy(strategy: ITargetExecutionStrategy<TTarget, TLocation>): Builder<TSource, TTarget, TLocation>;
173
+ withStrategy(factory: Func<ITargetExecutionStrategy<TTarget, TLocation>>): Builder<TSource, TTarget, TLocation>;
174
+ private track;
175
+ }
176
+
125
177
  /**
126
178
  * Build effects for a target.
179
+ * @template TSource The type of the source object.
180
+ * @template TLocation The type used to describe a location within an effect target. This is interpreted by the execution strategy and may represent a bookmark, anchor, or address.
127
181
  */
128
- declare class EffectFactory<TTarget, TSource extends object, TLocation = any> {
129
- protected _strategy: ITargetExecutionStrategy<TTarget, TLocation>;
130
- constructor(_strategy: ITargetExecutionStrategy<TTarget, TLocation>);
182
+ declare class EffectFactory<TSource extends object, TLocation = any> {
131
183
  /**
132
- * Create an effect that will be applied at the specified location.
133
- * @param location The location in `TTarget` where the effect is executed.
184
+ * Create an effect bound to a specific location on the target. Source value should be primitive type.
185
+ * @param location Identifies the location on the effect target where this effect will be executed.
134
186
  * @returns
135
187
  */
136
188
  at<T>(location: TLocation): Effect<TSource, T>;
137
189
  /**
138
- * Create an effect that will be applied at the specified location. Use `mapper` to transform the value.
139
- * @param location The location in `TTarget` where the effect is executed.
190
+ * 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 primitive type.
191
+ * @param location Identifies the location on the effect target where this effect will be executed.
140
192
  * @param mapper Function to transform the value.
141
193
  * @returns
142
194
  */
143
195
  atWith<T, R>(location: TLocation, mapper: Func1<T, R>): Effect<TSource, R>;
144
196
  /**
145
- * Create an effect that will be applied at the specified location for array data.
146
- * @param location The location in `TTarget` where the effect is executed.
197
+ * Create an effect bound to a specific location on the target. Source value should be an array.
198
+ * @param location Identifies the location on the effect target where this effect will be executed.
147
199
  * @returns
148
200
  */
149
201
  arrayAt<T, U = UnwrapArray<T>>(location: TLocation, options?: Partial<ArrayEffectOptions>): Effect<TSource, T>;
150
202
  /**
151
- * Create an effect that will be applied at the specified location for array data.
152
- * @param location The location in `TTarget` where the effect is executed.
203
+ * 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.
204
+ * @param location Identifies the location on the effect target where this effect will be executed.
153
205
  * @param mapper Function to transform the element of the array.
154
206
  * @returns
155
207
  */
@@ -162,15 +214,15 @@ declare class EffectFactory<TTarget, TSource extends object, TLocation = any> {
162
214
  */
163
215
  loop<T, U = T extends Array<infer K> ? K : never>(each: Func2<U, number, Effect<TSource, U>>): Effect<TSource, T>;
164
216
  /**
165
- * Create an effect that will be applied at the specified location for `TSource` object. Use `mapper` to transform the `TSource` object.
166
- * @param location The location in `TTarget` where the effect is executed.
217
+ * Create an effect bound to a specific location on the target for `TSource` object. When it executs, `TSource` object will be transformed with `mapper`.
218
+ * @param location Identifies the location on the effect target where this effect will be executed.
167
219
  * @param mapper Function to transform the `TSource` object.
168
220
  * @returns
169
221
  */
170
222
  sourceWith<T>(location: TLocation, mapper: Func1<TSource, string>): Effect<TSource, T>;
171
223
  /**
172
- * Create an effect that will be applied at the specified location for raw value. This effect will not read from `TSource` object.
173
- * @param location The location in `TTarget` where the effect is executed.
224
+ * Create an effect bound to a specific location on the target for raw value. This effect will not read from `TSource` object.
225
+ * @param location Identifies the location on the effect target where this effect will be executed.
174
226
  * @param rawValue The value to use.
175
227
  * @returns
176
228
  */
@@ -182,7 +234,7 @@ declare class EffectFactory<TTarget, TSource extends object, TLocation = any> {
182
234
  */
183
235
  sequence<T>(effects: Effect<TSource, T>[]): Effect<TSource, T>;
184
236
  /**
185
- * Call multiple effects in sequence. Use `mapper` to transform the value.
237
+ * Call multiple effects in sequence. When it executs, source value will be transformed with `mapper` first, then pass to `effects`.
186
238
  * @param effects Effects to call.
187
239
  * @param mapper Function to transform the value.
188
240
  * @returns
@@ -206,45 +258,44 @@ declare class EffectFactory<TTarget, TSource extends object, TLocation = any> {
206
258
  whenFromSource<T>(condition: Predicate<TSource>, ifTrue: Effect<TSource, any>, ifFalse?: Effect<TSource, any>): Effect<TSource, T>;
207
259
  }
208
260
 
209
- declare abstract class ProjectorBase<TSource> implements IProjector<TSource> {
210
- protected _schema: Schema<TSource>;
211
- protected _scheduler?: IScheduler<any>;
212
- constructor(_schema: Schema<TSource>);
213
- project(next: TSource, ...patches: Patch[]): void;
214
- protected _dispatch(next: TSource, patch: Patch): void;
215
- protected _ensureScheduler(): void;
216
- protected _resolveEffect(path: (string | symbol)[]): Effect<TSource, any> | null;
217
- }
218
- declare class Projector<TSource> extends ProjectorBase<TSource> {
219
- constructor(_schema: Schema<TSource>, _scheduler: IScheduler<any>);
220
- }
221
- declare class DynamicProjector<TSource> extends ProjectorBase<TSource> {
222
- private _schedulerFactory?;
223
- scheduleWith(scheduler: IScheduler<any>): IProjector<TSource>;
224
- scheduleWith(schedulerFactory: Func<IScheduler<any>>): IProjector<TSource>;
225
- protected _ensureScheduler(): void;
226
- }
227
-
228
261
  /**
229
262
  * Scheduler abstract class, used to schedule projector effects.
230
263
  */
231
264
  declare abstract class Scheduler<TTarget> implements IScheduler<TTarget> {
232
- protected _target?: TTarget | undefined;
233
- protected _targetFactory?: Func<TTarget>;
234
- constructor(_target?: TTarget | undefined);
235
- abstract enqueue(item: IScheduleItem<TTarget, any>): IScheduler<TTarget>;
236
- abstract flush(): MaybePromise<void>;
237
- withTarget(target: TTarget): IScheduler<TTarget>;
238
- withTarget(target: Func<TTarget>): IScheduler<TTarget>;
239
- protected checkTarget(): void;
265
+ protected _strategy?: ITargetExecutionStrategy<TTarget, any> | undefined;
266
+ protected readonly _queue: Map<string, IScheduleItem<any, any>>;
267
+ protected _strategyFactory?: Func<ITargetExecutionStrategy<TTarget, any>>;
268
+ constructor(_strategy?: ITargetExecutionStrategy<TTarget, any> | undefined);
269
+ enqueue(item: IScheduleItem<any, any>): IScheduler<TTarget>;
270
+ flush(): MaybePromise<void>;
271
+ withStrategy(strategy: ITargetExecutionStrategy<TTarget, any>): IScheduler<TTarget>;
272
+ withStrategy(factory: Func<ITargetExecutionStrategy<TTarget, any>>): IScheduler<TTarget>;
273
+ protected checkStrategy(): void;
274
+ protected abstract flushCore(): MaybePromise<void>;
275
+ protected run(list: IScheduleItem<any, any>[]): Promise<void>;
276
+ }
277
+ /**
278
+ * A scheduler that **delays and batches** effect executions using debounce.
279
+ *
280
+ * Effects are collected in a queue and only executed after the specified `wait`
281
+ * has passed without any new effects being enqueued. This helps reduce redundant
282
+ * executions (e.g. during rapid successive state updates) and is especially useful
283
+ * when projecting to expensive targets like UI rendering, DOM updates, or network requests.
284
+ *
285
+ * In contrast to `TotalScheduler` which eagerly executes all effects on every projection,
286
+ * `LazyScheduler` is more conservative: it waits for a quiet period before flushing the accumulated
287
+ * effects in batch.
288
+ */
289
+ declare class LazyScheduler<TTarget> extends Scheduler<TTarget> {
290
+ protected wait: number;
291
+ constructor(strategy?: ITargetExecutionStrategy<TTarget, any>, wait?: number);
292
+ protected readonly flushCore: lodash_es.DebouncedFunc<() => Promise<void>>;
240
293
  }
241
294
  /**
242
- * Buffered scheduler, will buffer effects and execute them in batch.
295
+ * Run all queued effects at once. The queue will NOT be cleared. The strategy will `reset()` before running any effects.
243
296
  */
244
- declare class BufferedScheduler<TTarget> extends Scheduler<TTarget> {
245
- protected readonly _queue: Map<string, IScheduleItem<TTarget, any>>;
246
- enqueue(item: IScheduleItem<TTarget, any>): IScheduler<TTarget>;
247
- flush(): Promise<void>;
297
+ declare class TotalScheduler<TTarget> extends Scheduler<TTarget> {
298
+ protected flushCore(): Promise<void>;
248
299
  }
249
300
 
250
301
  /**
@@ -254,4 +305,4 @@ declare class BufferedScheduler<TTarget> extends Scheduler<TTarget> {
254
305
  */
255
306
  declare function track<TSource extends object>(initial: TSource): [TSource, Recorder<TSource>];
256
307
 
257
- export { BufferedScheduler, DynamicProjector, EffectFactory, Projector, ProjectorBase, Recorder, Scheduler, track };
308
+ export { Builder, DynamicProjector, EffectFactory, LazyScheduler, Projector, ProjectorBase, Recorder, Scheduler, TotalScheduler, track };
package/types/types.d.ts CHANGED
@@ -16,8 +16,8 @@ export type Schema<TSource, T = TSource> = {
16
16
  /**
17
17
  * An effect defines how to project a value from source to target.
18
18
  */
19
- // todo: Solve this `any`
20
- export type Effect<TSource, TValue> = (target: any, ctx: IEffectContext<TSource, TValue>) => MaybePromise<void>;
19
+ // todo: Solve ITargetExecutionStrategy<any, any>. How to obtain TTarget and TLocation?
20
+ export type Effect<TSource, TValue> = (strategy: ITargetExecutionStrategy<any, any>, ctx: IEffectContext<TSource, TValue>) => MaybePromise<void>;
21
21
 
22
22
  /**
23
23
  * The context for an effect. It contains information about changes.
@@ -57,9 +57,10 @@ export type ArrayEffectOptions = {
57
57
  /**
58
58
  * Strategy defines actual execution methods for projecting values to target.
59
59
  */
60
- export interface ITargetExecutionStrategy<TTarget, TLocation = any> {
61
- execute<T extends any>(target: TTarget, location: TLocation, value: T): MaybePromise<void>;
62
- executeArray<T extends any>(target: TTarget, location: TLocation, rows: T[], options: ArrayEffectOptions): MaybePromise<void>;
60
+ export interface ITargetExecutionStrategy<TTarget, TLocation> {
61
+ execute<T extends any>(location: TLocation, value: T): MaybePromise<void>;
62
+ executeArray<T extends any>(location: TLocation, rows: T[], options: ArrayEffectOptions): MaybePromise<void>;
63
+ reset(): void;
63
64
  }
64
65
 
65
66
  export interface IProjector<TSource> {
@@ -69,8 +70,8 @@ export interface IProjector<TSource> {
69
70
  export interface IScheduler<TTarget> {
70
71
  enqueue(effect: IScheduleItem): void;
71
72
  flush(): MaybePromise<void>;
72
- withTarget(target: TTarget): IScheduler<TTarget>;
73
- withTarget(target: Func<TTarget>): IScheduler<TTarget>;
73
+ withStrategy(strategy: ITargetExecutionStrategy<TTarget, any>): IScheduler<TTarget>;
74
+ withStrategy(factory: Func<ITargetExecutionStrategy<TTarget, any>>): IScheduler<TTarget>;
74
75
  }
75
76
 
76
77
  export interface IScheduleItem<TSource, TValue> {