@expressive/mvc 0.10.0 → 0.11.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.esm.js CHANGED
@@ -22,11 +22,11 @@ function issues(register) {
22
22
  return Library;
23
23
  }
24
24
 
25
- const Oops$e = issues({
25
+ const Oops$f = issues({
26
26
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
27
27
  });
28
28
  function suspend(source, key) {
29
- const error = Oops$e.NotReady(source.subject, key);
29
+ const error = Oops$f.NotReady(source.subject, key);
30
30
  const promise = new Promise(resolve => {
31
31
  const release = source.addListener(forKey => {
32
32
  if (forKey == key)
@@ -66,7 +66,7 @@ function mayRetry(fn) {
66
66
  return compute();
67
67
  }
68
68
 
69
- const Oops$d = issues({
69
+ const Oops$e = issues({
70
70
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
71
71
  });
72
72
  const INFO = new WeakMap();
@@ -86,7 +86,7 @@ function computeMode(self, source, setter, key, required) {
86
86
  return setter.call(sub.proxy, sub.proxy);
87
87
  }
88
88
  catch (err) {
89
- Oops$d.Failed(subject, key, initial).warn();
89
+ Oops$e.Failed(subject, key, initial).warn();
90
90
  throw err;
91
91
  }
92
92
  };
@@ -157,6 +157,152 @@ function flush(control) {
157
157
  pending.clear();
158
158
  }
159
159
 
160
+ const Oops$d = issues({
161
+ BadCallback: () => `Callback for effect-callback may only return a function.`
162
+ });
163
+ function createEffect(model, callback, keys) {
164
+ return Control.for(model, control => {
165
+ let unSet;
166
+ let busy = false;
167
+ function effect(value) {
168
+ if (typeof unSet == "function")
169
+ unSet();
170
+ unSet = callback.call(this, value);
171
+ if (unSet instanceof Promise)
172
+ unSet = undefined;
173
+ if (unSet && typeof unSet !== "function")
174
+ throw Oops$d.BadCallback();
175
+ }
176
+ function invoke() {
177
+ if (busy)
178
+ return;
179
+ const output = mayRetry(() => {
180
+ effect.call(model, model);
181
+ });
182
+ if (output instanceof Promise) {
183
+ output.finally(() => busy = false);
184
+ busy = true;
185
+ }
186
+ }
187
+ if (Array.isArray(keys)) {
188
+ invoke();
189
+ return control.addListener(key => {
190
+ if (key === null) {
191
+ if (!keys.length)
192
+ invoke();
193
+ }
194
+ else if (keys.includes(key))
195
+ return invoke;
196
+ });
197
+ }
198
+ const sub = control.subscribe(() => invoke);
199
+ model = sub.proxy;
200
+ invoke();
201
+ return sub.commit();
202
+ });
203
+ }
204
+ function createValueEffect(callback) {
205
+ let unSet;
206
+ return function (value) {
207
+ if (typeof unSet == "function")
208
+ unSet(value);
209
+ const out = callback.call(this, value, this);
210
+ if (typeof out == "boolean")
211
+ return out;
212
+ if (!out || out instanceof Promise)
213
+ return;
214
+ if (typeof out == "function")
215
+ unSet = out;
216
+ else
217
+ throw Oops$d.BadCallback();
218
+ };
219
+ }
220
+
221
+ const Oops$c = issues({
222
+ Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
223
+ KeysExpected: (key) => `Key "${key}" was expected in current update.`,
224
+ StrictUpdate: () => `Expected update but none in progress.`,
225
+ StrictNoUpdate: () => `Update is not expected but one is in progress!`
226
+ });
227
+ function addEventListener(source, arg1, arg2, arg3) {
228
+ if (typeof arg1 == "string")
229
+ arg1 = [arg1];
230
+ return Control.for(source, control => {
231
+ for (const key of arg1)
232
+ try {
233
+ void source[key];
234
+ }
235
+ catch (e) { }
236
+ const removeListener = control.addListener(key => {
237
+ if (!key && !arg1.length)
238
+ arg2.call(source, []);
239
+ if (arg1.includes(key)) {
240
+ if (arg3)
241
+ removeListener();
242
+ return arg2.bind(source);
243
+ }
244
+ });
245
+ return removeListener;
246
+ });
247
+ }
248
+ function awaitUpdate(source, arg1, arg2) {
249
+ const single = typeof arg1 == "string";
250
+ const keys = typeof arg1 == "string" ? [arg1] :
251
+ typeof arg1 == "object" ? arg1 :
252
+ undefined;
253
+ return new Promise((resolve, reject) => {
254
+ const timeout = (message) => {
255
+ const k = keys ? keys.join(", ") : "any";
256
+ removeListener();
257
+ reject(Oops$c.Timeout(k, message));
258
+ };
259
+ const removeListener = Control.for(source, control => {
260
+ const pending = control.frame;
261
+ if (keys === null) {
262
+ if (pending.size)
263
+ reject(Oops$c.StrictNoUpdate());
264
+ else
265
+ resolve(null);
266
+ return;
267
+ }
268
+ if (keys) {
269
+ if (keys.length) {
270
+ if (arg2 === 0 && single && !pending.has(keys[0])) {
271
+ reject(Oops$c.KeysExpected(keys[0]));
272
+ return;
273
+ }
274
+ else
275
+ for (const key of keys)
276
+ try {
277
+ void source[key];
278
+ }
279
+ catch (e) { }
280
+ }
281
+ }
282
+ else if (!pending.size && arg1 === true || arg2 === 0) {
283
+ reject(Oops$c.StrictUpdate());
284
+ return;
285
+ }
286
+ else
287
+ control.waiting.add(resolve);
288
+ return control.addListener(key => {
289
+ if (!key) {
290
+ if (keys && !keys.length)
291
+ resolve([]);
292
+ else
293
+ timeout(`lifetime of ${source}`);
294
+ }
295
+ else if (!keys || keys.includes(key)) {
296
+ removeListener();
297
+ return keys => resolve(single ? control.state.get(key) : keys);
298
+ }
299
+ });
300
+ });
301
+ if (arg2 && typeof arg2 == "number")
302
+ setTimeout(() => timeout(`${arg2}ms`), arg2);
303
+ });
304
+ }
305
+
160
306
  const REGISTER$1 = new WeakMap();
161
307
  class Subscriber {
162
308
  constructor(parent, onUpdate) {
@@ -229,6 +375,102 @@ class Subscriber {
229
375
  }
230
376
  }
231
377
 
378
+ const Oops$b = issues({
379
+ NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
380
+ });
381
+ class Model {
382
+ constructor() {
383
+ new Control(this);
384
+ defineProperty(this, "is", { value: this });
385
+ }
386
+ on(arg1, arg2, arg3) {
387
+ if (typeof arg1 == "function")
388
+ return createEffect(this.is, arg1, arg2);
389
+ if (typeof arg2 != "function")
390
+ return awaitUpdate(this.is, arg1, arg2);
391
+ if (arg1)
392
+ return addEventListener(this.is, arg1, arg2, arg3);
393
+ }
394
+ get(arg1, arg2) {
395
+ const { state } = Control.for(this);
396
+ const extract = typeof arg1 == "string"
397
+ ? () => state.get(arg1)
398
+ : () => {
399
+ const output = {};
400
+ for (const key of arg1 || state.keys())
401
+ output[key] = state.get(key);
402
+ return output;
403
+ };
404
+ if (!arg1 || arg2 === undefined)
405
+ return extract();
406
+ if (typeof arg2 == "function")
407
+ return this.on(arg1, () => arg2(extract()));
408
+ const timeout = typeof arg2 == "number" ? arg2 : undefined;
409
+ return this.on(arg1, timeout).then(extract);
410
+ }
411
+ set(arg1, arg2) {
412
+ const control = Control.for(this);
413
+ if (typeof arg1 == "object")
414
+ for (const key in arg1) {
415
+ if (arg2 === true || (arg2 ? arg2.includes(key) : control.state.has(key))) {
416
+ control.state.set(key, arg1[key]);
417
+ control.update(key);
418
+ }
419
+ }
420
+ else if (typeof arg1 == "string") {
421
+ control.update(arg1);
422
+ if (1 in arguments) {
423
+ if (control.state.has(arg1))
424
+ control.state.set(arg1, arg2);
425
+ else if (arg1 in this) {
426
+ const method = this[arg1];
427
+ if (typeof method == "function")
428
+ method.call(this, arg2);
429
+ }
430
+ }
431
+ }
432
+ return {
433
+ then: (callback) => {
434
+ if (!callback)
435
+ throw Oops$b.NoChaining();
436
+ control.waiting.add(callback);
437
+ }
438
+ };
439
+ }
440
+ /**
441
+ * Clean up side effects and mark this instance for garbage-collection.
442
+ */
443
+ end() {
444
+ Control.for(this).clear();
445
+ }
446
+ /**
447
+ * Creates a new instance of this controller.
448
+ *
449
+ * Beyond `new this(...)`, method will activate managed-state.
450
+ *
451
+ * @param args - arguments sent to constructor
452
+ */
453
+ static new(...args) {
454
+ const instance = new this(...args);
455
+ Control.for(instance);
456
+ return instance;
457
+ }
458
+ /**
459
+ * Static equivalent of `x instanceof this`.
460
+ *
461
+ * Will determine if provided class is a subtype of this one.
462
+ */
463
+ static isTypeof(maybe) {
464
+ return (typeof maybe == "function" &&
465
+ maybe.prototype instanceof this);
466
+ }
467
+ }
468
+ defineProperty(Model.prototype, "toString", {
469
+ value() {
470
+ return this.constructor.name;
471
+ }
472
+ });
473
+
232
474
  const REGISTER = new WeakMap();
233
475
  const PENDING = new Map();
234
476
  class Control {
@@ -257,6 +499,10 @@ class Control {
257
499
  return;
258
500
  }
259
501
  state.set(key, value);
502
+ if (value instanceof Model) {
503
+ setRecursive(this, key, value);
504
+ return;
505
+ }
260
506
  defineProperty(subject, key, {
261
507
  enumerable: false,
262
508
  set: this.ref(key),
@@ -351,6 +597,68 @@ class Control {
351
597
  }
352
598
  }
353
599
 
600
+ const Parent = new WeakMap();
601
+ const Oops$a = issues({
602
+ BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
603
+ });
604
+ function getRecursive(key, from) {
605
+ const context = new WeakMap();
606
+ const { state } = from;
607
+ return (local) => {
608
+ if (!local)
609
+ return state.get(key);
610
+ if (!context.has(local)) {
611
+ let reset;
612
+ const init = () => {
613
+ if (reset)
614
+ reset();
615
+ const value = state.get(key);
616
+ if (Control.get(value)) {
617
+ const child = Control.for(value).subscribe(local.onUpdate);
618
+ if (local.active)
619
+ child.commit();
620
+ local.dependant.add(child);
621
+ context.set(local, child.proxy);
622
+ reset = () => {
623
+ child.release();
624
+ local.dependant.delete(child);
625
+ context.set(local, undefined);
626
+ reset = undefined;
627
+ };
628
+ }
629
+ return true;
630
+ };
631
+ local.add(key, init);
632
+ init();
633
+ }
634
+ return context.get(local);
635
+ };
636
+ }
637
+ function setRecursive(control, key, initial) {
638
+ const { state, subject } = control;
639
+ const Type = initial.constructor;
640
+ let get;
641
+ const onUpdate = (next) => {
642
+ state.set(key, next);
643
+ if (!(next instanceof Type))
644
+ throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
645
+ get = getRecursive(key, control);
646
+ Parent.set(next, subject);
647
+ Control.for(next);
648
+ return true;
649
+ };
650
+ onUpdate(initial);
651
+ defineProperty(subject, key, {
652
+ set: control.ref(key, onUpdate),
653
+ get() {
654
+ const local = Subscriber.get(this);
655
+ if (local)
656
+ local.add(key);
657
+ return get(local);
658
+ }
659
+ });
660
+ }
661
+
354
662
  /**
355
663
  * Run instruction as controller sets itself up.
356
664
  * This will specialize the behavior of a given property.
@@ -385,9 +693,9 @@ function add(instruction, label) {
385
693
  const control = this;
386
694
  defineProperty(subject, key, {
387
695
  enumerable: output.enumerable,
388
- set: onSet !== false
389
- ? this.ref(key, onSet)
390
- : undefined,
696
+ set: onSet === false
697
+ ? undefined
698
+ : this.ref(key, onSet),
391
699
  get() {
392
700
  if (!state.has(key) && shouldSuspend)
393
701
  throw suspend(control, key);
@@ -402,38 +710,6 @@ function add(instruction, label) {
402
710
  }
403
711
  PENDING.set(placeholder, setup);
404
712
  return placeholder;
405
- }
406
- function getRecursive(key, from) {
407
- const context = new WeakMap();
408
- return (local) => {
409
- if (!local)
410
- return from.state.get(key);
411
- if (!context.has(local)) {
412
- let reset;
413
- const init = () => {
414
- if (reset)
415
- reset();
416
- const value = from.state.get(key);
417
- if (Control.get(value)) {
418
- const child = Control.for(value).subscribe(local.onUpdate);
419
- if (local.active)
420
- child.commit();
421
- local.dependant.add(child);
422
- context.set(local, child.proxy);
423
- reset = () => {
424
- child.release();
425
- local.dependant.delete(child);
426
- context.set(local, undefined);
427
- reset = undefined;
428
- };
429
- }
430
- return true;
431
- };
432
- local.add(key, init);
433
- init();
434
- }
435
- return context.get(local);
436
- };
437
713
  }
438
714
 
439
715
  /*! *****************************************************************************
@@ -461,7 +737,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
461
737
  });
462
738
  }
463
739
 
464
- const Oops$c = issues({
740
+ const Oops$9 = issues({
465
741
  DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
466
742
  });
467
743
  function run(task) {
@@ -469,7 +745,7 @@ function run(task) {
469
745
  let pending = false;
470
746
  const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
471
747
  if (pending)
472
- return Promise.reject(Oops$c.DuplicatePending(key));
748
+ return Promise.reject(Oops$9.DuplicatePending(key));
473
749
  pending = true;
474
750
  this.update(key);
475
751
  try {
@@ -491,7 +767,7 @@ function run(task) {
491
767
  });
492
768
  }
493
769
 
494
- const Oops$b = issues({
770
+ const Oops$8 = issues({
495
771
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
496
772
  });
497
773
  function factoryMode(self, output, key, required) {
@@ -515,7 +791,7 @@ function factoryMode(self, output, key, required) {
515
791
  const suspend = () => {
516
792
  if (required === false)
517
793
  return undefined;
518
- const issue = Oops$b.NotReady(subject, key);
794
+ const issue = Oops$8.NotReady(subject, key);
519
795
  assign(pending, {
520
796
  message: issue.message,
521
797
  stack: issue.stack
@@ -532,7 +808,7 @@ function factoryMode(self, output, key, required) {
532
808
  };
533
809
  }
534
810
 
535
- const Oops$a = issues({
811
+ const Oops$7 = issues({
536
812
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
537
813
  ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
538
814
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
@@ -545,7 +821,7 @@ function get(arg0, arg1, arg2) {
545
821
  let getter;
546
822
  // Easy mistake, using a peer, will always be unresolved.
547
823
  if (typeof arg0 == "symbol")
548
- throw Oops$a.PeerNotAllowed(subject, key);
824
+ throw Oops$7.PeerNotAllowed(subject, key);
549
825
  // if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
550
826
  // throw Oops.BadSource(subject, key, arg0);
551
827
  this.state.set(key, undefined);
@@ -579,7 +855,7 @@ function get(arg0, arg1, arg2) {
579
855
  init();
580
856
  }
581
857
  catch (err) {
582
- Oops$a.ComputeFailed(subject, key).warn();
858
+ Oops$7.ComputeFailed(subject, key).warn();
583
859
  throw err;
584
860
  }
585
861
  return () => {
@@ -590,67 +866,6 @@ function get(arg0, arg1, arg2) {
590
866
  });
591
867
  }
592
868
 
593
- const Oops$9 = issues({
594
- BadCallback: () => `Callback for effect-callback may only return a function.`
595
- });
596
- function createEffect(model, callback, keys) {
597
- return Control.for(model, control => {
598
- let unSet;
599
- let busy = false;
600
- function effect(value) {
601
- if (typeof unSet == "function")
602
- unSet();
603
- unSet = callback.call(this, value);
604
- if (unSet instanceof Promise)
605
- unSet = undefined;
606
- if (unSet && typeof unSet !== "function")
607
- throw Oops$9.BadCallback();
608
- }
609
- function invoke() {
610
- if (busy)
611
- return;
612
- const output = mayRetry(() => {
613
- effect.call(model, model);
614
- });
615
- if (output instanceof Promise) {
616
- output.finally(() => busy = false);
617
- busy = true;
618
- }
619
- }
620
- if (Array.isArray(keys)) {
621
- invoke();
622
- return control.addListener(key => {
623
- if (key === null) {
624
- if (!keys.length)
625
- invoke();
626
- }
627
- else if (keys.includes(key))
628
- return invoke;
629
- });
630
- }
631
- const sub = control.subscribe(() => invoke);
632
- model = sub.proxy;
633
- invoke();
634
- return sub.commit();
635
- });
636
- }
637
- function createValueEffect(callback) {
638
- let unSet;
639
- return function (value) {
640
- if (typeof unSet == "function")
641
- unSet(value);
642
- const out = callback.call(this, value, this);
643
- if (typeof out == "boolean")
644
- return out;
645
- if (!out || out instanceof Promise)
646
- return;
647
- if (typeof out == "function")
648
- unSet = out;
649
- else
650
- throw Oops$9.BadCallback();
651
- };
652
- }
653
-
654
869
  function ref(arg, mapper) {
655
870
  return add(function ref(key) {
656
871
  let value = {};
@@ -845,8 +1060,7 @@ function createProxy(emit, watch) {
845
1060
  };
846
1061
  }
847
1062
 
848
- const Parent = new WeakMap();
849
- const Oops$8 = issues({
1063
+ const Oops$6 = issues({
850
1064
  BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
851
1065
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
852
1066
  });
@@ -858,12 +1072,11 @@ function use$1(input, argument) {
858
1072
  let error;
859
1073
  let get = (_local) => state.get(key);
860
1074
  if (typeof input === "function") {
861
- if ("prototype" in input &&
862
- input === input.prototype.constructor)
1075
+ if ("prototype" in input && input === input.prototype.constructor)
863
1076
  input = new input();
864
1077
  }
865
1078
  else if (input && typeof input !== "object")
866
- throw Oops$8.BadArgument(typeof input);
1079
+ throw Oops$6.BadArgument(typeof input);
867
1080
  if (input instanceof Map || input instanceof Set)
868
1081
  return keyed(this, key, input);
869
1082
  const onUpdate = (next) => {
@@ -880,7 +1093,7 @@ function use$1(input, argument) {
880
1093
  const suspend = () => {
881
1094
  if (required === false)
882
1095
  return;
883
- const issue = Oops$8.NotReady(subject, key);
1096
+ const issue = Oops$6.NotReady(subject, key);
884
1097
  assign(pending, {
885
1098
  message: issue.message,
886
1099
  stack: issue.stack
@@ -925,7 +1138,7 @@ function use$1(input, argument) {
925
1138
  });
926
1139
  }
927
1140
 
928
- const Oops$7 = issues({
1141
+ const Oops$5 = issues({
929
1142
  Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
930
1143
  Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
931
1144
  });
@@ -936,195 +1149,14 @@ function has(Type, required) {
936
1149
  const expected = Type.name;
937
1150
  if (!value) {
938
1151
  if (required !== false)
939
- throw Oops$7.Required(expected, child);
1152
+ throw Oops$5.Required(expected, child);
940
1153
  }
941
1154
  else if (!(value instanceof Type))
942
- throw Oops$7.Unexpected(expected, child, value);
1155
+ throw Oops$5.Unexpected(expected, child, value);
943
1156
  return { value };
944
1157
  });
945
1158
  }
946
1159
 
947
- const Oops$6 = issues({
948
- Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
949
- KeysExpected: (key) => `Key "${key}" was expected in current update.`,
950
- StrictUpdate: () => `Expected update but none in progress.`,
951
- StrictNoUpdate: () => `Update is not expected but one is in progress!`
952
- });
953
- function addEventListener(source, arg1, arg2, arg3) {
954
- if (typeof arg1 == "string")
955
- arg1 = [arg1];
956
- return Control.for(source, control => {
957
- for (const key of arg1)
958
- try {
959
- void source[key];
960
- }
961
- catch (e) { }
962
- const removeListener = control.addListener(key => {
963
- if (!key && !arg1.length)
964
- arg2.call(source, []);
965
- if (arg1.includes(key)) {
966
- if (arg3)
967
- removeListener();
968
- return arg2.bind(source);
969
- }
970
- });
971
- return removeListener;
972
- });
973
- }
974
- function awaitUpdate(source, arg1, arg2) {
975
- const single = typeof arg1 == "string";
976
- const keys = typeof arg1 == "string" ? [arg1] :
977
- typeof arg1 == "object" ? arg1 :
978
- undefined;
979
- return new Promise((resolve, reject) => {
980
- const timeout = (message) => {
981
- const k = keys ? keys.join(", ") : "any";
982
- removeListener();
983
- reject(Oops$6.Timeout(k, message));
984
- };
985
- const removeListener = Control.for(source, control => {
986
- const pending = control.frame;
987
- if (keys === null) {
988
- if (pending.size)
989
- reject(Oops$6.StrictNoUpdate());
990
- else
991
- resolve(null);
992
- return;
993
- }
994
- if (keys) {
995
- if (keys.length) {
996
- if (arg2 === 0 && single && !pending.has(keys[0])) {
997
- reject(Oops$6.KeysExpected(keys[0]));
998
- return;
999
- }
1000
- else
1001
- for (const key of keys)
1002
- try {
1003
- void source[key];
1004
- }
1005
- catch (e) { }
1006
- }
1007
- }
1008
- else if (!pending.size && arg1 === true || arg2 === 0) {
1009
- reject(Oops$6.StrictUpdate());
1010
- return;
1011
- }
1012
- else
1013
- control.waiting.add(resolve);
1014
- return control.addListener(key => {
1015
- if (!key) {
1016
- if (keys && !keys.length)
1017
- resolve([]);
1018
- else
1019
- timeout(`lifetime of ${source}`);
1020
- }
1021
- else if (!keys || keys.includes(key)) {
1022
- removeListener();
1023
- return keys => resolve(single ? control.state.get(key) : keys);
1024
- }
1025
- });
1026
- });
1027
- if (arg2 && typeof arg2 == "number")
1028
- setTimeout(() => timeout(`${arg2}ms`), arg2);
1029
- });
1030
- }
1031
-
1032
- const Oops$5 = issues({
1033
- NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
1034
- });
1035
- class Model {
1036
- constructor() {
1037
- new Control(this);
1038
- defineProperty(this, "is", { value: this });
1039
- }
1040
- on(arg1, arg2, arg3) {
1041
- if (typeof arg1 == "function")
1042
- return createEffect(this.is, arg1, arg2);
1043
- if (typeof arg2 != "function")
1044
- return awaitUpdate(this.is, arg1, arg2);
1045
- if (arg1)
1046
- return addEventListener(this.is, arg1, arg2, arg3);
1047
- }
1048
- get(arg1, arg2) {
1049
- const { state } = Control.for(this);
1050
- const extract = typeof arg1 == "string"
1051
- ? () => state.get(arg1)
1052
- : () => {
1053
- const output = {};
1054
- for (const key of arg1 || state.keys())
1055
- output[key] = state.get(key);
1056
- return output;
1057
- };
1058
- if (!arg1 || arg2 === undefined)
1059
- return extract();
1060
- if (typeof arg2 == "function")
1061
- return this.on(arg1, () => arg2(extract()));
1062
- const timeout = typeof arg2 == "number" ? arg2 : undefined;
1063
- return this.on(arg1, timeout).then(extract);
1064
- }
1065
- set(arg1, arg2) {
1066
- const control = Control.for(this);
1067
- if (typeof arg1 == "object")
1068
- for (const key in arg1) {
1069
- if (arg2 === true || (arg2 ? arg2.includes(key) : control.state.has(key))) {
1070
- control.state.set(key, arg1[key]);
1071
- control.update(key);
1072
- }
1073
- }
1074
- else if (typeof arg1 == "string") {
1075
- control.update(arg1);
1076
- if (1 in arguments) {
1077
- if (control.state.has(arg1))
1078
- control.state.set(arg1, arg2);
1079
- else if (arg1 in this) {
1080
- const method = this[arg1];
1081
- if (typeof method == "function")
1082
- method.call(this, arg2);
1083
- }
1084
- }
1085
- }
1086
- return {
1087
- then: (callback) => {
1088
- if (!callback)
1089
- throw Oops$5.NoChaining();
1090
- control.waiting.add(callback);
1091
- }
1092
- };
1093
- }
1094
- /**
1095
- * Clean up side effects and mark this instance for garbage-collection.
1096
- */
1097
- end() {
1098
- Control.for(this).clear();
1099
- }
1100
- /**
1101
- * Creates a new instance of this controller.
1102
- *
1103
- * Beyond `new this(...)`, method will activate managed-state.
1104
- *
1105
- * @param args - arguments sent to constructor
1106
- */
1107
- static new(...args) {
1108
- const instance = new this(...args);
1109
- Control.for(instance);
1110
- return instance;
1111
- }
1112
- /**
1113
- * Static equivalent of `x instanceof this`.
1114
- *
1115
- * Will determine if provided class is a subtype of this one.
1116
- */
1117
- static isTypeof(maybe) {
1118
- return (typeof maybe == "function" &&
1119
- maybe.prototype instanceof this);
1120
- }
1121
- }
1122
- defineProperty(Model.prototype, "toString", {
1123
- value() {
1124
- return this.constructor.name;
1125
- }
1126
- });
1127
-
1128
1160
  const Oops$4 = issues({
1129
1161
  NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
1130
1162
  });
@@ -1146,7 +1178,19 @@ class Lookup {
1146
1178
  get(T) {
1147
1179
  return this[this.key(T)];
1148
1180
  }
1149
- add(T, I, writable) {
1181
+ add(input) {
1182
+ let writable = true;
1183
+ let T;
1184
+ let I;
1185
+ if (typeof input == "function") {
1186
+ T = input;
1187
+ I = input.new();
1188
+ }
1189
+ else {
1190
+ I = input;
1191
+ T = I.constructor;
1192
+ writable = false;
1193
+ }
1150
1194
  do {
1151
1195
  const key = this.key(T);
1152
1196
  const conflict = this.hasOwnProperty(key);
@@ -1157,6 +1201,10 @@ class Lookup {
1157
1201
  });
1158
1202
  T = getPrototypeOf(T);
1159
1203
  } while (T !== Model);
1204
+ Control.for(I).state.forEach(value => {
1205
+ if (value instanceof Model)
1206
+ this.add(value);
1207
+ });
1160
1208
  }
1161
1209
  push() {
1162
1210
  return create(this);
@@ -1246,9 +1294,9 @@ function use(init) {
1246
1294
  function useNew(source, arg1, arg2) {
1247
1295
  const instance = React.useMemo(() => {
1248
1296
  const callback = arg2 || arg1;
1249
- const instance = Model.isTypeof(source) ?
1250
- source.new() :
1251
- source();
1297
+ const instance = Model.isTypeof(source)
1298
+ ? new source()
1299
+ : source();
1252
1300
  Control.for(instance);
1253
1301
  if (typeof callback == "function")
1254
1302
  callback(instance);
@@ -1324,9 +1372,11 @@ function useValue(source, compute, suspend) {
1324
1372
  }
1325
1373
  defineProperty(sub, "proxy", {
1326
1374
  get() {
1327
- if (value === undefined && suspend)
1375
+ if (value !== undefined)
1376
+ return value;
1377
+ if (suspend)
1328
1378
  throw new Promise(res => retry = res);
1329
- return value;
1379
+ return null;
1330
1380
  }
1331
1381
  });
1332
1382
  return sub;
@@ -1454,28 +1504,22 @@ function useNewContext(include, assign) {
1454
1504
  if (!include)
1455
1505
  throw Oops.NoType();
1456
1506
  const next = ambient.push();
1457
- function register(I) {
1458
- if (I instanceof Model)
1459
- next.add(I.constructor, I, false);
1460
- else
1461
- next.add(I, I.new(), true);
1462
- }
1463
1507
  if (include instanceof Model || typeof include == "function")
1464
- register(include);
1508
+ next.add(include);
1465
1509
  else
1466
- values(include).forEach(register);
1510
+ values(include).forEach(x => next.add(x));
1467
1511
  for (const instance of next.local)
1468
- if (instance)
1512
+ if (instance) {
1513
+ if (assign)
1514
+ assignWeak(instance, assign);
1469
1515
  for (const apply of getPending(instance))
1470
1516
  apply(next);
1517
+ }
1471
1518
  return next;
1472
1519
  }, []);
1473
- if (assign) {
1474
- for (const key in assign)
1475
- for (const into of context.local)
1476
- if (into && key in into)
1477
- into[key] = assign[key];
1478
- }
1520
+ if (assign)
1521
+ for (const into of context.local)
1522
+ assignWeak(into, assign);
1479
1523
  return context;
1480
1524
  }
1481
1525
  function RenderFunction(props) {
@@ -1488,6 +1532,11 @@ function RenderFunction(props) {
1488
1532
  if (hook.commit)
1489
1533
  React.useLayoutEffect(hook.commit, []);
1490
1534
  return props.render(hook.proxy);
1535
+ }
1536
+ function assignWeak(into, from) {
1537
+ for (const K in from)
1538
+ if (K in into)
1539
+ into[K] = from[K];
1491
1540
  }
1492
1541
 
1493
1542
  class Global extends MVC {