@expressive/mvc 0.10.1 → 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.js CHANGED
@@ -30,11 +30,11 @@ function issues(register) {
30
30
  return Library;
31
31
  }
32
32
 
33
- const Oops$e = issues({
33
+ const Oops$f = issues({
34
34
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
35
35
  });
36
36
  function suspend(source, key) {
37
- const error = Oops$e.NotReady(source.subject, key);
37
+ const error = Oops$f.NotReady(source.subject, key);
38
38
  const promise = new Promise(resolve => {
39
39
  const release = source.addListener(forKey => {
40
40
  if (forKey == key)
@@ -74,7 +74,7 @@ function mayRetry(fn) {
74
74
  return compute();
75
75
  }
76
76
 
77
- const Oops$d = issues({
77
+ const Oops$e = issues({
78
78
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
79
79
  });
80
80
  const INFO = new WeakMap();
@@ -94,7 +94,7 @@ function computeMode(self, source, setter, key, required) {
94
94
  return setter.call(sub.proxy, sub.proxy);
95
95
  }
96
96
  catch (err) {
97
- Oops$d.Failed(subject, key, initial).warn();
97
+ Oops$e.Failed(subject, key, initial).warn();
98
98
  throw err;
99
99
  }
100
100
  };
@@ -165,6 +165,152 @@ function flush(control) {
165
165
  pending.clear();
166
166
  }
167
167
 
168
+ const Oops$d = issues({
169
+ BadCallback: () => `Callback for effect-callback may only return a function.`
170
+ });
171
+ function createEffect(model, callback, keys) {
172
+ return Control.for(model, control => {
173
+ let unSet;
174
+ let busy = false;
175
+ function effect(value) {
176
+ if (typeof unSet == "function")
177
+ unSet();
178
+ unSet = callback.call(this, value);
179
+ if (unSet instanceof Promise)
180
+ unSet = undefined;
181
+ if (unSet && typeof unSet !== "function")
182
+ throw Oops$d.BadCallback();
183
+ }
184
+ function invoke() {
185
+ if (busy)
186
+ return;
187
+ const output = mayRetry(() => {
188
+ effect.call(model, model);
189
+ });
190
+ if (output instanceof Promise) {
191
+ output.finally(() => busy = false);
192
+ busy = true;
193
+ }
194
+ }
195
+ if (Array.isArray(keys)) {
196
+ invoke();
197
+ return control.addListener(key => {
198
+ if (key === null) {
199
+ if (!keys.length)
200
+ invoke();
201
+ }
202
+ else if (keys.includes(key))
203
+ return invoke;
204
+ });
205
+ }
206
+ const sub = control.subscribe(() => invoke);
207
+ model = sub.proxy;
208
+ invoke();
209
+ return sub.commit();
210
+ });
211
+ }
212
+ function createValueEffect(callback) {
213
+ let unSet;
214
+ return function (value) {
215
+ if (typeof unSet == "function")
216
+ unSet(value);
217
+ const out = callback.call(this, value, this);
218
+ if (typeof out == "boolean")
219
+ return out;
220
+ if (!out || out instanceof Promise)
221
+ return;
222
+ if (typeof out == "function")
223
+ unSet = out;
224
+ else
225
+ throw Oops$d.BadCallback();
226
+ };
227
+ }
228
+
229
+ const Oops$c = issues({
230
+ Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
231
+ KeysExpected: (key) => `Key "${key}" was expected in current update.`,
232
+ StrictUpdate: () => `Expected update but none in progress.`,
233
+ StrictNoUpdate: () => `Update is not expected but one is in progress!`
234
+ });
235
+ function addEventListener(source, arg1, arg2, arg3) {
236
+ if (typeof arg1 == "string")
237
+ arg1 = [arg1];
238
+ return Control.for(source, control => {
239
+ for (const key of arg1)
240
+ try {
241
+ void source[key];
242
+ }
243
+ catch (e) { }
244
+ const removeListener = control.addListener(key => {
245
+ if (!key && !arg1.length)
246
+ arg2.call(source, []);
247
+ if (arg1.includes(key)) {
248
+ if (arg3)
249
+ removeListener();
250
+ return arg2.bind(source);
251
+ }
252
+ });
253
+ return removeListener;
254
+ });
255
+ }
256
+ function awaitUpdate(source, arg1, arg2) {
257
+ const single = typeof arg1 == "string";
258
+ const keys = typeof arg1 == "string" ? [arg1] :
259
+ typeof arg1 == "object" ? arg1 :
260
+ undefined;
261
+ return new Promise((resolve, reject) => {
262
+ const timeout = (message) => {
263
+ const k = keys ? keys.join(", ") : "any";
264
+ removeListener();
265
+ reject(Oops$c.Timeout(k, message));
266
+ };
267
+ const removeListener = Control.for(source, control => {
268
+ const pending = control.frame;
269
+ if (keys === null) {
270
+ if (pending.size)
271
+ reject(Oops$c.StrictNoUpdate());
272
+ else
273
+ resolve(null);
274
+ return;
275
+ }
276
+ if (keys) {
277
+ if (keys.length) {
278
+ if (arg2 === 0 && single && !pending.has(keys[0])) {
279
+ reject(Oops$c.KeysExpected(keys[0]));
280
+ return;
281
+ }
282
+ else
283
+ for (const key of keys)
284
+ try {
285
+ void source[key];
286
+ }
287
+ catch (e) { }
288
+ }
289
+ }
290
+ else if (!pending.size && arg1 === true || arg2 === 0) {
291
+ reject(Oops$c.StrictUpdate());
292
+ return;
293
+ }
294
+ else
295
+ control.waiting.add(resolve);
296
+ return control.addListener(key => {
297
+ if (!key) {
298
+ if (keys && !keys.length)
299
+ resolve([]);
300
+ else
301
+ timeout(`lifetime of ${source}`);
302
+ }
303
+ else if (!keys || keys.includes(key)) {
304
+ removeListener();
305
+ return keys => resolve(single ? control.state.get(key) : keys);
306
+ }
307
+ });
308
+ });
309
+ if (arg2 && typeof arg2 == "number")
310
+ setTimeout(() => timeout(`${arg2}ms`), arg2);
311
+ });
312
+ }
313
+
168
314
  const REGISTER$1 = new WeakMap();
169
315
  class Subscriber {
170
316
  constructor(parent, onUpdate) {
@@ -237,6 +383,102 @@ class Subscriber {
237
383
  }
238
384
  }
239
385
 
386
+ const Oops$b = issues({
387
+ NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
388
+ });
389
+ class Model {
390
+ constructor() {
391
+ new Control(this);
392
+ defineProperty(this, "is", { value: this });
393
+ }
394
+ on(arg1, arg2, arg3) {
395
+ if (typeof arg1 == "function")
396
+ return createEffect(this.is, arg1, arg2);
397
+ if (typeof arg2 != "function")
398
+ return awaitUpdate(this.is, arg1, arg2);
399
+ if (arg1)
400
+ return addEventListener(this.is, arg1, arg2, arg3);
401
+ }
402
+ get(arg1, arg2) {
403
+ const { state } = Control.for(this);
404
+ const extract = typeof arg1 == "string"
405
+ ? () => state.get(arg1)
406
+ : () => {
407
+ const output = {};
408
+ for (const key of arg1 || state.keys())
409
+ output[key] = state.get(key);
410
+ return output;
411
+ };
412
+ if (!arg1 || arg2 === undefined)
413
+ return extract();
414
+ if (typeof arg2 == "function")
415
+ return this.on(arg1, () => arg2(extract()));
416
+ const timeout = typeof arg2 == "number" ? arg2 : undefined;
417
+ return this.on(arg1, timeout).then(extract);
418
+ }
419
+ set(arg1, arg2) {
420
+ const control = Control.for(this);
421
+ if (typeof arg1 == "object")
422
+ for (const key in arg1) {
423
+ if (arg2 === true || (arg2 ? arg2.includes(key) : control.state.has(key))) {
424
+ control.state.set(key, arg1[key]);
425
+ control.update(key);
426
+ }
427
+ }
428
+ else if (typeof arg1 == "string") {
429
+ control.update(arg1);
430
+ if (1 in arguments) {
431
+ if (control.state.has(arg1))
432
+ control.state.set(arg1, arg2);
433
+ else if (arg1 in this) {
434
+ const method = this[arg1];
435
+ if (typeof method == "function")
436
+ method.call(this, arg2);
437
+ }
438
+ }
439
+ }
440
+ return {
441
+ then: (callback) => {
442
+ if (!callback)
443
+ throw Oops$b.NoChaining();
444
+ control.waiting.add(callback);
445
+ }
446
+ };
447
+ }
448
+ /**
449
+ * Clean up side effects and mark this instance for garbage-collection.
450
+ */
451
+ end() {
452
+ Control.for(this).clear();
453
+ }
454
+ /**
455
+ * Creates a new instance of this controller.
456
+ *
457
+ * Beyond `new this(...)`, method will activate managed-state.
458
+ *
459
+ * @param args - arguments sent to constructor
460
+ */
461
+ static new(...args) {
462
+ const instance = new this(...args);
463
+ Control.for(instance);
464
+ return instance;
465
+ }
466
+ /**
467
+ * Static equivalent of `x instanceof this`.
468
+ *
469
+ * Will determine if provided class is a subtype of this one.
470
+ */
471
+ static isTypeof(maybe) {
472
+ return (typeof maybe == "function" &&
473
+ maybe.prototype instanceof this);
474
+ }
475
+ }
476
+ defineProperty(Model.prototype, "toString", {
477
+ value() {
478
+ return this.constructor.name;
479
+ }
480
+ });
481
+
240
482
  const REGISTER = new WeakMap();
241
483
  const PENDING = new Map();
242
484
  class Control {
@@ -265,6 +507,10 @@ class Control {
265
507
  return;
266
508
  }
267
509
  state.set(key, value);
510
+ if (value instanceof Model) {
511
+ setRecursive(this, key, value);
512
+ return;
513
+ }
268
514
  defineProperty(subject, key, {
269
515
  enumerable: false,
270
516
  set: this.ref(key),
@@ -359,6 +605,68 @@ class Control {
359
605
  }
360
606
  }
361
607
 
608
+ const Parent = new WeakMap();
609
+ const Oops$a = issues({
610
+ BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
611
+ });
612
+ function getRecursive(key, from) {
613
+ const context = new WeakMap();
614
+ const { state } = from;
615
+ return (local) => {
616
+ if (!local)
617
+ return state.get(key);
618
+ if (!context.has(local)) {
619
+ let reset;
620
+ const init = () => {
621
+ if (reset)
622
+ reset();
623
+ const value = state.get(key);
624
+ if (Control.get(value)) {
625
+ const child = Control.for(value).subscribe(local.onUpdate);
626
+ if (local.active)
627
+ child.commit();
628
+ local.dependant.add(child);
629
+ context.set(local, child.proxy);
630
+ reset = () => {
631
+ child.release();
632
+ local.dependant.delete(child);
633
+ context.set(local, undefined);
634
+ reset = undefined;
635
+ };
636
+ }
637
+ return true;
638
+ };
639
+ local.add(key, init);
640
+ init();
641
+ }
642
+ return context.get(local);
643
+ };
644
+ }
645
+ function setRecursive(control, key, initial) {
646
+ const { state, subject } = control;
647
+ const Type = initial.constructor;
648
+ let get;
649
+ const onUpdate = (next) => {
650
+ state.set(key, next);
651
+ if (!(next instanceof Type))
652
+ throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
653
+ get = getRecursive(key, control);
654
+ Parent.set(next, subject);
655
+ Control.for(next);
656
+ return true;
657
+ };
658
+ onUpdate(initial);
659
+ defineProperty(subject, key, {
660
+ set: control.ref(key, onUpdate),
661
+ get() {
662
+ const local = Subscriber.get(this);
663
+ if (local)
664
+ local.add(key);
665
+ return get(local);
666
+ }
667
+ });
668
+ }
669
+
362
670
  /**
363
671
  * Run instruction as controller sets itself up.
364
672
  * This will specialize the behavior of a given property.
@@ -393,9 +701,9 @@ function add(instruction, label) {
393
701
  const control = this;
394
702
  defineProperty(subject, key, {
395
703
  enumerable: output.enumerable,
396
- set: onSet !== false
397
- ? this.ref(key, onSet)
398
- : undefined,
704
+ set: onSet === false
705
+ ? undefined
706
+ : this.ref(key, onSet),
399
707
  get() {
400
708
  if (!state.has(key) && shouldSuspend)
401
709
  throw suspend(control, key);
@@ -409,39 +717,7 @@ function add(instruction, label) {
409
717
  });
410
718
  }
411
719
  PENDING.set(placeholder, setup);
412
- return placeholder;
413
- }
414
- function getRecursive(key, from) {
415
- const context = new WeakMap();
416
- return (local) => {
417
- if (!local)
418
- return from.state.get(key);
419
- if (!context.has(local)) {
420
- let reset;
421
- const init = () => {
422
- if (reset)
423
- reset();
424
- const value = from.state.get(key);
425
- if (Control.get(value)) {
426
- const child = Control.for(value).subscribe(local.onUpdate);
427
- if (local.active)
428
- child.commit();
429
- local.dependant.add(child);
430
- context.set(local, child.proxy);
431
- reset = () => {
432
- child.release();
433
- local.dependant.delete(child);
434
- context.set(local, undefined);
435
- reset = undefined;
436
- };
437
- }
438
- return true;
439
- };
440
- local.add(key, init);
441
- init();
442
- }
443
- return context.get(local);
444
- };
720
+ return placeholder;
445
721
  }
446
722
 
447
723
  /*! *****************************************************************************
@@ -469,7 +745,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
469
745
  });
470
746
  }
471
747
 
472
- const Oops$c = issues({
748
+ const Oops$9 = issues({
473
749
  DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
474
750
  });
475
751
  function run(task) {
@@ -477,7 +753,7 @@ function run(task) {
477
753
  let pending = false;
478
754
  const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
479
755
  if (pending)
480
- return Promise.reject(Oops$c.DuplicatePending(key));
756
+ return Promise.reject(Oops$9.DuplicatePending(key));
481
757
  pending = true;
482
758
  this.update(key);
483
759
  try {
@@ -499,7 +775,7 @@ function run(task) {
499
775
  });
500
776
  }
501
777
 
502
- const Oops$b = issues({
778
+ const Oops$8 = issues({
503
779
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
504
780
  });
505
781
  function factoryMode(self, output, key, required) {
@@ -523,7 +799,7 @@ function factoryMode(self, output, key, required) {
523
799
  const suspend = () => {
524
800
  if (required === false)
525
801
  return undefined;
526
- const issue = Oops$b.NotReady(subject, key);
802
+ const issue = Oops$8.NotReady(subject, key);
527
803
  assign(pending, {
528
804
  message: issue.message,
529
805
  stack: issue.stack
@@ -540,7 +816,7 @@ function factoryMode(self, output, key, required) {
540
816
  };
541
817
  }
542
818
 
543
- const Oops$a = issues({
819
+ const Oops$7 = issues({
544
820
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
545
821
  ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
546
822
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
@@ -553,7 +829,7 @@ function get(arg0, arg1, arg2) {
553
829
  let getter;
554
830
  // Easy mistake, using a peer, will always be unresolved.
555
831
  if (typeof arg0 == "symbol")
556
- throw Oops$a.PeerNotAllowed(subject, key);
832
+ throw Oops$7.PeerNotAllowed(subject, key);
557
833
  // if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
558
834
  // throw Oops.BadSource(subject, key, arg0);
559
835
  this.state.set(key, undefined);
@@ -587,7 +863,7 @@ function get(arg0, arg1, arg2) {
587
863
  init();
588
864
  }
589
865
  catch (err) {
590
- Oops$a.ComputeFailed(subject, key).warn();
866
+ Oops$7.ComputeFailed(subject, key).warn();
591
867
  throw err;
592
868
  }
593
869
  return () => {
@@ -598,67 +874,6 @@ function get(arg0, arg1, arg2) {
598
874
  });
599
875
  }
600
876
 
601
- const Oops$9 = issues({
602
- BadCallback: () => `Callback for effect-callback may only return a function.`
603
- });
604
- function createEffect(model, callback, keys) {
605
- return Control.for(model, control => {
606
- let unSet;
607
- let busy = false;
608
- function effect(value) {
609
- if (typeof unSet == "function")
610
- unSet();
611
- unSet = callback.call(this, value);
612
- if (unSet instanceof Promise)
613
- unSet = undefined;
614
- if (unSet && typeof unSet !== "function")
615
- throw Oops$9.BadCallback();
616
- }
617
- function invoke() {
618
- if (busy)
619
- return;
620
- const output = mayRetry(() => {
621
- effect.call(model, model);
622
- });
623
- if (output instanceof Promise) {
624
- output.finally(() => busy = false);
625
- busy = true;
626
- }
627
- }
628
- if (Array.isArray(keys)) {
629
- invoke();
630
- return control.addListener(key => {
631
- if (key === null) {
632
- if (!keys.length)
633
- invoke();
634
- }
635
- else if (keys.includes(key))
636
- return invoke;
637
- });
638
- }
639
- const sub = control.subscribe(() => invoke);
640
- model = sub.proxy;
641
- invoke();
642
- return sub.commit();
643
- });
644
- }
645
- function createValueEffect(callback) {
646
- let unSet;
647
- return function (value) {
648
- if (typeof unSet == "function")
649
- unSet(value);
650
- const out = callback.call(this, value, this);
651
- if (typeof out == "boolean")
652
- return out;
653
- if (!out || out instanceof Promise)
654
- return;
655
- if (typeof out == "function")
656
- unSet = out;
657
- else
658
- throw Oops$9.BadCallback();
659
- };
660
- }
661
-
662
877
  function ref(arg, mapper) {
663
878
  return add(function ref(key) {
664
879
  let value = {};
@@ -853,8 +1068,7 @@ function createProxy(emit, watch) {
853
1068
  };
854
1069
  }
855
1070
 
856
- const Parent = new WeakMap();
857
- const Oops$8 = issues({
1071
+ const Oops$6 = issues({
858
1072
  BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
859
1073
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
860
1074
  });
@@ -866,12 +1080,11 @@ function use$1(input, argument) {
866
1080
  let error;
867
1081
  let get = (_local) => state.get(key);
868
1082
  if (typeof input === "function") {
869
- if ("prototype" in input &&
870
- input === input.prototype.constructor)
1083
+ if ("prototype" in input && input === input.prototype.constructor)
871
1084
  input = new input();
872
1085
  }
873
1086
  else if (input && typeof input !== "object")
874
- throw Oops$8.BadArgument(typeof input);
1087
+ throw Oops$6.BadArgument(typeof input);
875
1088
  if (input instanceof Map || input instanceof Set)
876
1089
  return keyed(this, key, input);
877
1090
  const onUpdate = (next) => {
@@ -888,7 +1101,7 @@ function use$1(input, argument) {
888
1101
  const suspend = () => {
889
1102
  if (required === false)
890
1103
  return;
891
- const issue = Oops$8.NotReady(subject, key);
1104
+ const issue = Oops$6.NotReady(subject, key);
892
1105
  assign(pending, {
893
1106
  message: issue.message,
894
1107
  stack: issue.stack
@@ -933,7 +1146,7 @@ function use$1(input, argument) {
933
1146
  });
934
1147
  }
935
1148
 
936
- const Oops$7 = issues({
1149
+ const Oops$5 = issues({
937
1150
  Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
938
1151
  Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
939
1152
  });
@@ -944,195 +1157,14 @@ function has(Type, required) {
944
1157
  const expected = Type.name;
945
1158
  if (!value) {
946
1159
  if (required !== false)
947
- throw Oops$7.Required(expected, child);
1160
+ throw Oops$5.Required(expected, child);
948
1161
  }
949
1162
  else if (!(value instanceof Type))
950
- throw Oops$7.Unexpected(expected, child, value);
1163
+ throw Oops$5.Unexpected(expected, child, value);
951
1164
  return { value };
952
1165
  });
953
1166
  }
954
1167
 
955
- const Oops$6 = issues({
956
- Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
957
- KeysExpected: (key) => `Key "${key}" was expected in current update.`,
958
- StrictUpdate: () => `Expected update but none in progress.`,
959
- StrictNoUpdate: () => `Update is not expected but one is in progress!`
960
- });
961
- function addEventListener(source, arg1, arg2, arg3) {
962
- if (typeof arg1 == "string")
963
- arg1 = [arg1];
964
- return Control.for(source, control => {
965
- for (const key of arg1)
966
- try {
967
- void source[key];
968
- }
969
- catch (e) { }
970
- const removeListener = control.addListener(key => {
971
- if (!key && !arg1.length)
972
- arg2.call(source, []);
973
- if (arg1.includes(key)) {
974
- if (arg3)
975
- removeListener();
976
- return arg2.bind(source);
977
- }
978
- });
979
- return removeListener;
980
- });
981
- }
982
- function awaitUpdate(source, arg1, arg2) {
983
- const single = typeof arg1 == "string";
984
- const keys = typeof arg1 == "string" ? [arg1] :
985
- typeof arg1 == "object" ? arg1 :
986
- undefined;
987
- return new Promise((resolve, reject) => {
988
- const timeout = (message) => {
989
- const k = keys ? keys.join(", ") : "any";
990
- removeListener();
991
- reject(Oops$6.Timeout(k, message));
992
- };
993
- const removeListener = Control.for(source, control => {
994
- const pending = control.frame;
995
- if (keys === null) {
996
- if (pending.size)
997
- reject(Oops$6.StrictNoUpdate());
998
- else
999
- resolve(null);
1000
- return;
1001
- }
1002
- if (keys) {
1003
- if (keys.length) {
1004
- if (arg2 === 0 && single && !pending.has(keys[0])) {
1005
- reject(Oops$6.KeysExpected(keys[0]));
1006
- return;
1007
- }
1008
- else
1009
- for (const key of keys)
1010
- try {
1011
- void source[key];
1012
- }
1013
- catch (e) { }
1014
- }
1015
- }
1016
- else if (!pending.size && arg1 === true || arg2 === 0) {
1017
- reject(Oops$6.StrictUpdate());
1018
- return;
1019
- }
1020
- else
1021
- control.waiting.add(resolve);
1022
- return control.addListener(key => {
1023
- if (!key) {
1024
- if (keys && !keys.length)
1025
- resolve([]);
1026
- else
1027
- timeout(`lifetime of ${source}`);
1028
- }
1029
- else if (!keys || keys.includes(key)) {
1030
- removeListener();
1031
- return keys => resolve(single ? control.state.get(key) : keys);
1032
- }
1033
- });
1034
- });
1035
- if (arg2 && typeof arg2 == "number")
1036
- setTimeout(() => timeout(`${arg2}ms`), arg2);
1037
- });
1038
- }
1039
-
1040
- const Oops$5 = issues({
1041
- NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
1042
- });
1043
- class Model {
1044
- constructor() {
1045
- new Control(this);
1046
- defineProperty(this, "is", { value: this });
1047
- }
1048
- on(arg1, arg2, arg3) {
1049
- if (typeof arg1 == "function")
1050
- return createEffect(this.is, arg1, arg2);
1051
- if (typeof arg2 != "function")
1052
- return awaitUpdate(this.is, arg1, arg2);
1053
- if (arg1)
1054
- return addEventListener(this.is, arg1, arg2, arg3);
1055
- }
1056
- get(arg1, arg2) {
1057
- const { state } = Control.for(this);
1058
- const extract = typeof arg1 == "string"
1059
- ? () => state.get(arg1)
1060
- : () => {
1061
- const output = {};
1062
- for (const key of arg1 || state.keys())
1063
- output[key] = state.get(key);
1064
- return output;
1065
- };
1066
- if (!arg1 || arg2 === undefined)
1067
- return extract();
1068
- if (typeof arg2 == "function")
1069
- return this.on(arg1, () => arg2(extract()));
1070
- const timeout = typeof arg2 == "number" ? arg2 : undefined;
1071
- return this.on(arg1, timeout).then(extract);
1072
- }
1073
- set(arg1, arg2) {
1074
- const control = Control.for(this);
1075
- if (typeof arg1 == "object")
1076
- for (const key in arg1) {
1077
- if (arg2 === true || (arg2 ? arg2.includes(key) : control.state.has(key))) {
1078
- control.state.set(key, arg1[key]);
1079
- control.update(key);
1080
- }
1081
- }
1082
- else if (typeof arg1 == "string") {
1083
- control.update(arg1);
1084
- if (1 in arguments) {
1085
- if (control.state.has(arg1))
1086
- control.state.set(arg1, arg2);
1087
- else if (arg1 in this) {
1088
- const method = this[arg1];
1089
- if (typeof method == "function")
1090
- method.call(this, arg2);
1091
- }
1092
- }
1093
- }
1094
- return {
1095
- then: (callback) => {
1096
- if (!callback)
1097
- throw Oops$5.NoChaining();
1098
- control.waiting.add(callback);
1099
- }
1100
- };
1101
- }
1102
- /**
1103
- * Clean up side effects and mark this instance for garbage-collection.
1104
- */
1105
- end() {
1106
- Control.for(this).clear();
1107
- }
1108
- /**
1109
- * Creates a new instance of this controller.
1110
- *
1111
- * Beyond `new this(...)`, method will activate managed-state.
1112
- *
1113
- * @param args - arguments sent to constructor
1114
- */
1115
- static new(...args) {
1116
- const instance = new this(...args);
1117
- Control.for(instance);
1118
- return instance;
1119
- }
1120
- /**
1121
- * Static equivalent of `x instanceof this`.
1122
- *
1123
- * Will determine if provided class is a subtype of this one.
1124
- */
1125
- static isTypeof(maybe) {
1126
- return (typeof maybe == "function" &&
1127
- maybe.prototype instanceof this);
1128
- }
1129
- }
1130
- defineProperty(Model.prototype, "toString", {
1131
- value() {
1132
- return this.constructor.name;
1133
- }
1134
- });
1135
-
1136
1168
  const Oops$4 = issues({
1137
1169
  NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
1138
1170
  });
@@ -1154,7 +1186,19 @@ class Lookup {
1154
1186
  get(T) {
1155
1187
  return this[this.key(T)];
1156
1188
  }
1157
- add(T, I, writable) {
1189
+ add(input) {
1190
+ let writable = true;
1191
+ let T;
1192
+ let I;
1193
+ if (typeof input == "function") {
1194
+ T = input;
1195
+ I = input.new();
1196
+ }
1197
+ else {
1198
+ I = input;
1199
+ T = I.constructor;
1200
+ writable = false;
1201
+ }
1158
1202
  do {
1159
1203
  const key = this.key(T);
1160
1204
  const conflict = this.hasOwnProperty(key);
@@ -1165,6 +1209,10 @@ class Lookup {
1165
1209
  });
1166
1210
  T = getPrototypeOf(T);
1167
1211
  } while (T !== Model);
1212
+ Control.for(I).state.forEach(value => {
1213
+ if (value instanceof Model)
1214
+ this.add(value);
1215
+ });
1168
1216
  }
1169
1217
  push() {
1170
1218
  return create(this);
@@ -1254,9 +1302,9 @@ function use(init) {
1254
1302
  function useNew(source, arg1, arg2) {
1255
1303
  const instance = React__default["default"].useMemo(() => {
1256
1304
  const callback = arg2 || arg1;
1257
- const instance = Model.isTypeof(source) ?
1258
- source.new() :
1259
- source();
1305
+ const instance = Model.isTypeof(source)
1306
+ ? new source()
1307
+ : source();
1260
1308
  Control.for(instance);
1261
1309
  if (typeof callback == "function")
1262
1310
  callback(instance);
@@ -1464,28 +1512,22 @@ function useNewContext(include, assign) {
1464
1512
  if (!include)
1465
1513
  throw Oops.NoType();
1466
1514
  const next = ambient.push();
1467
- function register(I) {
1468
- if (I instanceof Model)
1469
- next.add(I.constructor, I, false);
1470
- else
1471
- next.add(I, I.new(), true);
1472
- }
1473
1515
  if (include instanceof Model || typeof include == "function")
1474
- register(include);
1516
+ next.add(include);
1475
1517
  else
1476
- values(include).forEach(register);
1518
+ values(include).forEach(x => next.add(x));
1477
1519
  for (const instance of next.local)
1478
- if (instance)
1520
+ if (instance) {
1521
+ if (assign)
1522
+ assignWeak(instance, assign);
1479
1523
  for (const apply of getPending(instance))
1480
1524
  apply(next);
1525
+ }
1481
1526
  return next;
1482
1527
  }, []);
1483
- if (assign) {
1484
- for (const key in assign)
1485
- for (const into of context.local)
1486
- if (into && key in into)
1487
- into[key] = assign[key];
1488
- }
1528
+ if (assign)
1529
+ for (const into of context.local)
1530
+ assignWeak(into, assign);
1489
1531
  return context;
1490
1532
  }
1491
1533
  function RenderFunction(props) {
@@ -1498,6 +1540,11 @@ function RenderFunction(props) {
1498
1540
  if (hook.commit)
1499
1541
  React__default["default"].useLayoutEffect(hook.commit, []);
1500
1542
  return props.render(hook.proxy);
1543
+ }
1544
+ function assignWeak(into, from) {
1545
+ for (const K in from)
1546
+ if (K in into)
1547
+ into[K] = from[K];
1501
1548
  }
1502
1549
 
1503
1550
  class Global extends MVC {