@expressive/mvc 0.24.1 → 0.25.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
@@ -22,15 +22,12 @@ declare namespace Context {
22
22
  };
23
23
  }
24
24
  declare class Context {
25
- /** Use */
26
25
  key: string;
27
26
  private table;
28
27
  private layer;
29
28
  private has;
30
29
  get<T extends Model>(Type: Model.Type<T>): T | undefined;
31
30
  include(inputs: Context.Inputs): Map<Model, boolean>;
32
- /** Context must force-reset becasue inputs are no longer safe. */
33
- private bailout;
34
31
  add<T extends Model>(input: T | Model.New<T>, implicit?: boolean): T;
35
32
  push(): this;
36
33
  pop(): void;
@@ -60,16 +57,17 @@ declare namespace Control {
60
57
  type Getter<T> = (source: Model) => T;
61
58
  type Setter<T> = (value: T) => boolean | void;
62
59
  type PropertyDescriptor<T = any> = {
63
- enumerable?: boolean;
64
- value?: T;
65
60
  get?: Getter<T>;
66
61
  set?: Setter<T> | false;
62
+ enumerable?: boolean;
63
+ value?: T;
67
64
  };
65
+ type Callback = (control: Control) => void;
68
66
  /**
69
67
  * Callback for Controller.for() static method.
70
68
  * Returned callback is forwarded.
71
69
  */
72
- type OnReady<T extends Model> = (control: Control<T>) => Callback | void;
70
+ type OnReady<T extends {}> = (control: Control<T>) => (() => void) | void;
73
71
  type RequestRefresh = (update: (tick: number) => number) => void;
74
72
  type GetContext = (target: Model) => (callback: (got: Context) => void) => void;
75
73
  type GetAdapter<T> = (refresh: RequestRefresh, context: Context) => {
@@ -78,15 +76,14 @@ declare namespace Control {
78
76
  } | void;
79
77
  type GetHook = <T>(adapter: GetAdapter<T>) => T | null;
80
78
  type UseAdapter<T extends Model, R> = (refresh: RequestRefresh) => {
81
- local: T;
79
+ instance: T;
82
80
  mount: () => (() => void) | void;
83
81
  render: R;
84
82
  };
85
83
  type UseHook = <T extends Model, R>(adapter: UseAdapter<T, R>) => R;
86
84
  }
87
- declare class Control<T extends Model = any> {
88
- subject: T;
89
- id: string | number;
85
+ declare class Control<T extends {} = any> {
86
+ static ready: Set<Control.Callback>;
90
87
  static after: Set<Callback>;
91
88
  static before: Set<Callback>;
92
89
  static pending: Set<Callback>;
@@ -96,6 +93,8 @@ declare class Control<T extends Model = any> {
96
93
  static for: typeof control;
97
94
  static apply: typeof apply;
98
95
  static watch: typeof watch;
96
+ id: string | number;
97
+ subject: T;
99
98
  state: {
100
99
  [key: string]: any;
101
100
  };
@@ -113,7 +112,7 @@ declare class Control<T extends Model = any> {
113
112
  }
114
113
  declare function control<T extends Model>(subject: T, ready: Control.OnReady<T>): Callback;
115
114
  declare function control<T extends Model>(subject: T, ready?: boolean): Control<T>;
116
- declare function watch<T extends Model>(on: T, cb: Observer): T;
115
+ declare function watch<T extends {}>(on: T, cb: Observer): T;
117
116
  declare function apply<T = any>(instruction: Control.Instruction<T>): T;
118
117
 
119
118
  declare const STATE = "__state";
@@ -156,20 +155,13 @@ type Debug<T extends Model = Model> = T & {
156
155
  };
157
156
 
158
157
  /** Type may not be undefined - instead will be null. */
159
- type NoVoid<T> = T extends undefined ? null : T;
160
- declare function get$1<T extends Model>(this: Model.Type<T>): T;
161
- /** Fetch instance of this class in passive mode. Will not subscribe to events. */
158
+ type NoVoid<T> = T extends undefined | void ? null : T;
159
+ /** Fetch instance of this class from context. */
162
160
  declare function get$1<T extends Model>(this: Model.Type<T>, ignoreUpdates?: true): T;
163
161
  /** Fetch instance of this class optionally. May be undefined, but will never subscribe. */
164
162
  declare function get$1<T extends Model>(this: Model.Type<T>, required: boolean): T | undefined;
165
- declare function get$1<T extends Model, R extends []>(this: Model.Type<T>, factory: Model.GetCallback<T, R | (() => R)>, expect?: boolean): R;
166
- declare function get$1<T extends Model, R extends []>(this: Model.Type<T>, factory: Model.GetCallback<T, Promise<R> | (() => R) | null>, expect?: boolean): R | null;
167
- declare function get$1<T extends Model, R extends []>(this: Model.Type<T>, factory: Model.GetCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
168
- declare function get$1<T extends Model, R>(this: Model.Type<T>, init: Model.GetCallback<T, () => R>): NoVoid<R>;
169
- declare function get$1<T extends Model, R>(this: Model.Type<T>, init: Model.GetCallback<T, (() => R) | null>): NoVoid<R> | null;
170
- declare function get$1<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
171
- declare function get$1<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R>>, expect?: boolean): NoVoid<R> | null;
172
- declare function get$1<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, R>, expect?: boolean): NoVoid<R>;
163
+ declare function get$1<T extends Model, R>(this: Model.Type<T>, factory: Model.GetCallback<T, (() => R) | R | Promise<R>>): NoVoid<R>;
164
+ declare function get$1<T extends Model, R>(this: Model.Type<T>, factory: Model.GetCallback<T, (() => R) | null>): NoVoid<R> | null;
173
165
 
174
166
  declare function use$1<T extends Model>(this: Model.New<T>, callback?: (instance: T) => void, repeat?: boolean): T;
175
167
  declare function use$1<T extends Model>(this: Model.New<T>, apply?: Model.Compat<T>, repeat?: boolean): T;
@@ -254,7 +246,7 @@ declare class Model {
254
246
  get<P extends Model.Key<this>>(select: Iterable<P>): Model.Get<this, P>;
255
247
  get<P extends Model.Key<this>>(select: P, listener: (this: this, value: this[P]) => void): Callback;
256
248
  get<P extends Model.Key<this>>(select: Iterable<P>, listener: (this: this, value: Model.Get<this, P>) => void): Callback;
257
- set<T extends Model.Compat<this>>(source: T, select?: (keyof T)[]): Promise<Model.Key<T>[]>;
249
+ set<T extends Model.Compat<this>>(source: T, only?: (keyof T)[]): Promise<Model.Key<T>[]>;
258
250
  set<K extends Model.Event<this>>(key: K, value?: Model.ValueOf<this, K>): Promise<Model.Event<this>[] | false>;
259
251
  /** Mark this instance for garbage collection. */
260
252
  null(): void;
@@ -387,11 +379,12 @@ declare function use<T extends Model>(): T | undefined;
387
379
  /** Create a new child instance of model. */
388
380
  declare function use<T extends Model>(Type: Model.New<T>, callback?: (i: T) => void): T;
389
381
  /** Assign the result of a factory as a child model. */
390
- declare function use<T extends Model>(from: () => Promise<T> | T, required?: true): T;
382
+ declare function use<T extends {}>(from: () => Promise<T> | T, required?: true): T;
391
383
  /** Assign the result of a factory as a child model. */
392
- declare function use<T extends Model>(from: () => Promise<T> | T, required: boolean): T | undefined;
384
+ declare function use<T extends {}>(from: () => Promise<T> | T, required: boolean): T | undefined;
393
385
  /** Create a managed child from factory function. */
394
- declare function use<T extends Model>(from: () => Promise<T> | T, callback?: (i: T) => void): T;
386
+ declare function use<T extends {}>(from: () => Promise<T> | T, callback?: (i: T) => void): T;
387
+ declare function use<T extends {}>(data: T): T;
395
388
  /**
396
389
  * Create child-instance relationship with provided model.
397
390
  *
package/lib/index.esm.js CHANGED
@@ -197,18 +197,18 @@ function awaitUpdate(source, select, timeout) {
197
197
  const Oops$6 = issues({
198
198
  NotFound: (name) => `Could not find ${name} in context.`
199
199
  });
200
- function get$1(arg1, arg2) {
200
+ function get$1(argument) {
201
201
  return Control.get((dispatch, context) => {
202
202
  const refresh = () => dispatch(x => x + 1);
203
203
  let onUpdate;
204
204
  let value;
205
- if (typeof arg1 !== "function") {
205
+ if (typeof argument !== "function") {
206
206
  const got = context.get(this);
207
207
  if (got)
208
- value = arg1 === undefined
208
+ value = argument === undefined
209
209
  ? Control.watch(got, k => k ? onUpdate : undefined)
210
210
  : got;
211
- else if (arg1 !== false)
211
+ else if (argument !== false)
212
212
  throw Oops$6.NotFound(this);
213
213
  return {
214
214
  mount() {
@@ -218,7 +218,7 @@ function get$1(arg1, arg2) {
218
218
  render: () => value
219
219
  };
220
220
  }
221
- let compute = arg1;
221
+ let compute = argument;
222
222
  let suspense;
223
223
  let getValue;
224
224
  let factory;
@@ -226,9 +226,6 @@ function get$1(arg1, arg2) {
226
226
  const found = context.get(this);
227
227
  if (!found)
228
228
  throw Oops$6.NotFound(this);
229
- proxy = Control.watch(found, () => factory ? null : onUpdate);
230
- getValue = () => compute.call(proxy, proxy, forceUpdate);
231
- value = getValue();
232
229
  function forceUpdate(action) {
233
230
  if (typeof action == "function")
234
231
  action = action();
@@ -239,6 +236,18 @@ function get$1(arg1, arg2) {
239
236
  if (action)
240
237
  return action.finally(refresh);
241
238
  }
239
+ function didUpdate(got) {
240
+ value = got;
241
+ if (suspense) {
242
+ suspense();
243
+ suspense = undefined;
244
+ }
245
+ else
246
+ refresh();
247
+ }
248
+ proxy = Control.watch(found, () => factory ? null : onUpdate);
249
+ getValue = () => compute.call(proxy, proxy, forceUpdate);
250
+ value = getValue();
242
251
  if (value === null) {
243
252
  getValue = undefined;
244
253
  onUpdate = null;
@@ -251,15 +260,6 @@ function get$1(arg1, arg2) {
251
260
  compute = () => get();
252
261
  value = get();
253
262
  }
254
- const didUpdate = (got) => {
255
- value = got;
256
- if (suspense) {
257
- suspense();
258
- suspense = undefined;
259
- }
260
- else
261
- refresh();
262
- };
263
263
  if (value instanceof Promise) {
264
264
  onUpdate = null;
265
265
  value.then(didUpdate);
@@ -268,7 +268,7 @@ function get$1(arg1, arg2) {
268
268
  else
269
269
  onUpdate = () => {
270
270
  const next = getValue();
271
- if (notEqual(value, next))
271
+ if (value !== next)
272
272
  didUpdate(next);
273
273
  };
274
274
  return {
@@ -278,30 +278,25 @@ function get$1(arg1, arg2) {
278
278
  render: () => {
279
279
  if (value !== undefined)
280
280
  return value;
281
- if (arg2)
282
- throw new Promise(res => {
283
- suspense = res;
284
- });
285
- return null;
281
+ if (onUpdate)
282
+ return null;
283
+ throw new Promise(res => {
284
+ suspense = res;
285
+ });
286
286
  }
287
287
  };
288
288
  });
289
- }
290
- /** Values are not equal for purposes of a refresh. */
291
- const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
292
- !Array.isArray(b) ||
293
- a.length !== b.length ||
294
- a.some((x, i) => x !== b[i])));
289
+ }
295
290
 
296
- function use$1(arg1, arg2) {
291
+ function use$1(apply, repeat) {
297
292
  const render = Control.use(dispatch => {
298
293
  const instance = this.new();
299
294
  const local = Control.watch(instance, () => onUpdate);
300
295
  const refresh = () => dispatch(x => x + 1);
301
296
  let onUpdate;
302
- let apply = !!arg1;
297
+ let shouldApply = !!apply;
303
298
  return {
304
- local,
299
+ instance,
305
300
  mount() {
306
301
  onUpdate = refresh;
307
302
  return () => {
@@ -310,7 +305,7 @@ function use$1(arg1, arg2) {
310
305
  };
311
306
  },
312
307
  render(props) {
313
- if (apply) {
308
+ if (shouldApply) {
314
309
  onUpdate = undefined;
315
310
  if (typeof props == "function")
316
311
  props(instance);
@@ -318,15 +313,15 @@ function use$1(arg1, arg2) {
318
313
  for (const key in instance)
319
314
  if (props.hasOwnProperty(key))
320
315
  instance[key] = props[key];
321
- if (!arg2)
322
- apply = false;
316
+ if (!repeat)
317
+ shouldApply = false;
323
318
  instance.on(0).then(() => onUpdate = refresh);
324
319
  }
325
320
  return local;
326
321
  }
327
322
  };
328
323
  });
329
- return render(arg1);
324
+ return render(apply);
330
325
  }
331
326
 
332
327
  class Model {
@@ -427,24 +422,27 @@ const Oops$5 = issues({
427
422
  BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
428
423
  });
429
424
  const INSTRUCTION = new Map();
425
+ const PENDING$1 = new WeakMap();
430
426
  const REGISTER = new WeakMap();
431
427
  const OBSERVER = new WeakMap();
432
428
  const PARENTS = new WeakMap();
433
429
  class Control {
434
- constructor(subject, id = uid()) {
435
- this.subject = subject;
436
- this.id = id;
430
+ constructor(subject, id) {
431
+ this.state = {};
437
432
  this.frame = new Set();
438
433
  this.followers = new Set();
439
434
  this.observers = new Map([["", this.followers]]);
435
+ this.id = typeof id == "undefined" ? uid() : id;
436
+ this.subject = subject;
440
437
  REGISTER.set(subject, this);
438
+ PENDING$1.set(this, new Set(Control.ready));
441
439
  }
442
440
  add(key) {
443
441
  const { value } = getOwnPropertyDescriptor(this.subject, key);
444
442
  const instruction = INSTRUCTION.get(value);
445
443
  if (typeof instruction == "function") {
446
444
  INSTRUCTION.delete(value);
447
- instruction(key, this);
445
+ instruction(this, key);
448
446
  }
449
447
  else if (value instanceof Model)
450
448
  setRecursive(this, key, value);
@@ -453,7 +451,7 @@ class Control {
453
451
  }
454
452
  watch(key, output) {
455
453
  const { state } = this;
456
- const { get, set, enumerable = true } = output;
454
+ const { set, enumerable = true } = output;
457
455
  const subs = new Set();
458
456
  this.observers.set(key, subs);
459
457
  if ("value" in output)
@@ -467,8 +465,9 @@ class Control {
467
465
  const event = OBSERVER.get(this);
468
466
  if (event)
469
467
  subs.add(event);
470
- const value = get ? get(this) : state[key];
471
- return event && value instanceof Model
468
+ const value = output.get
469
+ ? output.get(this) : state[key];
470
+ return event && REGISTER.has(value)
472
471
  ? watch(value, event)
473
472
  : value;
474
473
  }
@@ -528,31 +527,30 @@ class Control {
528
527
  this.observers.clear();
529
528
  }
530
529
  }
530
+ Control.ready = new Set();
531
531
  Control.after = new Set();
532
532
  Control.before = new Set();
533
533
  Control.pending = new Set();
534
534
  Control.for = control;
535
535
  Control.apply = apply;
536
536
  Control.watch = watch;
537
- const PENDING_INIT = new WeakMap();
538
537
  function control(subject, ready) {
539
538
  const control = REGISTER.get(subject.is);
540
- const onReady = typeof ready == "function" && ready;
541
- if (!control.state && ready) {
542
- let waiting = PENDING_INIT.get(control);
543
- if (!waiting)
544
- PENDING_INIT.set(control, waiting = new Set());
545
- if (onReady) {
546
- let callback;
547
- waiting.add(() => callback = onReady(control));
548
- return () => callback && callback();
549
- }
550
- control.state = {};
539
+ const pending = PENDING$1.get(control);
540
+ if (typeof ready == "function") {
541
+ if (!pending)
542
+ return ready(control);
543
+ let done;
544
+ pending.add(() => done = ready(control));
545
+ return () => done && done();
546
+ }
547
+ if (pending && ready) {
548
+ PENDING$1.delete(control);
551
549
  for (const key in control.subject)
552
550
  control.add(key);
553
- waiting.forEach(cb => cb());
551
+ pending.forEach(cb => cb(control));
554
552
  }
555
- return onReady ? onReady(control) : control;
553
+ return control;
556
554
  }
557
555
  function requestUpdateFrame(event) {
558
556
  const { after, before, pending } = Control;
@@ -585,10 +583,10 @@ function setRecursive(on, key, value) {
585
583
  on.watch(key, { set });
586
584
  set(value);
587
585
  }
588
- function parent(child, register) {
589
- if (!register)
586
+ function parent(child, assign) {
587
+ if (!assign)
590
588
  return PARENTS.get(child);
591
- PARENTS.set(child, register);
589
+ PARENTS.set(child, assign);
592
590
  }
593
591
  function watch(on, cb) {
594
592
  if (!on.hasOwnProperty("is"))
@@ -598,7 +596,7 @@ function watch(on, cb) {
598
596
  }
599
597
  function apply(instruction) {
600
598
  const placeholder = Symbol("instruction");
601
- INSTRUCTION.set(placeholder, (key, onto) => {
599
+ INSTRUCTION.set(placeholder, (onto, key) => {
602
600
  delete onto.subject[key];
603
601
  const output = instruction.call(onto, key, onto);
604
602
  if (output)
@@ -900,69 +898,63 @@ function use(input, argument) {
900
898
  return apply((key, source) => {
901
899
  const { state, subject } = source;
902
900
  const required = argument !== false;
903
- let pending;
904
- let error;
905
901
  if (typeof input === "function") {
906
902
  if ("prototype" in input && input === input.prototype.constructor)
907
903
  input = new input();
908
904
  }
909
905
  else if (input && typeof input !== "object")
910
906
  throw Oops$1.BadArgument(typeof input);
911
- const onUpdate = (next) => {
912
- state[key] = next;
913
- if (next) {
914
- parent(next, subject);
915
- control(next, true);
916
- }
917
- if (typeof argument == "function")
918
- argument(next);
919
- return true;
920
- };
921
- const suspend = () => {
922
- if (required === false)
923
- return;
924
- const issue = Oops$1.NotReady(subject, key);
925
- assign(pending, {
926
- message: issue.message,
927
- stack: issue.stack
928
- });
929
- throw pending;
930
- };
931
- const initialize = () => {
932
- const output = typeof input == "function" ?
907
+ function init() {
908
+ const result = typeof input == "function" ?
933
909
  mayRetry(() => input.call(subject, subject)) :
934
910
  input;
935
- if (output instanceof Promise) {
936
- pending = output
937
- .then(val => {
938
- onUpdate(val);
939
- return val;
911
+ if (result instanceof Promise) {
912
+ const pending = result
913
+ .then(value => {
914
+ output.get = undefined;
915
+ set(value);
916
+ return value;
917
+ })
918
+ .catch(err => {
919
+ output.get = () => { throw err; };
940
920
  })
941
- .catch(err => error = err)
942
921
  .finally(() => {
943
- pending = undefined;
944
922
  source.update(key);
945
923
  });
946
- return;
924
+ if (required !== false)
925
+ output.get = () => {
926
+ throw assign(pending, Oops$1.NotReady(subject, key));
927
+ };
947
928
  }
948
- onUpdate(output);
949
- };
950
- if (input !== undefined && required)
951
- initialize();
952
- return {
953
- set: onUpdate,
954
- get() {
955
- if (pending)
956
- return suspend();
957
- if (error)
958
- throw error;
959
- if (!(key in state))
960
- initialize();
961
- if (pending)
962
- return suspend();
963
- return state[key];
929
+ else
930
+ set(result);
931
+ }
932
+ function set(next) {
933
+ if (next instanceof Model) {
934
+ parent(next, subject);
935
+ control(next, true);
964
936
  }
965
- };
937
+ else if (next) {
938
+ const control = new Control(create(next));
939
+ control.state = next;
940
+ for (const key in next)
941
+ control.watch(key, {});
942
+ next = control.subject;
943
+ }
944
+ state[key] = next;
945
+ if (typeof argument == "function")
946
+ argument(next);
947
+ return true;
948
+ }
949
+ const output = { set };
950
+ if (required)
951
+ init();
952
+ else
953
+ output.get = () => {
954
+ init();
955
+ return state[key];
956
+ };
957
+ return output;
966
958
  });
967
959
  }
968
960
 
@@ -998,8 +990,12 @@ class Context {
998
990
  this.layer.set(key, input);
999
991
  init.set(instance, true);
1000
992
  }
1001
- else if (exists !== input)
1002
- return this.bailout(inputs);
993
+ // Context must force-reset becasue inputs are no longer safe.
994
+ else if (exists !== input) {
995
+ this.pop();
996
+ this.key = uid();
997
+ return this.include(inputs);
998
+ }
1003
999
  }
1004
1000
  for (const [model] of init) {
1005
1001
  const { state } = control(model, true);
@@ -1012,12 +1008,6 @@ class Context {
1012
1008
  }
1013
1009
  return init;
1014
1010
  }
1015
- /** Context must force-reset becasue inputs are no longer safe. */
1016
- bailout(inputs) {
1017
- this.pop();
1018
- this.key = uid();
1019
- return this.include(inputs);
1020
- }
1021
1011
  add(input, implicit) {
1022
1012
  let writable = true;
1023
1013
  let T;
package/lib/index.js CHANGED
@@ -201,18 +201,18 @@ function awaitUpdate(source, select, timeout) {
201
201
  const Oops$6 = issues({
202
202
  NotFound: (name) => `Could not find ${name} in context.`
203
203
  });
204
- function get$1(arg1, arg2) {
204
+ function get$1(argument) {
205
205
  return Control.get((dispatch, context) => {
206
206
  const refresh = () => dispatch(x => x + 1);
207
207
  let onUpdate;
208
208
  let value;
209
- if (typeof arg1 !== "function") {
209
+ if (typeof argument !== "function") {
210
210
  const got = context.get(this);
211
211
  if (got)
212
- value = arg1 === undefined
212
+ value = argument === undefined
213
213
  ? Control.watch(got, k => k ? onUpdate : undefined)
214
214
  : got;
215
- else if (arg1 !== false)
215
+ else if (argument !== false)
216
216
  throw Oops$6.NotFound(this);
217
217
  return {
218
218
  mount() {
@@ -222,7 +222,7 @@ function get$1(arg1, arg2) {
222
222
  render: () => value
223
223
  };
224
224
  }
225
- let compute = arg1;
225
+ let compute = argument;
226
226
  let suspense;
227
227
  let getValue;
228
228
  let factory;
@@ -230,9 +230,6 @@ function get$1(arg1, arg2) {
230
230
  const found = context.get(this);
231
231
  if (!found)
232
232
  throw Oops$6.NotFound(this);
233
- proxy = Control.watch(found, () => factory ? null : onUpdate);
234
- getValue = () => compute.call(proxy, proxy, forceUpdate);
235
- value = getValue();
236
233
  function forceUpdate(action) {
237
234
  if (typeof action == "function")
238
235
  action = action();
@@ -243,6 +240,18 @@ function get$1(arg1, arg2) {
243
240
  if (action)
244
241
  return action.finally(refresh);
245
242
  }
243
+ function didUpdate(got) {
244
+ value = got;
245
+ if (suspense) {
246
+ suspense();
247
+ suspense = undefined;
248
+ }
249
+ else
250
+ refresh();
251
+ }
252
+ proxy = Control.watch(found, () => factory ? null : onUpdate);
253
+ getValue = () => compute.call(proxy, proxy, forceUpdate);
254
+ value = getValue();
246
255
  if (value === null) {
247
256
  getValue = undefined;
248
257
  onUpdate = null;
@@ -255,15 +264,6 @@ function get$1(arg1, arg2) {
255
264
  compute = () => get();
256
265
  value = get();
257
266
  }
258
- const didUpdate = (got) => {
259
- value = got;
260
- if (suspense) {
261
- suspense();
262
- suspense = undefined;
263
- }
264
- else
265
- refresh();
266
- };
267
267
  if (value instanceof Promise) {
268
268
  onUpdate = null;
269
269
  value.then(didUpdate);
@@ -272,7 +272,7 @@ function get$1(arg1, arg2) {
272
272
  else
273
273
  onUpdate = () => {
274
274
  const next = getValue();
275
- if (notEqual(value, next))
275
+ if (value !== next)
276
276
  didUpdate(next);
277
277
  };
278
278
  return {
@@ -282,30 +282,25 @@ function get$1(arg1, arg2) {
282
282
  render: () => {
283
283
  if (value !== undefined)
284
284
  return value;
285
- if (arg2)
286
- throw new Promise(res => {
287
- suspense = res;
288
- });
289
- return null;
285
+ if (onUpdate)
286
+ return null;
287
+ throw new Promise(res => {
288
+ suspense = res;
289
+ });
290
290
  }
291
291
  };
292
292
  });
293
- }
294
- /** Values are not equal for purposes of a refresh. */
295
- const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
296
- !Array.isArray(b) ||
297
- a.length !== b.length ||
298
- a.some((x, i) => x !== b[i])));
293
+ }
299
294
 
300
- function use$1(arg1, arg2) {
295
+ function use$1(apply, repeat) {
301
296
  const render = Control.use(dispatch => {
302
297
  const instance = this.new();
303
298
  const local = Control.watch(instance, () => onUpdate);
304
299
  const refresh = () => dispatch(x => x + 1);
305
300
  let onUpdate;
306
- let apply = !!arg1;
301
+ let shouldApply = !!apply;
307
302
  return {
308
- local,
303
+ instance,
309
304
  mount() {
310
305
  onUpdate = refresh;
311
306
  return () => {
@@ -314,7 +309,7 @@ function use$1(arg1, arg2) {
314
309
  };
315
310
  },
316
311
  render(props) {
317
- if (apply) {
312
+ if (shouldApply) {
318
313
  onUpdate = undefined;
319
314
  if (typeof props == "function")
320
315
  props(instance);
@@ -322,15 +317,15 @@ function use$1(arg1, arg2) {
322
317
  for (const key in instance)
323
318
  if (props.hasOwnProperty(key))
324
319
  instance[key] = props[key];
325
- if (!arg2)
326
- apply = false;
320
+ if (!repeat)
321
+ shouldApply = false;
327
322
  instance.on(0).then(() => onUpdate = refresh);
328
323
  }
329
324
  return local;
330
325
  }
331
326
  };
332
327
  });
333
- return render(arg1);
328
+ return render(apply);
334
329
  }
335
330
 
336
331
  class Model {
@@ -431,24 +426,27 @@ const Oops$5 = issues({
431
426
  BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
432
427
  });
433
428
  const INSTRUCTION = new Map();
429
+ const PENDING$1 = new WeakMap();
434
430
  const REGISTER = new WeakMap();
435
431
  const OBSERVER = new WeakMap();
436
432
  const PARENTS = new WeakMap();
437
433
  class Control {
438
- constructor(subject, id = uid()) {
439
- this.subject = subject;
440
- this.id = id;
434
+ constructor(subject, id) {
435
+ this.state = {};
441
436
  this.frame = new Set();
442
437
  this.followers = new Set();
443
438
  this.observers = new Map([["", this.followers]]);
439
+ this.id = typeof id == "undefined" ? uid() : id;
440
+ this.subject = subject;
444
441
  REGISTER.set(subject, this);
442
+ PENDING$1.set(this, new Set(Control.ready));
445
443
  }
446
444
  add(key) {
447
445
  const { value } = getOwnPropertyDescriptor(this.subject, key);
448
446
  const instruction = INSTRUCTION.get(value);
449
447
  if (typeof instruction == "function") {
450
448
  INSTRUCTION.delete(value);
451
- instruction(key, this);
449
+ instruction(this, key);
452
450
  }
453
451
  else if (value instanceof Model)
454
452
  setRecursive(this, key, value);
@@ -457,7 +455,7 @@ class Control {
457
455
  }
458
456
  watch(key, output) {
459
457
  const { state } = this;
460
- const { get, set, enumerable = true } = output;
458
+ const { set, enumerable = true } = output;
461
459
  const subs = new Set();
462
460
  this.observers.set(key, subs);
463
461
  if ("value" in output)
@@ -471,8 +469,9 @@ class Control {
471
469
  const event = OBSERVER.get(this);
472
470
  if (event)
473
471
  subs.add(event);
474
- const value = get ? get(this) : state[key];
475
- return event && value instanceof Model
472
+ const value = output.get
473
+ ? output.get(this) : state[key];
474
+ return event && REGISTER.has(value)
476
475
  ? watch(value, event)
477
476
  : value;
478
477
  }
@@ -532,31 +531,30 @@ class Control {
532
531
  this.observers.clear();
533
532
  }
534
533
  }
534
+ Control.ready = new Set();
535
535
  Control.after = new Set();
536
536
  Control.before = new Set();
537
537
  Control.pending = new Set();
538
538
  Control.for = control;
539
539
  Control.apply = apply;
540
540
  Control.watch = watch;
541
- const PENDING_INIT = new WeakMap();
542
541
  function control(subject, ready) {
543
542
  const control = REGISTER.get(subject.is);
544
- const onReady = typeof ready == "function" && ready;
545
- if (!control.state && ready) {
546
- let waiting = PENDING_INIT.get(control);
547
- if (!waiting)
548
- PENDING_INIT.set(control, waiting = new Set());
549
- if (onReady) {
550
- let callback;
551
- waiting.add(() => callback = onReady(control));
552
- return () => callback && callback();
553
- }
554
- control.state = {};
543
+ const pending = PENDING$1.get(control);
544
+ if (typeof ready == "function") {
545
+ if (!pending)
546
+ return ready(control);
547
+ let done;
548
+ pending.add(() => done = ready(control));
549
+ return () => done && done();
550
+ }
551
+ if (pending && ready) {
552
+ PENDING$1.delete(control);
555
553
  for (const key in control.subject)
556
554
  control.add(key);
557
- waiting.forEach(cb => cb());
555
+ pending.forEach(cb => cb(control));
558
556
  }
559
- return onReady ? onReady(control) : control;
557
+ return control;
560
558
  }
561
559
  function requestUpdateFrame(event) {
562
560
  const { after, before, pending } = Control;
@@ -589,10 +587,10 @@ function setRecursive(on, key, value) {
589
587
  on.watch(key, { set });
590
588
  set(value);
591
589
  }
592
- function parent(child, register) {
593
- if (!register)
590
+ function parent(child, assign) {
591
+ if (!assign)
594
592
  return PARENTS.get(child);
595
- PARENTS.set(child, register);
593
+ PARENTS.set(child, assign);
596
594
  }
597
595
  function watch(on, cb) {
598
596
  if (!on.hasOwnProperty("is"))
@@ -602,7 +600,7 @@ function watch(on, cb) {
602
600
  }
603
601
  function apply(instruction) {
604
602
  const placeholder = Symbol("instruction");
605
- INSTRUCTION.set(placeholder, (key, onto) => {
603
+ INSTRUCTION.set(placeholder, (onto, key) => {
606
604
  delete onto.subject[key];
607
605
  const output = instruction.call(onto, key, onto);
608
606
  if (output)
@@ -904,69 +902,63 @@ function use(input, argument) {
904
902
  return apply((key, source) => {
905
903
  const { state, subject } = source;
906
904
  const required = argument !== false;
907
- let pending;
908
- let error;
909
905
  if (typeof input === "function") {
910
906
  if ("prototype" in input && input === input.prototype.constructor)
911
907
  input = new input();
912
908
  }
913
909
  else if (input && typeof input !== "object")
914
910
  throw Oops$1.BadArgument(typeof input);
915
- const onUpdate = (next) => {
916
- state[key] = next;
917
- if (next) {
918
- parent(next, subject);
919
- control(next, true);
920
- }
921
- if (typeof argument == "function")
922
- argument(next);
923
- return true;
924
- };
925
- const suspend = () => {
926
- if (required === false)
927
- return;
928
- const issue = Oops$1.NotReady(subject, key);
929
- assign(pending, {
930
- message: issue.message,
931
- stack: issue.stack
932
- });
933
- throw pending;
934
- };
935
- const initialize = () => {
936
- const output = typeof input == "function" ?
911
+ function init() {
912
+ const result = typeof input == "function" ?
937
913
  mayRetry(() => input.call(subject, subject)) :
938
914
  input;
939
- if (output instanceof Promise) {
940
- pending = output
941
- .then(val => {
942
- onUpdate(val);
943
- return val;
915
+ if (result instanceof Promise) {
916
+ const pending = result
917
+ .then(value => {
918
+ output.get = undefined;
919
+ set(value);
920
+ return value;
921
+ })
922
+ .catch(err => {
923
+ output.get = () => { throw err; };
944
924
  })
945
- .catch(err => error = err)
946
925
  .finally(() => {
947
- pending = undefined;
948
926
  source.update(key);
949
927
  });
950
- return;
928
+ if (required !== false)
929
+ output.get = () => {
930
+ throw assign(pending, Oops$1.NotReady(subject, key));
931
+ };
951
932
  }
952
- onUpdate(output);
953
- };
954
- if (input !== undefined && required)
955
- initialize();
956
- return {
957
- set: onUpdate,
958
- get() {
959
- if (pending)
960
- return suspend();
961
- if (error)
962
- throw error;
963
- if (!(key in state))
964
- initialize();
965
- if (pending)
966
- return suspend();
967
- return state[key];
933
+ else
934
+ set(result);
935
+ }
936
+ function set(next) {
937
+ if (next instanceof Model) {
938
+ parent(next, subject);
939
+ control(next, true);
968
940
  }
969
- };
941
+ else if (next) {
942
+ const control = new Control(create(next));
943
+ control.state = next;
944
+ for (const key in next)
945
+ control.watch(key, {});
946
+ next = control.subject;
947
+ }
948
+ state[key] = next;
949
+ if (typeof argument == "function")
950
+ argument(next);
951
+ return true;
952
+ }
953
+ const output = { set };
954
+ if (required)
955
+ init();
956
+ else
957
+ output.get = () => {
958
+ init();
959
+ return state[key];
960
+ };
961
+ return output;
970
962
  });
971
963
  }
972
964
 
@@ -1002,8 +994,12 @@ class Context {
1002
994
  this.layer.set(key, input);
1003
995
  init.set(instance, true);
1004
996
  }
1005
- else if (exists !== input)
1006
- return this.bailout(inputs);
997
+ // Context must force-reset becasue inputs are no longer safe.
998
+ else if (exists !== input) {
999
+ this.pop();
1000
+ this.key = uid();
1001
+ return this.include(inputs);
1002
+ }
1007
1003
  }
1008
1004
  for (const [model] of init) {
1009
1005
  const { state } = control(model, true);
@@ -1016,12 +1012,6 @@ class Context {
1016
1012
  }
1017
1013
  return init;
1018
1014
  }
1019
- /** Context must force-reset becasue inputs are no longer safe. */
1020
- bailout(inputs) {
1021
- this.pop();
1022
- this.key = uid();
1023
- return this.include(inputs);
1024
- }
1025
1015
  add(input, implicit) {
1026
1016
  let writable = true;
1027
1017
  let T;
package/package.json CHANGED
@@ -22,8 +22,10 @@
22
22
  "scripts": {
23
23
  "build": "rollup --config",
24
24
  "watch": "jest --watchAll",
25
- "test": "jest --collectCoverage"
25
+ "test": "jest --collectCoverage",
26
+ "prebuild": "rm -rf lib/",
27
+ "preversion": "npm run test && npm run build"
26
28
  },
27
- "version": "0.24.1",
28
- "gitHead": "09e4f6dfecbc618f675d6f3f8e2bad15c1bebf40"
29
+ "version": "0.25.0",
30
+ "gitHead": "a7c707bf59325bd4bf1388e061f7991acb726a13"
29
31
  }