@expressive/mvc 1.0.0-beta.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -2,7 +2,25 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var react = require('react');
5
+ var React = require('react');
6
+
7
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+
9
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
10
+
11
+ const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
12
+ const UID_CACHE = new WeakMap();
13
+ function assignWeak(into, from) {
14
+ for (const K in from)
15
+ if (K in into)
16
+ into[K] = from[K];
17
+ }
18
+ function uid(object) {
19
+ let uid = UID_CACHE.get(object);
20
+ if (!uid)
21
+ UID_CACHE.set(object, uid = Math.random());
22
+ return uid;
23
+ }
6
24
 
7
25
  class Issue extends Error {
8
26
  constructor() {
@@ -21,993 +39,1593 @@ function issues(register) {
21
39
  return Library;
22
40
  }
23
41
 
24
- const Oops$8 = issues({
25
- BadEffectCallback: () => `Callback for effect-callback may only return a function.`
42
+ const Oops$f = issues({
43
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
26
44
  });
27
- const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertyDescriptors, getOwnPropertySymbols, keys: keys$1, values } = Object;
28
- function define(target, key, value) {
29
- defineProperty(target, key, { value });
30
- }
31
- function defineLazy(object, property, init) {
32
- defineProperty(object, property, {
33
- configurable: true,
34
- get() {
35
- const value = init.call(this);
36
- defineProperty(this, property, { value });
37
- return value;
38
- }
45
+ function suspend(source, key) {
46
+ const error = Oops$f.NotReady(source.subject, key);
47
+ const promise = new Promise(resolve => {
48
+ const release = source.addListener(forKey => {
49
+ if (forKey == key)
50
+ return () => {
51
+ if (source.state.get(key) !== undefined) {
52
+ release();
53
+ resolve();
54
+ }
55
+ };
56
+ });
57
+ });
58
+ return assign(promise, {
59
+ toString: () => String(error),
60
+ name: "Suspense",
61
+ message: error.message,
62
+ stack: error.stack
39
63
  });
40
64
  }
41
- function setAlias(func, displayName) {
42
- assign(func, { displayName });
43
- }
44
- function entriesIn(object) {
45
- return entries(getOwnPropertyDescriptors(object));
46
- }
47
- function createEffect(callback) {
48
- let unSet;
49
- return function (value) {
50
- typeof unSet == "function" && unSet();
51
- unSet = callback.call(this, value);
52
- if (unSet instanceof Promise)
53
- unSet = undefined;
54
- if (unSet && typeof unSet !== "function")
55
- throw Oops$8.BadEffectCallback();
65
+ function mayRetry(fn) {
66
+ const retry = (err) => {
67
+ if (err instanceof Promise)
68
+ return err.then(compute);
69
+ else
70
+ throw err;
56
71
  };
57
- }
58
- function selectRecursive(using, keys) {
59
- const found = new Set();
60
- const spy = {};
61
- for (const key of new Set(keys))
62
- defineProperty(spy, key, {
63
- get() {
64
- found.add(key);
65
- return spy;
66
- }
67
- });
68
- using(spy);
69
- return Array.from(found);
72
+ const compute = () => {
73
+ try {
74
+ const output = fn();
75
+ return output instanceof Promise
76
+ ? output.catch(retry)
77
+ : output;
78
+ }
79
+ catch (err) {
80
+ return retry(err);
81
+ }
82
+ };
83
+ return compute();
70
84
  }
71
85
 
72
- const Lifecycle = {
73
- WILL_RENDER: "willRender",
74
- WILL_UPDATE: "willUpdate",
75
- WILL_MOUNT: "willMount",
76
- WILL_UNMOUNT: "willUnmount",
77
- DID_MOUNT: "didMount"
78
- };
79
- const lifecycleEvents = [
80
- "didCreate",
81
- "willDestroy",
82
- ...values(Lifecycle)
83
- ];
84
- function lifecycle(prefix) {
85
- const type = eventsFor(prefix);
86
- return function useLifecycle(sub, tag) {
87
- const emit = react.useMemo(() => {
88
- const { parent } = sub;
89
- const { subject } = parent;
90
- const id = typeof tag == "function" ? tag(subject) : tag;
91
- return (name) => {
92
- for (const key of [name, type(name)]) {
93
- const handler = subject[key];
94
- if (handler)
95
- handler.call(subject, id);
96
- parent.update(key);
97
- }
98
- };
99
- }, [sub, tag]);
100
- emit(Lifecycle.WILL_RENDER);
101
- emit(sub.active
102
- ? Lifecycle.WILL_UPDATE
103
- : Lifecycle.WILL_MOUNT);
104
- react.useLayoutEffect(() => {
86
+ const Oops$e = issues({
87
+ Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
88
+ });
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
+ }
109
+ };
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
+ }
124
+ }
125
+ };
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 {
105
143
  sub.commit();
106
- emit(Lifecycle.DID_MOUNT);
107
- return () => {
108
- emit(Lifecycle.WILL_UNMOUNT);
109
- sub.release();
110
- };
111
- }, [sub]);
144
+ order.set(refresh, order.size);
145
+ }
146
+ };
147
+ INFO.set(refresh, key);
148
+ return () => {
149
+ if (pending.has(refresh)) {
150
+ pending.delete(refresh);
151
+ refresh();
152
+ }
153
+ const value = sub ? state.get(key) : create();
154
+ if (value === undefined && required)
155
+ throw suspend(self, key);
156
+ return value;
112
157
  };
113
158
  }
114
- function eventsFor(prefix) {
115
- const map = new Map();
116
- for (const name of values(Lifecycle)) {
117
- const alias = prefix + name[0].toUpperCase() + name.slice(1);
118
- lifecycleEvents.push(alias);
119
- map.set(name, alias);
120
- }
121
- return (e) => map.get(e);
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();
122
175
  }
123
176
 
124
- class Controller {
125
- constructor(subject) {
126
- this.subject = subject;
127
- this.state = {};
128
- this.frame = new Set();
129
- this.handles = new Set();
130
- this.waiting = [];
131
- bootstrap(this);
132
- }
133
- get pending() {
134
- return this.frame.size > 0;
135
- }
136
- start() {
137
- getOwnPropertyNames(this.subject)
138
- .forEach(k => this.add(k));
139
- this.emit();
140
- return this;
141
- }
142
- select(using) {
143
- const keys = getOwnPropertyNames(this.state);
144
- return using
145
- ? selectRecursive(using, keys.concat(lifecycleEvents))
146
- : keys;
147
- }
148
- add(key) {
149
- const desc = getOwnPropertyDescriptor(this.subject, key);
150
- if (desc && "value" in desc) {
151
- const { value } = desc;
152
- if (apply(this, key, value))
153
- return;
154
- if (desc.enumerable && typeof value !== "function" || /^[A-Z]/.test(key))
155
- this.manage(key, value);
177
+ const Oops$d = issues({
178
+ BadCallback: () => `Callback for effect-callback may only return a function.`
179
+ });
180
+ function createEffect(model, callback, keys) {
181
+ return control(model, controller => {
182
+ let unSet;
183
+ let busy = false;
184
+ function effect(value) {
185
+ if (typeof unSet == "function")
186
+ unSet();
187
+ unSet = callback.call(this, value);
188
+ if (unSet instanceof Promise)
189
+ unSet = undefined;
190
+ if (unSet && typeof unSet !== "function")
191
+ throw Oops$d.BadCallback();
156
192
  }
157
- }
158
- manage(key, initial, effect) {
159
- const { state, subject } = this;
160
- state[key] = initial;
161
- defineProperty(subject, key, {
162
- enumerable: true,
163
- configurable: true,
164
- get: () => state[key],
165
- set: this.sets(key, effect)
166
- });
167
- }
168
- sets(key, handler) {
169
- const { state, subject } = this;
170
- return (value) => {
171
- if (state[key] == value)
193
+ function invoke() {
194
+ if (busy)
172
195
  return;
173
- if (handler)
174
- if (handler.call(subject, value) === false)
175
- return;
176
- this.update(key, value);
177
- };
178
- }
179
- watch(subset, handler, squash, once) {
180
- const set = keys(this, subset);
181
- const batch = {};
182
- const remove = this.addListener(batch);
183
- const callback = squash
184
- ? handler.bind(this.subject)
185
- : (frame) => {
186
- for (const key of frame)
187
- if (set.includes(key))
188
- handler.call(this.subject, this.state[key], key);
189
- };
190
- const handle = once
191
- ? (k) => { remove(); callback(k); }
192
- : callback;
193
- for (const key of set)
194
- batch[key] = handle;
195
- ensure(this, set);
196
- return remove;
197
- }
198
- addListener(batch) {
199
- this.handles.add(batch);
200
- return () => {
201
- this.handles.delete(batch);
202
- };
203
- }
204
- include(to) {
205
- if (capture(this, to))
196
+ const output = mayRetry(() => {
197
+ effect.call(model, model);
198
+ });
199
+ if (output instanceof Promise) {
200
+ output.finally(() => busy = false);
201
+ busy = true;
202
+ }
203
+ }
204
+ if (Array.isArray(keys)) {
205
+ invoke();
206
+ return controller.addListener(key => {
207
+ if (key === null) {
208
+ if (!keys.length)
209
+ invoke();
210
+ }
211
+ else if (keys.includes(key))
212
+ return invoke;
213
+ });
214
+ }
215
+ const sub = controller.subscribe(() => invoke);
216
+ model = sub.proxy;
217
+ invoke();
218
+ return sub.commit();
219
+ });
220
+ }
221
+ function createValueEffect(callback) {
222
+ let unSet;
223
+ return function (value) {
224
+ if (typeof unSet == "function")
225
+ unSet(value);
226
+ const out = callback.call(this, value, this);
227
+ if (typeof out == "boolean")
228
+ return out;
229
+ if (!out || out instanceof Promise)
206
230
  return;
231
+ if (typeof out == "function")
232
+ unSet = out;
207
233
  else
208
- this.waiting.push(to);
209
- }
210
- update(key, value) {
211
- if (1 in arguments)
212
- this.state[key] = value;
213
- if (this.frame.has(key))
214
- return;
215
- if (!this.frame.size)
216
- setTimeout(() => this.emit(), 0);
217
- this.frame.add(key);
218
- for (const subscription of this.handles)
219
- if (key in subscription)
220
- this.include(subscription[key]);
221
- }
222
- emit() {
223
- flush(this);
224
- const keys = Array.from(this.frame);
225
- const handle = new Set(this.waiting.splice(0));
226
- this.frame.clear();
227
- handle.forEach(cb => {
234
+ throw Oops$d.BadCallback();
235
+ };
236
+ }
237
+
238
+ const Oops$c = issues({
239
+ Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
240
+ KeysExpected: (key) => `Key "${key}" was expected in current update.`,
241
+ StrictUpdate: () => `Expected update but none in progress.`,
242
+ StrictNoUpdate: () => `Update is not expected but one is in progress!`
243
+ });
244
+ function addEventListener(source, arg1, arg2, arg3) {
245
+ if (typeof arg1 == "string")
246
+ arg1 = [arg1];
247
+ return control(source, controller => {
248
+ for (const key of arg1)
228
249
  try {
229
- cb(keys);
250
+ void source[key];
230
251
  }
231
252
  catch (e) { }
253
+ const removeListener = controller.addListener(key => {
254
+ if (!key && !arg1.length)
255
+ arg2.call(source, []);
256
+ if (arg1.includes(key)) {
257
+ if (arg3)
258
+ removeListener();
259
+ return arg2.bind(source);
260
+ }
232
261
  });
233
- }
262
+ return removeListener;
263
+ });
234
264
  }
235
- function keys(from, using) {
236
- if (typeof using == "string")
237
- return [using];
238
- if (typeof using == "object")
239
- return Array.from(using);
240
- return from.select(using);
241
- }
242
-
243
- const Oops$7 = issues({
244
- CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
245
- 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.`
246
- });
247
- const PendingContext = new WeakMap();
248
- const ContextWasUsed = new WeakMap();
249
- const tap = (type, required) => set(function tap(key) {
250
- const { subject } = this;
251
- if ("current" in type)
252
- defineLazy(subject, key, () => type.current);
253
- else if ("current" in subject.constructor)
254
- throw Oops$7.CantAttachGlobal(subject, type.name);
255
- else
256
- getPending(subject).push((context) => {
257
- const remote = context.get(type);
258
- if (!remote && required)
259
- throw Oops$7.AmbientRequired(type.name, subject, key);
260
- define(subject, key, remote);
265
+ function awaitUpdate(source, arg1, arg2) {
266
+ const single = typeof arg1 == "string";
267
+ const keys = typeof arg1 == "string" ? [arg1] :
268
+ typeof arg1 == "object" ? arg1 :
269
+ undefined;
270
+ return new Promise((resolve, reject) => {
271
+ const timeout = (message) => {
272
+ const k = keys ? keys.join(", ") : "any";
273
+ removeListener();
274
+ reject(Oops$c.Timeout(k, message));
275
+ };
276
+ const removeListener = control(source, controller => {
277
+ const pending = controller.frame;
278
+ if (keys === null) {
279
+ if (pending.size)
280
+ reject(Oops$c.StrictNoUpdate());
281
+ else
282
+ resolve(null);
283
+ return;
284
+ }
285
+ if (keys) {
286
+ if (keys.length) {
287
+ if (arg2 === 0 && single && !pending.has(keys[0])) {
288
+ reject(Oops$c.KeysExpected(keys[0]));
289
+ return;
290
+ }
291
+ else
292
+ for (const key of keys)
293
+ try {
294
+ void source[key];
295
+ }
296
+ catch (e) { }
297
+ }
298
+ }
299
+ else if (!pending.size && arg1 === true || arg2 === 0) {
300
+ reject(Oops$c.StrictUpdate());
301
+ return;
302
+ }
303
+ else
304
+ controller.waiting.add(resolve);
305
+ return controller.addListener(key => {
306
+ if (!key) {
307
+ if (keys && !keys.length)
308
+ resolve([]);
309
+ else
310
+ timeout(`lifetime of ${source}`);
311
+ }
312
+ else if (!keys || keys.includes(key)) {
313
+ removeListener();
314
+ return keys => resolve(single ? controller.state.get(key) : keys);
315
+ }
316
+ });
261
317
  });
262
- });
263
- function usePeerContext(subject) {
264
- if (ContextWasUsed.has(subject)) {
265
- if (ContextWasUsed.get(subject))
266
- useLookup();
267
- return;
268
- }
269
- const pending = PendingContext.get(subject);
270
- if (pending) {
271
- const local = useLookup();
272
- for (const init of pending)
273
- init(local);
274
- PendingContext.delete(subject);
275
- }
276
- ContextWasUsed.set(subject, !!pending);
277
- }
278
- function getPending(subject) {
279
- let pending = PendingContext.get(subject);
280
- if (!pending)
281
- PendingContext.set(subject, pending = []);
282
- return pending;
318
+ if (arg2 && typeof arg2 == "number")
319
+ setTimeout(() => timeout(`${arg2}ms`), arg2);
320
+ });
283
321
  }
284
322
 
323
+ const REGISTER$1 = new WeakMap();
285
324
  class Subscriber {
286
325
  constructor(parent, onUpdate) {
326
+ this.parent = parent;
287
327
  this.onUpdate = onUpdate;
288
328
  this.active = false;
289
- this.follows = {};
290
329
  this.dependant = new Set();
291
- if (!(parent instanceof Controller))
292
- parent = manage(parent);
293
- this.parent = parent;
294
- this.proxy = create(parent.subject);
295
- define(this.proxy, LOCAL, this);
296
- for (const key in parent.state)
297
- this.spy(key);
298
- }
299
- spy(key) {
300
- const { proxy, parent } = this;
301
- const intercept = () => {
302
- this.follow(key);
303
- delete proxy[key];
304
- return proxy[key];
305
- };
306
- setAlias(intercept, `tap ${key}`);
307
- defineProperty(proxy, key, {
308
- get: intercept,
309
- set: parent.sets(key),
330
+ this.watch = new Map();
331
+ const proxy = create(parent.subject);
332
+ const reset = () => this.latest = undefined;
333
+ REGISTER$1.set(proxy, this);
334
+ defineProperty(this, "proxy", {
310
335
  configurable: true,
311
- enumerable: true
336
+ get() {
337
+ setTimeout(reset, 0);
338
+ return proxy;
339
+ }
312
340
  });
313
341
  }
314
- follow(key, cb) {
315
- this.follows[key] = cb || this.onUpdate;
342
+ get using() {
343
+ return Array.from(this.watch.keys());
344
+ }
345
+ add(key, value) {
346
+ if (value !== undefined)
347
+ this.watch.set(key, value);
348
+ else if (!this.watch.has(key))
349
+ this.watch.set(key, true);
316
350
  }
317
351
  commit() {
318
- const { dependant, follows, parent } = this;
319
- const onDone = parent.addListener(follows);
352
+ const release = this.parent.addListener(key => {
353
+ if (this.active)
354
+ this.onEvent(key);
355
+ });
320
356
  this.active = true;
321
- dependant.forEach(x => x.commit());
357
+ this.dependant.forEach(x => x.commit());
322
358
  return this.release = () => {
323
- dependant.forEach(x => x.release());
324
- onDone();
359
+ this.dependant.forEach(x => x.release());
360
+ release();
325
361
  };
326
362
  }
363
+ onEvent(key) {
364
+ const { parent, watch } = this;
365
+ let handler = watch.get(key);
366
+ if (typeof handler == "function")
367
+ handler = handler();
368
+ if (handler) {
369
+ const notify = this.onUpdate(key, parent);
370
+ if (notify) {
371
+ parent.waiting.add(update => {
372
+ this.latest = update.filter(k => watch.has(k));
373
+ });
374
+ parent.waiting.add(notify);
375
+ }
376
+ }
377
+ }
378
+ }
379
+ function subscriber(from) {
380
+ return REGISTER$1.get(from);
327
381
  }
328
382
 
329
- const Oops$6 = issues({
330
- HasPropertyUndefined: (control, property) => `${control}.${property} is marked as required for this render.`
383
+ const Oops$b = issues({
384
+ NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
331
385
  });
332
- const useElementLifecycle = lifecycle("element");
333
- const useComponentLifecycle = lifecycle("component");
334
- function use$1(init) {
335
- const [state, update] = react.useState(() => [
336
- init(() => update(state.concat()))
337
- ]);
338
- return state[0];
339
- }
340
- function useLazy(Type, args) {
341
- const instance = react.useMemo(() => Type.create(...args), []);
342
- react.useLayoutEffect(() => () => instance.destroy(), []);
343
- return instance;
344
- }
345
- function useWatcher(target, focus, expected) {
346
- const hook = use$1(refresh => {
347
- const sub = new Subscriber(target, refresh);
348
- if (focus) {
349
- const src = sub.proxy;
350
- const key = keys(sub.parent, focus)[0];
351
- defineProperty(sub, "proxy", {
352
- get() {
353
- if (src[key] === undefined && expected)
354
- throw Oops$6.HasPropertyUndefined(target, key);
355
- return src[key];
386
+ class Model {
387
+ constructor() {
388
+ new Control(this);
389
+ defineProperty(this, "is", { value: this });
390
+ }
391
+ on(arg1, arg2, arg3) {
392
+ if (typeof arg1 == "function")
393
+ return createEffect(this.is, arg1, arg2);
394
+ if (typeof arg2 != "function")
395
+ return awaitUpdate(this.is, arg1, arg2);
396
+ if (arg1)
397
+ return addEventListener(this.is, arg1, arg2, arg3);
398
+ }
399
+ get(arg1, arg2) {
400
+ const { state } = control(this);
401
+ const extract = typeof arg1 == "string"
402
+ ? () => state.get(arg1)
403
+ : () => {
404
+ const output = {};
405
+ for (const key of arg1 || state.keys())
406
+ output[key] = state.get(key);
407
+ return output;
408
+ };
409
+ if (!arg1 || arg2 === undefined)
410
+ return extract();
411
+ if (typeof arg2 == "function")
412
+ return this.on(arg1, () => arg2(extract()));
413
+ const timeout = typeof arg2 == "number" ? arg2 : undefined;
414
+ return this.on(arg1, timeout).then(extract);
415
+ }
416
+ set(arg1, arg2) {
417
+ const controller = control(this);
418
+ const { state } = controller;
419
+ if (typeof arg1 == "object")
420
+ for (const key in arg1) {
421
+ if (arg2 === true || (arg2 ? arg2.includes(key) : state.has(key))) {
422
+ state.set(key, arg1[key]);
423
+ controller.update(key);
356
424
  }
357
- });
425
+ }
426
+ else if (typeof arg1 == "string") {
427
+ controller.update(arg1);
428
+ if (1 in arguments) {
429
+ if (state.has(arg1))
430
+ state.set(arg1, arg2);
431
+ else if (arg1 in this) {
432
+ const method = this[arg1];
433
+ if (typeof method == "function")
434
+ method.call(this, arg2);
435
+ }
436
+ }
358
437
  }
359
- return sub;
360
- });
361
- react.useLayoutEffect(() => hook.commit(), []);
362
- return hook.proxy;
363
- }
364
- function useSubscriber(target, tag) {
365
- const hook = use$1(refresh => new Subscriber(target, refresh));
366
- useElementLifecycle(hook, tag || 0);
367
- return hook.proxy;
438
+ return {
439
+ then: (callback) => {
440
+ if (!callback)
441
+ throw Oops$b.NoChaining();
442
+ controller.waiting.add(callback);
443
+ }
444
+ };
445
+ }
446
+ /**
447
+ * Clean up side effects and mark this instance for garbage-collection.
448
+ */
449
+ end() {
450
+ control(this).clear();
451
+ }
452
+ /**
453
+ * Creates a new instance of this controller.
454
+ *
455
+ * Beyond `new this(...)`, method will activate managed-state.
456
+ *
457
+ * @param args - arguments sent to constructor
458
+ */
459
+ static new(...args) {
460
+ const instance = new this(...args);
461
+ control(instance);
462
+ return instance;
463
+ }
464
+ /**
465
+ * Static equivalent of `x instanceof this`.
466
+ *
467
+ * Will determine if provided class is a subtype of this one.
468
+ */
469
+ static isTypeof(maybe) {
470
+ return (typeof maybe == "function" &&
471
+ maybe.prototype instanceof this);
472
+ }
368
473
  }
369
- function useModel(Type, args, callback) {
370
- const hook = use$1(refresh => {
371
- const instance = new Type(...args);
372
- const sub = new Subscriber(instance, refresh);
373
- instance.on(Lifecycle.WILL_UNMOUNT, () => {
374
- instance.destroy();
375
- });
376
- if (callback)
377
- callback(instance);
378
- return sub;
379
- });
380
- usePeerContext(hook.parent.subject);
381
- useComponentLifecycle(hook);
382
- return hook.proxy;
383
- }
474
+ defineProperty(Model.prototype, "toString", {
475
+ value() {
476
+ return this.constructor.name;
477
+ }
478
+ });
384
479
 
385
- class Lookup {
386
- constructor() {
387
- this.table = new Map();
480
+ const REGISTER = new WeakMap();
481
+ const PENDING = new Map();
482
+ class Control {
483
+ constructor(subject) {
484
+ this.subject = subject;
485
+ this.frame = new Set();
486
+ this.waiting = new Set();
487
+ this.followers = new Set();
488
+ REGISTER.set(subject, this);
388
489
  }
389
- get local() {
390
- return getOwnPropertySymbols(this).map((symbol) => this[symbol]);
490
+ subscribe(callback) {
491
+ return new Subscriber(this, callback);
391
492
  }
392
- key(T) {
393
- let key = this.table.get(T);
394
- if (!key) {
395
- key = Symbol(T.name);
396
- this.table.set(T, key);
493
+ watch(key) {
494
+ const { subject, state } = this;
495
+ const { value } = getOwnPropertyDescriptor(subject, key);
496
+ if (typeof value == "function")
497
+ return;
498
+ if (typeof value == "symbol") {
499
+ const instruction = PENDING.get(value);
500
+ if (instruction) {
501
+ delete subject[key];
502
+ PENDING.delete(value);
503
+ instruction.call(this, key, this);
504
+ }
505
+ return;
397
506
  }
398
- return key;
507
+ state.set(key, value);
508
+ if (value instanceof Model) {
509
+ setRecursive(this, key, value);
510
+ return;
511
+ }
512
+ defineProperty(subject, key, {
513
+ enumerable: false,
514
+ set: this.ref(key),
515
+ get() {
516
+ const sub = subscriber(this);
517
+ if (sub)
518
+ sub.add(key);
519
+ return state.get(key);
520
+ }
521
+ });
399
522
  }
400
- get(T) {
401
- return this[this.key(T)];
523
+ addListener(listener) {
524
+ this.followers.add(listener);
525
+ return () => {
526
+ this.followers.delete(listener);
527
+ };
402
528
  }
403
- push(I) {
404
- const next = create(this);
405
- if (I instanceof Model || typeof I == "function")
406
- next.register(I);
407
- else
408
- for (const i of values(I))
409
- next.register(i);
410
- return next;
529
+ ref(key, handler) {
530
+ const { subject, state } = this;
531
+ return (value) => {
532
+ if (state.get(key) == value)
533
+ return;
534
+ if (handler)
535
+ switch (handler.call(subject, value)) {
536
+ case true:
537
+ this.update(key);
538
+ case false:
539
+ return;
540
+ }
541
+ state.set(key, value);
542
+ this.update(key);
543
+ };
411
544
  }
412
- register(I) {
413
- let writable = true;
414
- let T;
415
- if (I instanceof Model) {
416
- T = I.constructor;
417
- writable = false;
418
- }
419
- else {
420
- T = I;
421
- I = I.create();
545
+ update(key) {
546
+ const { followers, frame, waiting } = this;
547
+ if (frame.has(key))
548
+ return;
549
+ else if (!frame.size)
550
+ setTimeout(() => {
551
+ flush(this);
552
+ const keys = this.latest = Array.from(frame);
553
+ setTimeout(() => this.latest = undefined, 0);
554
+ frame.clear();
555
+ for (const notify of waiting)
556
+ try {
557
+ waiting.delete(notify);
558
+ notify(keys);
559
+ }
560
+ catch (err) {
561
+ console.error(err);
562
+ }
563
+ }, 0);
564
+ frame.add(key);
565
+ for (const callback of followers) {
566
+ const event = callback(key, this);
567
+ if (typeof event == "function")
568
+ waiting.add(event);
422
569
  }
423
- do {
424
- defineProperty(this, this.key(T), {
425
- value: I,
426
- writable
427
- });
428
- } while (T = T.inherits);
429
- return I;
430
570
  }
431
- pop() {
432
- for (const key of getOwnPropertySymbols(this)) {
433
- const entry = getOwnPropertyDescriptor(this, key);
434
- if (entry.writable)
435
- entry.value.destroy();
436
- }
571
+ clear() {
572
+ const listeners = [...this.followers];
573
+ this.followers.clear();
574
+ listeners.forEach(x => x(null, this));
437
575
  }
438
- }
439
-
440
- const Oops$5 = issues({
441
- NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`,
442
- NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
443
- BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
444
- });
445
- const LookupContext = react.createContext(new Lookup());
446
- const useLookup = () => react.useContext(LookupContext);
447
- function useFromContext(Type, strict) {
448
- const instance = useLookup().get(Type);
449
- if (!instance && strict)
450
- throw Oops$5.NothingInContext(Type.name);
451
- return instance;
452
- }
453
- function Consumer(props) {
454
- const { get, has, children, of: Control } = props;
455
- if (typeof children == "function")
456
- return children(Control.tap());
457
- const callback = has || get;
458
- if (typeof callback == "function")
459
- callback(Control.get(!!has));
460
- else
461
- throw Oops$5.BadConsumerProps();
462
- return null;
463
- }
464
- function useNewContext(from, inject) {
465
- return react.useMemo(() => {
466
- if (!inject)
467
- throw Oops$5.NoProviderType();
468
- const context = from.push(inject);
469
- for (const instance of context.local)
470
- for (const apply of getPending(instance))
471
- apply(context);
472
- return context;
473
- }, []);
474
- }
475
- function useAppliedProps(within, props) {
476
- const update = react.useMemo(() => {
477
- const targets = within.local;
478
- return function integrate(props) {
479
- for (const [key, value] of entries(props))
480
- if (key != "of" && key != "children")
481
- for (const into of targets)
482
- if (key in into)
483
- into[key] = value;
484
- };
485
- }, []);
486
- update(props);
487
576
  }
488
- function RenderFunction(props) {
489
- const hook = use$1(refresh => {
490
- const targets = props.context.local;
491
- if (targets.length == 1)
492
- return new Subscriber(targets[0], refresh);
493
- return {};
494
- });
495
- if (hook.commit)
496
- react.useLayoutEffect(() => hook.commit(), []);
497
- return props.render(hook.proxy);
577
+ function controller(from) {
578
+ if ("is" in from)
579
+ from = from.is;
580
+ return REGISTER.get(from);
498
581
  }
499
- function Provider(props) {
500
- const render = props.children;
501
- const current = useLookup();
502
- const context = useNewContext(current, props.of);
503
- useAppliedProps(context, props);
504
- react.useLayoutEffect(() => () => context.pop(), []);
505
- return react.createElement(LookupContext.Provider, { value: context }, typeof render == "function"
506
- ? react.createElement(RenderFunction, { context, render })
507
- : render);
582
+ function control(subject, cb) {
583
+ const control = controller(subject) || new Control(subject);
584
+ if (!control.state) {
585
+ const { waiting } = control;
586
+ if (cb) {
587
+ let callback;
588
+ waiting.add(() => {
589
+ callback = cb(control);
590
+ });
591
+ return () => {
592
+ if (callback)
593
+ callback();
594
+ };
595
+ }
596
+ control.state = new Map();
597
+ for (const key in subject)
598
+ control.watch(key);
599
+ control.waiting = new Set();
600
+ for (const cb of waiting)
601
+ cb([]);
602
+ }
603
+ return cb ? cb(control) : control;
508
604
  }
509
605
 
510
- const Oops$4 = issues({
511
- StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`
606
+ const Parent = new WeakMap();
607
+ const Oops$a = issues({
608
+ BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
512
609
  });
513
- const CONTROL = Symbol("control");
514
- const LOCAL = Symbol("local");
515
- const STATE = Symbol("state");
516
- function manage(src) {
517
- return src[CONTROL];
518
- }
519
- class Model {
520
- constructor() {
521
- const control = new Controller(this);
522
- define(this, "get", this);
523
- define(this, "set", this);
524
- defer(control, "on");
525
- defer(control, "effect");
526
- defineLazy(this, CONTROL, () => {
527
- delete this.on;
528
- delete this.effect;
529
- this[STATE] = control.state;
530
- control.start();
531
- if (this.didCreate)
532
- this.didCreate();
533
- return control;
610
+ function getRecursive(key, from) {
611
+ const context = new WeakMap();
612
+ const { state } = from;
613
+ return (local) => {
614
+ if (!local)
615
+ return state.get(key);
616
+ if (!context.has(local)) {
617
+ let reset;
618
+ const init = () => {
619
+ if (reset)
620
+ reset();
621
+ const value = state.get(key);
622
+ if (value && controller(value)) {
623
+ const child = control(value).subscribe(local.onUpdate);
624
+ if (local.active)
625
+ child.commit();
626
+ local.dependant.add(child);
627
+ context.set(local, child.proxy);
628
+ reset = () => {
629
+ child.release();
630
+ local.dependant.delete(child);
631
+ context.set(local, undefined);
632
+ reset = undefined;
633
+ };
634
+ }
635
+ return true;
636
+ };
637
+ local.add(key, init);
638
+ init();
639
+ }
640
+ return context.get(local);
641
+ };
642
+ }
643
+ function setRecursive(controller, key, initial) {
644
+ const { state, subject } = controller;
645
+ const Type = initial.constructor;
646
+ let get;
647
+ const onUpdate = (next) => {
648
+ state.set(key, next);
649
+ if (!(next instanceof Type))
650
+ throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
651
+ get = getRecursive(key, controller);
652
+ Parent.set(next, subject);
653
+ control(next);
654
+ return true;
655
+ };
656
+ onUpdate(initial);
657
+ defineProperty(subject, key, {
658
+ set: controller.ref(key, onUpdate),
659
+ get() {
660
+ const local = subscriber(this);
661
+ if (local)
662
+ local.add(key);
663
+ return get(local);
664
+ }
665
+ });
666
+ }
667
+
668
+ /**
669
+ * Run instruction as controller sets itself up.
670
+ * This will specialize the behavior of a given property.
671
+ */
672
+ function add(instruction, label) {
673
+ const name = label || instruction.name || "pending";
674
+ const placeholder = Symbol(`${name} instruction`);
675
+ function setup(key) {
676
+ const { subject, state } = this;
677
+ let output = instruction.call(this, key, this);
678
+ if (typeof output == "function")
679
+ output = { get: output };
680
+ if (typeof output != "object")
681
+ return;
682
+ if ("explicit" in output && output.explicit) {
683
+ defineProperty(subject, key, output);
684
+ return false;
685
+ }
686
+ let { get: onGet, set: onSet, suspend: shouldSuspend } = output;
687
+ if ("value" in output)
688
+ state.set(key, output.value);
689
+ if ("recursive" in output && output.recursive)
690
+ onGet = getRecursive(key, this);
691
+ if ("destroy" in output) {
692
+ const { destroy } = output;
693
+ if (destroy)
694
+ this.addListener((key) => {
695
+ if (key == null)
696
+ destroy();
697
+ });
698
+ }
699
+ const control = this;
700
+ defineProperty(subject, key, {
701
+ enumerable: output.enumerable,
702
+ set: onSet === false
703
+ ? undefined
704
+ : this.ref(key, onSet),
705
+ get() {
706
+ if (!state.has(key) && shouldSuspend)
707
+ throw suspend(control, key);
708
+ const local = subscriber(this);
709
+ if (local)
710
+ local.add(key);
711
+ return onGet
712
+ ? onGet(local)
713
+ : state.get(key);
714
+ }
534
715
  });
535
716
  }
536
- tap(path, expect) {
537
- return useWatcher(this, path, expect);
538
- }
539
- tag(id) {
540
- return useSubscriber(this, id);
541
- }
542
- on(select, does, squash, once) {
543
- return manage(this).watch(select, does, squash, once);
717
+ PENDING.set(placeholder, setup);
718
+ return placeholder;
719
+ }
720
+
721
+ /*! *****************************************************************************
722
+ Copyright (c) Microsoft Corporation.
723
+
724
+ Permission to use, copy, modify, and/or distribute this software for any
725
+ purpose with or without fee is hereby granted.
726
+
727
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
728
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
729
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
730
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
731
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
732
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
733
+ PERFORMANCE OF THIS SOFTWARE.
734
+ ***************************************************************************** */
735
+
736
+ function __awaiter(thisArg, _arguments, P, generator) {
737
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
738
+ return new (P || (P = Promise))(function (resolve, reject) {
739
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
740
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
741
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
742
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
743
+ });
744
+ }
745
+
746
+ const Oops$9 = issues({
747
+ DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
748
+ });
749
+ function run(task) {
750
+ return add(function run(key) {
751
+ let pending = false;
752
+ const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
753
+ if (pending)
754
+ return Promise.reject(Oops$9.DuplicatePending(key));
755
+ pending = true;
756
+ this.update(key);
757
+ try {
758
+ return yield mayRetry(() => (task.apply(this.subject, args)));
759
+ }
760
+ finally {
761
+ pending = false;
762
+ this.update(key);
763
+ }
764
+ });
765
+ this.state.set(key, undefined);
766
+ defineProperty(invoke, "active", {
767
+ get: () => pending
768
+ });
769
+ return {
770
+ value: invoke,
771
+ set: false
772
+ };
773
+ });
774
+ }
775
+
776
+ const Oops$8 = issues({
777
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
778
+ });
779
+ function factoryMode(self, value, key, required) {
780
+ const { subject, state } = self;
781
+ let pending;
782
+ let error;
783
+ if (value instanceof Promise) {
784
+ state.set(key, undefined);
785
+ pending = value
786
+ .catch(err => error = err)
787
+ .then(val => {
788
+ state.set(key, val);
789
+ return val;
790
+ })
791
+ .finally(() => {
792
+ pending = undefined;
793
+ self.update(key);
794
+ });
544
795
  }
545
- once(select, does, squash) {
546
- if (does)
547
- return this.on(select, does, squash, true);
796
+ else
797
+ state.set(key, value);
798
+ const suspend = () => {
799
+ if (required === false)
800
+ return undefined;
801
+ const issue = Oops$8.NotReady(subject, key);
802
+ assign(pending, {
803
+ message: issue.message,
804
+ stack: issue.stack
805
+ });
806
+ throw pending;
807
+ };
808
+ return () => {
809
+ if (error)
810
+ throw error;
811
+ if (pending)
812
+ return suspend();
813
+ if (state.has(key))
814
+ return state.get(key);
815
+ };
816
+ }
817
+
818
+ const Oops$7 = issues({
819
+ PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
820
+ ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
821
+ Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
822
+ });
823
+ function get(arg0, arg1, arg2) {
824
+ return add(function get(key) {
825
+ const { subject } = this;
826
+ const computeRequired = arg1 === true || arg2 === true;
827
+ const factoryRequired = arg1 !== false && arg2 !== false;
828
+ let getter;
829
+ // Easy mistake, using a peer, will always be unresolved.
830
+ if (typeof arg0 == "symbol")
831
+ throw Oops$7.PeerNotAllowed(subject, key);
832
+ // if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
833
+ // throw Oops.BadSource(subject, key, arg0);
834
+ this.state.set(key, undefined);
835
+ const init = () => {
836
+ let source = this;
837
+ let setter;
838
+ if (typeof arg0 == "function") {
839
+ let result = mayRetry(arg0.bind(subject, key, subject));
840
+ if (typeof result == "function")
841
+ setter = result;
842
+ else {
843
+ getter = factoryMode(this, result, key, factoryRequired);
844
+ return;
845
+ }
846
+ }
847
+ else if (arg0 instanceof Promise) {
848
+ getter = factoryMode(this, arg0, key, factoryRequired);
849
+ return;
850
+ }
851
+ else if (typeof arg1 == "function") {
852
+ // replace source controller in-case it is different
853
+ source = control(arg0);
854
+ setter = arg1;
855
+ }
856
+ else
857
+ throw new Error(`Factory argument cannot be ${arg1}`);
858
+ getter = computeMode(this, source, setter, key, computeRequired);
859
+ };
860
+ if (typeof arg0 == "function" && computeRequired)
861
+ try {
862
+ init();
863
+ }
864
+ catch (err) {
865
+ Oops$7.ComputeFailed(subject, key).warn();
866
+ throw err;
867
+ }
868
+ return () => {
869
+ if (!getter)
870
+ init();
871
+ return getter();
872
+ };
873
+ });
874
+ }
875
+
876
+ function ref(arg, mapper) {
877
+ return add(function ref(key) {
878
+ let value = {};
879
+ this.state.set(key, undefined);
880
+ if (typeof arg != "object")
881
+ value = createRef(this, key, arg);
548
882
  else
549
- return new Promise(resolve => {
550
- this.on(select, resolve, true, true);
883
+ control(arg).state.forEach((_val, key) => {
884
+ defineProperty(value, key, mapper ? {
885
+ configurable: true,
886
+ get() {
887
+ const out = mapper(key);
888
+ defineProperty(value, key, { value: out });
889
+ return out;
890
+ }
891
+ } : {
892
+ value: createRef(this, key)
893
+ });
894
+ });
895
+ return { value, explicit: true };
896
+ });
897
+ }
898
+ function createRef(src, key, cb) {
899
+ const refObjectFunction = src.ref(key, cb && createValueEffect(cb));
900
+ defineProperty(refObjectFunction, "current", {
901
+ set: refObjectFunction,
902
+ get: () => src.state.get(key)
903
+ });
904
+ return refObjectFunction;
905
+ }
906
+
907
+ function set(value, argument) {
908
+ if (!(1 in arguments)) {
909
+ argument = value;
910
+ value = undefined;
911
+ }
912
+ return add(function set(key) {
913
+ if (value !== undefined)
914
+ this.state.set(key, value);
915
+ return {
916
+ suspend: true,
917
+ set: typeof argument == "function"
918
+ ? createValueEffect(argument)
919
+ : undefined
920
+ };
921
+ });
922
+ }
923
+
924
+ const ANY = Symbol("any");
925
+ function keyed(control, property, initial) {
926
+ const init = createProxy(emit, watch);
927
+ const frozen = new Set();
928
+ const context = new Map();
929
+ const users = new Map();
930
+ const watched = new WeakMap();
931
+ const update = new Set();
932
+ let managed = init(initial);
933
+ function watch(on, key) {
934
+ const include = watched.get(on);
935
+ if (include)
936
+ include.add(key);
937
+ }
938
+ function emit(key) {
939
+ control.update(property);
940
+ control.waiting.add(() => frozen.clear());
941
+ update.forEach(notify => notify(key));
942
+ }
943
+ function subscribe(local) {
944
+ const proxy = create(managed);
945
+ let watch = users.get(local);
946
+ if (!watch) {
947
+ const using = watch = new Set();
948
+ users.set(local, using);
949
+ function onEvent(key) {
950
+ if (frozen.has(local))
951
+ return;
952
+ if (key === ANY || using.has(key) || using.has(ANY)) {
953
+ const refresh = local.onUpdate(property, control);
954
+ if (refresh) {
955
+ frozen.add(local);
956
+ refresh();
957
+ }
958
+ }
959
+ }
960
+ local.add(property, false);
961
+ local.dependant.add({
962
+ commit() {
963
+ if (using.size === 0)
964
+ using.add(ANY);
965
+ update.add(onEvent);
966
+ },
967
+ release() {
968
+ update.delete(onEvent);
969
+ }
551
970
  });
552
- }
553
- effect(callback, select) {
554
- const control = manage(this);
555
- let target = this;
556
- const effect = createEffect(callback);
557
- const invoke = () => effect.call(target, target);
558
- if (select) {
559
- invoke();
560
- return this.on(select, invoke, true);
561
971
  }
562
- else {
563
- const sub = new Subscriber(control, invoke);
564
- target = sub.proxy;
565
- invoke();
566
- return sub.commit();
567
- }
568
- }
569
- import(from, subset) {
570
- for (const key of keys(manage(this), subset))
571
- if (key in from)
572
- this[key] = from[key];
573
- }
574
- export(subset) {
575
- const control = manage(this);
576
- const output = {};
577
- for (const key of keys(control, subset))
578
- output[key] = control.state[key];
579
- return output;
580
- }
581
- update(arg) {
582
- const control = manage(this);
583
- if (typeof arg == "boolean") {
584
- if (!control.pending === arg)
585
- return Promise.reject(Oops$4.StrictUpdate(arg));
586
- }
587
- else if (arg)
588
- for (const key of keys(control, arg))
589
- control.update(key);
590
- if (control.pending)
591
- return new Promise(cb => control.include(cb));
592
- return Promise.resolve(false);
593
- }
594
- destroy() {
595
- if (this.willDestroy)
596
- this.willDestroy();
597
- }
598
- toString() {
599
- return this.constructor.name;
972
+ watched.set(proxy, watch);
973
+ context.set(local, proxy);
974
+ return proxy;
600
975
  }
601
- static create(...args) {
602
- const instance = new this(...args);
603
- manage(instance);
604
- return instance;
605
- }
606
- static use(...args) {
607
- return useModel(this, args);
608
- }
609
- static uses(props, only) {
610
- return useModel(this, [], instance => {
611
- instance.import(props, only);
976
+ return {
977
+ value: initial,
978
+ get(local) {
979
+ return local ?
980
+ context.get(local) || subscribe(local) :
981
+ managed;
982
+ },
983
+ set(next) {
984
+ control.state.set(property, next);
985
+ managed = init(next);
986
+ context.clear();
987
+ emit(ANY);
988
+ },
989
+ destroy() {
990
+ update.clear();
991
+ context.clear();
992
+ }
993
+ };
994
+ }
995
+ function createProxy(emit, watch) {
996
+ return (from) => {
997
+ const proxy = create(from);
998
+ assign(proxy, {
999
+ from,
1000
+ delete(key) {
1001
+ // TODO: this commit's fix needs tests.
1002
+ // Was not cause by coverage.
1003
+ const out = from.delete(key);
1004
+ emit(key);
1005
+ return out;
1006
+ },
1007
+ clear() {
1008
+ from.clear();
1009
+ emit(ANY);
1010
+ },
1011
+ has(key) {
1012
+ watch(this, key);
1013
+ return from.has(key);
1014
+ },
1015
+ keys() {
1016
+ watch(this, ANY);
1017
+ return from.keys();
1018
+ },
1019
+ values() {
1020
+ watch(this, ANY);
1021
+ return from.values();
1022
+ },
1023
+ entries() {
1024
+ watch(this, ANY);
1025
+ return from.entries();
1026
+ },
1027
+ forEach(callbackfn, thisArg) {
1028
+ const acc = [];
1029
+ from.forEach((a, b, c) => {
1030
+ const result = callbackfn.call(thisArg, a, b, c);
1031
+ if (result !== undefined)
1032
+ acc.push(result);
1033
+ });
1034
+ watch(this, ANY);
1035
+ return acc;
1036
+ },
1037
+ [Symbol.iterator]() {
1038
+ watch(this, ANY);
1039
+ return from[Symbol.iterator]();
1040
+ },
1041
+ }, from instanceof Set
1042
+ ? {
1043
+ add(key) {
1044
+ from.add(key);
1045
+ emit(key);
1046
+ return this;
1047
+ }
1048
+ }
1049
+ : {
1050
+ get(key) {
1051
+ watch(this, ANY);
1052
+ return from.get(key);
1053
+ },
1054
+ set(key, value) {
1055
+ from.set(key, value);
1056
+ emit(key);
1057
+ return this;
1058
+ }
1059
+ });
1060
+ defineProperty(proxy, "size", {
1061
+ get() {
1062
+ watch(this, ANY);
1063
+ return from.size;
1064
+ }
612
1065
  });
1066
+ return proxy;
1067
+ };
1068
+ }
1069
+
1070
+ const Oops$6 = issues({
1071
+ BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
1072
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
1073
+ });
1074
+ function use$1(input, argument) {
1075
+ return add(function use(key) {
1076
+ const { state, subject } = this;
1077
+ const required = argument !== false;
1078
+ let pending;
1079
+ let error;
1080
+ let get = (_local) => state.get(key);
1081
+ if (typeof input === "function") {
1082
+ if ("prototype" in input && input === input.prototype.constructor)
1083
+ input = new input();
1084
+ }
1085
+ else if (input && typeof input !== "object")
1086
+ throw Oops$6.BadArgument(typeof input);
1087
+ if (input instanceof Map || input instanceof Set)
1088
+ return keyed(this, key, input);
1089
+ const onUpdate = (next) => {
1090
+ state.set(key, next);
1091
+ if (next) {
1092
+ get = getRecursive(key, this);
1093
+ Parent.set(next, subject);
1094
+ control(next);
1095
+ }
1096
+ if (typeof argument == "function")
1097
+ argument(next);
1098
+ return true;
1099
+ };
1100
+ const suspend = () => {
1101
+ if (required === false)
1102
+ return;
1103
+ const issue = Oops$6.NotReady(subject, key);
1104
+ assign(pending, {
1105
+ message: issue.message,
1106
+ stack: issue.stack
1107
+ });
1108
+ throw pending;
1109
+ };
1110
+ const initialize = () => {
1111
+ const output = typeof input == "function" ?
1112
+ mayRetry(() => input.call(subject, subject)) :
1113
+ input;
1114
+ if (output instanceof Promise) {
1115
+ pending = output
1116
+ .catch(err => error = err)
1117
+ .then(val => {
1118
+ onUpdate(val);
1119
+ return val;
1120
+ })
1121
+ .finally(() => {
1122
+ pending = undefined;
1123
+ this.update(key);
1124
+ });
1125
+ return;
1126
+ }
1127
+ onUpdate(output);
1128
+ };
1129
+ if (input !== undefined && required)
1130
+ initialize();
1131
+ return {
1132
+ set: onUpdate,
1133
+ get(local) {
1134
+ if (pending)
1135
+ return suspend();
1136
+ if (error)
1137
+ throw error;
1138
+ if (!state.has(key))
1139
+ initialize();
1140
+ if (pending)
1141
+ return suspend();
1142
+ return get(local);
1143
+ }
1144
+ };
1145
+ });
1146
+ }
1147
+
1148
+ const Oops$5 = issues({
1149
+ Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
1150
+ Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
1151
+ });
1152
+ function has(Type, required) {
1153
+ return add(function parent() {
1154
+ const child = this.subject;
1155
+ const value = Parent.get(child);
1156
+ const expected = Type.name;
1157
+ if (!value) {
1158
+ if (required !== false)
1159
+ throw Oops$5.Required(expected, child);
1160
+ }
1161
+ else if (!(value instanceof Type))
1162
+ throw Oops$5.Unexpected(expected, child, value);
1163
+ return { value };
1164
+ });
1165
+ }
1166
+
1167
+ const Oops$4 = issues({
1168
+ NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
1169
+ });
1170
+ class Lookup {
1171
+ constructor() {
1172
+ this.table = new Map();
613
1173
  }
614
- static using(props, only) {
615
- const instance = useModel(this, []);
616
- instance.import(props, only);
617
- return instance;
618
- }
619
- static new(...args) {
620
- return useLazy(this, args);
621
- }
622
- static get(key) {
623
- const instance = this.find(!!key);
624
- return (typeof key == "function" ?
625
- key(instance) :
626
- typeof key == "string" ?
627
- instance[key] :
628
- instance);
629
- }
630
- static tap(key, expect) {
631
- return useWatcher(this.find(true), key, expect);
632
- }
633
- static tag(id) {
634
- return useSubscriber(this.find(true), id);
1174
+ key(T) {
1175
+ let key = this.table.get(T);
1176
+ if (!key) {
1177
+ key = Symbol(T.name);
1178
+ this.table.set(T, key);
1179
+ }
1180
+ return key;
635
1181
  }
636
- static meta(path) {
637
- return useWatcher(this, path);
1182
+ get(Type) {
1183
+ return this[this.key(Type)];
1184
+ }
1185
+ has(key, input, callback) {
1186
+ if (MVC.isTypeof(input) && input.global)
1187
+ return input.new();
1188
+ if (this.register.get(key) === input)
1189
+ return typeof input == "object"
1190
+ ? input
1191
+ : this.get(input);
1192
+ const instance = this.add(input);
1193
+ this.register.set(key, input);
1194
+ if (callback)
1195
+ callback(instance);
1196
+ return instance;
638
1197
  }
639
- static find(strict) {
640
- return useFromContext(this, strict);
1198
+ add(input) {
1199
+ let writable = true;
1200
+ let T;
1201
+ let I;
1202
+ if (typeof input == "function") {
1203
+ T = input;
1204
+ I = new input();
1205
+ }
1206
+ else {
1207
+ I = input;
1208
+ T = I.constructor;
1209
+ writable = false;
1210
+ }
1211
+ do {
1212
+ const key = this.key(T);
1213
+ defineProperty(this, key, {
1214
+ configurable: true,
1215
+ value: this.hasOwnProperty(key) ? null : I,
1216
+ writable
1217
+ });
1218
+ T = getPrototypeOf(T);
1219
+ } while (T !== Model);
1220
+ return I;
641
1221
  }
642
- static isTypeof(maybe) {
643
- return (typeof maybe == "function" &&
644
- maybe.prototype instanceof this);
1222
+ push() {
1223
+ const next = create(this);
1224
+ next.register = new Map();
1225
+ return next;
645
1226
  }
646
- static get inherits() {
647
- const I = getPrototypeOf(this);
648
- if (I !== Model)
649
- return I;
1227
+ pop() {
1228
+ const items = new Set();
1229
+ for (const key of getOwnPropertySymbols(this)) {
1230
+ const entry = getOwnPropertyDescriptor(this, key);
1231
+ if (entry.writable && entry.value)
1232
+ items.add(entry.value);
1233
+ }
1234
+ for (const model of items)
1235
+ model.end();
650
1236
  }
651
1237
  }
652
- Model.STATE = STATE;
653
- Model.CONTROL = CONTROL;
654
- Model.LOCAL = LOCAL;
655
- defineLazy(Model, CONTROL, function () {
656
- return new Controller(this).start();
657
- });
658
- function defer(on, method) {
659
- const { subject, waiting } = on;
660
- const real = subject[method];
661
- subject[method] = (...args) => {
662
- let done;
663
- waiting.push(() => {
664
- done = real.apply(subject, args);
665
- });
666
- return () => done();
667
- };
1238
+ const LookupContext = React__default["default"].createContext(new Lookup());
1239
+ const useLookup = () => React__default["default"].useContext(LookupContext);
1240
+ function useContext(Type, required) {
1241
+ const instance = useLookup().get(Type);
1242
+ if (!instance && required !== false)
1243
+ throw Oops$4.NotFound(Type.name);
1244
+ return instance;
668
1245
  }
669
1246
 
670
1247
  const Oops$3 = issues({
671
- ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
672
- ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
1248
+ NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
1249
+ 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.`
673
1250
  });
674
- const ComputedInit = new WeakSet();
675
- const ComputedInfo = new WeakMap();
676
- const ComputedFor = new WeakMap();
677
- const ComputedKeys = new WeakMap();
678
- function bootstrap(on) {
679
- const defined = new Map();
680
- let scan = on.subject;
681
- ComputedFor.set(on, defined);
682
- while (scan !== Model && scan.constructor !== Model) {
683
- for (let [key, { get, set }] of entriesIn(scan))
684
- if (get && !defined.has(key))
685
- defined.set(key, prepare(on, key, get, set));
686
- scan = getPrototypeOf(scan);
1251
+ const Pending = new WeakMap();
1252
+ const Applied = new WeakMap();
1253
+ function tap(type, argument) {
1254
+ return add(function tap(key) {
1255
+ if (MVC.isTypeof(type) && type.global)
1256
+ return {
1257
+ recursive: true,
1258
+ value: type.get()
1259
+ };
1260
+ const { subject } = this;
1261
+ if (subject.constructor.global)
1262
+ throw Oops$3.NotAllowed(subject, type.name);
1263
+ getPending(subject).push(context => {
1264
+ let instance = context.get(type);
1265
+ if (typeof argument == "function") {
1266
+ if (argument(instance) === false)
1267
+ instance = undefined;
1268
+ }
1269
+ else if (!instance && argument)
1270
+ throw Oops$3.AmbientRequired(type.name, subject, key);
1271
+ this.state.set(key, instance);
1272
+ this.update(key);
1273
+ });
1274
+ return {
1275
+ recursive: true,
1276
+ suspend: true
1277
+ };
1278
+ });
1279
+ }
1280
+ function usePeerContext(subject) {
1281
+ if (Applied.has(subject)) {
1282
+ if (Applied.get(subject))
1283
+ useLookup();
1284
+ return;
1285
+ }
1286
+ const pending = Pending.get(subject);
1287
+ if (pending) {
1288
+ const local = useLookup();
1289
+ for (const init of pending)
1290
+ init(local);
1291
+ Pending.delete(subject);
687
1292
  }
1293
+ Applied.set(subject, !!pending);
688
1294
  }
689
- function prepare(on, key, getter, setter) {
690
- const { state, subject } = on;
691
- const info = {
692
- key, parent: on, priority: 1
693
- };
694
- let sub;
695
- function compute(initial) {
696
- try {
697
- return getter.call(sub.proxy, sub.proxy);
698
- }
699
- catch (err) {
700
- Oops$3.ComputeFailed(subject, key, !!initial).warn();
701
- throw err;
702
- }
1295
+ function getPending(subject) {
1296
+ let pending = Pending.get(subject);
1297
+ if (!pending)
1298
+ Pending.set(subject, pending = []);
1299
+ return pending;
1300
+ }
1301
+
1302
+ function useNew(source, arg1, arg2) {
1303
+ const instance = React__default["default"].useMemo(() => {
1304
+ const callback = arg2 || arg1;
1305
+ const instance = Model.isTypeof(source)
1306
+ ? new source()
1307
+ : source();
1308
+ control(instance);
1309
+ if (typeof callback == "function")
1310
+ callback(instance);
1311
+ return instance;
1312
+ }, []);
1313
+ usePeerContext(instance);
1314
+ if (Array.isArray(arg1)) {
1315
+ const update = React.useState(0)[1];
1316
+ React__default["default"].useLayoutEffect(() => {
1317
+ if (arg1.length && instance instanceof Model)
1318
+ instance.on(arg1, () => update(x => x + 1));
1319
+ return () => {
1320
+ if (Model.isTypeof(source))
1321
+ instance.end();
1322
+ };
1323
+ }, []);
1324
+ return instance;
703
1325
  }
704
- function update() {
705
- let value;
706
- try {
707
- value = compute(false);
708
- }
709
- catch (e) {
710
- console.error(e);
1326
+ const state = React__default["default"].useState(0);
1327
+ const local = React__default["default"].useMemo(() => {
1328
+ const refresh = state[1].bind(null, x => x + 1);
1329
+ return control(instance).subscribe(() => refresh);
1330
+ }, []);
1331
+ if (typeof arg1 == "object") {
1332
+ const { waiting, subject } = local.parent;
1333
+ let keys = arg2;
1334
+ local.active = false;
1335
+ if (!keys)
1336
+ keys = getOwnPropertyNames(subject);
1337
+ for (const key of keys)
1338
+ if (key in arg1)
1339
+ subject[key] = arg1[key];
1340
+ waiting.add(() => local.active = true);
1341
+ }
1342
+ React__default["default"].useLayoutEffect(() => {
1343
+ local.commit();
1344
+ return () => {
1345
+ local.release();
1346
+ if (Model.isTypeof(source))
1347
+ instance.end();
1348
+ };
1349
+ }, []);
1350
+ return local.proxy;
1351
+ }
1352
+
1353
+ function use(init, deps) {
1354
+ const state = React__default["default"].useState(0);
1355
+ return React__default["default"].useMemo(() => {
1356
+ return init(state[1].bind(null, x => x + 1));
1357
+ }, deps);
1358
+ }
1359
+
1360
+ function useCompute(source, compute, suspend) {
1361
+ const deps = [uid(source)];
1362
+ const local = use(refresh => {
1363
+ const sub = control(source).subscribe(() => update);
1364
+ const spy = sub.proxy;
1365
+ let make = () => compute.call(spy, spy, forceUpdate);
1366
+ function forceUpdate(passthru) {
1367
+ if (make)
1368
+ reassign(make());
1369
+ else
1370
+ refresh();
1371
+ if (passthru)
1372
+ return passthru.finally(refresh);
711
1373
  }
712
- finally {
713
- if (state[key] !== value) {
714
- on.update(key, value);
715
- return value;
1374
+ function reassign(next) {
1375
+ value = next;
1376
+ if (retry) {
1377
+ retry();
1378
+ retry = undefined;
716
1379
  }
1380
+ else
1381
+ refresh();
717
1382
  }
718
- }
719
- function create(early) {
720
- sub = new Subscriber(on, update);
721
- ComputedInfo.set(update, info);
722
- defineProperty(state, key, {
723
- value: undefined,
724
- writable: true
725
- });
726
- defineProperty(subject, key, {
727
- enumerable: true,
728
- configurable: true,
729
- get: () => state[key],
730
- set: setter
731
- });
732
- try {
733
- return state[key] = compute(true);
1383
+ let retry;
1384
+ let update;
1385
+ let value = make();
1386
+ if (value === null) {
1387
+ sub.watch.clear();
1388
+ make = undefined;
1389
+ return;
734
1390
  }
735
- catch (e) {
736
- if (early)
737
- Oops$3.ComputedEarly(key).warn();
738
- throw e;
1391
+ if (typeof value == "function") {
1392
+ const get = value;
1393
+ sub.watch.clear();
1394
+ compute = () => get();
1395
+ value = get();
739
1396
  }
740
- finally {
741
- let defined = ComputedFor.get(on);
1397
+ if (value instanceof Promise) {
1398
+ value.then(reassign);
1399
+ value = undefined;
1400
+ }
1401
+ else {
742
1402
  sub.commit();
743
- for (const key in sub.follows) {
744
- const compute = defined.get(key);
745
- if (compute && compute.priority >= info.priority)
746
- info.priority = compute.priority + 1;
747
- }
1403
+ update = () => {
1404
+ const next = make();
1405
+ if (value != next)
1406
+ reassign(next);
1407
+ };
748
1408
  }
749
- }
750
- function revert(value) {
751
- delete state[key];
752
- defineProperty(subject, key, {
753
- enumerable: true,
754
- configurable: true,
755
- value
756
- });
757
- }
758
- setAlias(update, `try ${key}`);
759
- setAlias(create, `new ${key}`);
760
- setAlias(getter, `run ${key}`);
761
- ComputedInit.add(create);
762
- for (const on of [state, subject])
763
- defineProperty(on, key, {
764
- get: create,
765
- set: setter || revert,
766
- configurable: true,
767
- enumerable: true
1409
+ defineProperty(sub, "proxy", {
1410
+ get() {
1411
+ if (value !== undefined)
1412
+ return value;
1413
+ if (suspend)
1414
+ throw new Promise(res => retry = res);
1415
+ return null;
1416
+ }
768
1417
  });
769
- return info;
770
- }
771
- function ensure(on, keys) {
772
- for (const key of keys) {
773
- const desc = getOwnPropertyDescriptor(on.subject, key);
774
- const getter = desc && desc.get;
775
- if (ComputedInit.has(getter))
776
- getter(true);
777
- }
778
- }
779
- function capture(on, request) {
780
- const compute = ComputedInfo.get(request);
781
- if (!compute)
782
- return;
783
- let pending = ComputedKeys.get(on);
784
- if (!pending)
785
- ComputedKeys.set(on, pending = []);
786
- if (compute.parent !== on)
787
- request();
788
- else {
789
- const byPriorty = (sib) => compute.priority > ComputedInfo.get(sib).priority;
790
- pending.splice(pending.findIndex(byPriorty) + 1, 0, request);
791
- }
792
- return true;
1418
+ return sub;
1419
+ }, deps);
1420
+ if (!local)
1421
+ return null;
1422
+ React__default["default"].useLayoutEffect(() => local.release, deps);
1423
+ return local.proxy;
1424
+ }
1425
+
1426
+ function useTap(source, arg1, arg2) {
1427
+ const instance = typeof source == "object"
1428
+ ? source
1429
+ : "get" in source
1430
+ ? source.get()
1431
+ : useContext(source);
1432
+ return typeof arg1 == "function"
1433
+ ? useCompute(instance, arg1, arg2)
1434
+ : useSubscribe(instance, arg1, arg2);
793
1435
  }
794
- function flush(on) {
795
- const handled = on.frame;
796
- let pending = ComputedKeys.get(on);
797
- if (pending) {
798
- while (pending.length) {
799
- const compute = pending.shift();
800
- const { key } = ComputedInfo.get(compute);
801
- if (!handled.has(key))
802
- compute();
803
- }
804
- ComputedKeys.delete(on);
805
- }
1436
+ function useSubscribe(source, path, expect) {
1437
+ const deps = [uid(source)];
1438
+ const local = use(refresh => (control(source).subscribe(() => refresh)), deps);
1439
+ React__default["default"].useLayoutEffect(() => local.commit(), deps);
1440
+ if (path === undefined)
1441
+ return local.proxy;
1442
+ const value = local.proxy[path];
1443
+ if (value === undefined && expect)
1444
+ throw suspend(local.parent, path);
1445
+ return value;
806
1446
  }
807
1447
 
1448
+ const Global$1 = new WeakMap();
808
1449
  const Oops$2 = issues({
809
- DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
1450
+ 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.`,
1451
+ AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
810
1452
  });
811
- const Pending = new Map();
812
- function set(instruction, name = instruction.name || "pending") {
813
- const placeholder = Symbol(`${name} instruction`);
814
- function apply(key) {
815
- let output = instruction.call(this, key);
816
- if (typeof output == "function") {
817
- const getter = output;
818
- output = Object.assign(Object.assign({}, getOwnPropertyDescriptor(this.subject, key)), { get() {
819
- return getter(this[LOCAL]);
820
- } });
821
- }
822
- if (output)
823
- defineProperty(this.subject, key, output);
824
- }
825
- Pending.set(placeholder, apply);
826
- return placeholder;
827
- }
828
- function apply(on, key, value) {
829
- const instruction = Pending.get(value);
830
- if (instruction) {
831
- Pending.delete(value);
832
- delete on.subject[key];
833
- instruction.call(on, key);
1453
+ class MVC extends Model {
1454
+ end(force) {
1455
+ const type = this.constructor;
1456
+ if (type.keepAlive && !force)
1457
+ return false;
1458
+ super.end();
1459
+ Global$1.delete(type);
834
1460
  return true;
835
1461
  }
836
- }
837
- const ref = (cb) => set(function ref(key) {
838
- const refObjectFunction = this.sets(key, cb && createEffect(cb));
839
- defineProperty(refObjectFunction, "current", {
840
- set: refObjectFunction,
841
- get: () => this.state[key]
842
- });
843
- return {
844
- value: refObjectFunction
845
- };
846
- });
847
- const on = (value, cb) => set(function on(key) {
848
- this.manage(key, value, cb && createEffect(cb));
849
- });
850
- const memo = (factory, defer) => set(function memo(key) {
851
- const source = this.subject;
852
- const get = () => factory.call(source);
853
- if (defer)
854
- defineLazy(source, key, get);
855
- else
856
- define(source, key, get());
857
- });
858
- const lazy = (value) => set(function lazy(key) {
859
- const source = this.subject;
860
- source[key] = value;
861
- defineProperty(this.state, key, {
862
- get: () => source[key]
863
- });
864
- });
865
- const act = (task) => set(function act(key) {
866
- let pending = false;
867
- const invoke = (...args) => {
868
- if (pending)
869
- return Promise.reject(Oops$2.DuplicateAction(key));
870
- pending = true;
871
- this.update(key);
872
- return new Promise(res => {
873
- res(task.apply(this.subject, args));
874
- }).finally(() => {
875
- pending = false;
876
- this.update(key);
877
- });
878
- };
879
- setAlias(invoke, `run ${key}`);
880
- defineProperty(invoke, "active", {
881
- get: () => pending
882
- });
883
- return {
884
- value: invoke,
885
- writable: false
886
- };
887
- });
888
- const from = (getter) => set(function from(key) {
889
- prepare(this, key, getter);
890
- });
1462
+ static new(...args) {
1463
+ if (Global$1.has(this))
1464
+ if (this.keepAlive)
1465
+ return Global$1.get(this);
1466
+ else
1467
+ throw Oops$2.AlreadyExists(this.name);
1468
+ const instance = super.new(...args);
1469
+ if (this.global)
1470
+ Global$1.set(this, instance);
1471
+ return instance;
1472
+ }
1473
+ static get(arg1, arg2) {
1474
+ let instance;
1475
+ const required = arg1 === undefined || arg1 === true;
1476
+ if (this.global) {
1477
+ instance = Global$1.get(this);
1478
+ if (!instance && required)
1479
+ throw Oops$2.DoesNotExist(this.name);
1480
+ }
1481
+ else
1482
+ instance = useContext(this, required);
1483
+ function callback(effect) {
1484
+ try {
1485
+ React__default["default"].useLayoutEffect(() => effect(instance), []);
1486
+ }
1487
+ catch (err) {
1488
+ if (instance)
1489
+ instance.on(effect, []);
1490
+ else
1491
+ effect(undefined);
1492
+ }
1493
+ }
1494
+ if (typeof arg1 === "string")
1495
+ return instance[arg1];
1496
+ if (typeof arg1 === "function" && instance)
1497
+ callback(arg1);
1498
+ else if (arg2)
1499
+ callback(arg2);
1500
+ return instance;
1501
+ }
1502
+ static tap(arg1, arg2) {
1503
+ const instance = this.get();
1504
+ return typeof arg1 == "function"
1505
+ ? useCompute(instance, arg1, arg2)
1506
+ : useSubscribe(instance, arg1, arg2);
1507
+ }
1508
+ static use(a, b) {
1509
+ return useNew(this, a, b);
1510
+ }
1511
+ static meta(arg1, arg2) {
1512
+ return typeof arg1 == "function"
1513
+ ? useCompute(this, arg1, arg2)
1514
+ : useSubscribe(this, arg1, arg2);
1515
+ }
1516
+ }
891
1517
 
892
- const Parent = new WeakMap();
893
1518
  const Oops$1 = issues({
894
- ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
895
- UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
896
- UndefinedNotAllowed: (key) => `Child property ${key} may not be undefined.`
1519
+ BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
897
1520
  });
898
- const use = (Peer, argument) => set(function use(key) {
899
- const Proxies = new WeakMap();
900
- let instance;
901
- const update = (next) => {
902
- instance = next;
903
- if (next) {
904
- Parent.set(instance, this.subject);
905
- manage(instance);
906
- }
907
- if (typeof argument == "function")
908
- argument(instance);
909
- else if (!instance && argument !== false)
910
- throw Oops$1.UndefinedNotAllowed(key);
911
- };
912
- const attach = (sub) => {
913
- let child;
914
- function create() {
915
- if (!instance)
916
- return;
917
- child = new Subscriber(instance, sub.onUpdate);
918
- if (sub.active)
919
- child.commit();
920
- sub.dependant.add(child);
921
- Proxies.set(sub, child.proxy);
922
- }
923
- function refresh() {
924
- if (child) {
925
- child.release();
926
- sub.dependant.delete(child);
927
- Proxies.set(sub, undefined);
928
- child = undefined;
929
- }
930
- create();
931
- sub.onUpdate();
932
- }
933
- create();
934
- sub.follow(key, refresh);
935
- };
936
- if (Peer) {
937
- instance = Model.isTypeof(Peer)
938
- ? new Peer()
939
- : Peer();
940
- if (instance)
941
- update(instance);
942
- }
1521
+ function Consumer(props) {
1522
+ const { get, has, children, for: type } = props;
1523
+ if (typeof children == "function")
1524
+ return children(useTap(type));
1525
+ const callback = has || get;
1526
+ if (typeof callback == "function")
1527
+ callback(useContext(type, !!has));
943
1528
  else
944
- argument = false;
945
- this.manage(key, instance, update);
946
- return (local) => {
947
- if (!local)
948
- return instance;
949
- if (!Proxies.has(local))
950
- attach(local);
951
- return Proxies.get(local);
952
- };
953
- });
954
- const parent = (Expects, required) => set(function parent() {
955
- const child = this.subject;
956
- const expected = Expects.name;
957
- const value = Parent.get(this.subject);
958
- if (!value) {
959
- if (required)
960
- throw Oops$1.ParentRequired(expected, child);
961
- }
962
- else if (!(value instanceof Expects))
963
- throw Oops$1.UnexpectedParent(expected, child, value);
964
- return { value };
965
- });
1529
+ throw Oops$1.BadProps();
1530
+ return null;
1531
+ }
966
1532
 
967
1533
  const Oops = issues({
968
- GlobalDoesNotExist: (name) => `Tried to access singleton ${name}, but none exist! Did you forget to initialize?\nCall ${name}.create() before attempting to access, or consider using ${name}.use() instead.`,
969
- GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
1534
+ NoType: () => "Provider 'for' prop must be Model, typeof Model or a collection of them."
970
1535
  });
971
- const Active = new WeakMap();
972
- class Singleton extends Model {
973
- static get current() {
974
- return Active.get(this);
975
- }
976
- static create(...args) {
977
- const Type = this;
978
- if (Active.has(Type))
979
- throw Oops.GlobalExists(this.name);
980
- let instance = super.create(...args);
981
- Active.set(Type, instance);
982
- return instance;
983
- }
984
- static find() {
985
- if (this.current)
986
- return this.current;
987
- throw Oops.GlobalDoesNotExist(this.name);
988
- }
989
- static reset() {
990
- if (this.current)
991
- this.current.destroy();
1536
+ function Provider(props) {
1537
+ const context = useNewContext(props.for, props.and);
1538
+ return (React__default["default"].createElement(LookupContext.Provider, { value: context }, props.fallback === false
1539
+ ? props.children
1540
+ : (React__default["default"].createElement(React.Suspense, { fallback: props.fallback || null }, props.children))));
1541
+ }
1542
+ function useNewContext(include, assign) {
1543
+ const init = new Set();
1544
+ const ambient = useLookup();
1545
+ const context = React__default["default"].useMemo(() => {
1546
+ if (!include)
1547
+ throw Oops.NoType();
1548
+ return ambient.push();
1549
+ }, []);
1550
+ function register(key, T) {
1551
+ const instance = context.has(key, T, i => init.add(i));
1552
+ if (assign)
1553
+ assignWeak(instance, assign);
992
1554
  }
993
- destroy() {
994
- super.destroy();
995
- Active.delete(this.constructor);
1555
+ if (typeof include == "function" || include instanceof Model)
1556
+ register(0, include);
1557
+ else
1558
+ entries(include).forEach(e => register(...e));
1559
+ for (const instance of init) {
1560
+ control(instance).state.forEach(value => {
1561
+ if (Parent.get(value) === instance) {
1562
+ context.add(value);
1563
+ init.add(value);
1564
+ }
1565
+ });
1566
+ for (const apply of getPending(instance))
1567
+ apply(context);
996
1568
  }
1569
+ React__default["default"].useLayoutEffect(() => () => context.pop(), []);
1570
+ return context;
997
1571
  }
998
1572
 
1573
+ class Global extends MVC {
1574
+ }
1575
+ Global.global = true;
1576
+ Global.keepAlive = true;
1577
+
1578
+ const LOCAL = "$debug local";
1579
+ const STATE = "$debug state";
1580
+ const UPDATE = "$debug update";
1581
+ const CONTROL = "$debug controller";
1582
+ defineProperties(Model.prototype, {
1583
+ [CONTROL]: {
1584
+ get() {
1585
+ return controller(this);
1586
+ }
1587
+ },
1588
+ [LOCAL]: {
1589
+ get() {
1590
+ return subscriber(this);
1591
+ }
1592
+ },
1593
+ [STATE]: {
1594
+ get() {
1595
+ const { state } = controller(this);
1596
+ const output = {};
1597
+ state.forEach((value, key) => output[key] = value);
1598
+ return output;
1599
+ }
1600
+ },
1601
+ [UPDATE]: {
1602
+ get() {
1603
+ return (subscriber(this) || controller(this)).latest;
1604
+ }
1605
+ }
1606
+ });
1607
+ const Debug = {
1608
+ CONTROL,
1609
+ LOCAL,
1610
+ STATE,
1611
+ UPDATE
1612
+ };
1613
+
999
1614
  exports.Consumer = Consumer;
1000
- exports.Model = Model;
1615
+ exports.Debug = Debug;
1616
+ exports.Global = Global;
1617
+ exports.MVC = MVC;
1618
+ exports.Model = MVC;
1001
1619
  exports.Provider = Provider;
1002
- exports.Singleton = Singleton;
1003
- exports.act = act;
1004
- exports.default = Model;
1005
- exports.from = from;
1006
- exports.lazy = lazy;
1007
- exports.memo = memo;
1008
- exports.on = on;
1009
- exports.parent = parent;
1620
+ exports.add = add;
1621
+ exports["default"] = MVC;
1622
+ exports.get = get;
1623
+ exports.has = has;
1010
1624
  exports.ref = ref;
1625
+ exports.run = run;
1011
1626
  exports.set = set;
1012
1627
  exports.tap = tap;
1013
- exports.use = use;
1628
+ exports.use = use$1;
1629
+ exports.useContext = useContext;
1630
+ exports.useNew = useNew;
1631
+ exports.useTap = useTap;