@expressive/mvc 1.0.0-beta.20 → 1.0.0-beta.24

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
@@ -313,18 +313,17 @@ function eventsFor(prefix) {
313
313
  }
314
314
 
315
315
  const CONTROL = Symbol("control");
316
- const CREATE = Symbol("start");
317
316
  const LOCAL = Symbol("local");
318
317
  const STATE = Symbol("state");
319
- const Pending = new Map();
320
318
  function manage(src) {
321
319
  return src[CONTROL];
322
320
  }
323
- function set(instruction, label) {
324
- const name = label || instruction.name || "pending";
321
+ const Pending = new Map();
322
+ function apply(fn, label) {
323
+ const name = label || fn.name || "pending";
325
324
  const placeholder = Symbol(`${name} instruction`);
326
- Pending.set(placeholder, function set(key) {
327
- let output = instruction.call(this, key, this);
325
+ function setup(key) {
326
+ let output = fn.call(this, key, this);
328
327
  if (typeof output == "function") {
329
328
  const getter = output;
330
329
  output = Object.assign(Object.assign({}, getOwnPropertyDescriptor(this.subject, key)), { get() {
@@ -333,7 +332,8 @@ function set(instruction, label) {
333
332
  }
334
333
  if (output)
335
334
  defineProperty(this.subject, key, output);
336
- });
335
+ }
336
+ Pending.set(placeholder, setup);
337
337
  return placeholder;
338
338
  }
339
339
  class Controller {
@@ -345,14 +345,10 @@ class Controller {
345
345
  this.waiting = [];
346
346
  }
347
347
  static setup(onto) {
348
- const create = onto[CREATE];
349
348
  const control = new this(onto);
350
- const after = create && create.call(onto, control);
351
349
  defineLazy(onto, CONTROL, () => {
352
350
  onto[STATE] = control.state;
353
351
  control.start();
354
- if (after)
355
- after();
356
352
  if (onto.didCreate)
357
353
  onto.didCreate();
358
354
  return control;
@@ -457,56 +453,57 @@ function keys(from, using) {
457
453
  return from.select(using);
458
454
  }
459
455
 
460
- const attach = (from, name) => set(function attach(key) {
461
- const proxyCache = new WeakMap();
462
- const getCurrent = from.call(this, key);
463
- function subscribe(sub) {
464
- let child;
465
- function start() {
466
- const instance = getCurrent();
467
- if (instance) {
468
- child = new Subscriber(instance, sub.onUpdate);
469
- if (sub.active)
470
- child.commit();
471
- sub.dependant.add(child);
472
- proxyCache.set(sub, child.proxy);
456
+ function child(from, name) {
457
+ return apply(function child(key) {
458
+ const proxyCache = new WeakMap();
459
+ const getCurrent = from.call(this, key);
460
+ function subscribe(sub) {
461
+ let child;
462
+ function start() {
463
+ const instance = getCurrent();
464
+ if (instance) {
465
+ child = new Subscriber(instance, sub.onUpdate);
466
+ if (sub.active)
467
+ child.commit();
468
+ sub.dependant.add(child);
469
+ proxyCache.set(sub, child.proxy);
470
+ }
473
471
  }
474
- }
475
- function refresh() {
476
- if (child) {
477
- child.release();
478
- sub.dependant.delete(child);
479
- proxyCache.set(sub, undefined);
480
- child = undefined;
472
+ function refresh() {
473
+ if (child) {
474
+ child.release();
475
+ sub.dependant.delete(child);
476
+ proxyCache.set(sub, undefined);
477
+ child = undefined;
478
+ }
479
+ start();
480
+ sub.onUpdate();
481
481
  }
482
482
  start();
483
- sub.onUpdate();
483
+ sub.follow(key, refresh);
484
484
  }
485
- start();
486
- sub.follow(key, refresh);
487
- }
488
- return (local) => {
489
- if (!local)
490
- return getCurrent();
491
- if (!proxyCache.has(local))
492
- subscribe(local);
493
- return proxyCache.get(local);
494
- };
495
- }, name || from.name);
485
+ return (local) => {
486
+ if (!local)
487
+ return getCurrent();
488
+ if (!proxyCache.has(local))
489
+ subscribe(local);
490
+ return proxyCache.get(local);
491
+ };
492
+ }, name || from.name);
493
+ }
496
494
 
497
495
  const Oops$7 = issues({
498
496
  HasPropertyUndefined: (control, property) => `${control}.${property} is marked as required for this render.`
499
497
  });
500
- const useElementLifecycle = lifecycle("element");
501
498
  function use$1(init) {
502
499
  const [state, update] = react.useState(() => [
503
500
  init(() => update(state.concat()))
504
501
  ]);
505
502
  return state[0];
506
503
  }
507
- function useLazy(Type, args, callback) {
504
+ function useLazy(Type, callback) {
508
505
  const instance = react.useMemo(() => {
509
- const instance = Type.create(...args || []);
506
+ const instance = Type.create();
510
507
  if (callback)
511
508
  callback(instance);
512
509
  return instance;
@@ -533,14 +530,9 @@ function useWatcher(target, focus, expected) {
533
530
  react.useLayoutEffect(() => hook.commit(), []);
534
531
  return hook.proxy;
535
532
  }
536
- function useSubscriber(target, tag) {
537
- const hook = use$1(refresh => new Subscriber(target, refresh));
538
- useElementLifecycle(hook, tag || 0);
539
- return hook.proxy;
540
- }
541
- function useModel(Type, args, callback) {
533
+ function useModel(Type, callback) {
542
534
  const hook = use$1(refresh => {
543
- const instance = new Type(...args || []);
535
+ const instance = new Type();
544
536
  const control = manage(instance);
545
537
  const sub = new Subscriber(control, refresh);
546
538
  const release = control.addListener({
@@ -556,6 +548,56 @@ function useModel(Type, args, callback) {
556
548
  return hook.proxy;
557
549
  }
558
550
 
551
+ const Oops$6 = issues({
552
+ CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
553
+ AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
554
+ });
555
+ const PendingContext = new WeakMap();
556
+ const ContextWasUsed = new WeakMap();
557
+ function tap(type, argument) {
558
+ return child(function tap(key) {
559
+ return pendingAccess(this.subject, type, key, argument);
560
+ });
561
+ }
562
+ function pendingAccess(from, type, key, argument) {
563
+ if ("current" in type)
564
+ return () => type.current;
565
+ if ("current" in from.constructor)
566
+ throw Oops$6.CantAttachGlobal(from, type.name);
567
+ let instance;
568
+ getPending(from).push(context => {
569
+ instance = context.get(type);
570
+ if (typeof argument == "function") {
571
+ if (argument(instance) === false)
572
+ instance = undefined;
573
+ }
574
+ else if (!instance && argument)
575
+ throw Oops$6.AmbientRequired(type.name, from, key);
576
+ });
577
+ return () => instance;
578
+ }
579
+ function usePeerContext(subject) {
580
+ if (ContextWasUsed.has(subject)) {
581
+ if (ContextWasUsed.get(subject))
582
+ useLookup();
583
+ return;
584
+ }
585
+ const pending = PendingContext.get(subject);
586
+ if (pending) {
587
+ const local = useLookup();
588
+ for (const init of pending)
589
+ init(local);
590
+ PendingContext.delete(subject);
591
+ }
592
+ ContextWasUsed.set(subject, !!pending);
593
+ }
594
+ function getPending(subject) {
595
+ let pending = PendingContext.get(subject);
596
+ if (!pending)
597
+ PendingContext.set(subject, pending = []);
598
+ return pending;
599
+ }
600
+
559
601
  class Lookup {
560
602
  constructor() {
561
603
  this.table = new Map();
@@ -611,7 +653,7 @@ class Lookup {
611
653
  }
612
654
  }
613
655
 
614
- const Oops$6 = issues({
656
+ const Oops$5 = issues({
615
657
  NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`,
616
658
  NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
617
659
  BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
@@ -621,7 +663,7 @@ const useLookup = () => react.useContext(LookupContext);
621
663
  function useFromContext(Type, strict) {
622
664
  const instance = useLookup().get(Type);
623
665
  if (!instance && strict)
624
- throw Oops$6.NothingInContext(Type.name);
666
+ throw Oops$5.NothingInContext(Type.name);
625
667
  return instance;
626
668
  }
627
669
  function Consumer(props) {
@@ -632,13 +674,13 @@ function Consumer(props) {
632
674
  if (typeof callback == "function")
633
675
  callback(Control.get(!!has));
634
676
  else
635
- throw Oops$6.BadConsumerProps();
677
+ throw Oops$5.BadConsumerProps();
636
678
  return null;
637
679
  }
638
680
  function useNewContext(from, inject) {
639
681
  return react.useMemo(() => {
640
682
  if (!inject)
641
- throw Oops$6.NoProviderType();
683
+ throw Oops$5.NoProviderType();
642
684
  const context = from.push(inject);
643
685
  for (const instance of context.local)
644
686
  for (const apply of getPending(instance))
@@ -681,63 +723,88 @@ function Provider(props) {
681
723
  : render);
682
724
  }
683
725
 
684
- const Oops$5 = issues({
685
- CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
686
- AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
687
- });
688
- const PendingContext = new WeakMap();
689
- const ContextWasUsed = new WeakMap();
690
- const tap = (type, argument) => attach(function tap(key) {
691
- return pendingAccess(this.subject, type, key, argument);
692
- });
693
- function pendingAccess(from, type, key, argument) {
694
- if ("current" in type)
695
- return () => type.current;
696
- if ("current" in from.constructor)
697
- throw Oops$5.CantAttachGlobal(from, type.name);
698
- let instance;
699
- getPending(from).push(context => {
700
- instance = context.get(type);
701
- if (typeof argument == "function") {
702
- if (argument(instance) === false)
703
- instance = undefined;
704
- }
705
- else if (!instance && argument)
706
- throw Oops$5.AmbientRequired(type.name, from, key);
707
- });
708
- return () => instance;
709
- }
710
- function usePeerContext(subject) {
711
- if (ContextWasUsed.has(subject)) {
712
- if (ContextWasUsed.get(subject))
713
- useLookup();
714
- return;
715
- }
716
- const pending = PendingContext.get(subject);
717
- if (pending) {
718
- const local = useLookup();
719
- for (const init of pending)
720
- init(local);
721
- PendingContext.delete(subject);
722
- }
723
- ContextWasUsed.set(subject, !!pending);
724
- }
725
- function getPending(subject) {
726
- let pending = PendingContext.get(subject);
727
- if (!pending)
728
- PendingContext.set(subject, pending = []);
729
- return pending;
730
- }
731
-
732
726
  const Oops$4 = issues({
733
727
  StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
734
728
  NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
735
729
  });
736
- class State {
730
+ const useElementLifecycle = lifecycle("element");
731
+ const useComponentLifecycle = lifecycle("component");
732
+ class Model {
737
733
  constructor() {
738
- Controller.setup(this);
734
+ const control = Controller.setup(this);
739
735
  define(this, "get", this);
740
736
  define(this, "set", this);
737
+ defer(control, "on");
738
+ defer(control, "effect");
739
+ control.include(() => {
740
+ delete this.on;
741
+ delete this.effect;
742
+ });
743
+ }
744
+ tap(path, expect) {
745
+ const proxy = useWatcher(this, path, expect);
746
+ this.update("willRender", true);
747
+ return proxy;
748
+ }
749
+ tag(id) {
750
+ const hook = use$1(refresh => {
751
+ return new Subscriber(this, refresh);
752
+ });
753
+ useElementLifecycle(hook, id || 0);
754
+ return hook.proxy;
755
+ }
756
+ use(callback) {
757
+ const hook = use$1(refresh => {
758
+ if (callback)
759
+ callback(this);
760
+ return new Subscriber(this, refresh);
761
+ });
762
+ useComponentLifecycle(hook);
763
+ return hook.proxy;
764
+ }
765
+ on(subset, handler, squash, once) {
766
+ const control = manage(this);
767
+ const set = keys(control, subset);
768
+ const batch = {};
769
+ const remove = control.addListener(batch);
770
+ const callback = squash
771
+ ? handler.bind(this)
772
+ : (frame) => {
773
+ for (const key of frame)
774
+ if (set.includes(key))
775
+ handler.call(this, control.state[key], key);
776
+ };
777
+ const handle = once
778
+ ? (k) => { remove(); callback(k); }
779
+ : callback;
780
+ for (const key of set)
781
+ batch[key] = handle;
782
+ ensure(control, set);
783
+ return remove;
784
+ }
785
+ once(select, callback, squash) {
786
+ if (callback)
787
+ return this.on(select, callback, squash, true);
788
+ else
789
+ return new Promise(resolve => {
790
+ this.on(select, resolve, true, true);
791
+ });
792
+ }
793
+ effect(callback, select) {
794
+ const control = manage(this);
795
+ let target = this;
796
+ const effect = createEffect(callback);
797
+ const invoke = () => effect.call(target, target);
798
+ if (select) {
799
+ invoke();
800
+ return this.on(select, invoke, true);
801
+ }
802
+ else {
803
+ const sub = new Subscriber(control, invoke);
804
+ target = sub.proxy;
805
+ invoke();
806
+ return sub.commit();
807
+ }
741
808
  }
742
809
  import(from, subset) {
743
810
  for (const key of keys(manage(this), subset))
@@ -788,34 +855,16 @@ class State {
788
855
  toString() {
789
856
  return this.constructor.name;
790
857
  }
791
- tap(path, expect) {
792
- const proxy = useWatcher(this, path, expect);
793
- this.update("willRender", true);
794
- return proxy;
795
- }
796
858
  static create(...args) {
797
859
  const instance = new this(...args);
798
860
  manage(instance);
799
861
  return instance;
800
862
  }
801
- static new(args, callback) {
802
- const instance = useLazy(this, args, callback);
863
+ static new(callback) {
864
+ const instance = useLazy(this, callback);
803
865
  instance.update("willRender", true);
804
866
  return instance;
805
867
  }
806
- static use(args, callback) {
807
- return useModel(this, args, callback);
808
- }
809
- static uses(props, only) {
810
- return this.use([], instance => {
811
- instance.import(props, only);
812
- });
813
- }
814
- static using(props, only) {
815
- const instance = this.use([]);
816
- instance.import(props, only);
817
- return instance;
818
- }
819
868
  static find(strict) {
820
869
  return useFromContext(this, strict);
821
870
  }
@@ -830,86 +879,36 @@ class State {
830
879
  static tap(key, expect) {
831
880
  return this.find(true).tap(key, expect);
832
881
  }
833
- static isTypeof(maybe) {
834
- return (typeof maybe == "function" &&
835
- maybe.prototype instanceof this);
836
- }
837
- }
838
- State.CONTROL = CONTROL;
839
- State.STATE = STATE;
840
- State.INIT = CREATE;
841
- State.LOCAL = LOCAL;
842
-
843
- const useComponentLifecycle = lifecycle("component");
844
- class Model extends State {
845
- [CREATE](using) {
846
- defer(using, "on");
847
- defer(using, "effect");
848
- return () => {
849
- delete this.on;
850
- delete this.effect;
851
- };
852
- }
853
- on(subset, handler, squash, once) {
854
- const control = manage(this);
855
- const set = keys(control, subset);
856
- const batch = {};
857
- const remove = control.addListener(batch);
858
- const callback = squash
859
- ? handler.bind(this)
860
- : (frame) => {
861
- for (const key of frame)
862
- if (set.includes(key))
863
- handler.call(this, control.state[key], key);
864
- };
865
- const handle = once
866
- ? (k) => { remove(); callback(k); }
867
- : callback;
868
- for (const key of set)
869
- batch[key] = handle;
870
- ensure(control, set);
871
- return remove;
872
- }
873
- once(select, callback, squash) {
874
- if (callback)
875
- return this.on(select, callback, squash, true);
876
- else
877
- return new Promise(resolve => {
878
- this.on(select, resolve, true, true);
879
- });
880
- }
881
- effect(callback, select) {
882
- const control = manage(this);
883
- let target = this;
884
- const effect = createEffect(callback);
885
- const invoke = () => effect.call(target, target);
886
- if (select) {
887
- invoke();
888
- return this.on(select, invoke, true);
889
- }
890
- else {
891
- const sub = new Subscriber(control, invoke);
892
- target = sub.proxy;
893
- invoke();
894
- return sub.commit();
895
- }
896
- }
897
- tag(id) {
898
- return useSubscriber(this, id);
882
+ static tag(id) {
883
+ return this.find(true).tag(id);
899
884
  }
900
- static use(args, callback) {
901
- const instance = useModel(this, args, callback);
885
+ static use(callback) {
886
+ const instance = useModel(this, callback);
902
887
  useComponentLifecycle(instance[LOCAL]);
903
888
  usePeerContext(instance.get);
904
889
  return instance;
905
890
  }
906
- static tag(id) {
907
- return this.find(true).tag(id);
891
+ static uses(props, only) {
892
+ return this.use(instance => {
893
+ instance.import(props, only);
894
+ });
895
+ }
896
+ static using(props, only) {
897
+ const instance = this.use();
898
+ instance.import(props, only);
899
+ return instance;
908
900
  }
909
901
  static meta(path) {
910
902
  return useWatcher(this, path);
911
903
  }
904
+ static isTypeof(maybe) {
905
+ return (typeof maybe == "function" &&
906
+ maybe.prototype instanceof this);
907
+ }
912
908
  }
909
+ Model.CONTROL = CONTROL;
910
+ Model.STATE = STATE;
911
+ Model.LOCAL = LOCAL;
913
912
  defineLazy(Model, CONTROL, function () {
914
913
  return new Controller(this).start();
915
914
  });
@@ -939,73 +938,86 @@ function bootstrap(object) {
939
938
  defineProperty(control, key, breakdown[key]);
940
939
  return control;
941
940
  }
942
- const use = (input, argument) => attach(function use(key) {
943
- let instance;
944
- const update = (next) => {
945
- instance =
946
- next instanceof Model ? next :
947
- next && bootstrap(next);
948
- if (instance) {
949
- Parent.set(instance, this.subject);
950
- manage(instance);
941
+ function use(input, argument) {
942
+ return child(function use(key) {
943
+ let instance;
944
+ const update = (next) => {
945
+ instance =
946
+ next instanceof Model ? next :
947
+ next && bootstrap(next);
948
+ if (instance) {
949
+ Parent.set(instance, this.subject);
950
+ manage(instance);
951
+ }
952
+ if (typeof argument == "function")
953
+ argument(instance);
954
+ else if (!instance && argument !== false)
955
+ throw Oops$3.UndefinedNotAllowed(key);
956
+ };
957
+ if (input) {
958
+ instance =
959
+ Model.isTypeof(input) ? new input() :
960
+ input instanceof Model ? input :
961
+ typeof input === "function" ? input() :
962
+ typeof input === "object" ? bootstrap(input) :
963
+ Oops$3.BadArgument(typeof input).throw();
964
+ if (instance)
965
+ update(instance);
951
966
  }
952
- if (typeof argument == "function")
953
- argument(instance);
954
- else if (!instance && argument !== false)
955
- throw Oops$3.UndefinedNotAllowed(key);
956
- };
957
- if (input) {
958
- instance =
959
- Model.isTypeof(input) ? new input() :
960
- input instanceof Model ? input :
961
- typeof input === "function" ? input() :
962
- typeof input === "object" ? bootstrap(input) :
963
- Oops$3.BadArgument(typeof input).throw();
964
- if (instance)
965
- update(instance);
966
- }
967
- else
968
- argument = false;
969
- this.manage(key, instance, update);
970
- return () => instance;
971
- });
972
- const parent = (Expects, required) => set(function parent() {
973
- const child = this.subject;
974
- const expected = Expects.name;
975
- const value = Parent.get(this.subject);
976
- if (!value) {
977
- if (required)
978
- throw Oops$3.ParentRequired(expected, child);
979
- }
980
- else if (!(value instanceof Expects))
981
- throw Oops$3.UnexpectedParent(expected, child, value);
982
- return { value };
983
- });
967
+ else
968
+ argument = false;
969
+ this.manage(key, instance, update);
970
+ return () => instance;
971
+ });
972
+ }
973
+ function parent(Expects, required) {
974
+ return apply(function parent() {
975
+ const child = this.subject;
976
+ const expected = Expects.name;
977
+ const value = Parent.get(this.subject);
978
+ if (!value) {
979
+ if (required)
980
+ throw Oops$3.ParentRequired(expected, child);
981
+ }
982
+ else if (!(value instanceof Expects))
983
+ throw Oops$3.UnexpectedParent(expected, child, value);
984
+ return { value };
985
+ });
986
+ }
984
987
 
985
988
  const Oops$2 = issues({
986
989
  DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
987
990
  BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
988
991
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
989
992
  });
990
- function ref(cb) {
991
- return set(function ref(key) {
992
- const refObjectFunction = this.setter(key, cb && createValueEffect(cb));
993
- defineProperty(refObjectFunction, "current", {
994
- set: refObjectFunction,
995
- get: () => this.state[key]
996
- });
997
- return {
998
- value: refObjectFunction
999
- };
993
+ function createRef(key, cb) {
994
+ const refObjectFunction = this.setter(key, cb && createValueEffect(cb));
995
+ defineProperty(refObjectFunction, "current", {
996
+ set: refObjectFunction,
997
+ get: () => this.state[key]
998
+ });
999
+ return refObjectFunction;
1000
+ }
1001
+ function ref(arg) {
1002
+ return apply(function ref(key) {
1003
+ let value = {};
1004
+ if (typeof arg == "object") {
1005
+ const source = manage(arg);
1006
+ for (const key in source.state)
1007
+ defineLazy(value, key, createRef.bind(source, key));
1008
+ }
1009
+ else
1010
+ value = createRef.call(this, key, arg);
1011
+ return { value };
1000
1012
  });
1001
1013
  }
1002
1014
  function on(initial, cb) {
1003
- return set(function on(key) {
1015
+ return apply(function on(key) {
1004
1016
  this.manage(key, initial, cb && createValueEffect(cb));
1005
1017
  });
1006
1018
  }
1007
1019
  function memo(factory, defer) {
1008
- return set(function memo(key) {
1020
+ return apply(function memo(key) {
1009
1021
  const source = this.subject;
1010
1022
  const get = () => factory.call(source);
1011
1023
  if (defer)
@@ -1015,7 +1027,7 @@ function memo(factory, defer) {
1015
1027
  });
1016
1028
  }
1017
1029
  function lazy(value) {
1018
- return set(function lazy(key) {
1030
+ return apply(function lazy(key) {
1019
1031
  const source = this.subject;
1020
1032
  source[key] = value;
1021
1033
  defineProperty(this.state, key, {
@@ -1024,7 +1036,7 @@ function lazy(value) {
1024
1036
  });
1025
1037
  }
1026
1038
  function act(task) {
1027
- return set(function act(key) {
1039
+ return apply(function act(key) {
1028
1040
  let pending = false;
1029
1041
  const invoke = (...args) => {
1030
1042
  if (pending)
@@ -1049,7 +1061,7 @@ function act(task) {
1049
1061
  });
1050
1062
  }
1051
1063
  function from(source, setter, getter) {
1052
- return set(function from(key) {
1064
+ return apply(function from(key) {
1053
1065
  const { subject } = this;
1054
1066
  let getSource;
1055
1067
  // Easy mistake, using a peer, will always be unresolved.
@@ -1076,51 +1088,76 @@ function from(source, setter, getter) {
1076
1088
  const Oops$1 = issues({
1077
1089
  ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
1078
1090
  });
1091
+ function pending(source, compute) {
1092
+ return (source === undefined ?
1093
+ suspendForValue() :
1094
+ typeof source == "function" && !source.prototype ?
1095
+ suspendForAsync(source) :
1096
+ suspendForComputed(source, compute));
1097
+ }
1079
1098
  /**
1080
- * Create suspense promise also interpretable as an error.
1081
- * React will handle it but other contexts probably won't.
1099
+ * Get value, suspend instead if undefined.
1100
+ *
1101
+ * Throws suspense promise also interpretable as an error.
1102
+ * React could handle it but other contexts probably not.
1082
1103
  */
1083
- function suspense(model, key) {
1084
- const { message, stack } = Oops$1.ValueNotReady(model, key);
1104
+ function pendingValue(via, key) {
1105
+ const value = via.state[key];
1106
+ if (value !== undefined)
1107
+ return value;
1108
+ const error = Oops$1.ValueNotReady(via.subject, key);
1085
1109
  const promise = new Promise(resolve => {
1086
- const release = model.on(key, (value) => {
1087
- if (value !== undefined)
1088
- release(), resolve();
1110
+ const release = via.addListener({
1111
+ [key](value) {
1112
+ if (value !== undefined) {
1113
+ release();
1114
+ resolve();
1115
+ }
1116
+ }
1089
1117
  });
1090
1118
  });
1091
- return Object.assign(promise, { message, stack });
1119
+ throw Object.assign(promise, {
1120
+ toString: () => String(error),
1121
+ message: error.message,
1122
+ stack: error.stack
1123
+ });
1092
1124
  }
1093
- function pending(source, compute) {
1094
- if (typeof source == "function" && !source.prototype)
1095
- return suspendForAsync(source);
1096
- else
1097
- return from(source, compute, function getter(value, key) {
1098
- if (value === undefined)
1099
- throw suspense(this, key);
1100
- return value;
1101
- });
1125
+ function suspendForComputed(source, compute) {
1126
+ function getter(_value, key) {
1127
+ return pendingValue(manage(this), key);
1128
+ }
1129
+ return from(source, compute, getter);
1130
+ }
1131
+ function suspendForValue() {
1132
+ return apply(function pending(key) {
1133
+ this.state[key] = undefined;
1134
+ return {
1135
+ set: this.setter(key),
1136
+ get: () => pendingValue(this, key)
1137
+ };
1138
+ });
1102
1139
  }
1103
1140
  function suspendForAsync(source) {
1104
- return set(function suspense(key) {
1141
+ return apply(function suspense(key) {
1142
+ const subject = this.subject;
1105
1143
  let waiting = true;
1106
- let output;
1144
+ let value;
1107
1145
  let error;
1108
1146
  return () => {
1109
- if (waiting) {
1110
- const issue = Oops$1.ValueNotReady(this.subject, key);
1111
- const promise = source
1112
- .call(this.subject, key)
1113
- .catch(err => error = err)
1114
- .then((value) => output = value)
1115
- .finally(() => waiting = false);
1116
- throw Object.assign(promise, {
1117
- message: issue.message,
1118
- stack: issue.stack
1119
- });
1120
- }
1121
1147
  if (error)
1122
1148
  throw error;
1123
- return output;
1149
+ if (!waiting)
1150
+ return value;
1151
+ const issue = Oops$1.ValueNotReady(subject, key);
1152
+ let suspend = source
1153
+ .call(subject, key)
1154
+ .catch(err => error = err)
1155
+ .then(out => value = out)
1156
+ .finally(() => waiting = false);
1157
+ throw Object.assign(suspend, {
1158
+ message: issue.message,
1159
+ stack: issue.stack
1160
+ });
1124
1161
  };
1125
1162
  });
1126
1163
  }
@@ -1170,9 +1207,9 @@ exports.Consumer = Consumer;
1170
1207
  exports.Model = Model;
1171
1208
  exports.Provider = Provider;
1172
1209
  exports.Singleton = Singleton;
1173
- exports.State = State;
1174
1210
  exports.act = act;
1175
- exports.attach = attach;
1211
+ exports.apply = apply;
1212
+ exports.child = child;
1176
1213
  exports["default"] = Model;
1177
1214
  exports.from = from;
1178
1215
  exports.lazy = lazy;
@@ -1181,6 +1218,6 @@ exports.on = on;
1181
1218
  exports.parent = parent;
1182
1219
  exports.pending = pending;
1183
1220
  exports.ref = ref;
1184
- exports.set = set;
1185
1221
  exports.tap = tap;
1186
1222
  exports.use = use;
1223
+ //# sourceMappingURL=index.js.map