@cyysummer/projector 0.0.2 → 0.0.4

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,6 +1,7 @@
1
1
  /**
2
- * @cyysummer/projector v0.0.2
2
+ * @cyysummer/projector v0.0.4
3
3
  * (c) 2021-PRESENT Chris Liu
4
4
  * @license MIT
5
5
  **/
6
- import _ from"on-change";import{set as g}from"lodash-es";import{withEvents as S}from"@cyysummer/core";var T=class extends S(){constructor(e){super();this._paused=!1;this._shadow=structuredClone(e)}record(e,r){this._paused||(g(this._shadow,e,r),this.emit("record",{next:this._shadow,path:e,value:r}))}pause(){this._paused=!0}resume(){this._paused=!1}};import{get as p}from"lodash-es";var l=a=>{},h=class{constructor(t){this._strategy=t}chain(t){return async(e,r)=>{let c=s(r);for(let o of t)await o(e,{value:c})}}chainWith(t,e){return async(c,o)=>{let u=s(o),n=e(u);for(let f of t)await f(c,{value:n})}}create(t){return(e,r)=>{let c=s(r);return this._strategy.execute(e,t,c)}}createIf(t,e,r=l){return(c,o)=>{let u=s(o);return(t(u)?e:r)(c,{value:u})}}createIfRoot(t,e,r=l){return(c,o)=>(t(o.source)?e:r)(c,o)}createRoot(t,e){return(r,c)=>{let o=e(c.source);return this._strategy.execute(r,t,o)}}createForArray(t){return(e,r)=>{let c=r.path?p(r.source,r.path):r.value;if(c&&Array.isArray(c)&&c.length>0){let o=Object.keys(c[0]);return this._strategy.executeArray(e,t,o,c)}}}createForRaw(t,e){return(r,c)=>this._strategy.execute(r,t,e)}createWith(t,e){return(c,o)=>{let u=s(o),n=e(u);return this._strategy.execute(c,t,n)}}};function s(a){return a.source&&a.path?p(a.source,a.path):a.value}var y=class{constructor(t,e){this._schema=t;this._scheduler=e}project(t,...e){if(!this._schema)throw new Error("Schema not loaded");for(let r of e)this._dispatch(t,r)}_dispatch(t,e){let{path:r,value:c}=e,o=this._resolveEffect(r);o&&this._scheduler.enqueue({path:r.join("."),effect:o,ctx:{source:t,path:r,value:c}})}_resolveEffect(t){let e=this._schema;for(let r of t){if(!e)return null;e=e[r]}return typeof e=="function"?e:null}};var i=class{constructor(t=null){this._target=t;this._targetFactory=null}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")}},d=class extends i{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");let e=[...this._queue.values()];this._queue.clear();for(let r of e){let{effect:c,ctx:o}=r,u=c(this._target,o);u instanceof Promise&&await u}}};function F(a){let t=new T(a);return[_(a,t.record.bind(t),{pathAsArray:!0}),t]}export{d as BufferedScheduler,h as EffectBuilder,y as Projector,T as Recorder,i as Scheduler,F as track};
6
+ import _ from"on-change";import{set as d}from"lodash-es";import{withEvents as g}from"@cyysummer/core";var i=class extends g(){constructor(e){super();this._paused=!1;this._shadow=structuredClone(e)}receive(e,r){if(this._paused)return;d(this._shadow,e,r);let c=[{path:e,value:r}];this.emit("record",{next:this._shadow,patches:c}),this._checkProjector(),this._projector?.project(this._shadow,...c)}sendTo(e){typeof e=="function"?this._projectorFactory=e:this._projector=e}pause(){this._paused=!0}resume(){this._paused=!1}_checkProjector(){!this._projector&&this._projectorFactory&&(this._projector=this._projectorFactory())}};import{get as l}from"lodash-es";var h=a=>{},p=class{constructor(t){this._strategy=t}chain(t){return async(e,r)=>{let c=n(r);for(let o of t)await o(e,{value:c})}}chainWith(t,e){return async(c,o)=>{let u=n(o),s=e(u);for(let f of t)await f(c,{value:s})}}create(t){return(e,r)=>{let c=n(r);return this._strategy.execute(e,t,c)}}createIf(t,e,r=h){return(c,o)=>{let u=n(o);return(t(u)?e:r)(c,{value:u})}}createIfRoot(t,e,r=h){return(c,o)=>(t(o.source)?e:r)(c,o)}createRoot(t,e){return(r,c)=>{let o=e(c.source);return this._strategy.execute(r,t,o)}}createForArray(t){return(e,r)=>{let c=r.path?l(r.source,r.path):r.value;if(c&&Array.isArray(c)&&c.length>0){let o=Object.keys(c[0]);return this._strategy.executeArray(e,t,o,c)}}}createForRaw(t,e){return(r,c)=>this._strategy.execute(r,t,e)}createWith(t,e){return(c,o)=>{let u=n(o),s=e(u);return this._strategy.execute(c,t,s)}}};function n(a){return a.source&&a.path?l(a.source,a.path):a.value}var y=class{constructor(t,e){this._schema=t;this._scheduler=e}project(t,...e){if(!this._schema)throw new Error("Schema not loaded");for(let r of e)this._dispatch(t,r)}_dispatch(t,e){let{path:r,value:c}=e,o=this._resolveEffect(r);o&&this._scheduler.enqueue({path:r.join("."),effect:o,ctx:{source:t,path:r,value:c}})}_resolveEffect(t){let e=this._schema;for(let r of t){if(!e)return null;e=e[r]}return typeof e=="function"?e:null}};var T=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")}},S=class extends T{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");let e=[...this._queue.values()];this._queue.clear();for(let r of e){let{effect:c,ctx:o}=r,u=c(this._target,o);u instanceof Promise&&await u}}};function F(a){let t=new i(a);return[_(a,t.receive.bind(t),{pathAsArray:!0}),t]}export{S as BufferedScheduler,p as EffectBuilder,y as Projector,i as Recorder,T as Scheduler,F as track};
7
+ //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@cyysummer/projector",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "A powerful state projection library for creating anything.",
5
5
  "license": "MIT",
