@expressive/mvc 0.32.0 → 0.34.0

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/lib/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
- type Async<T = any> = (...args: any[]) => Promise<T>;
1
+ type Async<T = any, Y extends any[] = any> = {
2
+ (...args: Y): Promise<T>;
3
+ active: boolean;
4
+ };
2
5
  /**
3
6
  * Sets an exotic method with managed ready-state. Property accepts an async function.
4
7
  *
@@ -9,40 +12,7 @@ type Async<T = any> = (...args: any[]) => Promise<T>;
9
12
  *
10
13
  * @param action - Action to fire when resulting property is invoked.
11
14
  */
12
- declare function run(action: Async): typeof action & {
13
- active: boolean;
14
- };
15
- declare function run<S>(action: Async<S>): typeof action & {
16
- active: boolean;
17
- };
18
-
19
- /** Type may not be undefined - instead will be null. */
20
- type NoVoid<T> = T extends undefined | void ? null : T;
21
- type ForceUpdate = {
22
- /** Force an update in current component. */
23
- (): void;
24
- /**
25
- * Force an update and again after promise either resolves or rejects.
26
- * Will return a duplicate of given Promise, which resolves after refresh.
27
- */
28
- <T = void>(passthru: Promise<T>): Promise<T>;
29
- /**
30
- * Force a update while calling async function.
31
- * A refresh will occur both before and after given function.
32
- * Any actions performed before first `await` will occur before refresh!
33
- */
34
- <T = void>(invoke: () => Promise<T>): Promise<T>;
35
- };
36
- type Factory<T extends Model, R> = (this: T, current: T, update: ForceUpdate) => R;
37
- /** Fetch instance of this class from context. */
38
- declare function get$1<T extends Model>(this: Model.Type<T>, ignoreUpdates?: true): Model.Focus<T>;
39
- /** Fetch instance of this class optionally. May be undefined, but will never subscribe. */
40
- declare function get$1<T extends Model>(this: Model.Type<T>, required: boolean): Model.Focus<T> | undefined;
41
- declare function get$1<T extends Model, R>(this: Model.Type<T>, factory: Factory<T, (() => R) | R | Promise<R>>): NoVoid<R>;
42
- declare function get$1<T extends Model, R>(this: Model.Type<T>, factory: Factory<T, (() => R) | null>): NoVoid<R> | null;
43
-
44
- declare function use$1<T extends Model>(this: Model.New<T>, callback?: (instance: T) => void, repeat?: boolean): Model.Focus<T>;
45
- declare function use$1<T extends Model>(this: Model.New<T>, apply?: Model.Values<T>, repeat?: boolean): Model.Focus<T>;
15
+ declare function run<T, Y extends any[]>(action: (...args: Y) => T | Promise<T>): Async<T, Y>;
46
16
 
47
17
  type Callback = () => void;
48
18
 
@@ -53,43 +23,25 @@ declare global {
53
23
  toUpdate(): Promise<R>;
54
24
 
55
25
  /** Assert model did update with keys specified. */
56
- toHaveUpdated<R>(keys: string[]): Promise<R>;
26
+ toHaveUpdated<R>(...keys: string[]): Promise<R>;
57
27
  }
58
28
  }
59
29
  }
60
30
 
61
- type SelectOne<T, K extends Model.Key<T>> = K;
62
- type SelectFew<T, K extends Model.Key<T>> = K[];
63
- type Select<T, K extends Model.Key<T> = Model.Key<T>> = K | K[];
64
- type Export<T, S> = S extends SelectOne<T, infer P> ? T[P] : S extends SelectFew<T, infer P> ? Model.Export<T, P> : never;
65
- type OnUpdate<T, S> = (this: T, value: Export<T, S>, updated: Model.Event<T>[]) => void;
66
- interface Observable {
67
- get(): Model.Export<this>;
68
- get<P extends Select<this>>(select: P): Export<this, P>;
69
- get<P extends Select<this>>(select: P, onUpdate: OnUpdate<this, P>, once?: true): Callback;
70
- get<P extends Select<this>>(select: P, onUpdate: OnUpdate<this, P>, initial?: false): Callback;
71
- get(effect: Model.Effect<this>): Callback;
72
- set(): Promise<Model.Event<this>[]>;
73
- set(timeout: number): Promise<Model.Event<this>[] | false>;
74
- set<T extends Model.Values<this>>(from: T, only?: (keyof T)[]): Promise<Model.Event<T>[] | false>;
75
- set<K extends Model.Key<this>>(key: K, value: Model.Value<this[K]>): Promise<Model.Event<this>[] | false>;
76
- set<K extends Model.Event<this>>(key: K): Promise<Model.Event<this>[] | false>;
77
- }
78
-
79
31
  type InstanceOf<T> = T extends {
80
32
  prototype: infer U;
81
33
  } ? U : never;
