@expressive/mvc 0.4.7 → 0.6.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,30 +1,5 @@
1
1
  import React, { useLayoutEffect, useState, useMemo } from 'react';
2
2
 
3
- /*! *****************************************************************************
4
- Copyright (c) Microsoft Corporation.
5
-
6
- Permission to use, copy, modify, and/or distribute this software for any
7
- purpose with or without fee is hereby granted.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
- PERFORMANCE OF THIS SOFTWARE.
16
- ***************************************************************************** */
17
-
18
- function __awaiter(thisArg, _arguments, P, generator) {
19
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
20
- return new (P || (P = Promise))(function (resolve, reject) {
21
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
22
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
23
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
24
- step((generator = generator.apply(thisArg, _arguments || [])).next());
25
- });
26
- }
27
-
28
3
  class Issue extends Error {
29
4
  constructor() {
30
5
  super(...arguments);
@@ -87,22 +62,95 @@ function mayRetry(fn) {
87
62
  }
88
63
 
89
64
  const Oops$b = issues({
90
- BadCallback: () => `Callback for effect-callback may only return a function.`
65
+ Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
91
66
  });
92
- const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
93
- function define(target, key, value) {
94
- defineProperty(target, key, { value });
95
- }
96
- function defineLazy(object, property, init) {
97
- defineProperty(object, property, {
98
- configurable: true,
99
- get() {
100
- const value = init.call(this);
101
- defineProperty(this, property, { value });
67
+ const INFO = new WeakMap();
68
+ const KEYS = new WeakMap();
69
+ const ORDER = new WeakMap();
70
+ function computeMode(self, source, setter, key, required) {
71
+ const { subject, state } = self;
72
+ let sub;
73
+ let order = ORDER.get(self);
74
+ if (!order)
75
+ ORDER.set(self, order = []);
76
+ const compute = (initial) => {
77
+ try {
78
+ return setter.call(sub.proxy, sub.proxy);
79
+ }
80
+ catch (err) {
81
+ Oops$b.Failed(subject, key, initial).warn();
82
+ throw err;
83
+ }
84
+ };
85
+ const refresh = () => {
86
+ let value;
87
+ try {
88
+ value = compute(false);
89
+ }
90
+ catch (e) {
91
+ console.error(e);
92
+ }
93
+ finally {
94
+ if (state.get(key) !== value) {
95
+ state.set(key, value);
96
+ self.update(key);
97
+ return value;
98
+ }
99
+ }
100
+ };
101
+ const update = (_key, source) => {
102
+ if (source !== self) {
103
+ refresh();
104
+ return;
105
+ }
106
+ let pending = KEYS.get(self);
107
+ if (!pending)
108
+ KEYS.set(self, pending = []);
109
+ pending.push(refresh);
110
+ };
111
+ const create = () => {
112
+ sub = source.subscribe(update);
113
+ try {
114
+ const value = compute(true);
115
+ state.set(key, value);
102
116
  return value;
103
117
  }
104
- });
118
+ catch (e) {
119
+ throw e;
120
+ }
121
+ finally {
122
+ sub.commit();
123
+ order.push(refresh);
124
+ }
125
+ };
126
+ INFO.set(refresh, key);
127
+ return () => {
128
+ const value = sub ? state.get(key) : create();
129
+ if (value === undefined && required)
130
+ throw suspend(self, key);
131
+ return value;
132
+ };
105
133
  }
134
+ function flush(control) {
135
+ const pending = KEYS.get(control);
136
+ if (!pending)
137
+ return;
138
+ const list = ORDER.get(control);
139
+ while (pending.length) {
140
+ const compute = pending
141
+ .sort((a, b) => list.indexOf(b) - list.indexOf(a))
142
+ .pop();
143
+ const key = INFO.get(compute);
144
+ if (!control.frame.has(key))
145
+ compute();
146
+ }
147
+ KEYS.delete(control);
148
+ }
149
+
150
+ const Oops$a = issues({
151
+ BadCallback: () => `Callback for effect-callback may only return a function.`
152
+ });
153
+ const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
106
154
  function createEffect(callback) {
107
155
  let unSet;
108
156
  return function (value) {
@@ -112,7 +160,7 @@ function createEffect(callback) {
112
160
  if (unSet instanceof Promise)
113
161
  unSet = undefined;
114
162
  if (unSet && typeof unSet !== "function")
115
- throw Oops$b.BadCallback();
163
+ throw Oops$a.BadCallback();
116
164
  };
117
165
  }
118
166
  function createValueEffect(callback) {
@@ -128,321 +176,41 @@ function createValueEffect(callback) {
128
176
  if (typeof out == "function")
129
177
  unSet = out;
130
178
  else
131
- throw Oops$b.BadCallback();
179
+ throw Oops$a.BadCallback();
132
180
  };
133
181
  }
134
182
 
135
- function ensure(subject, cb) {
136
- let control = subject[CONTROL];
137
- if (!control) {
138
- control = new Controller(subject);
139
- define(subject, CONTROL, control);
140
- }
141
- if (!control.state) {
142
- const { waiting } = control;
143
- if (cb) {
144
- let done;
145
- waiting.add(() => {
146
- done = cb(control);
147
- });
148
- return () => done && done();
149
- }
150
- control.state = new Map();
151
- for (const key in subject)
152
- control.add(key);
153
- const callback = Array.from(waiting);
154
- waiting.clear();
155
- for (const cb of callback)
156
- cb();
157
- }
158
- return cb ? cb(control) : control;
159
- }
160
-
161
- const Oops$a = issues({
162
- BadSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
163
- PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
164
- Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
165
- });
166
- const INFO = new WeakMap();
167
- const KEYS = new WeakMap();
168
- const ORDER = new WeakMap();
169
- function get(source, arg1, arg2) {
170
- return apply(function from(key) {
171
- const { subject, state } = this;
172
- const required = arg2 === true || arg1 === true;
173
- let getSource;
174
- if (typeof arg1 == "boolean")
175
- arg1 = undefined;
176
- // Easy mistake, using a peer, will always be unresolved.
177
- if (typeof source == "symbol")
178
- throw Oops$a.PeerNotAllowed(subject, key);
179
- // replace source controller in-case it is different
180
- if (typeof source == "object")
181
- getSource = () => ensure(source);
182
- // specifically an arrow function (getter factory)
183
- else if (!source.prototype) {
184
- arg1 = source.call(subject, key);
185
- getSource = () => this;
186
- }
187
- // Regular function is too ambiguous so not allowed.
188
- else
189
- throw Oops$a.BadSource(subject, key, source);
190
- const setter = arg1;
191
- const info = { key, parent: this };
192
- let sub;
193
- let order = ORDER.get(this);
194
- if (!order)
195
- ORDER.set(this, order = []);
196
- state.set(key, undefined);
197
- const compute = (initial) => {
198
- try {
199
- return setter.call(sub.proxy, sub.proxy);
200
- }
201
- catch (err) {
202
- Oops$a.Failed(subject, key, initial).warn();
203
- throw err;
204
- }
205
- };
206
- const refreshValue = () => {
207
- let value;
208
- try {
209
- value = compute(false);
210
- }
211
- catch (e) {
212
- console.error(e);
213
- }
214
- finally {
215
- if (state.get(key) !== value) {
216
- state.set(key, value);
217
- this.update(key);
218
- return value;
219
- }
220
- }
221
- };
222
- const dependancyDidUpdate = (_key, source) => {
223
- if (source !== this) {
224
- refreshValue();
225
- return;
226
- }
227
- let pending = KEYS.get(this);
228
- if (!pending)
229
- KEYS.set(this, pending = []);
230
- pending.push(refreshValue);
231
- };
232
- const create = () => {
233
- const control = getSource();
234
- sub = control.subscribe(dependancyDidUpdate);
235
- try {
236
- const value = compute(true);
237
- state.set(key, value);
238
- return value;
239
- }
240
- catch (e) {
241
- throw e;
242
- }
243
- finally {
244
- sub.commit();
245
- order.push(refreshValue);
246
- }
247
- };
248
- INFO.set(refreshValue, info);
249
- return () => {
250
- const value = sub ? state.get(key) : create();
251
- if (value === undefined && required)
252
- throw suspend(this, key);
253
- return value;
254
- };
255
- });
256
- }
257
- function flush(control) {
258
- const pending = KEYS.get(control);
259
- if (!pending)
260
- return;
261
- const list = ORDER.get(control);
262
- while (pending.length) {
263
- const compute = pending
264
- .sort((a, b) => list.indexOf(b) - list.indexOf(a))
265
- .pop();
266
- const { key } = INFO.get(compute);
267
- if (!control.frame.has(key))
268
- compute();
269
- }
270
- KEYS.delete(control);
271
- }
272
-
273
- class Subscriber {
274
- constructor(parent, onUpdate) {
275
- this.onUpdate = onUpdate;
276
- this.active = false;
277
- this.dependant = new Set();
278
- const proxy = create(parent.subject);
279
- const using = new Map();
280
- define(proxy, LOCAL, this);
281
- defineProperty(this, "proxy", {
282
- configurable: true,
283
- get() {
284
- if (UPDATE.has(proxy))
285
- setTimeout(() => UPDATE.delete(proxy), 0);
286
- return proxy;
287
- }
288
- });
289
- const release = parent.addListener(key => {
290
- if (!this.active)
291
- return;
292
- const handler = using.get(key);
293
- let notify;
294
- if (typeof handler == "function") {
295
- const callback = handler();
296
- if (callback === true)
297
- notify = this.onUpdate(key, parent);
298
- }
299
- else if (handler === true)
300
- notify = this.onUpdate(key, parent);
301
- const getWhy = () => {
302
- const update = getUpdate(parent.subject);
303
- const applicable = update.filter(k => using.has(k));
304
- UPDATE.set(proxy, applicable);
305
- };
306
- if (notify) {
307
- parent.waiting.add(getWhy);
308
- parent.waiting.add(notify);
309
- }
310
- });
311
- this.commit = () => {
312
- this.active = true;
313
- this.dependant.forEach(x => x.commit());
314
- return this.release;
315
- };
316
- this.release = () => {
317
- this.dependant.forEach(x => x.release());
318
- release();
319
- };
320
- this.add = (key, value) => {
321
- if (value !== undefined)
322
- using.set(key, value);
323
- else if (!using.has(key))
324
- using.set(key, true);
325
- };
326
- }
327
- }
328
-
329
- const UPDATE = new WeakMap();
330
- function getUpdate(subject) {
331
- return UPDATE.get(subject);
332
- }
333
- class Controller {
334
- constructor(subject) {
335
- this.subject = subject;
336
- this.frame = new Set();
337
- this.waiting = new Set();
338
- this.followers = new Set();
339
- }
340
- subscribe(callback) {
341
- return new Subscriber(this, callback);
342
- }
343
- add(key) {
344
- const { subject, state } = this;
345
- const { value } = getOwnPropertyDescriptor(subject, key);
346
- if (typeof value == "function")
347
- return;
348
- if (typeof value == "symbol") {
349
- const instruction = PENDING.get(value);
350
- if (instruction)
351
- instruction.call(this, key, this);
352
- return;
353
- }
354
- state.set(key, value);
355
- defineProperty(subject, key, {
356
- enumerable: false,
357
- set: this.ref(key),
358
- get() {
359
- const local = this[LOCAL];
360
- if (local)
361
- local.add(key);
362
- return state.get(key);
363
- }
364
- });
365
- }
366
- addListener(listener) {
367
- this.followers.add(listener);
368
- return () => {
369
- this.followers.delete(listener);
370
- };
371
- }
372
- ref(key, handler) {
373
- const { subject, state } = this;
374
- return (value) => {
375
- if (state.get(key) == value)
376
- return;
377
- if (handler)
378
- switch (handler.call(subject, value)) {
379
- case true:
380
- this.update(key);
381
- case false:
382
- return;
383
- }
384
- state.set(key, value);
385
- this.update(key);
386
- };
387
- }
388
- update(key) {
389
- const { followers, frame, subject, waiting } = this;
390
- if (frame.has(key))
391
- return;
392
- else if (!frame.size)
393
- setTimeout(() => {
394
- flush(this);
395
- UPDATE.set(subject, Array.from(frame));
396
- setTimeout(() => {
397
- UPDATE.delete(subject);
398
- }, 0);
399
- frame.clear();
400
- for (const notify of waiting)
401
- try {
402
- waiting.delete(notify);
403
- notify();
404
- }
405
- catch (err) {
406
- console.error(err);
407
- }
408
- }, 0);
409
- frame.add(key);
410
- for (const callback of followers) {
411
- const event = callback(key, this);
412
- if (typeof event == "function")
413
- waiting.add(event);
414
- }
415
- }
416
- clear() {
417
- const listeners = [...this.followers];
418
- this.followers.clear();
419
- listeners.forEach(x => x(null, this));
420
- }
421
- }
422
-
423
183
  const Oops$9 = issues({
424
184
  Timeout: (keys, timeout) => `No update for [${keys}] within ${timeout}.`,
425
185
  StrictUpdate: () => `Strict update() did not find pending updates.`,
426
186
  NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
427
187
  });
428
- const CONTROL = Symbol("CONTROL");
429
188
  const WHY = Symbol("UPDATE");
430
189
  const LOCAL = Symbol("LOCAL");
431
190
  const STATE = Symbol("STATE");
432
191
  class Model {
433
192
  constructor() {
434
- define(this, CONTROL, new Controller(this));
435
- define(this, "get", this);
436
- define(this, "is", this);
437
- defineLazy(this, "set", () => {
438
- const controller = ensure(this);
439
- const assign = (key, value) => {
440
- controller.state.set(key, value);
441
- controller.update(key);
442
- };
443
- for (const key of controller.state.keys())
444
- define(assign, key, controller.ref(key));
445
- return assign;
193
+ defineProperty(this, CONTROL, {
194
+ value: new Controller(this)
195
+ });
196
+ defineProperty(this, "is", {
197
+ value: this
198
+ });
199
+ defineProperty(this, "set", {
200
+ configurable: true,
201
+ get: () => {
202
+ const controller = ensure(this);
203
+ const value = (key, value) => {
204
+ controller.state.set(key, value);
205
+ controller.update(key);
206
+ };
207
+ for (const key of controller.state.keys())
208
+ defineProperty(value, key, {
209
+ value: controller.ref(key)
210
+ });
211
+ defineProperty(this, "set", { value });
212
+ return value;
213
+ }
446
214
  });
447
215
  }
448
216
  get [STATE]() {
@@ -628,6 +396,183 @@ class Model {
628
396
  }
629
397
  }
630
398
 
399
+ class Subscriber {
400
+ constructor(parent, onUpdate) {
401
+ this.onUpdate = onUpdate;
402
+ this.active = false;
403
+ this.dependant = new Set();
404
+ const proxy = create(parent.subject);
405
+ const using = new Map();
406
+ const listen = this.add = (key, value) => {
407
+ if (value !== undefined)
408
+ using.set(key, value);
409
+ else if (!using.has(key))
410
+ using.set(key, true);
411
+ };
412
+ LISTEN.set(proxy, listen);
413
+ defineProperty(proxy, LOCAL, { value: this });
414
+ defineProperty(this, "proxy", {
415
+ configurable: true,
416
+ get() {
417
+ if (UPDATE.has(proxy))
418
+ setTimeout(() => UPDATE.delete(proxy), 0);
419
+ return proxy;
420
+ }
421
+ });
422
+ const release = parent.addListener(key => {
423
+ if (!this.active)
424
+ return;
425
+ const handler = using.get(key);
426
+ let notify;
427
+ if (typeof handler == "function") {
428
+ const callback = handler();
429
+ if (callback === true)
430
+ notify = this.onUpdate(key, parent);
431
+ }
432
+ else if (handler === true)
433
+ notify = this.onUpdate(key, parent);
434
+ if (!notify)
435
+ return;
436
+ const notate = () => {
437
+ UPDATE.set(proxy, getUpdate(parent.subject).filter(k => using.has(k)));
438
+ };
439
+ parent.waiting.add(notate);
440
+ parent.waiting.add(notify);
441
+ });
442
+ this.commit = () => {
443
+ this.active = true;
444
+ this.dependant.forEach(x => x.commit());
445
+ return this.release;
446
+ };
447
+ this.release = () => {
448
+ this.dependant.forEach(x => x.release());
449
+ release();
450
+ };
451
+ }
452
+ }
453
+
454
+ const UPDATE = new WeakMap();
455
+ const LISTEN = new WeakMap();
456
+ const CONTROL = Symbol("CONTROL");
457
+ function getUpdate(subject) {
458
+ return UPDATE.get(subject);
459
+ }
460
+ class Controller {
461
+ constructor(subject) {
462
+ this.subject = subject;
463
+ this.frame = new Set();
464
+ this.waiting = new Set();
465
+ this.followers = new Set();
466
+ }
467
+ subscribe(callback) {
468
+ return new Subscriber(this, callback);
469
+ }
470
+ add(key) {
471
+ const { subject, state } = this;
472
+ const { value } = getOwnPropertyDescriptor(subject, key);
473
+ if (typeof value == "function")
474
+ return;
475
+ if (typeof value == "symbol") {
476
+ const instruction = PENDING.get(value);
477
+ if (instruction)
478
+ instruction.call(this, key, this);
479
+ return;
480
+ }
481
+ state.set(key, value);
482
+ defineProperty(subject, key, {
483
+ enumerable: false,
484
+ set: this.ref(key),
485
+ get() {
486
+ const listen = LISTEN.get(this);
487
+ if (listen)
488
+ listen(key);
489
+ return state.get(key);
490
+ }
491
+ });
492
+ }
493
+ addListener(listener) {
494
+ this.followers.add(listener);
495
+ return () => {
496
+ this.followers.delete(listener);
497
+ };
498
+ }
499
+ ref(key, handler) {
500
+ const { subject, state } = this;
501
+ return (value) => {
502
+ if (state.get(key) == value)
503
+ return;
504
+ if (handler)
505
+ switch (handler.call(subject, value)) {
506
+ case true:
507
+ this.update(key);
508
+ case false:
509
+ return;
510
+ }
511
+ state.set(key, value);
512
+ this.update(key);
513
+ };
514
+ }
515
+ update(key) {
516
+ const { followers, frame, subject, waiting } = this;
517
+ if (frame.has(key))
518
+ return;
519
+ else if (!frame.size)
520
+ setTimeout(() => {
521
+ flush(this);
522
+ UPDATE.set(subject, Array.from(frame));
523
+ setTimeout(() => {
524
+ UPDATE.delete(subject);
525
+ }, 0);
526
+ frame.clear();
527
+ for (const notify of waiting)
528
+ try {
529
+ waiting.delete(notify);
530
+ notify();
531
+ }
532
+ catch (err) {
533
+ console.error(err);
534
+ }
535
+ }, 0);
536
+ frame.add(key);
537
+ for (const callback of followers) {
538
+ const event = callback(key, this);
539
+ if (typeof event == "function")
540
+ waiting.add(event);
541
+ }
542
+ }
543
+ clear() {
544
+ const listeners = [...this.followers];
545
+ this.followers.clear();
546
+ listeners.forEach(x => x(null, this));
547
+ }
548
+ }
549
+ function ensure(subject, cb) {
550
+ let control = subject[CONTROL];
551
+ if (!control)
552
+ defineProperty(subject, CONTROL, {
553
+ value: control =
554
+ new Controller(subject)
555
+ });
556
+ if (!control.state) {
557
+ const { waiting } = control;
558
+ if (cb) {
559
+ let done;
560
+ waiting.add(() => {
561
+ done = cb(control);
562
+ });
563
+ return () => done && done();
564
+ }
565
+ control.state = new Map();
566
+ for (const key in subject)
567
+ control.add(key);
568
+ const callback = Array.from(waiting);
569
+ waiting.clear();
570
+ for (const cb of callback)
571
+ cb();
572
+ }
573
+ return cb ? cb(control) : control;
574
+ }
575
+
631
576
  const PENDING = new Map();
632
577
  function apply(fn, label) {
633
578
  const name = label || fn.name || "pending";
@@ -646,11 +591,11 @@ function apply(fn, label) {
646
591
  defineProperty(subject, key, output);
647
592
  return false;
648
593
  }
594
+ let { get: onGet, set: onSet, suspense } = output;
595
+ if ("value" in output)
596
+ state.set(key, output.value);
649
597
  if ("recursive" in output && output.recursive)
650
- output = Object.assign(Object.assign({}, output), { get: getRecursive(key, this) });
651
- const desc = output;
652
- if ("value" in desc)
653
- state.set(key, desc.value);
598
+ onGet = getRecursive(key, this);
654
599
  if ("destroy" in output) {
655
600
  const { destroy } = output;
656
601
  if (destroy)
@@ -659,57 +604,85 @@ function apply(fn, label) {
659
604
  destroy();
660
605
  });
661
606
  }
662
- const { get: onGet, set: onSet, enumerable, suspense } = desc;
663
- const set = onSet !== false
664
- ? this.ref(key, onSet)
665
- : undefined;
666
- function get() {
667
- if (!state.has(key) && suspense)
668
- throw suspend(control, key);
669
- const local = this[LOCAL];
670
- if (local)
671
- local.add(key);
672
- return onGet
673
- ? onGet(local)
674
- : state.get(key);
675
- }
676
- defineProperty(subject, key, { enumerable, get, set });
607
+ defineProperty(subject, key, {
608
+ enumerable: output.enumerable,
609
+ set: onSet !== false
610
+ ? this.ref(key, onSet)
611
+ : undefined,
612
+ get() {
613
+ if (!state.has(key) && suspense)
614
+ throw suspend(control, key);
615
+ const listen = LISTEN.get(this);
616
+ const local = this[LOCAL];
617
+ if (listen)
618
+ listen(key);
619
+ return onGet
620
+ ? onGet(local)
621
+ : state.get(key);
622
+ }
623
+ });
677
624
  }
678
625
  PENDING.set(placeholder, setup);
679
626
  return placeholder;
680
627
  }
681
628
  function getRecursive(key, from) {
682
629
  const context = new WeakMap();
683
- const { state } = from;
684
630
  return (local) => {
685
631
  if (!local)
686
- return state.get(key);
632
+ return from.state.get(key);
687
633
  if (!context.has(local)) {
688
- let child;
634
+ let reset;
689
635
  const init = () => {
690
- if (child) {
691
- child.release();
692
- local.dependant.delete(child);
693
- context.set(local, undefined);
694
- child = undefined;
695
- }
696
- const value = state.get(key);
636
+ if (reset)
637
+ reset();
638
+ const value = from.state.get(key);
697
639
  if (value && CONTROL in value) {
698
- child = ensure(value).subscribe(local.onUpdate);
640
+ const child = ensure(value).subscribe(local.onUpdate);
699
641
  if (local.active)
700
642
  child.commit();
701
643
  local.dependant.add(child);
702
644
  context.set(local, child.proxy);
645
+ reset = () => {
646
+ child.release();
647
+ local.dependant.delete(child);
648
+ context.set(local, undefined);
649
+ reset = undefined;
650
+ };
703
651
  }
704
652
  return true;
705
653
  };
706
- init();
707
654
  local.add(key, init);
655
+ init();
708
656
  }
709
657
  return context.get(local);
710
658
  };
711
659
  }
712
660
 
661
+ /*! *****************************************************************************
662
+ Copyright (c) Microsoft Corporation.
663
+
664
+ Permission to use, copy, modify, and/or distribute this software for any
665
+ purpose with or without fee is hereby granted.
666
+
667
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
668
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
669
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
670
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
671
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
672
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
673
+ PERFORMANCE OF THIS SOFTWARE.
674
+ ***************************************************************************** */
675
+
676
+ function __awaiter(thisArg, _arguments, P, generator) {
677
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
678
+ return new (P || (P = Promise))(function (resolve, reject) {
679
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
680
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
681
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
682
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
683
+ });
684
+ }
685
+
713
686
  const Oops$8 = issues({
714
687
  DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
715
688
  });
@@ -740,161 +713,115 @@ function act(task) {
740
713
  });
741
714
  }
742
715
 
743
- class Managed extends Array {
744
- constructor(onUpdate) {
745
- super();
746
- this.lastUpdate = [0, 0];
747
- this.update = (from, to) => {
748
- this.lastUpdate = [from, to];
749
- onUpdate();
750
- };
751
- }
752
- push(...items) {
753
- const { length } = this;
754
- const end = super.push(...items);
755
- this.update(length, end);
756
- return end;
757
- }
758
- unshift(...items) {
759
- const end = super.push(...items);
760
- this.update(0, end);
761
- return end;
762
- }
763
- splice(start, deleteCount, ...rest) {
764
- const end = deleteCount !== rest.length ? Infinity : deleteCount;
765
- this.update(start, end);
766
- return super.splice(start, deleteCount, ...rest);
716
+ function factoryMode(self, output, key, required) {
717
+ const { subject, state } = self;
718
+ let pending;
719
+ let error;
720
+ if (output instanceof Promise) {
721
+ state.set(key, undefined);
722
+ pending = output
723
+ .catch(err => error = err)
724
+ .then(val => {
725
+ state.set(key, val);
726
+ return val;
727
+ })
728
+ .finally(() => {
729
+ pending = undefined;
730
+ self.update(key);
731
+ });
767
732
  }
768
- }
769
- function array() {
770
- return apply(function array(key) {
771
- const context = new WeakMap();
772
- const array = new Managed(() => this.update(key));
773
- const getLocal = (context) => {
774
- const proxy = Object.create(array);
775
- let rangeA = 0;
776
- let rangeB = 0;
777
- const onUpdate = () => {
778
- const [lastA, lastB] = array.lastUpdate;
779
- if (rangeA <= lastB && rangeB >= lastA)
780
- return true;
781
- };
782
- const listen = (eventA, eventB) => {
783
- if (context.active)
784
- return;
785
- context.add(key, onUpdate);
786
- rangeA = Math.min(rangeA, eventA);
787
- rangeB = Math.max(rangeB, eventB);
788
- };
789
- proxy[Symbol.iterator] = () => {
790
- listen(0, Infinity);
791
- return array[Symbol.iterator]();
792
- };
793
- return proxy;
794
- };
795
- return {
796
- value: array,
797
- set: false,
798
- get: (local) => {
799
- if (!local)
800
- return this.state.get(key);
801
- if (context.has(local))
802
- return context.get(local);
803
- const output = getLocal(local);
804
- context.set(local, output);
805
- return output;
806
- }
807
- };
808
- });
809
- }
810
-
811
- function ref(callback) {
812
- return apply(function ref(key) {
813
- const value = this.ref(key, callback && createValueEffect(callback));
814
- defineProperty(value, "current", {
815
- set: value,
816
- get: () => this.state.get(key)
733
+ state.set(key, output);
734
+ const suspend = () => {
735
+ if (required === false)
736
+ return undefined;
737
+ const issue = Oops$7.NotReady(subject, key);
738
+ Object.assign(pending, {
739
+ message: issue.message,
740
+ stack: issue.stack
817
741
  });
818
- return {
819
- value,
820
- explicit: true
821
- };
822
- });
742
+ throw pending;
743
+ };
744
+ return () => {
745
+ if (error)
746
+ throw error;
747
+ if (pending)
748
+ return suspend();
749
+ if (state.has(key))
750
+ return state.get(key);
751
+ };
823
752
  }
824
753
 
825
754
  const Oops$7 = issues({
826
- NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
755
+ BadSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
756
+ PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
757
+ ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
827
758
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
828
- Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
759
+ FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
760
+ Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
829
761
  });
830
- function put(factory, argument) {
831
- return apply(function set(key) {
832
- const { subject, state } = this;
833
- const required = argument === true || argument === undefined;
834
- let set;
835
- let get;
836
- let pending;
837
- let error;
762
+ function get(arg0, arg1, arg2) {
763
+ return apply(function get(key) {
764
+ const { subject } = this;
765
+ const computeRequired = arg1 === true || arg2 === true;
766
+ const factoryRequired = arg1 !== false && arg2 !== false;
767
+ let getter;
768
+ // Easy mistake, using a peer, will always be unresolved.
769
+ if (typeof arg0 == "symbol")
770
+ throw Oops$7.PeerNotAllowed(subject, key);
771
+ if (typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
772
+ throw Oops$7.BadSource(subject, key, arg0);
773
+ this.state.set(key, undefined);
838
774
  const init = () => {
839
- const output = typeof factory == "function" ?
840
- mayRetry(() => factory.call(subject, key, subject)) :
841
- factory;
842
- if (output instanceof Promise) {
843
- pending = output
844
- .catch(err => error = err)
845
- .then(val => {
846
- state.set(key, val);
847
- return val;
848
- })
849
- .finally(() => {
850
- pending = undefined;
851
- this.update(key);
852
- });
775
+ let source = this;
776
+ let setter;
777
+ if (typeof arg0 == "function") {
778
+ const result = mayRetry(() => arg0.call(subject, key, subject));
779
+ if (typeof result == "function")
780
+ setter = result;
781
+ else {
782
+ getter = factoryMode(this, result, key, factoryRequired);
783
+ return;
784
+ }
785
+ }
786
+ else if (arg0 instanceof Promise) {
787
+ getter = factoryMode(this, arg0, key, factoryRequired);
853
788
  return;
854
789
  }
855
- state.set(key, output);
856
- return output;
857
- };
858
- const suspend = () => {
859
- if (required === false)
860
- return undefined;
861
- const issue = Oops$7.NotReady(subject, key);
862
- Object.assign(pending, {
863
- message: issue.message,
864
- stack: issue.stack
865
- });
866
- throw pending;
790
+ else if (typeof arg1 == "function") {
791
+ // replace source controller in-case it is different
792
+ source = ensure(arg0);
793
+ setter = arg1;
794
+ }
795
+ else
796
+ throw new Error(`Factory argument cannot be ${arg1}`);
797
+ getter = computeMode(this, source, setter, key, computeRequired);
867
798
  };
868
- if (required)
799
+ if (typeof arg0 == "function" && factoryRequired)
869
800
  try {
870
801
  init();
871
802
  }
872
803
  catch (err) {
873
- Oops$7.Failed(subject, key).warn();
804
+ Oops$7.ComputeFailed(subject, key).warn();
874
805
  throw err;
875
806
  }
876
- get = () => {
877
- if (pending)
878
- return suspend();
879
- if (error)
880
- throw error;
881
- if (state.has(key))
882
- return state.get(key);
883
- let output = init();
884
- return pending
885
- ? suspend()
886
- : output;
807
+ return () => {
808
+ if (!getter)
809
+ init();
810
+ return getter();
887
811
  };
888
- if (typeof argument == "function")
889
- set = createValueEffect(argument);
890
- else
891
- set = (value) => {
892
- if (value === undefined && required)
893
- throw Oops$7.NonOptional(subject, key);
894
- };
812
+ });
813
+ }
814
+
815
+ function ref(callback) {
816
+ return apply(function ref(key) {
817
+ const value = this.ref(key, callback && createValueEffect(callback));
818
+ defineProperty(value, "current", {
819
+ set: value,
820
+ get: () => this.state.get(key)
821
+ });
895
822
  return {
896
- set,
897
- get
823
+ value,
824
+ explicit: true
898
825
  };
899
826
  });
900
827
  }
@@ -916,106 +843,25 @@ function set(value, argument) {
916
843
  });
917
844
  }
918
845
 
919
- const Parent = new WeakMap();
920
- const Oops$6 = issues({
921
- Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
922
- Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
923
- });
924
- function parent(Expects, required) {
925
- return apply(function parent() {
926
- const child = this.subject;
927
- const value = Parent.get(child);
928
- const expected = Expects.name;
929
- if (!value) {
930
- if (required !== false)
931
- throw Oops$6.Required(expected, child);
932
- }
933
- else if (!(value instanceof Expects))
934
- throw Oops$6.Unexpected(expected, child, value);
935
- return { value };
936
- });
937
- }
938
-
939
846
  const ANY = Symbol("any");
940
847
  function keyed(control, property, initial) {
848
+ const init = createProxy(emit, watch);
849
+ const frozen = new Set();
941
850
  const context = new Map();
942
851
  const users = new Map();
943
852
  const watched = new WeakMap();
944
853
  const update = new Set();
945
- const frozen = new Set();
946
- let managed;
947
- manage(initial);
948
- function reset() {
949
- frozen.clear();
950
- }
854
+ let managed = init(initial);
951
855
  function watch(on, key) {
952
856
  const include = watched.get(on);
953
857
  if (include)
954
858
  include.add(key);
955
859
  }
956
860
  function emit(key) {
957
- control.waiting.add(reset);
958
861
  control.update(property);
862
+ control.waiting.add(() => frozen.clear());
959
863
  update.forEach(notify => notify(key));
960
864
  }
961
- function manage(current) {
962
- managed = create(current);
963
- context.clear();
964
- assign(managed, {
965
- delete(key) {
966
- emit(key);
967
- return current.delete(key);
968
- },
969
- clear() {
970
- emit(ANY);
971
- current.clear();
972
- },
973
- has(key) {
974
- watch(this, key);
975
- return current.has(key);
976
- },
977
- keys() {
978
- watch(this, ANY);
979
- return current.keys();
980
- },
981
- values() {
982
- watch(this, ANY);
983
- return current.values();
984
- },
985
- entries() {
986
- watch(this, ANY);
987
- return current.entries();
988
- },
989
- [Symbol.iterator]() {
990
- watch(this, ANY);
991
- return current[Symbol.iterator]();
992
- },
993
- }, current instanceof Set
994
- ? {
995
- add(key) {
996
- current.add(key);
997
- emit(key);
998
- return this;
999
- }
1000
- }
1001
- : {
1002
- get(key) {
1003
- watch(this, ANY);
1004
- return current.get(key);
1005
- },
1006
- set(key, value) {
1007
- current.set(key, value);
1008
- emit(key);
1009
- return this;
1010
- }
1011
- });
1012
- defineProperty(managed, "size", {
1013
- get() {
1014
- watch(this, ANY);
1015
- return current.size;
1016
- }
1017
- });
1018
- }
1019
865
  function subscribe(local) {
1020
866
  const proxy = create(managed);
1021
867
  let watch = users.get(local);
@@ -1058,46 +904,185 @@ function keyed(control, property, initial) {
1058
904
  },
1059
905
  set(next) {
1060
906
  control.state.set(property, next);
1061
- manage(next);
907
+ managed = init(next);
908
+ context.clear();
1062
909
  emit(ANY);
1063
910
  },
1064
911
  destroy() {
1065
912
  update.clear();
913
+ context.clear();
1066
914
  }
1067
915
  };
916
+ }
917
+ function createProxy(emit, watch) {
918
+ return (from) => {
919
+ const proxy = create(from);
920
+ assign(proxy, {
921
+ from,
922
+ delete(key) {
923
+ emit(key);
924
+ return from.delete(key);
925
+ },
926
+ clear() {
927
+ emit(ANY);
928
+ from.clear();
929
+ },
930
+ has(key) {
931
+ watch(this, key);
932
+ return from.has(key);
933
+ },
934
+ keys() {
935
+ watch(this, ANY);
936
+ return from.keys();
937
+ },
938
+ values() {
939
+ watch(this, ANY);
940
+ return from.values();
941
+ },
942
+ entries() {
943
+ watch(this, ANY);
944
+ return from.entries();
945
+ },
946
+ forEach(callbackfn, thisArg) {
947
+ const acc = [];
948
+ from.forEach((a, b, c) => {
949
+ const result = callbackfn.call(thisArg, a, b, c);
950
+ if (result !== undefined)
951
+ acc.push(result);
952
+ });
953
+ watch(this, ANY);
954
+ return acc;
955
+ },
956
+ [Symbol.iterator]() {
957
+ watch(this, ANY);
958
+ return from[Symbol.iterator]();
959
+ },
960
+ }, from instanceof Set
961
+ ? {
962
+ add(key) {
963
+ from.add(key);
964
+ emit(key);
965
+ return this;
966
+ }
967
+ }
968
+ : {
969
+ get(key) {
970
+ watch(this, ANY);
971
+ return from.get(key);
972
+ },
973
+ set(key, value) {
974
+ from.set(key, value);
975
+ emit(key);
976
+ return this;
977
+ }
978
+ });
979
+ defineProperty(proxy, "size", {
980
+ get() {
981
+ watch(this, ANY);
982
+ return from.size;
983
+ }
984
+ });
985
+ return proxy;
986
+ };
1068
987
  }
1069
988
 
1070
- const Oops$5 = issues({
989
+ const Parent = new WeakMap();
990
+ const Oops$6 = issues({
1071
991
  BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
992
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
1072
993
  });
1073
994
  function use$1(input, argument) {
1074
995
  return apply(function use(key) {
1075
996
  const { state, subject } = this;
997
+ const required = argument !== false;
998
+ let pending;
999
+ let error;
1000
+ let get = (_local) => state.get(key);
1076
1001
  if (typeof input === "function")
1077
- input = "prototype" in input ? new input() : input();
1002
+ input = /^[A-Z]/.test(input.name)
1003
+ ? new input() : input;
1078
1004
  else if (input && typeof input !== "object")
1079
- throw Oops$5.BadArgument(typeof input);
1005
+ throw Oops$6.BadArgument(typeof input);
1080
1006
  if (input instanceof Map || input instanceof Set)
1081
1007
  return keyed(this, key, input);
1082
- function onUpdate(next) {
1008
+ const onUpdate = (next) => {
1083
1009
  state.set(key, next);
1084
1010
  if (next) {
1011
+ get = getRecursive(key, this);
1085
1012
  Parent.set(next, subject);
1086
1013
  ensure(next);
1087
1014
  }
1088
1015
  if (typeof argument == "function")
1089
1016
  argument(next);
1090
1017
  return true;
1091
- }
1092
- if (input)
1093
- onUpdate(input);
1018
+ };
1019
+ const suspend = () => {
1020
+ if (required === false)
1021
+ return;
1022
+ const issue = Oops$6.NotReady(subject, key);
1023
+ Object.assign(pending, {
1024
+ message: issue.message,
1025
+ stack: issue.stack
1026
+ });
1027
+ throw pending;
1028
+ };
1029
+ const initialize = () => {
1030
+ const output = typeof input == "function" ?
1031
+ mayRetry(() => input.call(subject, subject)) :
1032
+ input;
1033
+ if (output instanceof Promise) {
1034
+ pending = output
1035
+ .catch(err => error = err)
1036
+ .then(val => {
1037
+ onUpdate(val);
1038
+ return val;
1039
+ })
1040
+ .finally(() => {
1041
+ pending = undefined;
1042
+ this.update(key);
1043
+ });
1044
+ return;
1045
+ }
1046
+ onUpdate(output);
1047
+ };
1048
+ if (input !== undefined && required)
1049
+ initialize();
1094
1050
  return {
1095
1051
  set: onUpdate,
1096
- recursive: true
1052
+ get(local) {
1053
+ if (pending)
1054
+ return suspend();
1055
+ if (error)
1056
+ throw error;
1057
+ if (!state.has(key))
1058
+ initialize();
1059
+ if (pending)
1060
+ return suspend();
1061
+ return get(local);
1062
+ }
1097
1063
  };
1098
1064
  });
1099
1065
  }
1100
1066
 
1067
+ const Oops$5 = issues({
1068
+ Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
1069
+ Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
1070
+ });
1071
+ function has(Expects, required) {
1072
+ return apply(function parent() {
1073
+ const child = this.subject;
1074
+ const value = Parent.get(child);
1075
+ const expected = Expects.name;
1076
+ if (!value) {
1077
+ if (required !== false)
1078
+ throw Oops$5.Required(expected, child);
1079
+ }
1080
+ else if (!(value instanceof Expects))
1081
+ throw Oops$5.Unexpected(expected, child, value);
1082
+ return { value };
1083
+ });
1084
+ }
1085
+
1101
1086
  class Lookup {
1102
1087
  constructor() {
1103
1088
  this.table = new Map();
@@ -1382,12 +1367,12 @@ class MVC extends Model {
1382
1367
  });
1383
1368
  return instance;
1384
1369
  }, []);
1385
- usePeerContext(instance.get);
1370
+ usePeerContext(instance.is);
1386
1371
  return instance;
1387
1372
  }
1388
1373
  static use(a, b) {
1389
1374
  const instance = useModel(this, a, b);
1390
- usePeerContext(instance.get);
1375
+ usePeerContext(instance.is);
1391
1376
  return instance;
1392
1377
  }
1393
1378
  /**
@@ -1521,5 +1506,5 @@ class Global extends MVC {
1521
1506
  }
1522
1507
  }
1523
1508
 
1524
- export { CONTROL, Consumer, Global, LOCAL, MVC as Model, Provider, STATE, WHY, act, apply, array, MVC as default, get as from, get, parent, put, ref, set, tap, use$1 as use, useFrom, useLocal, useModel, useTap };
1509
+ export { CONTROL, Consumer, Global, LOCAL, MVC as Model, Provider, STATE, WHY, act, apply, MVC as default, get, has, ref, set, tap, use$1 as use, useFrom, useLocal, useModel, useTap };
1525
1510
  //# sourceMappingURL=index.esm.js.map