@expressive/mvc 1.0.0-beta.30 → 1.0.0-beta.33

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
@@ -24,7 +24,7 @@ function issues(register) {
24
24
  return Library;
25
25
  }
26
26
 
27
- const Oops$8 = issues({
27
+ const Oops$9 = issues({
28
28
  BadEffectCallback: () => `Callback for effect-callback may only return a function.`
29
29
  });
30
30
  const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertyDescriptors, getOwnPropertySymbols, keys: keys$1, values } = Object;
@@ -53,7 +53,7 @@ function createEffect(callback) {
53
53
  if (unSet instanceof Promise)
54
54
  unSet = undefined;
55
55
  if (unSet && typeof unSet !== "function")
56
- throw Oops$8.BadEffectCallback();
56
+ throw Oops$9.BadEffectCallback();
57
57
  };
58
58
  }
59
59
  function createValueEffect(callback) {
@@ -69,7 +69,7 @@ function createValueEffect(callback) {
69
69
  if (typeof out == "function")
70
70
  unSet = out;
71
71
  else
72
- throw Oops$8.BadEffectCallback();
72
+ throw Oops$9.BadEffectCallback();
73
73
  };
74
74
  }
75
75
  function select(source, select) {
@@ -157,7 +157,7 @@ class Subscriber {
157
157
  }
158
158
  }
159
159
 
