@expressive/mvc 0.2.4 → 0.3.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
@@ -148,6 +148,9 @@ function applyUpdate(subject, keys) {
148
148
  UPDATE.delete(subject);
149
149
  }, 0);
150
150
  };
151
+ }
152
+ function getUpdate(subject) {
153
+ return UPDATE.get(subject);
151
154
  }
152
155
 
153
156
  const CONTROL = Symbol("CONTROL");
@@ -179,21 +182,30 @@ class Model {
179
182
  return control(this, control => {
180
183
  if (typeof select == "function")
181
184
  return control.addListener(select);
182
- const keys = typeof select == "string" ? [select] :
185
+ const selection = typeof select == "string" ? [select] :
183
186
  !select.length ? getOwnPropertyNames(control.state) :
184
187
  select;
185
- ensure(control, keys);
188
+ ensure(control, selection);
186
189
  const callback = squash
187
- ? handler.bind(this)
188
- : frame => frame
189
- .filter(k => keys.includes(k))
190
- .forEach(k => handler.call(this, control.state[k], k));
191
- const trigger = once
192
- ? frame => { remove(); callback(frame); }
190
+ ? () => {
191
+ handler.call(this, getUpdate(this));
192
+ }
193
+ : () => {
194
+ getUpdate(this)
195
+ .filter(k => selection.includes(k))
196
+ .forEach(k => {
197
+ handler.call(this, control.state[k], k);
198
+ });
199
+ };
200
+ const onEvent = once
201
+ ? () => {
202
+ remove();
203
+ callback();
204
+ }
193
205
  : callback;
194
206
  const remove = control.addListener(key => {
195
- if (keys.includes(key))
196
- return trigger;
207
+ if (selection.includes(key))
208
+ return onEvent;
197
209
  });
198
210
  return remove;
199
211
  });
@@ -209,7 +221,7 @@ class Model {
209
221
  const effect = createEffect(callback);
210
222
  return control(this, control => {
211
223
  let busy = false;
212
- let inject = this.get;
224
+ let inject = this.is;
213
225
  const invoke = () => {
214
226
  if (busy)
215
227
  return;
@@ -314,6 +326,7 @@ class Subscriber {
314
326
  this.watch = {};
315
327
  const parent = target instanceof Controller
316
328
  ? target : control(target);
329
+ const subject = parent.subject;
317
330
  const proxy = create(parent.proxy);
318
331
  let reset;
319
332
  define(proxy, LOCAL, this);
@@ -332,8 +345,10 @@ class Subscriber {
332
345
  if (typeof handler == "function")
333
346
  handler();
334
347
  const notify = this.onUpdate(key, parent);
335
- const getWhy = (keys) => {
336
- reset = applyUpdate(proxy, keys.filter(k => k in this.watch));
348
+ const getWhy = () => {
349
+ const update = getUpdate(subject);
350
+ const applicable = update.filter(k => k in this.watch);
351
+ reset = applyUpdate(proxy, applicable);
337
352
  };
338
353
  if (notify) {
339
354
  parent.requestUpdate(getWhy);
@@ -418,9 +433,9 @@ function from(source, arg1, arg2) {
418
433
  }
419
434
  }
420
435
  function defer(_key, from) {
421
- let pending = KEYS.get(from);
436
+ let pending = KEYS.get(from.frame);
422
437
  if (!pending)
423
- KEYS.set(from, pending = []);
438
+ KEYS.set(from.frame, pending = []);
424
439
  if (info.parent !== from)
425
440
  update();
426
441
  else {
@@ -474,19 +489,17 @@ function ensure(on, keys) {
474
489
  getter(true);
475
490
  }
476
491
  }
477
- function flush(on) {
478
- const handled = on.frame;
479
- const pending = KEYS.get(on);
492
+ function flush(frame) {
493
+ const pending = KEYS.get(frame);
480
494
  if (!pending)
481
495
  return;
482
496
  while (pending.length) {
483
- const why = [...handled];
484
497
  const compute = pending.shift();
485
498
  const { key } = INFO.get(compute);
486
- if (!handled.has(key))
487
- compute(why);
499
+ if (!frame.has(key))
500
+ compute();
488
501
  }
489
- KEYS.delete(on);
502
+ KEYS.delete(frame);
490
503
  }
491
504
 
492
505
  const Oops$9 = issues({
@@ -500,41 +513,41 @@ class Controller {
500
513
  this.subject = subject;
501
514
  this.state = {};
502
515
  this.frame = new Set();
503
- this.waiting = new Set();
504
516
  this.onDestroy = new Set();
517
+ this.waiting = new Set();
505
518
  this.followers = new Set();
506
519
  this.proxy = Object.create(subject);
507
520
  }
508
521
  start() {
509
522
  READY.add(this);
510
523
  for (const key in this.subject) {
511
- const { value: entry } = getOwnPropertyDescriptor(this.subject, key);
512
- if (typeof entry == "function")
524
+ const { value } = getOwnPropertyDescriptor(this.subject, key);
525
+ if (typeof value == "function")
513
526
  continue;
514
- if (typeof entry == "symbol") {
515
- const instruction = PENDING.get(entry);
527
+ if (typeof value == "symbol") {
528
+ const instruction = PENDING.get(value);
516
529
  if (instruction)
517
530
  instruction.call(this, key, this);
518
531
  continue;
519
532
  }
520
- this.manage(key, entry);
533
+ this.manage(key, value);
521
534
  }
522
- this.emit([]);
535
+ this.flush();
523
536
  }
524
537
  stop() {
525
538
  this.followers.clear();
526
539
  this.onDestroy.forEach(x => x());
527
540
  }
528
541
  manage(key, value) {
529
- const { proxy, state, subject } = this;
530
- state[key] = value;
542
+ const { state } = this;
531
543
  const set = this.ref(key);
532
- defineProperty(subject, key, {
544
+ state[key] = value;
545
+ defineProperty(this.subject, key, {
533
546
  enumerable: false,
534
547
  get: () => state[key],
535
548
  set
536
549
  });
537
- defineProperty(proxy, key, {
550
+ defineProperty(this.proxy, key, {
538
551
  enumerable: false,
539
552
  get() {
540
553
  const local = this[LOCAL];
@@ -566,53 +579,56 @@ class Controller {
566
579
  this.followers.delete(listener);
567
580
  };
568
581
  }
569
- emit(keys) {
570
- const waiting = [...this.waiting];
571
- this.waiting.clear();
572
- applyUpdate(this.subject, keys)();
573
- for (const callback of waiting)
574
- try {
575
- callback(keys);
576
- }
577
- catch (err) {
578
- console.error(err);
579
- }
580
- }
581
582
  update(key, value) {
583
+ const { frame } = this;
582
584
  if (1 in arguments)
583
585
  this.state[key] = value;
584
- if (this.frame.has(key))
585
- return;
586
- if (!this.frame.size)
586
+ if (!frame.size)
587
587
  setTimeout(() => {
588
- flush(this);
589
- const keys = Object.freeze([...this.frame]);
590
- this.frame.clear();
591
- this.emit(keys);
588
+ flush(frame);
589
+ this.flush();
592
590
  }, 0);
593
- this.frame.add(key);
591
+ else if (frame.has(key))
592
+ return;
593
+ frame.add(key);
594
594
  for (const callback of this.followers) {
595
595
  const event = callback(key, this);
596
596
  if (typeof event == "function")
597
597
  this.waiting.add(event);
598
598
  }
599
599
  }
600
+ flush() {
601
+ const waiting = Array.from(this.waiting);
602
+ const keys = Array.from(this.frame);
603
+ this.frame.clear();
604
+ this.waiting.clear();
605
+ applyUpdate(this.subject, keys)();
606
+ for (const callback of waiting)
607
+ try {
608
+ callback();
609
+ }
610
+ catch (err) {
611
+ console.error(err);
612
+ }
613
+ }
600
614
  requestUpdate(arg) {
615
+ const { frame, subject, waiting } = this;
601
616
  if (typeof arg == "function") {
602
- this.waiting.add(arg);
617
+ waiting.add(arg);
603
618
  return;
604
619
  }
605
- if (arg === true && this.frame.size < 1)
620
+ if (!frame.size && arg === true)
606
621
  return Promise.reject(Oops$9.StrictUpdate());
607
622
  return {
608
623
  then: (callback) => {
609
- if (callback)
610
- if (this.frame.size || arg !== false)
611
- this.waiting.add(callback);
612
- else
613
- callback(false);
614
- else
624
+ if (!callback)
615
625
  throw Oops$9.NoChaining();
626
+ if (frame.size || arg !== false)
627
+ waiting.add(() => {
628
+ callback(getUpdate(subject));
629
+ });
630
+ else
631
+ callback(false);
616
632
  }
617
633
  };
618
634
  }
@@ -835,65 +851,60 @@ const Oops$7 = issues({
835
851
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
836
852
  Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
837
853
  });
838
- function set(factory, argument) {
854
+ function put(factory, argument) {
839
855
  return apply(function set(key) {
840
856
  const { subject, state } = this;
841
857
  const required = argument === true || argument === undefined;
842
858
  let set;
843
859
  let get;
844
- let suspense;
845
- if (factory === undefined)
846
- suspense = true;
847
- else {
848
- let pending;
849
- let error;
850
- const init = () => {
851
- const output = typeof factory == "function" ?
852
- mayRetry(() => factory.call(subject, key, subject)) :
853
- factory;
854
- if (output instanceof Promise) {
855
- pending = output
856
- .catch(err => error = err)
857
- .then(val => state[key] = val)
858
- .finally(() => {
859
- pending = undefined;
860
- this.update(key);
861
- });
862
- return;
863
- }
864
- return state[key] = 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
860
+ let pending;
861
+ let error;
862
+ const init = () => {
863
+ const output = typeof factory == "function" ?
864
+ mayRetry(() => factory.call(subject, key, subject)) :
865
+ factory;
866
+ if (output instanceof Promise) {
867
+ pending = output
868
+ .catch(err => error = err)
869
+ .then(val => state[key] = val)
870
+ .finally(() => {
871
+ pending = undefined;
872
+ this.update(key);
873
873
  });
874
- throw pending;
875
- };
876
- if (required)
877
- try {
878
- init();
879
- }
880
- catch (err) {
881
- Oops$7.Failed(subject, key).warn();
882
- throw err;
883
- }
884
- get = () => {
885
- if (pending)
886
- return suspend();
887
- if (error)
888
- throw error;
889
- if (key in state)
890
- return state[key];
891
- let output = init();
892
- return pending
893
- ? suspend()
894
- : output;
895
- };
896
- }
874
+ return;
875
+ }
876
+ return state[key] = output;
877
+ };
878
+ const suspend = () => {
879
+ if (required === false)
880
+ return undefined;
881
+ const issue = Oops$7.NotReady(subject, key);
882
+ Object.assign(pending, {
883
+ message: issue.message,
884
+ stack: issue.stack
885
+ });
886
+ throw pending;
887
+ };
888
+ if (required)
889
+ try {
890
+ init();
891
+ }
892
+ catch (err) {
893
+ Oops$7.Failed(subject, key).warn();
894
+ throw err;
895
+ }
896
+ get = () => {
897
+ if (pending)
898
+ return suspend();
899
+ if (error)
900
+ throw error;
901
+ if (key in state)
902
+ return state[key];
903
+ let output = init();
904
+ return pending
905
+ ? suspend()
906
+ : output;
907
+ };
897
908
  if (typeof argument == "function")
898
909
  set = createValueEffect(argument);
899
910
  else
@@ -903,8 +914,24 @@ function set(factory, argument) {
903
914
  };
904
915
  return {
905
916
  set,
906
- get,
907
- suspense
917
+ get
918
+ };
919
+ });
920
+ }
921
+
922
+ function set(value, argument) {
923
+ if (!(1 in arguments)) {
924
+ argument = value;
925
+ value = undefined;
926
+ }
927
+ return apply(function set(key) {
928
+ if (value !== undefined)
929
+ this.state[key] = value;
930
+ return {
931
+ suspense: true,
932
+ set: typeof argument == "function"
933
+ ? createValueEffect(argument)
934
+ : undefined
908
935
  };
909
936
  });
910
937
  }
@@ -1410,6 +1437,7 @@ exports.array = array;
1410
1437
  exports["default"] = MVC;
1411
1438
  exports.from = from;
1412
1439
  exports.parent = parent;
1440
+ exports.put = put;
1413
1441
  exports.ref = ref;
1414
1442
  exports.set = set;
1415
1443
  exports.tap = tap;