@expressive/mvc 1.0.0-beta.27 → 1.0.0-beta.28

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$9 = issues({
27
+ const Oops$8 = 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$9.BadEffectCallback();
56
+ throw Oops$8.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$9.BadEffectCallback();
72
+ throw Oops$8.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$8 = issues({
160
+ const Oops$7 = 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
  });
@@ -183,7 +183,7 @@ function prepare(parent, key, source, setter, getter) {
183
183
  return setter.call(sub.proxy, sub.proxy);
184
184
  }
185
185
  catch (err) {
186
- Oops$8.ComputeFailed(subject, key, !!initial).warn();
186
+ Oops$7.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$8.ComputedEarly(key).warn();
232
+ Oops$7.ComputedEarly(key).warn();
233
233
  throw e;
234
234
  }
235
235
  finally {
@@ -510,9 +510,214 @@ function child(source, name) {
510
510
  }, name || source.name);
511
511
  }
512
512
 
513
- const Oops$7 = issues({
514
- HasPropertyUndefined: (control, property) => `${control}.${property} is marked as required for this render.`
513
+ const Oops$6 = issues({
514
+ CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
515
+ 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.`
516
+ });
517
+ const PendingContext = new WeakMap();
518
+ const ContextWasUsed = new WeakMap();
519
+ function tap(type, argument) {
520
+ return child(function tap(key) {
521
+ return pendingAccess(this.subject, type, key, argument);
522
+ });
523
+ }
524
+ function pendingAccess(from, type, key, argument) {
525
+ if ("current" in type)
526
+ return () => type.current;
527
+ if ("current" in from.constructor)
528
+ throw Oops$6.CantAttachGlobal(from, type.name);
529
+ let instance;
530
+ getPending(from).push(context => {
531
+ instance = context.get(type);
532
+ if (typeof argument == "function") {
533
+ if (argument(instance) === false)
534
+ instance = undefined;
535
+ }
536
+ else if (!instance && argument)
537
+ throw Oops$6.AmbientRequired(type.name, from, key);
538
+ });
539
+ return () => instance;
540
+ }
541
+ function usePeerContext(subject) {
542
+ if (ContextWasUsed.has(subject)) {
543
+ if (ContextWasUsed.get(subject))
544
+ useLookup();
545
+ return;
546
+ }
547
+ const pending = PendingContext.get(subject);
548
+ if (pending) {
549
+ const local = useLookup();
550
+ for (const init of pending)
551
+ init(local);
552
+ PendingContext.delete(subject);
553
+ }
554
+ ContextWasUsed.set(subject, !!pending);
555
+ }
556
+ function getPending(subject) {
557
+ let pending = PendingContext.get(subject);
558
+ if (!pending)
559
+ PendingContext.set(subject, pending = []);
560
+ return pending;
561
+ }
562
+
563
+ const Oops$5 = issues({
564
+ DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
565
+ BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
566
+ PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
515
567
  });
568
+ function createRef(key, cb) {
569
+ const refObjectFunction = this.setter(key, cb && createValueEffect(cb));
570
+ defineProperty(refObjectFunction, "current", {
571
+ set: refObjectFunction,
572
+ get: () => this.state[key]
573
+ });
574
+ return refObjectFunction;
575
+ }
576
+ function ref(arg) {
577
+ return apply(function ref(key) {
578
+ let value = {};
579
+ if (typeof arg == "object") {
580
+ const source = manage(arg);
581
+ for (const key in source.state)
582
+ defineLazy(value, key, createRef.bind(source, key));
583
+ }
584
+ else
585
+ value = createRef.call(this, key, arg);
586
+ return { value };
587
+ });
588
+ }
589
+ function act(task) {
590
+ return apply(function act(key) {
591
+ let pending = false;
592
+ const invoke = (...args) => {
593
+ if (pending)
594
+ return Promise.reject(Oops$5.DuplicateAction(key));
595
+ pending = true;
596
+ this.update(key);
597
+ return new Promise(res => {
598
+ res(task.apply(this.subject, args));
599
+ }).finally(() => {
600
+ pending = false;
601
+ this.update(key);
602
+ });
603
+ };
604
+ setAlias(invoke, `run ${key}`);
605
+ defineProperty(invoke, "active", {
606
+ get: () => pending
607
+ });
608
+ return {
609
+ value: invoke,
610
+ writable: false
611
+ };
612
+ });
613
+ }
614
+ function from(source, setter, getter) {
615
+ return apply(function from(key) {
616
+ const { subject } = this;
617
+ let getSource;
618
+ // Easy mistake, using a peer, will always be unresolved.
619
+ if (typeof source == "symbol")
620
+ throw Oops$5.PeerNotAllowed(subject, key);
621
+ // replace source controller in-case different
622
+ if (typeof source == "object")
623
+ getSource = () => manage(source);
624
+ // specifically an arrow function (getter factory)
625
+ else if (!source.prototype) {
626
+ setter = source.call(subject, key);
627
+ getSource = () => this;
628
+ }
629
+ // is a peer Model (constructor)
630
+ else if (Model.isTypeof(source))
631
+ getSource = pendingAccess(subject, source, key, true);
632
+ // Regular function is to ambiguous so not allowed.
633
+ else
634
+ throw Oops$5.BadComputedSource(subject, key, source);
635
+ prepare(this, key, getSource, setter, getter);
636
+ });
637
+ }
638
+
639
+ const Oops$4 = issues({
640
+ ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
641
+ });
642
+ function pending(source, compute) {
643
+ return (source === undefined ?
644
+ suspendForValue() :
645
+ typeof source == "function" && !source.prototype ?
646
+ suspendForAsync(source) :
647
+ suspendForComputed(source, compute));
648
+ }
649
+ /**
650
+ * Get value, suspend instead if undefined.
651
+ *
652
+ * Throws suspense promise also interpretable as an error.
653
+ * React could handle it but other contexts probably not.
654
+ */
655
+ function pendingValue(via, key) {
656
+ const value = via.state[key];
657
+ if (value === undefined)
658
+ throw suspend(via, key);
659
+ return value;
660
+ }
661
+ function suspend(source, key) {
662
+ const error = Oops$4.ValueNotReady(source.subject, key);
663
+ const promise = new Promise(resolve => {
664
+ const release = source.addListener(forKey => {
665
+ if (forKey == key)
666
+ return () => {
667
+ if (source.state[key] !== undefined) {
668
+ release();
669
+ resolve();
670
+ }
671
+ };
672
+ });
673
+ });
674
+ return Object.assign(promise, {
675
+ toString: () => String(error),
676
+ name: "Suspense",
677
+ message: error.message,
678
+ stack: error.stack
679
+ });
680
+ }
681
+ function suspendForComputed(source, compute) {
682
+ function getter(_value, key) {
683
+ return pendingValue(manage(this), key);
684
+ }
685
+ return from(source, compute, getter);
686
+ }
687
+ function suspendForValue() {
688
+ return apply(function pending(key) {
689
+ this.state[key] = undefined;
690
+ return {
691
+ set: this.setter(key),
692
+ get: () => pendingValue(this, key)
693
+ };
694
+ });
695
+ }
696
+ function suspendForAsync(source) {
697
+ return apply(function suspense(key) {
698
+ const subject = this.subject;
699
+ let waiting = true;
700
+ let value;
701
+ let error;
702
+ return () => {
703
+ if (error)
704
+ throw error;
705
+ if (!waiting)
706
+ return value;
707
+ const issue = Oops$4.ValueNotReady(subject, key);
708
+ let suspend = source
709
+ .call(subject, key)
710
+ .catch(err => error = err)
711
+ .then(out => value = out)
712
+ .finally(() => waiting = false);
713
+ throw Object.assign(suspend, {
714
+ message: issue.message,
715
+ stack: issue.stack
716
+ });
717
+ };
718
+ });
719
+ }
720
+
516
721
  function use$1(init) {
517
722
  const [state, update] = react.useState(() => [
518
723
  init(() => update(state.concat()))
@@ -533,13 +738,14 @@ function useWatcher(target, focus, expected) {
533
738
  const hook = use$1(refresh => {
534
739
  const sub = new Subscriber(target, () => refresh);
535
740
  if (focus) {
536
- const src = sub.proxy;
741
+ const source = sub.proxy;
537
742
  const key = keys(sub.parent, focus)[0];
538
743
  defineProperty(sub, "proxy", {
539
744
  get() {
540
- if (src[key] === undefined && expected)
541
- throw Oops$7.HasPropertyUndefined(target, key);
542
- return src[key];
745
+ const value = source[key];
746
+ if (value === undefined && expected)
747
+ throw suspend(sub.parent, key);
748
+ return value;
543
749
  }
544
750
  });
545
751
  }
@@ -567,56 +773,6 @@ function useModel(Type, callback) {
567
773
  return hook.proxy;
568
774
  }
569
775
 
570
- const Oops$6 = issues({
571
- CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
572
- 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.`
573
- });
574
- const PendingContext = new WeakMap();
575
- const ContextWasUsed = new WeakMap();
576
- function tap(type, argument) {
577
- return child(function tap(key) {
578
- return pendingAccess(this.subject, type, key, argument);
579
- });
580
- }
581
- function pendingAccess(from, type, key, argument) {
582
- if ("current" in type)
583
- return () => type.current;
584
- if ("current" in from.constructor)
585
- throw Oops$6.CantAttachGlobal(from, type.name);
586
- let instance;
587
- getPending(from).push(context => {
588
- instance = context.get(type);
589
- if (typeof argument == "function") {
590
- if (argument(instance) === false)
591
- instance = undefined;
592
- }
593
- else if (!instance && argument)
594
- throw Oops$6.AmbientRequired(type.name, from, key);
595
- });
596
- return () => instance;
597
- }
598
- function usePeerContext(subject) {
599
- if (ContextWasUsed.has(subject)) {
600
- if (ContextWasUsed.get(subject))
601
- useLookup();
602
- return;
603
- }
604
- const pending = PendingContext.get(subject);
605
- if (pending) {
606
- const local = useLookup();
607
- for (const init of pending)
608
- init(local);
609
- PendingContext.delete(subject);
610
- }
611
- ContextWasUsed.set(subject, !!pending);
612
- }
613
- function getPending(subject) {
614
- let pending = PendingContext.get(subject);
615
- if (!pending)
616
- PendingContext.set(subject, pending = []);
617
- return pending;
618
- }
619
-
620
776
  class Lookup {
621
777
  constructor() {
622
778
  this.table = new Map();
@@ -672,7 +828,7 @@ class Lookup {
672
828
  }
673
829
  }
674
830
 
675
- const Oops$5 = issues({
831
+ const Oops$3 = issues({
676
832
  NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`,
677
833
  NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
678
834
  BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
@@ -682,7 +838,7 @@ const useLookup = () => react.useContext(LookupContext);
682
838
  function useFromContext(Type, strict) {
683
839
  const instance = useLookup().get(Type);
684
840
  if (!instance && strict)
685
- throw Oops$5.NothingInContext(Type.name);
841
+ throw Oops$3.NothingInContext(Type.name);
686
842
  return instance;
687
843
  }
688
844
  function Consumer(props) {
@@ -693,13 +849,13 @@ function Consumer(props) {
693
849
  if (typeof callback == "function")
694
850
  callback(Control.get(!!has));
695
851
  else
696
- throw Oops$5.BadConsumerProps();
852
+ throw Oops$3.BadConsumerProps();
697
853
  return null;
698
854
  }
699
855
  function useNewContext(from, inject) {
700
856
  return react.useMemo(() => {
701
857
  if (!inject)
702
- throw Oops$5.NoProviderType();
858
+ throw Oops$3.NoProviderType();
703
859
  const context = from.push(inject);
704
860
  for (const instance of context.local)
705
861
  for (const apply of getPending(instance))
@@ -742,7 +898,7 @@ function Provider(props) {
742
898
  : render);
743
899
  }
744
900
 
745
- const Oops$4 = issues({
901
+ const Oops$2 = issues({
746
902
  StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
747
903
  NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
748
904
  });
@@ -841,7 +997,7 @@ class Model {
841
997
  arg = select(this, arg);
842
998
  if (typeof arg == "boolean") {
843
999
  if (!control.pending === arg)
844
- return Promise.reject(Oops$4.StrictUpdate(arg));
1000
+ return Promise.reject(Oops$2.StrictUpdate(arg));
845
1001
  }
846
1002
  else if (arg) {
847
1003
  control.update(arg);
@@ -862,7 +1018,7 @@ class Model {
862
1018
  else
863
1019
  callback(false);
864
1020
  else
865
- throw Oops$4.NoChaining();
1021
+ throw Oops$2.NoChaining();
866
1022
  }
867
1023
  };
868
1024
  }
@@ -943,7 +1099,7 @@ function defer(on, method) {
943
1099
  }
944
1100
 
945
1101
  const Parent = new WeakMap();
946
- const Oops$3 = issues({
1102
+ const Oops$1 = issues({
947
1103
  ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
948
1104
  UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
949
1105
  UndefinedNotAllowed: (key) => `Child property ${key} may not be undefined.`,
@@ -968,7 +1124,7 @@ function use(input, argument) {
968
1124
  let current;
969
1125
  const onUpdate = (next, initial) => {
970
1126
  if (mode === true && !initial)
971
- throw Oops$3.IsReadOnly(subject, key);
1127
+ throw Oops$1.IsReadOnly(subject, key);
972
1128
  if (next) {
973
1129
  current = next instanceof Model
974
1130
  ? next : bootstrap(next);
@@ -976,7 +1132,7 @@ function use(input, argument) {
976
1132
  manage(current);
977
1133
  }
978
1134
  else if (mode === undefined)
979
- throw Oops$3.UndefinedNotAllowed(key);
1135
+ throw Oops$1.UndefinedNotAllowed(key);
980
1136
  else
981
1137
  current = undefined;
982
1138
  if (typeof argument == "function")
@@ -988,11 +1144,11 @@ function use(input, argument) {
988
1144
  input instanceof Model ? input :
989
1145
  typeof input === "function" ? input() :
990
1146
  typeof input === "object" ? bootstrap(input) :
991
- Oops$3.BadArgument(typeof input).throw();
1147
+ Oops$1.BadArgument(typeof input).throw();
992
1148
  if (current)
993
1149
  mode = onUpdate(current, true) || mode;
994
1150
  else if (mode == true)
995
- throw Oops$3.MustBeDefined(subject, key);
1151
+ throw Oops$1.MustBeDefined(subject, key);
996
1152
  }
997
1153
  else
998
1154
  mode = false;
@@ -1007,10 +1163,10 @@ function parent(Expects, required) {
1007
1163
  const value = Parent.get(this.subject);
1008
1164
  if (!value) {
1009
1165
  if (required)
1010
- throw Oops$3.ParentRequired(expected, child);
1166
+ throw Oops$1.ParentRequired(expected, child);
1011
1167
  }
1012
1168
  else if (!(value instanceof Expects))
1013
- throw Oops$3.UnexpectedParent(expected, child, value);
1169
+ throw Oops$1.UnexpectedParent(expected, child, value);
1014
1170
  return { value };
1015
1171
  });
1016
1172
  }
@@ -1040,160 +1196,6 @@ function lazy(value) {
1040
1196
  });
1041
1197
  }
1042
1198
 
1043
- const Oops$2 = issues({
1044
- DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
1045
- BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
1046
- PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
1047
- });
1048
- function createRef(key, cb) {
1049
- const refObjectFunction = this.setter(key, cb && createValueEffect(cb));
1050
- defineProperty(refObjectFunction, "current", {
1051
- set: refObjectFunction,
1052
- get: () => this.state[key]
1053
- });
1054
- return refObjectFunction;
1055
- }
1056
- function ref(arg) {
1057
- return apply(function ref(key) {
1058
- let value = {};
1059
- if (typeof arg == "object") {
1060
- const source = manage(arg);
1061
- for (const key in source.state)
1062
- defineLazy(value, key, createRef.bind(source, key));
1063
- }
1064
- else
1065
- value = createRef.call(this, key, arg);
1066
- return { value };
1067
- });
1068
- }
1069
- function act(task) {
1070
- return apply(function act(key) {
1071
- let pending = false;
1072
- const invoke = (...args) => {
1073
- if (pending)
1074
- return Promise.reject(Oops$2.DuplicateAction(key));
1075
- pending = true;
1076
- this.update(key);
1077
- return new Promise(res => {
1078
- res(task.apply(this.subject, args));
1079
- }).finally(() => {
1080
- pending = false;
1081
- this.update(key);
1082
- });
1083
- };
1084
- setAlias(invoke, `run ${key}`);
1085
- defineProperty(invoke, "active", {
1086
- get: () => pending
1087
- });
1088
- return {
1089
- value: invoke,
1090
- writable: false
1091
- };
1092
- });
1093
- }
1094
- function from(source, setter, getter) {
1095
- return apply(function from(key) {
1096
- const { subject } = this;
1097
- let getSource;
1098
- // Easy mistake, using a peer, will always be unresolved.
1099
- if (typeof source == "symbol")
1100
- throw Oops$2.PeerNotAllowed(subject, key);
1101
- // replace source controller in-case different
1102
- if (typeof source == "object")
1103
- getSource = () => manage(source);
1104
- // specifically an arrow function (getter factory)
1105
- else if (!source.prototype) {
1106
- setter = source.call(subject, key);
1107
- getSource = () => this;
1108
- }
1109
- // is a peer Model (constructor)
1110
- else if (Model.isTypeof(source))
1111
- getSource = pendingAccess(subject, source, key, true);
1112
- // Regular function is to ambiguous so not allowed.
1113
- else
1114
- throw Oops$2.BadComputedSource(subject, key, source);
1115
- prepare(this, key, getSource, setter, getter);
1116
- });
1117
- }
1118
-
1119
- const Oops$1 = issues({
1120
- ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
1121
- });
1122
- function pending(source, compute) {
1123
- return (source === undefined ?
1124
- suspendForValue() :
1125
- typeof source == "function" && !source.prototype ?
1126
- suspendForAsync(source) :
1127
- suspendForComputed(source, compute));
1128
- }
1129
- /**
1130
- * Get value, suspend instead if undefined.
1131
- *
1132
- * Throws suspense promise also interpretable as an error.
1133
- * React could handle it but other contexts probably not.
1134
- */
1135
- function pendingValue(via, key) {
1136
- const value = via.state[key];
1137
- if (value !== undefined)
1138
- return value;
1139
- const error = Oops$1.ValueNotReady(via.subject, key);
1140
- const promise = new Promise(resolve => {
1141
- const release = via.addListener(forKey => {
1142
- if (forKey == key)
1143
- return () => {
1144
- if (via.state[key] !== undefined) {
1145
- release();
1146
- resolve();
1147
- }
1148
- };
1149
- });
1150
- });
1151
- throw Object.assign(promise, {
1152
- toString: () => String(error),
1153
- message: error.message,
1154
- stack: error.stack
1155
- });
1156
- }
1157
- function suspendForComputed(source, compute) {
1158
- function getter(_value, key) {
1159
- return pendingValue(manage(this), key);
1160
- }
1161
- return from(source, compute, getter);
1162
- }
1163
- function suspendForValue() {
1164
- return apply(function pending(key) {
1165
- this.state[key] = undefined;
1166
- return {
1167
- set: this.setter(key),
1168
- get: () => pendingValue(this, key)
1169
- };
1170
- });
1171
- }
1172
- function suspendForAsync(source) {
1173
- return apply(function suspense(key) {
1174
- const subject = this.subject;
1175
- let waiting = true;
1176
- let value;
1177
- let error;
1178
- return () => {
1179
- if (error)
1180
- throw error;
1181
- if (!waiting)
1182
- return value;
1183
- const issue = Oops$1.ValueNotReady(subject, key);
1184
- let suspend = source
1185
- .call(subject, key)
1186
- .catch(err => error = err)
1187
- .then(out => value = out)
1188
- .finally(() => waiting = false);
1189
- throw Object.assign(suspend, {
1190
- message: issue.message,
1191
- stack: issue.stack
1192
- });
1193
- };
1194
- });
1195
- }
1196
-
1197
1199
  const Oops = issues({
1198
1200
  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.`,
1199
1201
  GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`