34
+ type Class = new (...args: any[]) => any;
35
+ type Predicate = (key: string) => boolean | void;
82
36
  declare namespace Model {
83
37
  /** Any typeof Model, using class constructor as the reference. */
84
38
  type Type<T extends Model = Model> = abstract new (...args: any[]) => T;
85
39
  /** A typeof Model, specifically one which can be created without any arguments. */
86
40
  type New<T extends Model = Model> = (new () => T) & typeof Model;
87
- /** A callback function which is subscribed to parent and updates when values change. */
88
- type Effect<T> = (this: T, argument: T) => Callback | Promise<void> | void;
89
41
  /** Subset of `keyof T` which are not methods or defined by base Model U. **/
90
- type Key<T, U = Observable> = Extract<Exclude<keyof T, keyof U>, string>;
91
- /** Including but not limited to `keyof T` which are not methods or defined by base Model. */
92
- type Event<T> = Key<T> | (string & {});
42
+ type Key<T> = Exclude<keyof T, keyof Model> & string;
43
+ /** Actual value stored in state. */
44
+ type Value<R> = R extends Ref<infer T> ? T : R extends Model ? Export<R> : R;
93
45
  /** Object comperable to data found in T. */
94
46
  type Values<T> = {
95
47
  [P in Key<T>]?: Value<T[P]>;
@@ -98,32 +50,50 @@ declare namespace Model {
98
50
  * Values from current state of given controller.
99
51
  * Differs from `Values` as values here will drill into "real" values held by exotics like ref.
100
52
  */
101
- type Export<T, K extends Key<T> = Key<T>> = {
102
- [P in K]: Value<T[P]>;
103
- };
104
- /**
105
- * Reference to `this` without a subscription.
106
- * Use to obtain full reference from a destructure.
107
- */
108
- type Focus<T> = T & {
109
- is: T;
53
+ type Export<T> = {
54
+ [P in keyof T]: Value<T[P]>;
110
55
  };
111
- /** Exotic value, actual value is contained. */
56
+ /** Exotic value, where actual value is contained within. */
112
57
  type Ref<T = any> = {
113
58
  (next: T): void;
114
59
  current: T | null;
115
60
  };
116
- /** Actual value stored in state. */
117
- type Value<R> = R extends Ref<infer T> ? T : R extends Observable ? Export<R> : R;
118
- }
119
- interface Model extends Observable {
61
+ /** A callback function which is subscribed to parent and updates when values change. */
62
+ type Effect<T> = (this: T, argument: T) => Callback | Promise<void> | void;
63
+ type Event = (key: string) => Callback | void;
120
64
  }
121
65
  declare class Model {
66
+ is: this;
122
67
  constructor(id?: string | number);
68
+ /** Pull current values from state. Flattens all models and exotic values amongst properties. */
69
+ get(): Model.Export<this>;
70
+ /** Run a function which will automatically run again when accessed properties change. */
71
+ get(effect: Model.Effect<this>): Callback;
72
+ /** Assert update is in progress. Returns a promise which resolves updated keys. */
73
+ set(): Promise<Model.Values<this> | false>;
74
+ /**
75
+ * Expect an update to state within timeout.
76
+ *
77
+ * @param timeout - milliseconds to wait for update
78
+ * @param predicate - optional function to filter updates. If returns true, update is accepted.
79
+ *
80
+ * @returns a promise which resolves full update.
81
+ */
82
+ set(timeout: number, predicate?: Predicate): Promise<Model.Values<this>>;
83
+ /**
84
+ * Call a function when an update to state has occured.
85
+ *
86
+ * @param callback - Function to call when any update occurs.
87
+ * Note: This will be called for every assignment which changes the value.
88
+ * To run logic on final value only, this callback may return a function.
89
+ * Returning the same function for the same (or multiple for that matter)
90
+ * will ensure it is only called once.
91
+ *
92
+ * @returns a function to remove listener
93
+ */
94
+ set(callback: Model.Event): Callback;
123
95
  /** Mark this instance for garbage collection. */
124
96
  null(): void;
125
- static get: typeof get$1;
126
- static use: typeof use$1;
127
97
  /**
128
98
  * Creates a new instance of this controller.
129
99
  *
@@ -131,19 +101,38 @@ declare class Model {
131
101
  *
132
102
  * @param args - arguments sent to constructor
133
103
  */
134
- static new<T extends new (...args: any[]) => any>(this: T, ...args: ConstructorParameters<T>): InstanceOf<T>;
104
+ static new<T extends Class>(this: T, ...args: ConstructorParameters<T>): InstanceOf<T>;
135
105
  /**
136
106
  * Static equivalent of `x instanceof this`.
137
- *
138
- * Will determine if provided class is a subtype of this one.
107
+ * Determines if provided class is a subtype of this one.
108
+ * If so, language server will make available all static
109
+ * methods and properties of this class.
139
110
  */
140
111
  static is<T extends Model.Type>(this: T, maybe: any): maybe is T;
141
112
  }
142
113
 
114
+ declare namespace Context {
115
+ type Inputs = {
116
+ [key: string | number]: Model | Model.New;
117
+ };
118
+ }
119
+ declare class Context {
120
+ key: string;
121
+ private table;
122
+ private layer;
123
+ private has;
124
+ get<T extends Model>(Type: Model.Type<T>): T | undefined;
125
+ include(inputs: Context.Inputs): Map<Model, boolean>;
126
+ add<T extends Model>(input: T | Model.New<T>, implicit?: boolean): T;
127
+ push(): this;
128
+ pop(): void;
129
+ }
130
+
143
131
  declare namespace get {
144
132
  type Function<T, S = any> = (this: S, on: S) => T;
145
133
  type Factory<R, T> = (this: T, property: string, on: T) => Function<R, T>;
146
- type Source<T extends Model = Model> = (callback: (x: T) => void) => void;
134
+ type Source<T extends Model = Model> = (resolve: (x: T) => void) => void;
135
+ function from(target: Model): (resolve: (got: Context) => void) => void;
147
136
  }
148
137
  /**
149
138
  * Fetches and assigns the controller which spawned this host.
@@ -151,11 +140,25 @@ declare namespace get {
151
140
  * will be made available to child upon this request.
152
141
  *
153
142
  * @param Type - Type of controller compatible with this class.
154
- * @param required - Throw if controller is created independantly.
143
+ * @param required - If true, will throw if Model is created without a parent.
155
144
  */
156
145
  declare function get<T extends Model>(Type: Model.Type<T>, required?: true): T;
146
+ /**
147
+ * Fetches and assigns the controller which spawned this host.
148
+ * When parent assigns an instance via `use()` directive, it
149
+ * will be made available to child upon this request.
150
+ *
151
+ * @param Type - Type of controller compatible with this class.
152
+ * @param required - If false, property may be undefined. Otherwise will throw suspense.
153
+ */
157
154
  declare function get<T extends Model>(Type: Model.Type<T>, required: boolean): T | undefined;
158
- declare function get<R, T extends Model>(Type: Model.Type<T>, compute: (this: T, on: T) => R): Exclude<R, undefined>;
155
+ /**
156
+ * Implement a computed value from a foreign model. Output will be generated by provided function,
157
+ * where the foreign model will be passed to that function.
158
+ *
159
+ * @param source - Type of Model to fetch for computation.
160
+ * @param compute - Compute function. Will update automatically as input values change.
161
+ */
159
162
  declare function get<R, T extends Model>(Type: Model.Type<T>, compute: (this: T, on: T) => R): R;
160
163
  /**
161
164
  * Implement a computed value; output will be generated by provided function.
@@ -163,14 +166,12 @@ declare function get<R, T extends Model>(Type: Model.Type<T>, compute: (this: T,
163
166
  * @param source - Source model from which computed value will be a subscriber.
164
167
  * @param compute - Compute function. Bound to a subscriber-proxy of source, returns output value. Will update automatically as input values change.
165
168
  */
166
- declare function get<R, T extends Model>(source: T, compute: (this: T, on: T) => R): Exclude<R, undefined>;
167
169
  declare function get<R, T extends Model>(source: T, compute: (this: T, on: T) => R): R;
168
170
  /**
169
171
  * Implement a computed value; output is returned by function from provided factory.
170
172
  *
171
173
  * @param compute - Factory function to generate a getter to subscribe dependancies.
172
174
  */
173
- declare function get<R, T>(compute: (property: string, on: T) => (this: T, state: T) => R): Exclude<R, undefined>;
174
175
  declare function get<R, T>(compute: (property: string, on: T) => (this: T, state: T) => R): R;
175
176
 
176
177
  declare namespace ref {
@@ -226,7 +227,7 @@ declare function ref<T = HTMLElement>(callback?: ref.Callback<T>): ref.Object<T>
226
227
  declare function ref<T = HTMLElement>(callback: ref.Callback<T | null>, ignoreNull: boolean): ref.Object<T>;
227
228
 
228
229
  declare namespace set {
229
- type Callback<T, S = any> = (this: S, argument: T) => ((next: T) => void) | Promise<any> | void | boolean;
230
+ type Callback<T, S = any> = (this: S, next: T, previous: T) => ((next: T) => void) | Promise<any> | void | boolean;
230
231
  type Factory<T, S = any> = (this: S, key: string, thisArg: S) => Promise<T> | T;
231
232
  }
232
233
  /**
@@ -239,29 +240,30 @@ declare function set<T = any>(): T;
239
240
  /**
240
241
  * Set property with a factory function.
241
242
  *
242
- * If async, poperty cannot be accessed until resolves, yeilding a result.
243
- * If accessed while still processing, React Suspense will be thrown.
243
+ * Run factory only if/when accessed. Value will be undefined until
244
+ * factory resolves, which will also dispatch an update for the property.
245
+ */
246
+ declare function set<T>(factory: set.Factory<T> | Promise<T>, required: false): T | undefined;
247
+ /**
248
+ * Set property with a factory function.
244
249
  *
245
- * - `required: true` (default) -
246
- * Run factory immediately upon creation of model instance.
247
- * - `required: false` -
248
- * Run factory only if/when accessed.
249
- * Value will always throw suspense at least once - use with caution.
250
+ * If async, property cannot be accessed until resolves, yeilding a result.
251
+ * If accessed while still processing, React Suspense will be thrown.
250
252
  *
251
253
  * @param factory - Callback run to derrive property value.
252
- * @param required - (default: true) Run factory immediately on creation, otherwise on access.
254
+ * @param required - If true run factory immediately on creation, otherwise on access.
253
255
  */
254
- declare function set<T>(factory: set.Factory<T> | Promise<T>, required: false): T | undefined;
255
256
  declare function set<T>(factory: set.Factory<T> | Promise<T>, required?: boolean): T;
256
- declare function set<T>(value: undefined, onUpdate: set.Callback<T>): T;
257
- declare function set<T>(value: T, onUpdate: set.Callback<T>): T;
257
+ /**
258
+ * Set a property with empty placeholder and update callback.
259
+ *
260
+ * @param value - Starting value for property. If undefined, suspense will be thrown on access, until value is set and accepted by callback.
261
+ * @param onUpdate - Callback run when property is set. If returns false, update is not accepted and property will keep previous value.
262
+ */
263
+ declare function set<T>(value: T | undefined, onUpdate: set.Callback<T>): T;
258
264
 
259
- type Empty = Record<string, never>;
260
265
  declare namespace use {
261
- type Record<T> = {
262
- [key: string | number]: T;
263
- } & Observable;
264
- type Object<T extends {}> = T & Observable;
266
+ type Object<T extends {}> = T;
265
267
  }
266
268
  /** Create a placeholder for specified Model type. */
267
269
  declare function use<T extends Model>(): T | undefined;
@@ -276,29 +278,9 @@ declare function use<T extends Model>(Type: Model.New<T>, ready?: (i: T) => void
276
278
  * already active.
277
279
  **/
278
280
  declare function use<T extends Model>(model: T, ready?: (i: T) => void): T;
279
- /** Create a managed record with observable entries. */
280
- declare function use<T = any, C = use.Record<T>>(record: Empty, ready?: (object: C) => void): C;
281
281
  /** Create a managed object with observable entries. */
282
282
  declare function use<T extends {}, O = use.Object<T>>(data: T, ready?: (object: O) => void): O;
283
283
 
284
- declare namespace Context {
285
- type Inputs = {
286
- [key: string | number]: Model | Model.New;
287
- };
288
- }
289
- declare class Context {
290
- key: string;
291
- private table;
292
- private layer;
293
- private has;
294
- get<T extends Model>(Type: Model.Type<T>): T | undefined;
295
- include(inputs: Context.Inputs): Map<Model, boolean>;
296
- add<T extends Model>(input: T | Model.New<T>, implicit?: boolean): T;
297
- push(): this;
298
- pop(): void;
299
- }
300
-
301
- type Observer<T extends Model = any> = (key: Model.Event<T> | null | undefined, source: Control) => Callback | null | void;
302
284
  declare namespace Control {
303
285
  /**
304
286
  * Property initializer, will run upon instance creation.
@@ -306,7 +288,7 @@ declare namespace Control {
306
288
  */
307
289
  type Instruction<T> = (this: Control, key: string, thisArg: Control) => PropertyDescriptor<T> | Getter<T> | void;
308
290
  type Getter<T> = (source: Model) => T;
309
- type Setter<T> = (value: T) => boolean | void;
291
+ type Setter<T> = (value: T, previous: T) => boolean | void;
310
292
  type PropertyDescriptor<T = any> = {
311
293
  get?: Getter<T>;
312
294
  set?: Setter<T> | false;
@@ -319,55 +301,35 @@ declare namespace Control {
319
301
  * Returned callback is forwarded.
320
302
  */
321
303
  type OnReady<T extends {}> = (control: Control<T>) => (() => void) | void;
322
- type RequestRefresh = (update: (tick: number) => number) => void;
323
- type GetContext = (target: Model) => (callback: (got: Context) => void) => void;
324
- type GetAdapter<T> = (refresh: RequestRefresh, context: Context) => {
325
- mount: () => (() => void) | void;
326
- render: () => T;
327
- } | void;
328
- type GetHook = <T>(adapter: GetAdapter<T>) => T | null;
329
- type UseAdapter<T extends Model, R> = (refresh: RequestRefresh) => {
330
- instance: T;
331
- mount: () => (() => void) | void;
332
- render: R;
333
- };
334
- type UseHook = <T extends Model, R>(adapter: UseAdapter<T, R>) => R;
304
+ type OnUpdate<T extends {} = any> = (key: Model.Key<T> | null | undefined, source: T) => (() => void) | null | void;
305
+ type OnChange = (this: {}, next: unknown, previous: unknown) => boolean | void;
335
306
  }
336
307
  declare class Control<T extends {} = any> {
337
- static ready: Set<Control.Callback>;
338
- static after: Set<Callback>;
339
- static before: Set<Callback>;
340
- static pending: Set<Callback>;
341
- static get: Control.GetHook;
342
- static use: Control.UseHook;
343
- static has: Control.GetContext;
344
- static for: typeof control;
345
- static apply: typeof apply;
346
308
  static watch: typeof watch;
347
- id: string | number | false;
309
+ static for: typeof control;
310
+ static add: typeof add;
311
+ static on(event: "ready", callback: Control.Callback): Callback;
312
+ static on(event: "update" | "didUpdate", callback: Callback): Callback;
313
+ id: string;
348
314
  subject: T;
349
315
  state: {
350
- [key: string]: any;
316
+ [property: string]: unknown;
317
+ };
318
+ frame: {
319
+ [property: string]: unknown;
351
320
  };
352
- latest?: Model.Event<T>[];
353
- frame: Set<string>;
354
- followers: Set<Observer<any>>;
355
- observers: Map<string, Set<Observer<any>>>;
356
- constructor(subject: T, id: string | number | false);
357
- add(key: string): void;
321
+ listeners: Map<Control.OnUpdate, Set<string> | undefined>;
322
+ constructor(subject: T, id?: string | number | false);
358
323
  watch(key: string, output: Control.PropertyDescriptor<any>): void;
359
- ref<K extends Model.Key<T>>(key: K, callback?: (this: T, value: T[K]) => boolean | void): (value: any) => void;
360
- update(key: string): void;
361
- addListener(fn: Observer): () => boolean;
324
+ update(key: string, value?: unknown): void;
325
+ fetch(key: string, required?: boolean): () => unknown;
326
+ addListener<T extends Model>(fn: Control.OnUpdate<T>): () => boolean;
362
327
  clear(): void;
363
328
  }
364
329
  declare function control<T extends Model>(subject: T, ready: Control.OnReady<T>): Callback;
365
330
  declare function control<T extends Model>(subject: T, ready?: boolean): Control<T>;
366
- type Focus<T extends {}> = T & {
367
- is: T;
368
- };
369
- declare function watch<T extends {}>(value: T, cb: Observer): Focus<T>;
370
- declare function apply<T = any>(instruction: Control.Instruction<T>): T;
331
+ declare function watch<T extends {}>(value: T, argument: Control.OnUpdate): T;
332
+ declare function add<T = any>(instruction: Control.Instruction<T>): T;
371
333
 
372
334
  declare const STATE = "__state";
373
335
  declare const UPDATE = "__update";
@@ -401,7 +363,7 @@ type Debug<T extends Model = Model> = T & {
401
363
  * If accessed directly, will contain all keys from last push.
402
364
  * If within a subscribed function, will contain only keys which explicitly caused a refresh.
403
365
  */
404
- [UPDATE]?: readonly Model.Event<T>[];
366
+ [UPDATE]?: Model.Values<T>;
405
367
  /**
406
368
  * Parent currently assigned to parent. Usually the model which this one is a property of.
407
369
  */