160
- const Oops$7 = issues({
160
+ const Oops$8 = issues({
161
161
  ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
162
162
  ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
163
163
  });
@@ -176,14 +176,14 @@ function prepare(parent, key, source, setter, getter) {
176
176
  }
177
177
  register.set(key, info);
178
178
  const current = getter
179
- ? () => getter.call(subject, state[key], key)
179
+ ? () => getter(parent, key)
180
180
  : () => state[key];
181
181
  function compute(initial) {
182
182
  try {
183
183
  return setter.call(sub.proxy, sub.proxy);
184
184
  }
185
185
  catch (err) {
186
- Oops$7.ComputeFailed(subject, key, !!initial).warn();
186
+ Oops$8.ComputeFailed(subject, key, !!initial).warn();
187
187
  throw err;
188
188
  }
189
189
  }
@@ -229,7 +229,7 @@ function prepare(parent, key, source, setter, getter) {
229
229
  }
230
230
  catch (e) {
231
231
  if (early)
232
- Oops$7.ComputedEarly(key).warn();
232
+ Oops$8.ComputedEarly(key).warn();
233
233
  throw e;
234
234
  }
235
235
  finally {
@@ -510,6 +510,61 @@ function child(source, name) {
510
510
  }, name || source.name);
511
511
  }
512
512
 
513
+ const Oops$7 = issues({
514
+ NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
515
+ BadFactory: () => `Set instruction can only accept a factory or undefined.`,
516
+ FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
517
+ });
518
+ function lazy(value) {
519
+ return apply(function lazy(key) {
520
+ const source = this.subject;
521
+ source[key] = value;
522
+ defineProperty(this.state, key, {
523
+ get: () => source[key]
524
+ });
525
+ });
526
+ }
527
+ function set(factory, argument) {
528
+ return apply(function set(key) {
529
+ let onSet;
530
+ let onGet;
531
+ const required = argument === true || argument === undefined;
532
+ if (factory === undefined)
533
+ onGet = () => pendingValue(this, key);
534
+ else if (typeof factory !== "function")
535
+ throw Oops$7.BadFactory();
536
+ else {
537
+ onGet = pendingFactory(this, key, factory);
538
+ if (required)
539
+ try {
540
+ onGet();
541
+ }
542
+ catch (err) {
543
+ if (err instanceof Promise)
544
+ ;
545
+ else {
546
+ Oops$7.FactoryFailed(this.subject, key).warn();
547
+ throw err;
548
+ }
549
+ }
550
+ }
551
+ if (typeof argument == "function")
552
+ onSet = createValueEffect(argument);
553
+ else if (required)
554
+ onSet = (value) => {
555
+ if (value === undefined)
556
+ throw Oops$7.NonOptional(this.subject, key);
557
+ };
558
+ return {
559
+ set: this.setter(key, onSet),
560
+ get: onGet
561
+ };
562
+ });
563
+ }
564
+ function on(initial, onUpdate) {
565
+ return set(initial && (() => initial), onUpdate);
566
+ }
567
+
513
568
  const Oops$6 = issues({
514
569
  CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
515
570
  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.`
@@ -612,10 +667,13 @@ function act(task) {
612
667
  };
613
668
  });
614
669
  }
615
- function from(source, setter, getter) {
670
+ function from(source, setter, argument) {
616
671
  return apply(function from(key) {
617
672
  const { subject } = this;
618
673
  let getSource;
674
+ let getter = argument === true
675
+ ? pendingValue
676
+ : argument || undefined;
619
677
  // Easy mistake, using a peer, will always be unresolved.
620
678
  if (typeof source == "symbol")
621
679
  throw Oops$5.PeerNotAllowed(subject, key);
@@ -630,7 +688,7 @@ function from(source, setter, getter) {
630
688
  // is a peer Model (constructor)
631
689
  else if (Model.isTypeof(source))
632
690
  getSource = pendingAccess(subject, source, key, true);
633
- // Regular function is to ambiguous so not allowed.
691
+ // Regular function is too ambiguous so not allowed.
634
692
  else
635
693
  throw Oops$5.BadComputedSource(subject, key, source);
636
694
  prepare(this, key, getSource, setter, getter);
@@ -640,12 +698,14 @@ function from(source, setter, getter) {
640
698
  const Oops$4 = issues({
641
699
  ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
642
700
  });
701
+ /* deprecated - ignore coverage */
702
+ /* istanbul ignore next */
643
703
  function pending(source, compute) {
644
- return (source === undefined ?
645
- suspendForValue() :
646
- typeof source == "function" && !source.prototype ?
647
- suspendForAsync(source) :
648
- suspendForComputed(source, compute));
704
+ if (source === undefined)
705
+ return set();
706
+ if (typeof source == "function" && !source.prototype)
707
+ return set(source);
708
+ return from(source, compute, true);
649
709
  }
650
710
  /**
651
711
  * Get value, suspend instead if undefined.
@@ -659,6 +719,40 @@ function pendingValue(via, key) {
659
719
  throw suspend(via, key);
660
720
  return value;
661
721
  }
722
+ function pendingFactory(via, key, fn) {
723
+ const { subject, state } = via;
724
+ let waiting;
725
+ let error;
726
+ return () => {
727
+ if (waiting)
728
+ throw waiting;
729
+ if (error)
730
+ throw error;
731
+ if (key in state)
732
+ return state[key];
733
+ let output;
734
+ try {
735
+ output = fn.call(subject, key, subject);
736
+ }
737
+ catch (err) {
738
+ throw error = err;
739
+ }
740
+ if (output instanceof Promise) {
741
+ const issue = Oops$4.ValueNotReady(subject, key);
742
+ output
743
+ .catch(err => error = err)
744
+ .then(out => state[key] = out)
745
+ .finally(() => waiting = undefined);
746
+ throw waiting = Object.assign(output, {
747
+ message: issue.message,
748
+ stack: issue.stack
749
+ });
750
+ }
751
+ else {
752
+ return state[key] = output;
753
+ }
754
+ };
755
+ }
662
756
  function suspend(source, key) {
663
757
  const error = Oops$4.ValueNotReady(source.subject, key);
664
758
  const promise = new Promise(resolve => {
@@ -678,45 +772,6 @@ function suspend(source, key) {
678
772
  message: error.message,
679
773
  stack: error.stack
680
774
  });
681
- }
682
- function suspendForComputed(source, compute) {
683
- function getter(_value, key) {
684
- return pendingValue(manage(this), key);
685
- }
686
- return from(source, compute, getter);
687
- }
688
- function suspendForValue() {
689
- return apply(function pending(key) {
690
- this.state[key] = undefined;
691
- return {
692
- set: this.setter(key),
693
- get: () => pendingValue(this, key)
694
- };
695
- });
696
- }
697
- function suspendForAsync(source) {
698
- return apply(function suspense(key) {
699
- const subject = this.subject;
700
- let waiting = true;
701
- let value;
702
- let error;
703
- return () => {
704
- if (error)
705
- throw error;
706
- if (!waiting)
707
- return value;
708
- const issue = Oops$4.ValueNotReady(subject, key);
709
- let suspend = source
710
- .call(subject, key)
711
- .catch(err => error = err)
712
- .then(out => value = out)
713
- .finally(() => waiting = false);
714
- throw Object.assign(suspend, {
715
- message: issue.message,
716
- stack: issue.stack
717
- });
718
- };
719
- });
720
775
  }
721
776
 
722
777
  function use$1(init) {
@@ -740,12 +795,11 @@ function useWatcher(target, focus, expected) {
740
795
  const sub = new Subscriber(target, () => refresh);
741
796
  if (focus) {
742
797
  const source = sub.proxy;
743
- const key = keys(sub.parent, focus)[0];
744
798
  defineProperty(sub, "proxy", {
745
799
  get() {
746
- const value = source[key];
800
+ const value = source[focus];
747
801
  if (value === undefined && expected)
748
- throw suspend(sub.parent, key);
802
+ throw suspend(sub.parent, focus);
749
803
  return value;
750
804
  }
751
805
  });
@@ -755,6 +809,39 @@ function useWatcher(target, focus, expected) {
755
809
  react.useLayoutEffect(() => hook.commit(), []);
756
810
  return hook.proxy;
757
811
  }
812
+ function useComputed(target, compute, expected) {
813
+ const hook = use$1(refresh => {
814
+ const sub = new Subscriber(target, () => update);
815
+ const { proxy } = sub;
816
+ let value;
817
+ let retry;
818
+ const update = () => {
819
+ const next = compute.call(proxy, proxy);
820
+ if (value == next)
821
+ return;
822
+ value = next;
823
+ if (retry) {
824
+ retry();
825
+ retry = undefined;
826
+ }
827
+ else
828
+ refresh();
829
+ };
830
+ const access = () => {
831
+ if (value === undefined && expected)
832
+ throw new Promise(res => {
833
+ retry = res;
834
+ });
835
+ return value;
836
+ };
837
+ value = compute.call(proxy, proxy);
838
+ sub.commit();
839
+ defineProperty(sub, "proxy", { get: access });
840
+ return sub;
841
+ });
842
+ react.useLayoutEffect(() => hook.release, []);
843
+ return hook.proxy;
844
+ }
758
845
  function useModel(Type, callback) {
759
846
  const hook = use$1(refresh => {
760
847
  const instance = new Type();
@@ -918,14 +1005,14 @@ class Model {
918
1005
  });
919
1006
  }
920
1007
  tap(path, expect) {
1008
+ if (typeof path == "function")
1009
+ return useComputed(this, path, expect);
921
1010
  const proxy = useWatcher(this, path, expect);
922
1011
  this.update("willRender", true);
923
1012
  return proxy;
924
1013
  }
925
1014
  tag(id) {
926
- const hook = use$1(refresh => {
927
- return new Subscriber(this, () => refresh);
928
- });
1015
+ const hook = use$1(refresh => (new Subscriber(this, () => refresh)));
929
1016
  useElementLifecycle(hook, id || 0);
930
1017
  return hook.proxy;
931
1018
  }
@@ -973,12 +1060,10 @@ class Model {
973
1060
  invoke();
974
1061
  return this.on(select, invoke, true);
975
1062
  }
976
- else {
977
- const sub = new Subscriber(control, () => invoke);
978
- target = sub.proxy;
979
- invoke();
980
- return sub.commit();
981
- }
1063
+ const sub = new Subscriber(control, () => invoke);
1064
+ target = sub.proxy;
1065
+ invoke();
1066
+ return sub.commit();
982
1067
  }
983
1068
  import(from, subset) {
984
1069
  for (const key of keys(manage(this), subset))
@@ -1073,7 +1158,9 @@ class Model {
1073
1158
  return instance;
1074
1159
  }
1075
1160
  static meta(path) {
1076
- return useWatcher(this, path);
1161
+ return typeof path == "function"
1162
+ ? useComputed(this, path)
1163
+ : useWatcher(this, path);
1077
1164
  }
1078
1165
  static isTypeof(maybe) {
1079
1166
  return (typeof maybe == "function" &&
@@ -1172,31 +1259,6 @@ function parent(Expects, required) {
1172
1259
  });
1173
1260
  }
1174
1261
 
1175
- function on(initial, cb) {
1176
- return apply(function on(key) {
1177
- this.manage(key, initial, cb && createValueEffect(cb));
1178
- });
1179
- }
1180
- function memo(factory, defer) {
1181
- return apply(function memo(key) {
1182
- const source = this.subject;
1183
- const get = () => factory.call(source);
1184
- if (defer)
1185
- defineLazy(source, key, get);
1186
- else
1187
- define(source, key, get());
1188
- });
1189
- }
1190
- function lazy(value) {
1191
- return apply(function lazy(key) {
1192
- const source = this.subject;
1193
- source[key] = value;
1194
- defineProperty(this.state, key, {
1195
- get: () => source[key]
1196
- });
1197
- });
1198
- }
1199
-
1200
1262
  const Oops = issues({
1201
1263
  GlobalDoesNotExist: (name) => `Tried to access singleton ${name}, but none exist! Did you forget to initialize?\nCall ${name}.create() before attempting to access, or consider using ${name}.use() instead.`,
1202
1264
  GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
@@ -1248,11 +1310,12 @@ exports.child = child;
1248
1310
  exports["default"] = Model;
1249
1311
  exports.from = from;
1250
1312
  exports.lazy = lazy;
1251
- exports.memo = memo;
1313
+ exports.memo = set;
1252
1314
  exports.on = on;
1253
1315
  exports.parent = parent;
1254
1316
  exports.pending = pending;
1255
1317
  exports.ref = ref;
1318
+ exports.set = set;
1256
1319
  exports.tap = tap;
1257
1320
  exports.use = use;
1258
1321
  //# sourceMappingURL=index.js.map