@expressive/mvc 0.16.0 → 0.17.1

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
@@ -8,6 +8,23 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
8
8
 
9
9
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
10
10
 
11
+ class Issue extends Error {
12
+ constructor() {
13
+ super(...arguments);
14
+ // drop first line (error factory) in stack trace.
15
+ this.stack = this.stack.replace(/\n.+/, "");
16
+ }
17
+ warn() {
18
+ console.warn(this.message);
19
+ }
20
+ }
21
+ function issues(register) {
22
+ const Library = {};
23
+ for (const name in register)
24
+ Library[name] = (...args) => new Issue(register[name].apply(null, args));
25
+ return Library;
26
+ }
27
+
11
28
  const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
12
29
  const UID_CACHE = new WeakMap();
13
30
  function assignWeak(into, from) {
@@ -22,28 +39,82 @@ function uid(object) {
22
39
  return uid;
23
40
  }
24
41
 
25
- class Issue extends Error {
26
- constructor() {
27
- super(...arguments);
28
- // drop first line (error factory) in stack trace.
29
- this.stack = this.stack.replace(/\n.+/, "");
42
+ const REGISTER$1 = new WeakMap();
43
+ class Subscriber {
44
+ constructor(parent, onUpdate, strict) {
45
+ this.parent = parent;
46
+ this.onUpdate = onUpdate;
47
+ this.strict = strict;
48
+ this.active = false;
49
+ this.dependant = new Set();
50
+ this.watch = new Map();
51
+ const proxy = create(parent.subject);
52
+ const reset = () => this.latest = undefined;
53
+ REGISTER$1.set(proxy, this);
54
+ defineProperty(this, "proxy", {
55
+ configurable: true,
56
+ get() {
57
+ setTimeout(reset, 0);
58
+ return proxy;
59
+ }
60
+ });
61
+ this.clear = parent.addListener(key => {
62
+ if (this.active)
63
+ this.notify(key);
64
+ });
30
65
  }
31
- warn() {
32
- console.warn(this.message);
66
+ get using() {
67
+ return Array.from(this.watch.keys());
68
+ }
69
+ apply(values, keys) {
70
+ const { waiting, subject } = this.parent;
71
+ this.active = false;
72
+ if (!keys)
73
+ keys = getOwnPropertyNames(subject);
74
+ for (const key of keys)
75
+ if (key in values)
76
+ subject[key] = values[key];
77
+ waiting.add(() => this.active = true);
78
+ }
79
+ follow(key, value) {
80
+ if (value !== undefined)
81
+ this.watch.set(key, value);
82
+ else if (!this.watch.has(key))
83
+ this.watch.set(key, true);
84
+ }
85
+ commit() {
86
+ this.active = true;
87
+ this.dependant.forEach(x => x.commit());
88
+ }
89
+ release() {
90
+ this.clear();
91
+ this.dependant.forEach(x => x.release());
92
+ }
93
+ notify(key) {
94
+ const { parent, watch } = this;
95
+ const handler = watch.get(key);
96
+ if (!handler)
97
+ return;
98
+ if (typeof handler == "function")
99
+ handler();
100
+ const notify = this.onUpdate(key, parent);
101
+ if (notify) {
102
+ parent.waiting.add(update => {
103
+ this.latest = update.filter(k => watch.has(k));
104
+ });
105
+ parent.waiting.add(notify);
106
+ }
33
107
  }
34
108
  }
35
- function issues(register) {
36
- const Library = {};
37
- for (const name in register)
38
- Library[name] = (...args) => new Issue(register[name].apply(null, args));
39
- return Library;
109
+ function subscriber(from) {
110
+ return REGISTER$1.get(from);
40
111
  }
41
112
 
42
- const Oops$f = issues({
113
+ const Oops$c = issues({
43
114
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
44
115
  });
45
116
  function suspend(source, key) {
46
- const error = Oops$f.NotReady(source.subject, key);
117
+ const error = Oops$c.NotReady(source.subject, key);
47
118
  const promise = new Promise(resolve => {
48
119
  const release = source.addListener(forKey => {
49
120
  if (forKey == key)
@@ -83,98 +154,87 @@ function mayRetry(fn) {
83
154
  return compute();
84
155
  }
85
156
 
86
- const Oops$e = issues({
87
- Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
157
+ const Parent = new WeakMap();
158
+ const Oops$b = issues({
159
+ BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`,
160
+ Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
161
+ Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
88
162
  });
89
- const INFO = new WeakMap();
90
- const KEYS = new WeakMap();
91
- const ORDER = new WeakMap();
92
- function computeMode(self, source, setter, key, required) {
93
- const { subject, state } = self;
94
- let sub;
95
- let order = ORDER.get(self);
96
- let pending = KEYS.get(self);
97
- if (!order)
98
- ORDER.set(self, order = new Map());
99
- if (!pending)
100
- KEYS.set(self, pending = new Set());
101
- const compute = (initial) => {
102
- try {
103
- return setter.call(sub.proxy, sub.proxy);
104
- }
105
- catch (err) {
106
- Oops$e.Failed(subject, key, initial).warn();
107
- throw err;
108
- }
163
+ function getParentForGetInstruction(type, relativeTo, required) {
164
+ const item = getParent(type, relativeTo);
165
+ return (_refresh) => {
166
+ if (item)
167
+ return item;
168
+ if (required)
169
+ throw Oops$b.Required(type.name, relativeTo);
109
170
  };
110
- const refresh = () => {
111
- let value;
112
- try {
113
- value = compute(false);
114
- }
115
- catch (e) {
116
- console.error(e);
117
- }
118
- finally {
119
- if (state.get(key) !== value) {
120
- state.set(key, value);
121
- self.update(key);
122
- return value;
123
- }
171
+ }
172
+ function getParent(type, from) {
173
+ const value = Parent.get(from);
174
+ if (value && !(value instanceof type))
175
+ throw Oops$b.Unexpected(type.name, from, value);
176
+ return value;
177
+ }
178
+ function getRecursive(key, from) {
179
+ const context = new WeakMap();
180
+ const { state } = from;
181
+ return (local) => {
182
+ if (!state.has(key))
183
+ throw suspend(from, key);
184
+ if (!local)
185
+ return state.get(key);
186
+ if (!context.has(local)) {
187
+ let reset;
188
+ const init = () => {
189
+ if (reset)
190
+ reset();
191
+ const value = state.get(key);
192
+ if (value && controller(value)) {
193
+ const child = new Subscriber(control(value), local.onUpdate);
194
+ if (local.active)
195
+ child.commit();
196
+ local.dependant.add(child);
197
+ context.set(local, child.proxy);
198
+ reset = () => {
199
+ child.release();
200
+ local.dependant.delete(child);
201
+ context.set(local, undefined);
202
+ reset = undefined;
203
+ };
204
+ }
205
+ };
206
+ local.follow(key, init);
207
+ init();
124
208
  }
209
+ return context.get(local);
125
210
  };
126
- const create = () => {
127
- sub = source.subscribe((_, source) => {
128
- if (source !== self)
129
- refresh();
130
- else
131
- pending.add(refresh);
132
- });
133
- sub.watch.set(key, false);
134
- try {
135
- const value = compute(true);
136
- state.set(key, value);
137
- return value;
138
- }
139
- catch (e) {
140
- throw e;
141
- }
142
- finally {
143
- sub.commit();
144
- order.set(refresh, order.size);
145
- }
211
+ }
212
+ function setRecursive(controller, key, initial) {
213
+ const { state, subject } = controller;
214
+ const Type = initial.constructor;
215
+ let get;
216
+ const onUpdate = (next) => {
217
+ state.set(key, next);
218
+ if (!(next instanceof Type))
219
+ throw Oops$b.BadAssignment(`${subject}.${key}`, Type.name, String(next));
220
+ get = getRecursive(key, controller);
221
+ Parent.set(next, subject);
222
+ control(next);
223
+ return true;
146
224
  };
147
- INFO.set(refresh, key);
148
- return () => {
149
- if (pending.has(refresh)) {
150
- pending.delete(refresh);
151
- refresh();
225
+ onUpdate(initial);
226
+ defineProperty(subject, key, {
227
+ set: controller.ref(key, onUpdate),
228
+ get() {
229
+ const local = subscriber(this);
230
+ if (local)
231
+ local.follow(key);
232
+ return get(local);
152
233
  }
153
- const value = sub ? state.get(key) : create();
154
- if (value === undefined && required)
155
- throw suspend(self, key);
156
- return value;
157
- };
158
- }
159
- function flush(control) {
160
- const pending = KEYS.get(control);
161
- if (!pending || !pending.size)
162
- return;
163
- const priority = ORDER.get(control);
164
- while (pending.size) {
165
- let compute;
166
- for (const item of pending)
167
- if (!compute || priority.get(item) < priority.get(compute))
168
- compute = item;
169
- pending.delete(compute);
170
- const key = INFO.get(compute);
171
- if (!control.frame.has(key))
172
- compute();
173
- }
174
- pending.clear();
234
+ });
175
235
  }
176
236
 
177
- const Oops$d = issues({
237
+ const Oops$a = issues({
178
238
  BadCallback: () => `Callback for effect-callback may only return a function.`
179
239
  });
180
240
  function createEffect(model, callback, keys) {
@@ -188,7 +248,7 @@ function createEffect(model, callback, keys) {
188
248
  if (unSet instanceof Promise)
189
249
  unSet = undefined;
190
250
  if (unSet && typeof unSet !== "function")
191
- throw Oops$d.BadCallback();
251
+ throw Oops$a.BadCallback();
192
252
  }
193
253
  function invoke() {
194
254
  if (busy)
@@ -212,10 +272,11 @@ function createEffect(model, callback, keys) {
212
272
  return invoke;
213
273
  });
214
274
  }
215
- const sub = controller.subscribe(() => invoke);
275
+ const sub = new Subscriber(controller, () => invoke);
216
276
  model = sub.proxy;
217
277
  invoke();
218
- return sub.commit();
278
+ sub.commit();
279
+ return () => sub.release();
219
280
  });
220
281
  }
221
282
  function createValueEffect(callback) {
@@ -231,11 +292,11 @@ function createValueEffect(callback) {
231
292
  if (typeof out == "function")
232
293
  unSet = out;
233
294
  else
234
- throw Oops$d.BadCallback();
295
+ throw Oops$a.BadCallback();
235
296
  };
236
297
  }
237
298
 
238
- const Oops$c = issues({
299
+ const Oops$9 = issues({
239
300
  Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
240
301
  KeysExpected: (key) => `Key "${key}" was expected in current update.`,
241
302
  StrictUpdate: () => `Expected update but none in progress.`,
@@ -271,13 +332,13 @@ function awaitUpdate(source, arg1, arg2) {
271
332
  const timeout = (message) => {
272
333
  const k = keys ? keys.join(", ") : "any";
273
334
  removeListener();
274
- reject(Oops$c.Timeout(k, message));
335
+ reject(Oops$9.Timeout(k, message));
275
336
  };
276
337
  const removeListener = control(source, controller => {
277
338
  const pending = controller.frame;
278
339
  if (keys === null) {
279
340
  if (pending.size)
280
- reject(Oops$c.StrictNoUpdate());
341
+ reject(Oops$9.StrictNoUpdate());
281
342
  else
282
343
  resolve(null);
283
344
  return;
@@ -285,7 +346,7 @@ function awaitUpdate(source, arg1, arg2) {
285
346
  if (keys) {
286
347
  if (keys.length) {
287
348
  if (arg2 === 0 && single && !pending.has(keys[0])) {
288
- reject(Oops$c.KeysExpected(keys[0]));
349
+ reject(Oops$9.KeysExpected(keys[0]));
289
350
  return;
290
351
  }
291
352
  else
@@ -297,7 +358,7 @@ function awaitUpdate(source, arg1, arg2) {
297
358
  }
298
359
  }
299
360
  else if (!pending.size && arg1 === true || arg2 === 0) {
300
- reject(Oops$c.StrictUpdate());
361
+ reject(Oops$9.StrictUpdate());
301
362
  return;
302
363
  }
303
364
  else
@@ -320,68 +381,7 @@ function awaitUpdate(source, arg1, arg2) {
320
381
  });
321
382
  }
322
383
 
323
- const REGISTER$1 = new WeakMap();
324
- class Subscriber {
325
- constructor(parent, onUpdate, suspend) {
326
- this.parent = parent;
327
- this.onUpdate = onUpdate;
328
- this.suspend = suspend;
329
- this.active = false;
330
- this.dependant = new Set();
331
- this.watch = new Map();
332
- const proxy = create(parent.subject);
333
- const reset = () => this.latest = undefined;
334
- REGISTER$1.set(proxy, this);
335
- defineProperty(this, "proxy", {
336
- configurable: true,
337
- get() {
338
- setTimeout(reset, 0);
339
- return proxy;
340
- }
341
- });
342
- }
343
- get using() {
344
- return Array.from(this.watch.keys());
345
- }
346
- add(key, value) {
347
- if (value !== undefined)
348
- this.watch.set(key, value);
349
- else if (!this.watch.has(key))
350
- this.watch.set(key, true);
351
- }
352
- commit() {
353
- const release = this.parent.addListener(key => {
354
- if (this.active)
355
- this.onEvent(key);
356
- });
357
- this.active = true;
358
- this.dependant.forEach(x => x.commit());
359
- return this.release = () => {
360
- this.dependant.forEach(x => x.release());
361
- release();
362
- };
363
- }
364
- onEvent(key) {
365
- const { parent, watch } = this;
366
- let handler = watch.get(key);
367
- if (typeof handler == "function")
368
- handler = handler();
369
- if (handler) {
370
- const notify = this.onUpdate(key, parent);
371
- if (notify) {
372
- parent.waiting.add(update => {
373
- this.latest = update.filter(k => watch.has(k));
374
- });
375
- parent.waiting.add(notify);
376
- }
377
- }
378
- }
379
- }
380
- function subscriber(from) {
381
- return REGISTER$1.get(from);
382
- }
383
-
384
- const Oops$b = issues({
384
+ const Oops$8 = issues({
385
385
  NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
386
386
  });
387
387
  class Model {
@@ -439,7 +439,7 @@ class Model {
439
439
  return {
440
440
  then: (callback) => {
441
441
  if (!callback)
442
- throw Oops$b.NoChaining();
442
+ throw Oops$8.NoChaining();
443
443
  controller.waiting.add(callback);
444
444
  }
445
445
  };
@@ -472,11 +472,150 @@ class Model {
472
472
  maybe.prototype instanceof this);
473
473
  }
474
474
  }
475
- defineProperty(Model.prototype, "toString", {
476
- value() {
477
- return this.constructor.name;
475
+ defineProperty(Model.prototype, "toString", {
476
+ value() {
477
+ return this.constructor.name;
478
+ }
479
+ });
480
+ const FindInstruction = new WeakMap([
481
+ [Model, getParentForGetInstruction]
482
+ ]);
483
+
484
+ const Oops$7 = issues({
485
+ PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
486
+ Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
487
+ });
488
+ function get(arg0, arg1) {
489
+ return add(function get(key) {
490
+ const { subject, state } = this;
491
+ // Easy mistake, using a peer, will always be unresolved.
492
+ if (typeof arg0 == "symbol")
493
+ throw Oops$7.PeerNotAllowed(subject, key);
494
+ let source;
495
+ const sourceRequired = arg1 !== false;
496
+ if (arg0 instanceof Model) {
497
+ source = () => arg0;
498
+ if (typeof arg1 !== "function")
499
+ throw new Error(`Factory argument cannot be ${arg1}`);
500
+ }
501
+ else if (Model.isTypeof(arg0)) {
502
+ source = find(arg0, subject, sourceRequired);
503
+ }
504
+ else if (typeof arg0 == "function") {
505
+ arg1 = arg0.call(subject, key, subject);
506
+ source = () => subject;
507
+ }
508
+ if (typeof arg1 == "function")
509
+ return getComputed(key, this, source, arg1);
510
+ else {
511
+ const init = source((got) => {
512
+ state.set(key, got);
513
+ this.update(key);
514
+ });
515
+ // TODO: remove fixes suspense test
516
+ if (init || arg1 === false)
517
+ state.set(key, init);
518
+ return getRecursive(key, this);
519
+ }
520
+ });
521
+ }
522
+ function getComputed(key, parent, source, setter) {
523
+ const { state } = parent;
524
+ let sub;
525
+ let order = ORDER.get(parent);
526
+ let pending = KEYS.get(parent);
527
+ let instance;
528
+ if (!order)
529
+ ORDER.set(parent, order = new Map());
530
+ if (!pending)
531
+ KEYS.set(parent, pending = new Set());
532
+ const compute = (initial) => {
533
+ try {
534
+ return setter.call(sub.proxy, sub.proxy);
535
+ }
536
+ catch (err) {
537
+ Oops$7.Failed(instance, key, initial).warn();
538
+ throw err;
539
+ }
540
+ };
541
+ const create = () => {
542
+ // TODO: replace create with a cleanup function
543
+ const got = source(create);
544
+ if (!got)
545
+ throw suspend(parent, key);
546
+ instance = got;
547
+ sub = new Subscriber(control(instance), (_, control) => {
548
+ if (control !== parent)
549
+ refresh();
550
+ else
551
+ pending.add(refresh);
552
+ });
553
+ sub.watch.set(key, false);
554
+ try {
555
+ const value = compute(true);
556
+ state.set(key, value);
557
+ return value;
558
+ }
559
+ finally {
560
+ sub.commit();
561
+ order.set(refresh, order.size);
562
+ }
563
+ };
564
+ const refresh = () => {
565
+ let value;
566
+ try {
567
+ value = compute(false);
568
+ }
569
+ catch (e) {
570
+ console.error(e);
571
+ }
572
+ finally {
573
+ if (state.get(key) !== value) {
574
+ state.set(key, value);
575
+ parent.update(key);
576
+ return value;
577
+ }
578
+ }
579
+ };
580
+ INFO.set(refresh, key);
581
+ return () => {
582
+ if (pending.has(refresh)) {
583
+ pending.delete(refresh);
584
+ refresh();
585
+ }
586
+ return sub ? state.get(key) : create();
587
+ };
588
+ }
589
+ const INFO = new WeakMap();
590
+ const KEYS = new WeakMap();
591
+ const ORDER = new WeakMap();
592
+ function flush(control) {
593
+ const pending = KEYS.get(control);
594
+ if (!pending || !pending.size)
595
+ return;
596
+ const priority = ORDER.get(control);
597
+ while (pending.size) {
598
+ let compute;
599
+ for (const item of pending)
600
+ if (!compute || priority.get(item) < priority.get(compute))
601
+ compute = item;
602
+ pending.delete(compute);
603
+ const key = INFO.get(compute);
604
+ if (!control.frame.has(key))
605
+ compute();
478
606
  }
479
- });
607
+ pending.clear();
608
+ }
609
+ // TODO: collapse this function when MVC is merged into Model.
610
+ function find(type, relativeTo, required) {
611
+ let T = type;
612
+ do {
613
+ T = getPrototypeOf(T);
614
+ const getter = FindInstruction.get(T);
615
+ if (getter)
616
+ return getter(type, relativeTo, required);
617
+ } while (T.prototype instanceof Model);
618
+ }
480
619
 
481
620
  const REGISTER = new WeakMap();
482
621
  const PENDING = new Map();
@@ -488,9 +627,6 @@ class Control {
488
627
  this.followers = new Set();
489
628
  REGISTER.set(subject, this);
490
629
  }
491
- subscribe(callback) {
492
- return new Subscriber(this, callback);
493
- }
494
630
  watch(key) {
495
631
  const { subject, state } = this;
496
632
  const { value } = getOwnPropertyDescriptor(subject, key);
@@ -501,7 +637,7 @@ class Control {
501
637
  if (instruction) {
502
638
  delete subject[key];
503
639
  PENDING.delete(value);
504
- instruction.call(this, key, this);
640
+ instruction(this, key);
505
641
  }
506
642
  return;
507
643
  }
@@ -517,8 +653,8 @@ class Control {
517
653
  const sub = subscriber(this);
518
654
  const value = state.get(key);
519
655
  if (sub) {
520
- sub.add(key);
521
- if (value === undefined && sub.suspend)
656
+ sub.follow(key);
657
+ if (value === undefined && sub.strict)
522
658
  throw suspend(this, key);
523
659
  }
524
660
  return value;
@@ -579,6 +715,8 @@ class Control {
579
715
  listeners.forEach(x => x(null, this));
580
716
  }
581
717
  }
718
+ Control.get = controller;
719
+ Control.for = control;
582
720
  function controller(from) {
583
721
  if ("is" in from)
584
722
  from = from.is;
@@ -608,68 +746,6 @@ function control(subject, cb) {
608
746
  return cb ? cb(control) : control;
609
747
  }
610
748
 
611
- const Parent = new WeakMap();
612
- const Oops$a = issues({
613
- BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
614
- });
615
- function getRecursive(key, from) {
616
- const context = new WeakMap();
617
- const { state } = from;
618
- return (local) => {
619
- if (!local)
620
- return state.get(key);
621
- if (!context.has(local)) {
622
- let reset;
623
- const init = () => {
624
- if (reset)
625
- reset();
626
- const value = state.get(key);
627
- if (value && controller(value)) {
628
- const child = control(value).subscribe(local.onUpdate);
629
- if (local.active)
630
- child.commit();
631
- local.dependant.add(child);
632
- context.set(local, child.proxy);
633
- reset = () => {
634
- child.release();
635
- local.dependant.delete(child);
636
- context.set(local, undefined);
637
- reset = undefined;
638
- };
639
- }
640
- return true;
641
- };
642
- local.add(key, init);
643
- init();
644
- }
645
- return context.get(local);
646
- };
647
- }
648
- function setRecursive(controller, key, initial) {
649
- const { state, subject } = controller;
650
- const Type = initial.constructor;
651
- let get;
652
- const onUpdate = (next) => {
653
- state.set(key, next);
654
- if (!(next instanceof Type))
655
- throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
656
- get = getRecursive(key, controller);
657
- Parent.set(next, subject);
658
- control(next);
659
- return true;
660
- };
661
- onUpdate(initial);
662
- defineProperty(subject, key, {
663
- set: controller.ref(key, onUpdate),
664
- get() {
665
- const local = subscriber(this);
666
- if (local)
667
- local.add(key);
668
- return get(local);
669
- }
670
- });
671
- }
672
-
673
749
  /**
674
750
  * Run instruction as controller sets itself up.
675
751
  * This will specialize the behavior of a given property.
@@ -677,64 +753,42 @@ function setRecursive(controller, key, initial) {
677
753
  function add(instruction, label) {
678
754
  const name = label || instruction.name || "pending";
679
755
  const placeholder = Symbol(`${name} instruction`);
680
- function setup(key) {
681
- const { subject, state } = this;
682
- let output = instruction.call(this, key, this);
756
+ PENDING.set(placeholder, (control, key) => {
757
+ let output = instruction.call(control, key, control);
758
+ if (!output)
759
+ return undefined;
683
760
  if (typeof output == "function")
684
761
  output = { get: output };
685
- if (typeof output != "object")
686
- return;
687
- if ("explicit" in output && output.explicit) {
688
- defineProperty(subject, key, output);
689
- return false;
690
- }
691
- let { get: onGet, set: onSet, suspend: shouldSuspend } = output;
692
762
  if ("value" in output)
693
- state.set(key, output.value);
694
- if ("recursive" in output && output.recursive)
695
- onGet = getRecursive(key, this);
696
- if ("destroy" in output) {
697
- const { destroy } = output;
698
- if (destroy)
699
- this.addListener((key) => {
700
- if (key == null)
701
- destroy();
702
- });
703
- }
704
- const control = this;
705
- defineProperty(subject, key, {
706
- enumerable: output.enumerable,
707
- set: onSet === false
763
+ control.state.set(key, output.value);
764
+ let { enumerable, get, set } = output;
765
+ defineProperty(control.subject, key, {
766
+ enumerable,
767
+ set: set === false
708
768
  ? undefined
709
- : this.ref(key, onSet),
769
+ : control.ref(key, set),
710
770
  get() {
711
- if (!state.has(key) && shouldSuspend)
712
- throw suspend(control, key);
713
771
  const local = subscriber(this);
714
- const required = local && local.suspend;
715
772
  if (local)
716
- local.add(key);
773
+ local.follow(key);
717
774
  try {
718
- const value = onGet
719
- ? onGet(local)
720
- : state.get(key);
721
- if (value === undefined && required === true)
775
+ const value = get ? get(local) : control.state.get(key);
776
+ if (value === undefined && local && local.strict === true)
722
777
  throw suspend(control, key);
723
778
  return value;
724
779
  }
725
780
  catch (err) {
726
- if (err instanceof Promise && required === false)
781
+ if (err instanceof Promise && local && local.strict === false)
727
782
  return;
728
783
  throw err;
729
784
  }
730
785
  }
731
786
  });
732
- }
733
- PENDING.set(placeholder, setup);
787
+ });
734
788
  return placeholder;
735
789
  }
736
790
 
737
- /*! *****************************************************************************
791
+ /******************************************************************************
738
792
  Copyright (c) Microsoft Corporation.
739
793
 
740
794
  Permission to use, copy, modify, and/or distribute this software for any
@@ -759,7 +813,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
759
813
  });
760
814
  }
761
815
 
762
- const Oops$9 = issues({
816
+ const Oops$6 = issues({
763
817
  DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
764
818
  });
765
819
  function run(task) {
@@ -767,7 +821,7 @@ function run(task) {
767
821
  let pending = false;
768
822
  const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
769
823
  if (pending)
770
- return Promise.reject(Oops$9.DuplicatePending(key));
824
+ return Promise.reject(Oops$6.DuplicatePending(key));
771
825
  pending = true;
772
826
  this.update(key);
773
827
  try {
@@ -789,106 +843,6 @@ function run(task) {
789
843
  });
790
844
  }
791
845
 
792
- const Oops$8 = issues({
793
- NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
794
- });
795
- function factoryMode(self, value, key, required) {
796
- const { subject, state } = self;
797
- let pending;
798
- let error;
799
- if (value instanceof Promise) {
800
- state.set(key, undefined);
801
- pending = value
802
- .catch(err => error = err)
803
- .then(val => {
804
- state.set(key, val);
805
- return val;
806
- })
807
- .finally(() => {
808
- pending = undefined;
809
- self.update(key);
810
- });
811
- }
812
- else
813
- state.set(key, value);
814
- const suspend = () => {
815
- if (required === false)
816
- return undefined;
817
- const issue = Oops$8.NotReady(subject, key);
818
- assign(pending, {
819
- message: issue.message,
820
- stack: issue.stack
821
- });
822
- throw pending;
823
- };
824
- return () => {
825
- if (error)
826
- throw error;
827
- if (pending)
828
- return suspend();
829
- if (state.has(key))
830
- return state.get(key);
831
- };
832
- }
833
-
834
- const Oops$7 = issues({
835
- PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
836
- ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
837
- Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
838
- });
839
- function get(arg0, arg1, arg2) {
840
- return add(function get(key) {
841
- const { subject } = this;
842
- const computeRequired = arg1 === true || arg2 === true;
843
- const factoryRequired = arg1 !== false && arg2 !== false;
844
- let getter;
845
- // Easy mistake, using a peer, will always be unresolved.
846
- if (typeof arg0 == "symbol")
847
- throw Oops$7.PeerNotAllowed(subject, key);
848
- // if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
849
- // throw Oops.BadSource(subject, key, arg0);
850
- this.state.set(key, undefined);
851
- const init = () => {
852
- let source = this;
853
- let setter;
854
- if (typeof arg0 == "function") {
855
- const result = mayRetry(arg0.bind(subject, key, subject));
856
- if (typeof result == "function")
857
- setter = result;
858
- else {
859
- getter = factoryMode(this, result, key, factoryRequired);
860
- return;
861
- }
862
- }
863
- else if (arg0 instanceof Promise) {
864
- getter = factoryMode(this, arg0, key, factoryRequired);
865
- return;
866
- }
867
- else if (typeof arg1 == "function") {
868
- // replace source controller in-case it is different
869
- source = control(arg0);
870
- setter = arg1;
871
- }
872
- else
873
- throw new Error(`Factory argument cannot be ${arg1}`);
874
- getter = computeMode(this, source, setter, key, computeRequired);
875
- };
876
- if (typeof arg0 == "function" && computeRequired)
877
- try {
878
- init();
879
- }
880
- catch (err) {
881
- Oops$7.ComputeFailed(subject, key).warn();
882
- throw err;
883
- }
884
- return () => {
885
- if (!getter)
886
- init();
887
- return getter();
888
- };
889
- });
890
- }
891
-
892
846
  function ref(arg, mapper) {
893
847
  return add(function ref(key) {
894
848
  let value = {};
@@ -908,7 +862,7 @@ function ref(arg, mapper) {
908
862
  value: createRef(this, key)
909
863
  });
910
864
  });
911
- return { value, explicit: true };
865
+ defineProperty(this.subject, key, { value });
912
866
  });
913
867
  }
914
868
  function createRef(src, key, cb) {
@@ -920,16 +874,78 @@ function createRef(src, key, cb) {
920
874
  return refObjectFunction;
921
875
  }
922
876
 
877
+ const Oops$5 = issues({
878
+ ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
879
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
880
+ });
923
881
  function set(value, argument) {
924
- if (!(1 in arguments)) {
925
- argument = value;
926
- value = undefined;
927
- }
928
882
  return add(function set(key) {
883
+ const { state, subject } = this;
884
+ if (typeof value == "function" || value instanceof Promise) {
885
+ const required = argument !== false;
886
+ let getter;
887
+ const init = () => {
888
+ try {
889
+ if (typeof value == "function")
890
+ value = mayRetry(value.bind(subject, key, subject));
891
+ let pending;
892
+ let error;
893
+ if (value instanceof Promise) {
894
+ state.set(key, undefined);
895
+ pending = value
896
+ .catch(err => error = err)
897
+ .then(val => {
898
+ state.set(key, val);
899
+ return val;
900
+ })
901
+ .finally(() => {
902
+ pending = undefined;
903
+ this.update(key);
904
+ });
905
+ }
906
+ else
907
+ state.set(key, value);
908
+ const suspend = () => {
909
+ if (required === false)
910
+ return undefined;
911
+ const issue = Oops$5.NotReady(subject, key);
912
+ assign(pending, {
913
+ message: issue.message,
914
+ stack: issue.stack
915
+ });
916
+ throw pending;
917
+ };
918
+ getter = () => {
919
+ if (error)
920
+ throw error;
921
+ if (pending)
922
+ return suspend();
923
+ if (state.has(key))
924
+ return state.get(key);
925
+ };
926
+ }
927
+ catch (err) {
928
+ Oops$5.ComputeFailed(subject, key).warn();
929
+ throw err;
930
+ }
931
+ };
932
+ if (argument === true)
933
+ init();
934
+ return () => {
935
+ if (!getter)
936
+ init();
937
+ return getter();
938
+ };
939
+ }
929
940
  if (value !== undefined)
930
- this.state.set(key, value);
941
+ state.set(key, value);
931
942
  return {
932
- suspend: true,
943
+ get: () => {
944
+ if (state.has(key))
945
+ return state.get(key);
946
+ else
947
+ throw suspend(this, key);
948
+ },
933
949
  set: typeof argument == "function"
934
950
  ? createValueEffect(argument)
935
951
  : undefined
@@ -973,7 +989,7 @@ function keyed(control, property, initial) {
973
989
  }
974
990
  }
975
991
  }
976
- local.add(property, false);
992
+ local.follow(property, false);
977
993
  local.dependant.add({
978
994
  commit() {
979
995
  if (using.size === 0)
@@ -989,6 +1005,12 @@ function keyed(control, property, initial) {
989
1005
  context.set(local, proxy);
990
1006
  return proxy;
991
1007
  }
1008
+ control.addListener(key => {
1009
+ if (key === null) {
1010
+ update.clear();
1011
+ context.clear();
1012
+ }
1013
+ });
992
1014
  return {
993
1015
  value: initial,
994
1016
  get(local) {
@@ -1001,10 +1023,6 @@ function keyed(control, property, initial) {
1001
1023
  managed = init(next);
1002
1024
  context.clear();
1003
1025
  emit(ANY);
1004
- },
1005
- destroy() {
1006
- update.clear();
1007
- context.clear();
1008
1026
  }
1009
1027
  };
1010
1028
  }
@@ -1083,11 +1101,11 @@ function createProxy(emit, watch) {
1083
1101
  };
1084
1102
  }
1085
1103
 
1086
- const Oops$6 = issues({
1104
+ const Oops$4 = issues({
1087
1105
  BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
1088
1106
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
1089
1107
  });
1090
- function use$1(input, argument) {
1108
+ function use(input, argument) {
1091
1109
  return add(function use(key) {
1092
1110
  const { state, subject } = this;
1093
1111
  const required = argument !== false;
@@ -1099,7 +1117,7 @@ function use$1(input, argument) {
1099
1117
  input = new input();
1100
1118
  }
1101
1119
  else if (input && typeof input !== "object")
1102
- throw Oops$6.BadArgument(typeof input);
1120
+ throw Oops$4.BadArgument(typeof input);
1103
1121
  if (input instanceof Map || input instanceof Set)
1104
1122
  return keyed(this, key, input);
1105
1123
  const onUpdate = (next) => {
@@ -1116,7 +1134,7 @@ function use$1(input, argument) {
1116
1134
  const suspend = () => {
1117
1135
  if (required === false)
1118
1136
  return;
1119
- const issue = Oops$6.NotReady(subject, key);
1137
+ const issue = Oops$4.NotReady(subject, key);
1120
1138
  assign(pending, {
1121
1139
  message: issue.message,
1122
1140
  stack: issue.stack
@@ -1161,33 +1179,11 @@ function use$1(input, argument) {
1161
1179
  });
1162
1180
  }
1163
1181
 
1164
- const Oops$5 = issues({
1165
- Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
1166
- Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
1167
- });
1168
- function has(Type, required) {
1169
- return add(function parent() {
1170
- const child = this.subject;
1171
- const value = Parent.get(child);
1172
- const expected = Type.name;
1173
- if (!value) {
1174
- if (required !== false)
1175
- throw Oops$5.Required(expected, child);
1176
- }
1177
- else if (!(value instanceof Type))
1178
- throw Oops$5.Unexpected(expected, child, value);
1179
- return { value };
1180
- });
1181
- }
1182
-
1183
- const Oops$4 = issues({
1184
- NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
1185
- });
1186
- class Lookup {
1182
+ class Register {
1187
1183
  constructor() {
1188
1184
  this.table = new Map();
1189
1185
  }
1190
- key(T) {
1186
+ has(T) {
1191
1187
  let key = this.table.get(T);
1192
1188
  if (!key) {
1193
1189
  key = Symbol(T.name);
@@ -1196,22 +1192,9 @@ class Lookup {
1196
1192
  return key;
1197
1193
  }
1198
1194
  get(Type) {
1199
- return this[this.key(Type)];
1200
- }
1201
- has(key, input, callback) {
1202
- if (MVC.isTypeof(input) && input.global)
1203
- return input.new();
1204
- if (this.register.get(key) === input)
1205
- return typeof input == "object"
1206
- ? input
1207
- : this.get(input);
1208
- const instance = this.add(input);
1209
- this.register.set(key, input);
1210
- if (callback)
1211
- callback(instance);
1212
- return instance;
1195
+ return this[this.has(Type)];
1213
1196
  }
1214
- add(input) {
1197
+ add(input, key) {
1215
1198
  let writable = true;
1216
1199
  let T;
1217
1200
  let I;
@@ -1220,19 +1203,21 @@ class Lookup {
1220
1203
  I = new input();
1221
1204
  }
1222
1205
  else {
1223
- I = input;
1206
+ I = input.is;
1224
1207
  T = I.constructor;
1225
1208
  writable = false;
1226
1209
  }
1227
1210
  do {
1228
- const key = this.key(T);
1211
+ const key = this.has(T);
1229
1212
  defineProperty(this, key, {
1230
1213
  configurable: true,
1231
- value: this.hasOwnProperty(key) ? null : I,
1214
+ value: this.hasOwnProperty(key) && I !== this[key] ? null : I,
1232
1215
  writable
1233
1216
  });
1234
1217
  T = getPrototypeOf(T);
1235
1218
  } while (T !== Model);
1219
+ if (key !== undefined)
1220
+ this.register.set(key, input);
1236
1221
  return I;
1237
1222
  }
1238
1223
  push() {
@@ -1246,52 +1231,77 @@ class Lookup {
1246
1231
  const entry = getOwnPropertyDescriptor(this, key);
1247
1232
  if (entry.writable && entry.value)
1248
1233
  items.add(entry.value);
1234
+ delete this[key];
1249
1235
  }
1250
1236
  for (const model of items)
1251
1237
  model.end();
1252
1238
  }
1239
+ delete(instance) {
1240
+ for (const key of getOwnPropertySymbols(this)) {
1241
+ const entry = getOwnPropertyDescriptor(this, key);
1242
+ if (entry.value === instance)
1243
+ delete this[key];
1244
+ }
1245
+ }
1246
+ }
1247
+ const Global$1 = new Register();
1248
+
1249
+ const Oops$3 = issues({
1250
+ AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`,
1251
+ DoesNotExist: (name) => `Tried to access singleton ${name}, but none exist! Did you forget to initialize?\nCall ${name}.new() before attempting to access, or consider using ${name}.use() instead.`,
1252
+ NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
1253
+ MultipleExist: (name) => `Did find ${name} in context, but multiple were defined by same Provider.`
1254
+ });
1255
+ const LookupContext = React__default["default"].createContext(Global$1);
1256
+ function useLookup() {
1257
+ try {
1258
+ return React__default["default"].useContext(LookupContext);
1259
+ }
1260
+ catch (err) {
1261
+ return Global$1;
1262
+ }
1253
1263
  }
1254
- const LookupContext = React__default["default"].createContext(new Lookup());
1255
- const useLookup = () => React__default["default"].useContext(LookupContext);
1256
1264
  function useContext(Type, required) {
1257
1265
  const instance = useLookup().get(Type);
1266
+ if (instance === null)
1267
+ throw Oops$3.MultipleExist(Type.name);
1258
1268
  if (!instance && required !== false)
1259
- throw Oops$4.NotFound(Type.name);
1269
+ throw MVC.isTypeof(Type) && Type.global
1270
+ ? Oops$3.DoesNotExist(Type.name)
1271
+ : Oops$3.NotFound(Type.name);
1260
1272
  return instance;
1261
1273
  }
1262
1274
 
1263
- const Oops$3 = issues({
1275
+ const Oops$2 = issues({
1264
1276
  NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
1265
- AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
1277
+ AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
1266
1278
  });
1267
1279
  const Pending = new WeakMap();
1268
1280
  const Applied = new WeakMap();
1269
- function tap(type, argument) {
1270
- return add(function tap(key) {
1271
- if (MVC.isTypeof(type) && type.global)
1272
- return {
1273
- recursive: true,
1274
- value: type.get()
1275
- };
1276
- const { subject } = this;
1277
- if (subject.constructor.global)
1278
- throw Oops$3.NotAllowed(subject, type.name);
1279
- getPending(subject).push(context => {
1280
- let instance = context.get(type);
1281
- if (typeof argument == "function") {
1282
- if (argument(instance) === false)
1283
- instance = undefined;
1281
+ function getContextForGetInstruction(type, relativeTo, required) {
1282
+ let item = getParent(type, relativeTo);
1283
+ return (refresh) => {
1284
+ if (item)
1285
+ return item;
1286
+ findRelative(relativeTo, type, got => {
1287
+ if (got) {
1288
+ item = got;
1289
+ refresh(got);
1284
1290
  }
1285
- else if (!instance && argument)
1286
- throw Oops$3.AmbientRequired(type.name, subject, key);
1287
- this.state.set(key, instance);
1288
- this.update(key);
1291
+ else if (required)
1292
+ throw Oops$2.AmbientRequired(type.name, relativeTo);
1293
+ });
1294
+ };
1295
+ }
1296
+ function findRelative(from, type, callback) {
1297
+ if (MVC.isTypeof(type) && type.global)
1298
+ callback(Global$1.get(type));
1299
+ else if (from.constructor.global)
1300
+ throw Oops$2.NotAllowed(from, type.name);
1301
+ else
1302
+ getPending(from).push(context => {
1303
+ callback(context.get(type));
1289
1304
  });
1290
- return {
1291
- recursive: true,
1292
- suspend: true
1293
- };
1294
- });
1295
1305
  }
1296
1306
  function usePeerContext(subject) {
1297
1307
  if (Applied.has(subject)) {
@@ -1315,7 +1325,7 @@ function getPending(subject) {
1315
1325
  return pending;
1316
1326
  }
1317
1327
 
1318
- function useNew(source, arg1, arg2) {
1328
+ function useModel(source, arg1, arg2) {
1319
1329
  const instance = React__default["default"].useMemo(() => {
1320
1330
  const callback = arg2 || arg1;
1321
1331
  const instance = Model.isTypeof(source)
@@ -1328,7 +1338,7 @@ function useNew(source, arg1, arg2) {
1328
1338
  }, []);
1329
1339
  usePeerContext(instance);
1330
1340
  if (Array.isArray(arg1)) {
1331
- const update = React.useState(0)[1];
1341
+ const update = React__default["default"].useState(0)[1];
1332
1342
  React__default["default"].useLayoutEffect(() => {
1333
1343
  if (arg1.length && instance instanceof Model)
1334
1344
  instance.on(arg1, () => update(x => x + 1));
@@ -1342,19 +1352,10 @@ function useNew(source, arg1, arg2) {
1342
1352
  const state = React__default["default"].useState(0);
1343
1353
  const local = React__default["default"].useMemo(() => {
1344
1354
  const refresh = state[1].bind(null, x => x + 1);
1345
- return control(instance).subscribe(() => refresh);
1355
+ return new Subscriber(control(instance), () => refresh);
1346
1356
  }, []);
1347
- if (typeof arg1 == "object") {
1348
- const { waiting, subject } = local.parent;
1349
- let keys = arg2;
1350
- local.active = false;
1351
- if (!keys)
1352
- keys = getOwnPropertyNames(subject);
1353
- for (const key of keys)
1354
- if (key in arg1)
1355
- subject[key] = arg1[key];
1356
- waiting.add(() => local.active = true);
1357
- }
1357
+ if (typeof arg1 == "object")
1358
+ local.apply(arg1, arg2);
1358
1359
  React__default["default"].useLayoutEffect(() => {
1359
1360
  local.commit();
1360
1361
  return () => {
@@ -1366,19 +1367,22 @@ function useNew(source, arg1, arg2) {
1366
1367
  return local.proxy;
1367
1368
  }
1368
1369
 
1369
- function use(init, deps) {
1370
+ function useTap(source, arg1, arg2) {
1371
+ const instance = typeof source == "object"
1372
+ ? source
1373
+ : "get" in source
1374
+ ? source.get()
1375
+ : source();
1376
+ const deps = [uid(instance)];
1370
1377
  const state = React__default["default"].useState(0);
1371
- return React__default["default"].useMemo(() => {
1372
- return init(state[1].bind(null, x => x + 1));
1373
- }, deps);
1374
- }
1375
-
1376
- function useCompute(source, compute, suspend) {
1377
- const deps = [uid(source)];
1378
- const local = use(refresh => {
1379
- const sub = control(source).subscribe(() => update);
1378
+ const local = React__default["default"].useMemo(() => {
1379
+ const refresh = state[1].bind(null, x => x + 1);
1380
+ const controller = control(instance);
1381
+ if (typeof arg1 != "function")
1382
+ return new Subscriber(controller, () => refresh, arg1);
1383
+ const sub = new Subscriber(controller, () => update);
1380
1384
  const spy = sub.proxy;
1381
- let make = () => compute.call(spy, spy, forceUpdate);
1385
+ let make = () => arg1.call(spy, spy, forceUpdate);
1382
1386
  function forceUpdate(passthru) {
1383
1387
  if (typeof passthru == "function")
1384
1388
  passthru = passthru();
@@ -1409,7 +1413,7 @@ function useCompute(source, compute, suspend) {
1409
1413
  if (typeof value == "function") {
1410
1414
  const get = value;
1411
1415
  sub.watch.clear();
1412
- compute = () => get();
1416
+ arg1 = () => get();
1413
1417
  value = get();
1414
1418
  }
1415
1419
  if (value instanceof Promise) {
@@ -1428,7 +1432,7 @@ function useCompute(source, compute, suspend) {
1428
1432
  get() {
1429
1433
  if (value !== undefined)
1430
1434
  return value;
1431
- if (suspend)
1435
+ if (arg2)
1432
1436
  throw new Promise(res => retry = res);
1433
1437
  return null;
1434
1438
  }
@@ -1437,7 +1441,10 @@ function useCompute(source, compute, suspend) {
1437
1441
  }, deps);
1438
1442
  if (!local)
1439
1443
  return null;
1440
- React__default["default"].useLayoutEffect(() => local.release, deps);
1444
+ React__default["default"].useLayoutEffect(() => {
1445
+ local.commit();
1446
+ return () => local.release();
1447
+ }, deps);
1441
1448
  return local.proxy;
1442
1449
  }
1443
1450
  /** Values are not equal for purposes of a refresh. */
@@ -1446,58 +1453,35 @@ const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
1446
1453
  a.length !== b.length ||
1447
1454
  a.some((x, i) => x !== b[i])));
1448
1455
 
1449
- function useTap(source, arg1, arg2) {
1450
- const instance = typeof source == "object"
1451
- ? source
1452
- : "get" in source
1453
- ? source.get()
1454
- : useContext(source);
1455
- return typeof arg1 == "function"
1456
- ? useCompute(instance, arg1, arg2)
1457
- : useSubscribe(instance, arg1);
1458
- }
1459
- function useSubscribe(source, expect) {
1460
- const deps = [uid(source)];
1461
- const local = use(refresh => (new Subscriber(control(source), () => refresh, expect)), deps);
1462
- React__default["default"].useLayoutEffect(() => local.commit(), deps);
1463
- return local.proxy;
1464
- }
1465
-
1466
- const Global$1 = new WeakMap();
1467
- const Oops$2 = issues({
1468
- DoesNotExist: (name) => `Tried to access singleton ${name}, but none exist! Did you forget to initialize?\nCall ${name}.new() before attempting to access, or consider using ${name}.use() instead.`,
1469
- AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
1470
- });
1471
1456
  class MVC extends Model {
1472
1457
  end(force) {
1473
1458
  const type = this.constructor;
1474
1459
  if (type.keepAlive && !force)
1475
1460
  return false;
1476
1461
  super.end();
1477
- Global$1.delete(type);
1462
+ Global$1.delete(this);
1478
1463
  return true;
1479
1464
  }
1480
1465
  static new(...args) {
1481
- if (Global$1.has(this))
1466
+ const exists = Global$1.get(this);
1467
+ if (exists)
1482
1468
  if (this.keepAlive)
1483
- return Global$1.get(this);
1469
+ return exists;
1484
1470
  else
1485
- throw Oops$2.AlreadyExists(this.name);
1471
+ throw Oops$3.AlreadyExists(this.name);
1486
1472
  const instance = super.new(...args);
1487
1473
  if (this.global)
1488
- Global$1.set(this, instance);
1474
+ Global$1.add(instance);
1489
1475
  return instance;
1490
1476
  }
1491
1477
  static get(arg1, arg2) {
1492
- let instance;
1493
1478
  const required = arg1 === undefined || arg1 === true;
1494
- if (this.global) {
1495
- instance = Global$1.get(this);
1496
- if (!instance && required)
1497
- throw Oops$2.DoesNotExist(this.name);
1498
- }
1499
- else
1500
- instance = useContext(this, required);
1479
+ const instance = useContext(this, required);
1480
+ if (typeof arg1 === "function" && instance)
1481
+ callback(arg1);
1482
+ else if (arg2)
1483
+ callback(arg2);
1484
+ return instance;
1501
1485
  function callback(effect) {
1502
1486
  try {
1503
1487
  React__default["default"].useLayoutEffect(() => effect(instance), []);
@@ -1509,29 +1493,18 @@ class MVC extends Model {
1509
1493
  effect(undefined);
1510
1494
  }
1511
1495
  }
1512
- if (typeof arg1 === "string")
1513
- return instance[arg1];
1514
- if (typeof arg1 === "function" && instance)
1515
- callback(arg1);
1516
- else if (arg2)
1517
- callback(arg2);
1518
- return instance;
1519
1496
  }
1520
1497
  static tap(arg1, arg2) {
1521
- const instance = this.get();
1522
- return typeof arg1 == "function"
1523
- ? useCompute(instance, arg1, arg2)
1524
- : useSubscribe(instance, arg1);
1498
+ return useTap(this, arg1, arg2);
1525
1499
  }
1526
1500
  static use(a, b) {
1527
- return useNew(this, a, b);
1501
+ return useModel(this, a, b);
1528
1502
  }
1529
1503
  static meta(arg1, arg2) {
1530
- return typeof arg1 == "function"
1531
- ? useCompute(this, arg1, arg2)
1532
- : useSubscribe(this, arg1);
1504
+ return useTap(() => this, arg1, arg2);
1533
1505
  }
1534
- }
1506
+ }
1507
+ FindInstruction.set(MVC, getContextForGetInstruction);
1535
1508
 
1536
1509
  const Oops$1 = issues({
1537
1510
  BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
@@ -1565,8 +1538,17 @@ function useNewContext(include, assign) {
1565
1538
  throw Oops.NoType();
1566
1539
  return ambient.push();
1567
1540
  }, []);
1568
- function register(key, T) {
1569
- const instance = context.has(key, T, i => init.add(i));
1541
+ function register(key, input) {
1542
+ let instance;
1543
+ if (MVC.isTypeof(input) && input.global)
1544
+ instance = input.new();
1545
+ else if (context.register.get(key) === input)
1546
+ instance = typeof input == "object"
1547
+ ? input
1548
+ : context.get(input);
1549
+ else
1550
+ instance = context.add(input, key);
1551
+ init.add(instance);
1570
1552
  if (assign)
1571
1553
  assignWeak(instance, assign);
1572
1554
  }
@@ -1576,6 +1558,7 @@ function useNewContext(include, assign) {
1576
1558
  entries(include).forEach(e => register(...e));
1577
1559
  for (const instance of init) {
1578
1560
  control(instance).state.forEach(value => {
1561
+ // TODO: should this run repeatedly?
1579
1562
  if (Parent.get(value) === instance) {
1580
1563
  context.add(value);
1581
1564
  init.add(value);
@@ -1583,6 +1566,8 @@ function useNewContext(include, assign) {
1583
1566
  });
1584
1567
  for (const apply of getPending(instance))
1585
1568
  apply(context);
1569
+ // TODO: add test to validate this.
1570
+ init.delete(instance);
1586
1571
  }
1587
1572
  React__default["default"].useLayoutEffect(() => () => context.pop(), []);
1588
1573
  return context;
@@ -1638,12 +1623,7 @@ exports.Provider = Provider;
1638
1623
  exports.add = add;
1639
1624
  exports["default"] = MVC;
1640
1625
  exports.get = get;
1641
- exports.has = has;
1642
1626
  exports.ref = ref;
1643
1627
  exports.run = run;
1644
1628
  exports.set = set;
1645
- exports.tap = tap;
1646
- exports.use = use$1;
1647
- exports.useContext = useContext;
1648
- exports.useNew = useNew;
1649
- exports.useTap = useTap;
1629
+ exports.use = use;