6
6
  "author": "Chris Liu",
7
7
  "files": [
8
- "dist/**",
8
+ "dist/*.js",
9
9
  "types/**"
10
10
  ],
11
11
  "type": "module",
package/types/lib.d.ts CHANGED
@@ -1,8 +1,80 @@
1
+ /**
2
+ * A Schema defines how to project changes from a source object to a target object.
3
+ */
4
+ // prettier-ignore
5
+ type Schema<TSource, T = any> = TSource extends object ?
6
+ Partial<{
7
+ // If the property is an array, map whole array to effect.
8
+ // Else map property to schema.
9
+ [K in keyof T]:
10
+ T[K] extends Array<infer U> ?
11
+ Effect<TSource, U>
12
+ // If TSource is an object, map each property to schema, or write effect for the property.
13
+ : Schema<TSource, T[K]> | Effect<TSource, T[K]>;
14
+ }>
15
+ // Else map T to effect.
16
+ : Effect<TSource, T>;
17
+
18
+ /**
19
+ * An effect defines how to project a value from source to target.
20
+ */
21
+ // todo: Solve this `any`
22
+ type Effect<TSource, TValue> = (target: any, ctx: IEffectContext<TSource, TValue>) => MaybePromise<void>;
23
+
24
+ /**
25
+ * The context for an effect. It contains information about changes.
26
+ */
27
+ interface IEffectContext<TSource, TValue> {
28
+ /**
29
+ * The source object.
30
+ */
31
+ source?: TSource;
32
+ /**
33
+ * The path of the property.
34
+ */
35
+ path?: string;
36
+ /**
37
+ * The value of the property.
38
+ *
39
+ * If `source` or `path` is not specified, the value is passed from another effect.
40
+ */
41
+ value: TValue;
42
+ }
43
+
44
+ /**
45
+ * Strategy defines actual execution methods for projecting values to target.
46
+ */
47
+ interface ITargetExecutionStrategy<TTarget, TLocation = any> {
48
+ execute<T>(target: TTarget, at: TLocation, value: T): MaybePromise<void>;
49
+ executeArray<T>(target: TTarget, at: TLocation, keys: Partial<keyof T>[], rows: T[]): MaybePromise<void>;
50
+ }
51
+
52
+ interface IProjector<TSource> {
53
+ project(next: TSource, ...patches: Patch[]): void;
54
+ }
55
+
56
+ interface IScheduler<TTarget> {
57
+ enqueue(effect: IScheduleItem): void;
58
+ flush(): MaybePromise<void>;
59
+ withTarget(target: TTarget): IScheduler<TTarget>;
60
+ withTarget(target: Func<TTarget>): IScheduler<TTarget>;
61
+ }
62
+
63
+ interface IScheduleItem<TSource, TValue> {
64
+ path: string;
65
+ effect: Effect<TSource, TValue>;
66
+ ctx: IEffectContext<TSource, TValue>;
67
+ }
68
+
69
+ interface Patch {
70
+ path: (string | symbol)[];
71
+ value: any;
72
+ }
73
+
1
74
  type RecorderEvents = {
2
75
  record: {
3
76
  next: any;
4
- path: any[];
5
- value: any;
77
+ patches: Patch[];
6
78
  };
7
79
  };
