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