@expressive/mvc 0.1.1 → 0.2.2

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
@@ -51,10 +51,10 @@ function issues(register) {
51
51
  }
52
52
 
53
53
  const Oops$c = issues({
54
- ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
54
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
55
55
  });
56
56
  function suspend(source, key) {
57
- const error = Oops$c.ValueNotReady(source.subject, key);
57
+ const error = Oops$c.NotReady(source.subject, key);
58
58
  const promise = new Promise(resolve => {
59
59
  const release = source.addListener(forKey => {
60
60
  if (forKey == key)
@@ -95,7 +95,7 @@ function mayRetry(fn) {
95
95
  }
96
96
 
97
97
  const Oops$b = issues({
98
- BadEffectCallback: () => `Callback for effect-callback may only return a function.`
98
+ BadCallback: () => `Callback for effect-callback may only return a function.`
99
99
  });
100
100
  const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
101
101
  function define(target, key, value) {
@@ -120,7 +120,7 @@ function createEffect(callback) {
120
120
  if (unSet instanceof Promise)
121
121
  unSet = undefined;
122
122
  if (unSet && typeof unSet !== "function")
123
- throw Oops$b.BadEffectCallback();
123
+ throw Oops$b.BadCallback();
124
124
  };
125
125
  }
126
126
  function createValueEffect(callback) {
@@ -136,7 +136,7 @@ function createValueEffect(callback) {
136
136
  if (typeof out == "function")
137
137
  unSet = out;
138
138
  else
139
- throw Oops$b.BadEffectCallback();
139
+ throw Oops$b.BadCallback();
140
140
  };
141
141
  }
142
142
 
@@ -156,16 +156,16 @@ const LOCAL = Symbol("LOCAL");
156
156
  const STATE = Symbol("STATE");
157
157
  class Model {
158
158
  constructor() {
159
- const control = new Controller(this);
160
- define(this, CONTROL, control);
159
+ define(this, CONTROL, new Controller(this));
161
160
  define(this, "get", this);
161
+ define(this, "is", this);
162
162
  defineLazy(this, "set", () => {
163
+ const controller = control(this);
163
164
  const assign = (key, value) => {
164
- control.update(key, value);
165
+ controller.update(key, value);
165
166
  };
166
- ready(control);
167
- for (const key of getOwnPropertyNames(control.proxy))
168
- define(assign, key, control.ref(key));
167
+ for (const key of getOwnPropertyNames(controller.proxy))
168
+ define(assign, key, controller.ref(key));
169
169
  return assign;
170
170
  });
171
171
  }
@@ -353,10 +353,10 @@ class Subscriber {
353
353
  }
354
354
 
355
355
  const Oops$a = issues({
356
- BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
356
+ BadSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
357
357
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
358
- ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
359
- ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
358
+ Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
359
+ Early: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
360
360
  });
361
361
  const INIT = new WeakSet();
362
362
  const INFO = new WeakMap();
@@ -383,7 +383,7 @@ function from(source, arg1, arg2) {
383
383
  }
384
384
  // Regular function is too ambiguous so not allowed.
385
385
  else
386
- throw Oops$a.BadComputedSource(subject, key, source);
386
+ throw Oops$a.BadSource(subject, key, source);
387
387
  let sub;
388
388
  const setter = arg1;
389
389
  const info = { key, parent, priority: 1 };
@@ -398,7 +398,7 @@ function from(source, arg1, arg2) {
398
398
  return setter.call(sub.proxy, sub.proxy);
399
399
  }
400
400
  catch (err) {
401
- Oops$a.ComputeFailed(subject, key, !!initial).warn();
401
+ Oops$a.Failed(subject, key, !!initial).warn();
402
402
  throw err;
403
403
  }
404
404
  }
@@ -439,7 +439,7 @@ function from(source, arg1, arg2) {
439
439
  }
440
440
  catch (e) {
441
441
  if (early)
442
- Oops$a.ComputedEarly(key).warn();
442
+ Oops$a.Early(key).warn();
443
443
  throw e;
444
444
  }
445
445
  finally {
@@ -623,9 +623,6 @@ function control(subject, cb) {
623
623
  control = new Controller(subject);
624
624
  define(subject, CONTROL, control);
625
625
  }
626
- return ready(control, cb);
627
- }
628
- function ready(control, cb) {
629
626
  const ready = READY.has(control);
630
627
  if (!ready) {
631
628
  if (cb) {
@@ -723,14 +720,14 @@ function forSubscriber(fn) {
723
720
  }
724
721
 
725
722
  const Oops$8 = issues({
726
- DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
723
+ DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
727
724
  });
728
725
  function act(task) {
729
726
  return apply(function act(key) {
730
727
  let pending = false;
731
728
  const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
732
729
  if (pending)
733
- return Promise.reject(Oops$8.DuplicateAction(key));
730
+ return Promise.reject(Oops$8.DuplicatePending(key));
734
731
  pending = true;
735
732
  this.update(key);
736
733
  try {
@@ -835,28 +832,74 @@ function createRef(key, cb) {
835
832
 
836
833
  const Oops$7 = issues({
837
834
  NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
838
- BadFactory: () => `Set instruction can only accept a factory or undefined.`,
839
- ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
840
- FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
835
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
836
+ Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
841
837
  });
842
838
  function set(factory, argument) {
843
839
  return apply(function set(key) {
840
+ const { subject, state } = this;
841
+ const required = argument === true || argument === undefined;
844
842
  let set;
845
843
  let get;
846
844
  let suspense;
847
- const required = argument === true || argument === undefined;
848
845
  if (factory === undefined)
849
846
  suspense = true;
850
- else if (typeof factory === "function")
851
- get = pendingFactory(this, key, factory, required);
852
- else
853
- throw Oops$7.BadFactory();
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
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
+ }
854
897
  if (typeof argument == "function")
855
898
  set = createValueEffect(argument);
856
899
  else
857
900
  set = (value) => {
858
901
  if (value === undefined && required)
859
- throw Oops$7.NonOptional(this.subject, key);
902
+ throw Oops$7.NonOptional(subject, key);
860
903
  };
861
904
  return {
862
905
  set,
@@ -864,63 +907,12 @@ function set(factory, argument) {
864
907
  suspense
865
908
  };
866
909
  });
867
- }
868
- function pendingFactory(parent, key, fn, required) {
869
- const { subject, state } = parent;
870
- let pending;
871
- let error;
872
- const init = () => {
873
- const output = mayRetry(() => {
874
- return fn.call(subject, key, subject);
875
- });
876
- if (output instanceof Promise) {
877
- pending = output
878
- .catch(err => error = err)
879
- .then(val => state[key] = val)
880
- .finally(() => {
881
- pending = undefined;
882
- parent.update(key);
883
- });
884
- return;
885
- }
886
- return state[key] = output;
887
- };
888
- const suspend = () => {
889
- if (required === false)
890
- return undefined;
891
- const issue = Oops$7.ValueNotReady(subject, key);
892
- Object.assign(pending, {
893
- message: issue.message,
894
- stack: issue.stack
895
- });
896
- throw pending;
897
- };
898
- if (required)
899
- try {
900
- init();
901
- }
902
- catch (err) {
903
- Oops$7.FactoryFailed(subject, key).warn();
904
- throw err;
905
- }
906
- return () => {
907
- if (pending)
908
- return suspend();
909
- if (error)
910
- throw error;
911
- if (key in state)
912
- return state[key];
913
- let output = init();
914
- return pending
915
- ? suspend()
916
- : output;
917
- };
918
910
  }
919
911
 
920
912
  const Parent = new WeakMap();
921
913
  const Oops$6 = issues({
922
- ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
923
- UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
914
+ Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
915
+ Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
924
916
  });
925
917
  function parent(Expects, required) {
926
918
  return apply(function parent() {
@@ -929,10 +921,10 @@ function parent(Expects, required) {
929
921
  const expected = Expects.name;
930
922
  if (!value) {
931
923
  if (required !== false)
932
- throw Oops$6.ParentRequired(expected, child);
924
+ throw Oops$6.Required(expected, child);
933
925
  }
934
926
  else if (!(value instanceof Expects))
935
- throw Oops$6.UnexpectedParent(expected, child, value);
927
+ throw Oops$6.Unexpected(expected, child, value);
936
928
  return { value };
937
929
  });
938
930
  }
@@ -1037,19 +1029,24 @@ class Lookup {
1037
1029
  const LookupContext = React__default["default"].createContext(new Lookup());
1038
1030
  const useLookup = () => React__default["default"].useContext(LookupContext);
1039
1031
  const Oops$4 = issues({
1040
- NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
1032
+ NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
1041
1033
  });
1042
1034
  function useLocal(Type, arg) {
1043
1035
  const instance = useLookup().get(Type);
1044
1036
  if (!instance && arg !== false)
1045
- throw Oops$4.NothingInContext(Type.name);
1046
- return typeof arg == "string" ?
1047
- instance[arg] :
1048
- instance;
1037
+ throw Oops$4.NotFound(Type.name);
1038
+ switch (typeof arg) {
1039
+ case "string":
1040
+ return instance[arg];
1041
+ case "function":
1042
+ React.useLayoutEffect(() => arg(instance), []);
1043
+ default:
1044
+ return instance;
1045
+ }
1049
1046
  }
1050
1047
 
1051
1048
  const Oops$3 = issues({
1052
- CantAttachGlobal: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
1049
+ NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
1053
1050
  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.`
1054
1051
  });
1055
1052
  const PendingContext = new WeakMap();
@@ -1063,7 +1060,7 @@ function tap(type, argument) {
1063
1060
  };
1064
1061
  const { subject } = this;
1065
1062
  if ("set" in subject.constructor)
1066
- throw Oops$3.CantAttachGlobal(subject, type.name);
1063
+ throw Oops$3.NotAllowed(subject, type.name);
1067
1064
  getPending(subject).push(context => {
1068
1065
  let instance = context.get(type);
1069
1066
  if (typeof argument == "function") {
@@ -1241,8 +1238,8 @@ class MVC extends Model {
1241
1238
  use(arg, callback) {
1242
1239
  return useModel(this, arg, callback);
1243
1240
  }
1244
- static get(required) {
1245
- return useLocal(this, required);
1241
+ static get(arg) {
1242
+ return useLocal(this, arg);
1246
1243
  }
1247
1244
  static tap(key, expect) {
1248
1245
  return useTap(this, key, expect);
@@ -1288,25 +1285,28 @@ class MVC extends Model {
1288
1285
  }
1289
1286
 
1290
1287
  const Oops$2 = issues({
1291
- BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
1288
+ BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
1292
1289
  });
1293
1290
  function Consumer(props) {
1294
- const { get, has, children, of: Control } = props;
1291
+ const { get, has, children, for: type } = props;
1295
1292
  if (typeof children == "function")
1296
- return children(useTap(Control));
1293
+ return children(useTap(type));
1297
1294
  const callback = has || get;
1298
1295
  if (typeof callback == "function")
1299
- callback(useLocal(Control, !!has));
1296
+ callback(useLocal(type, !!has));
1300
1297
  else
1301
- throw Oops$2.BadConsumerProps();
1298
+ throw Oops$2.BadProps();
1302
1299
  return null;
1303
1300
  }
1304
1301
 
1305
1302
  const Oops$1 = issues({
1306
- NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`
1303
+ NoType: () => "Provider 'of' prop must be Model, typeof Model or a collection of them.",
1304
+ PropDeprecated: () => "Provider `of` prop is deprecated, use `for` instead."
1307
1305
  });
1308
1306
  function Provider(props) {
1309
- const context = useNewContext(props.of);
1307
+ if ("of" in props)
1308
+ throw Oops$1.PropDeprecated();
1309
+ const context = useNewContext(props.for);
1310
1310
  const render = props.children;
1311
1311
  useAppliedProps(context, props);
1312
1312
  React__default["default"].useLayoutEffect(() => () => context.pop(), []);
@@ -1318,7 +1318,7 @@ function useNewContext(inject) {
1318
1318
  const from = useLookup();
1319
1319
  return React__default["default"].useMemo(() => {
1320
1320
  if (!inject)
1321
- throw Oops$1.NoProviderType();
1321
+ throw Oops$1.NoType();
1322
1322
  const context = from.push(inject);
1323
1323
  for (const instance of context.local)
1324
1324
  if (instance)
@@ -1332,7 +1332,7 @@ function useAppliedProps(within, props) {
1332
1332
  const targets = within.local;
1333
1333
  return function integrate(props) {
1334
1334
  for (const [key, value] of entries(props))
1335
- if (key != "of" && key != "children")
1335
+ if (["of", "for", "children"].indexOf(key) < 0)
1336
1336
  for (const into of targets)
1337
1337
  if (into && key in into)
1338
1338
  into[key] = value;
@@ -1353,15 +1353,15 @@ function RenderFunction(props) {
1353
1353
  }
1354
1354
 
1355
1355
  const Oops = issues({
1356
- 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.`,
1357
- GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
1356
+ DoesNotExist: (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.`,
1357
+ AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
1358
1358
  });
1359
1359
  const Active = new WeakMap();
1360
1360
  class Global extends MVC {
1361
1361
  static create(...args) {
1362
1362
  const Type = this;
1363
1363
  if (Active.has(Type))
1364
- throw Oops.GlobalExists(this.name);
1364
+ throw Oops.AlreadyExists(this.name);
1365
1365
  const instance = super.create(...args);
1366
1366
  Active.set(Type, instance);
1367
1367
  return instance;
@@ -1379,7 +1379,7 @@ class Global extends MVC {
1379
1379
  static get(arg) {
1380
1380
  const instance = Active.get(this);
1381
1381
  if (!instance && arg !== false)
1382
- throw Oops.GlobalDoesNotExist(this.name);
1382
+ throw Oops.DoesNotExist(this.name);
1383
1383
  return (typeof arg == "string" ?
1384
1384
  instance[arg] :
1385
1385
  instance);