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