8
80
  declare const Recorder_base: Constructor<object> & (new (...args: any[]) => object & IEventful<RecorderEvents>);
@@ -11,11 +83,30 @@ declare const Recorder_base: Constructor<object> & (new (...args: any[]) => obje
11
83
  */
12
84
  declare class Recorder<TSource extends object> extends Recorder_base {
13
85
  private _paused;
86
+ private _projector?;
87
+ private _projectorFactory?;
14
88
  private _shadow;
15
89
  constructor(initial: TSource);
16
- record(path: any[], value: any): void;
90
+ /**
91
+ * Receive changes from the tracked object.
92
+ * @param path
93
+ * @param value
94
+ * @returns
95
+ */
96
+ receive(path: any[], value: any): void;
97
+ /**
98
+ * Send changes to a projector.
99
+ * @param projector
100
+ */
101
+ sendTo(projector: IProjector<TSource>): void;
102
+ /**
103
+ * Send changes to a projector.
104
+ * @param factory
105
+ */
106
+ sendTo(factory: Func<IProjector<TSource>>): void;
17
107
  pause(): void;
18
108
  resume(): void;
109
+ private _checkProjector;
19
110
  }
20
111
 
21
112
  /**
@@ -23,7 +114,7 @@ declare class Recorder<TSource extends object> extends Recorder_base {
23
114
  */
24
115
  declare class EffectBuilder<TTarget, TSource extends object> {
25
116
  private _strategy;
26
- constructor(_strategy: ITargetStrategy<TTarget>);
117
+ constructor(_strategy: ITargetExecutionStrategy<TTarget>);
27
118
  /**
28
119
  * Call multiple effects in sequence.
29
120
  * @param effects Effects to call.
@@ -101,9 +192,9 @@ declare class Projector<TSource> implements IProjector<TSource> {
101
192
  * Scheduler abstract class, used to schedule projector effects.
102
193
  */
103
194
  declare abstract class Scheduler<TTarget> implements IScheduler<TTarget> {
104
- protected _target: TTarget | null;
105
- protected _targetFactory: Func<TTarget> | null;
106
- constructor(_target?: TTarget | null);
195
+ protected _target?: TTarget | undefined;
196
+ protected _targetFactory?: Func<TTarget>;
197
+ constructor(_target?: TTarget | undefined);
107
198
  abstract enqueue(item: IScheduleItem<TTarget, any>): IScheduler<TTarget>;
108
199
  abstract flush(): MaybePromise<void>;
109
200
  withTarget(target: TTarget): IScheduler<TTarget>;
@@ -119,6 +210,11 @@ declare class BufferedScheduler<TTarget> extends Scheduler<TTarget> {
119
210
  flush(): Promise<void>;
120
211
  }
121
212
 
213
+ /**
214
+ * Track changes to an object.
215
+ * @param initial Source object to track. This must the raw object, not reactive-enabled object.
216
+ * @returns A tuple of the tracked object and a recorder.
217
+ */
122
218
  declare function track<TSource extends object>(initial: TSource): [TSource, Recorder<TSource>];
123
219
 
124
220
  export { BufferedScheduler, EffectBuilder, Projector, Recorder, Scheduler, track };
package/types/types.d.ts CHANGED
@@ -1,5 +1,8 @@
1
+ /**
2
+ * A Schema defines how to project changes from a source object to a target object.
3
+ */
1
4
  // prettier-ignore
2
- type Schema<TSource, T = any> = TSource extends object ?
5
+ export type Schema<TSource, T = any> = TSource extends object ?
3
6
  Partial<{
4
7
  // If the property is an array, map whole array to effect.
5
8
  // Else map property to schema.
@@ -12,10 +15,16 @@ type Schema<TSource, T = any> = TSource extends object ?
12
15
  // Else map T to effect.
13
16
  : Effect<TSource, T>;
14
17
 
18
+ /**
19
+ * An effect defines how to project a value from source to target.
20
+ */
15
21
  // todo: Solve this `any`
16
- type Effect<TSource, TValue> = (target: any, ctx: IEffectContext<TSource, TValue>) => MaybePromise<void>;
22
+ export type Effect<TSource, TValue> = (target: any, ctx: IEffectContext<TSource, TValue>) => MaybePromise<void>;
17
23
 
18
- interface IEffectContext<TSource, TValue> {
24
+ /**
25
+ * The context for an effect. It contains information about changes.
26
+ */
27
+ export interface IEffectContext<TSource, TValue> {
19
28
  /**
20
29
  * The source object.
21
30
  */
@@ -32,29 +41,32 @@ interface IEffectContext<TSource, TValue> {
32
41
  value: TValue;
33
42
  }
34
43
 
35
- interface ITargetStrategy<TTarget> {
36
- execute<T>(target: TTarget, at: string, value: T): MaybePromise<void>;
37
- executeArray<T>(target: TTarget, at: string, keys: Partial<keyof T>[], rows: T[]): MaybePromise<void>;
44
+ /**
45
+ * Strategy defines actual execution methods for projecting values to target.
46
+ */
47
+ export interface ITargetExecutionStrategy<TTarget, TLocation = any> {
48
+ execute<T>(target: TTarget, at: TLocation, value: T): MaybePromise<void>;
49
+ executeArray<T>(target: TTarget, at: TLocation, keys: Partial<keyof T>[], rows: T[]): MaybePromise<void>;
38
50
  }
39
51
 
40
- interface IProjector<TSource> {
52
+ export interface IProjector<TSource> {
41
53
  project(next: TSource, ...patches: Patch[]): void;
42
54
  }
43
55
 
44
- interface IScheduler<TTarget> {
56
+ export interface IScheduler<TTarget> {
45
57
  enqueue(effect: IScheduleItem): void;
46
58
  flush(): MaybePromise<void>;
47
59
  withTarget(target: TTarget): IScheduler<TTarget>;
48
60
  withTarget(target: Func<TTarget>): IScheduler<TTarget>;
49
61
  }
50
62
 
51
- interface IScheduleItem<TSource, TValue> {
63
+ export interface IScheduleItem<TSource, TValue> {
52
64
  path: string;
53
65
  effect: Effect<TSource, TValue>;
54
66
  ctx: IEffectContext<TSource, TValue>;
55
67
  }
56
68
 
57
- interface Patch {
69
+ export interface Patch {
58
70
  path: (string | symbol)[];
59
71
  value: any;
60
72
  }