@expressive/mvc 0.0.4 → 0.2.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
@@ -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
 
@@ -158,7 +158,16 @@ class Model {
158
158
  constructor() {
159
159
  define(this, CONTROL, new Controller(this));
160
160
  define(this, "get", this);
161
- define(this, "set", this);
161
+ define(this, "is", this);
162
+ defineLazy(this, "set", () => {
163
+ const controller = control(this);
164
+ const assign = (key, value) => {
165
+ controller.update(key, value);
166
+ };
167
+ for (const key of getOwnPropertyNames(controller.proxy))
168
+ define(assign, key, controller.ref(key));
169
+ return assign;
170
+ });
162
171
  }
163
172
  get [STATE]() {
164
173
  return this[CONTROL].state;
@@ -295,10 +304,7 @@ class Model {
295
304
  return (typeof maybe == "function" &&
296
305
  maybe.prototype instanceof this);
297
306
  }
298
- }
299
- defineLazy(Model, CONTROL, function () {
300
- return new Controller(this);
301
- });
307
+ }
302
308
 
303
309
  class Subscriber {
304
310
  constructor(target, onUpdate) {
@@ -347,10 +353,10 @@ class Subscriber {
347
353
  }
348
354
 
349
355
  const Oops$a = issues({
350
- 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}.`,
351
357
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
352
- ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
353
- 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.`
354
360
  });
355
361
  const INIT = new WeakSet();
356
362
  const INFO = new WeakMap();
@@ -377,7 +383,7 @@ function from(source, arg1, arg2) {
377
383
  }
378
384
  // Regular function is too ambiguous so not allowed.
379
385
  else
380
- throw Oops$a.BadComputedSource(subject, key, source);
386
+ throw Oops$a.BadSource(subject, key, source);
381
387
  let sub;
382
388
  const setter = arg1;
383
389
  const info = { key, parent, priority: 1 };
@@ -392,7 +398,7 @@ function from(source, arg1, arg2) {
392
398
  return setter.call(sub.proxy, sub.proxy);
393
399
  }
394
400
  catch (err) {
395
- Oops$a.ComputeFailed(subject, key, !!initial).warn();
401
+ Oops$a.Failed(subject, key, !!initial).warn();
396
402
  throw err;
397
403
  }
398
404
  }
@@ -433,7 +439,7 @@ function from(source, arg1, arg2) {
433
439
  }
434
440
  catch (e) {
435
441
  if (early)
436
- Oops$a.ComputedEarly(key).warn();
442
+ Oops$a.Early(key).warn();
437
443
  throw e;
438
444
  }
439
445
  finally {
@@ -500,26 +506,28 @@ class Controller {
500
506
  this.proxy = Object.create(subject);
501
507
  }
502
508
  start() {
503
- for (const key in this.subject)
504
- this.manage(key);
509
+ READY.add(this);
510
+ for (const key in this.subject) {
511
+ const { value: entry } = getOwnPropertyDescriptor(this.subject, key);
512
+ if (typeof entry == "function")
513
+ continue;
514
+ if (typeof entry == "symbol") {
515
+ const instruction = PENDING.get(entry);
516
+ if (instruction)
517
+ instruction.call(this, key, this);
518
+ continue;
519
+ }
520
+ this.manage(key, entry);
521
+ }
505
522
  this.emit([]);
506
523
  }
507
524
  stop() {
508
525
  this.followers.clear();
509
526
  this.onDestroy.forEach(x => x());
510
527
  }
511
- manage(key) {
528
+ manage(key, value) {
512
529
  const { proxy, state, subject } = this;
513
- const { value: entry } = getOwnPropertyDescriptor(subject, key);
514
- if (typeof entry == "function")
515
- return;
516
- if (typeof entry == "symbol") {
517
- const instruction = PENDING.get(entry);
518
- if (instruction)
519
- instruction.call(this, key, this);
520
- return;
521
- }
522
- state[key] = entry;
530
+ state[key] = value;
523
531
  const set = this.ref(key);
524
532
  defineProperty(subject, key, {
525
533
  enumerable: false,
@@ -611,26 +619,20 @@ class Controller {
611
619
  }
612
620
  function control(subject, cb) {
613
621
  let control = subject[CONTROL];
614
- const ready = READY.has(control);
615
622
  if (!control) {
616
623
  control = new Controller(subject);
617
624
  define(subject, CONTROL, control);
618
625
  }
619
- if (!cb) {
620
- if (!ready) {
621
- READY.add(control);
622
- control.start();
623
- }
624
- return control;
625
- }
626
+ const ready = READY.has(control);
626
627
  if (!ready) {
627
- let done;
628
- control.requestUpdate(() => {
629
- done = cb(control);
630
- });
631
- return () => done && done();
628
+ if (cb) {
629
+ let done;
630
+ control.requestUpdate(() => done = cb(control));
631
+ return () => done && done();
632
+ }
633
+ control.start();
632
634
  }
633
- return cb(control);
635
+ return cb ? cb(control) : control;
634
636
  }
635
637
 
636
638
  function apply(fn, label) {
@@ -718,14 +720,14 @@ function forSubscriber(fn) {
718
720
  }
719
721
 
720
722
  const Oops$8 = issues({
721
- DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
723
+ DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
722
724
  });
723
725
  function act(task) {
724
726
  return apply(function act(key) {
725
727
  let pending = false;
726
728
  const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
727
729
  if (pending)
728
- return Promise.reject(Oops$8.DuplicateAction(key));
730
+ return Promise.reject(Oops$8.DuplicatePending(key));
729
731
  pending = true;
730
732
  this.update(key);
731
733
  try {
@@ -831,8 +833,8 @@ function createRef(key, cb) {
831
833
  const Oops$7 = issues({
832
834
  NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
833
835
  BadFactory: () => `Set instruction can only accept a factory or undefined.`,
834
- ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
835
- FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
836
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
837
+ Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
836
838
  });
837
839
  function set(factory, argument) {
838
840
  return apply(function set(key) {
@@ -883,7 +885,7 @@ function pendingFactory(parent, key, fn, required) {
883
885
  const suspend = () => {
884
886
  if (required === false)
885
887
  return undefined;
886
- const issue = Oops$7.ValueNotReady(subject, key);
888
+ const issue = Oops$7.NotReady(subject, key);
887
889
  Object.assign(pending, {
888
890
  message: issue.message,
889
891
  stack: issue.stack
@@ -895,7 +897,7 @@ function pendingFactory(parent, key, fn, required) {
895
897
  init();
896
898
  }
897
899
  catch (err) {
898
- Oops$7.FactoryFailed(subject, key).warn();
900
+ Oops$7.Failed(subject, key).warn();
899
901
  throw err;
900
902
  }
901
903
  return () => {
@@ -914,8 +916,8 @@ function pendingFactory(parent, key, fn, required) {
914
916
 
915
917
  const Parent = new WeakMap();
916
918
  const Oops$6 = issues({
917
- ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
918
- UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
919
+ Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
920
+ Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
919
921
  });
920
922
  function parent(Expects, required) {
921
923
  return apply(function parent() {
@@ -924,10 +926,10 @@ function parent(Expects, required) {
924
926
  const expected = Expects.name;
925
927
  if (!value) {
926
928
  if (required !== false)
927
- throw Oops$6.ParentRequired(expected, child);
929
+ throw Oops$6.Required(expected, child);
928
930
  }
929
931
  else if (!(value instanceof Expects))
930
- throw Oops$6.UnexpectedParent(expected, child, value);
932
+ throw Oops$6.Unexpected(expected, child, value);
931
933
  return { value };
932
934
  });
933
935
  }
@@ -1032,19 +1034,19 @@ class Lookup {
1032
1034
  const LookupContext = React__default["default"].createContext(new Lookup());
1033
1035
  const useLookup = () => React__default["default"].useContext(LookupContext);
1034
1036
  const Oops$4 = issues({
1035
- NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
1037
+ NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
1036
1038
  });
1037
- function useInContext(Type, arg) {
1039
+ function useLocal(Type, arg) {
1038
1040
  const instance = useLookup().get(Type);
1039
1041
  if (!instance && arg !== false)
1040
- throw Oops$4.NothingInContext(Type.name);
1042
+ throw Oops$4.NotFound(Type.name);
1041
1043
  return typeof arg == "string" ?
1042
1044
  instance[arg] :
1043
1045
  instance;
1044
1046
  }
1045
1047
 
1046
1048
  const Oops$3 = issues({
1047
- 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.`,
1048
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.`
1049
1051
  });
1050
1052
  const PendingContext = new WeakMap();
@@ -1058,7 +1060,7 @@ function tap(type, argument) {
1058
1060
  };
1059
1061
  const { subject } = this;
1060
1062
  if ("set" in subject.constructor)
1061
- throw Oops$3.CantAttachGlobal(subject, type.name);
1063
+ throw Oops$3.NotAllowed(subject, type.name);
1062
1064
  getPending(subject).push(context => {
1063
1065
  let instance = context.get(type);
1064
1066
  if (typeof argument == "function") {
@@ -1202,7 +1204,7 @@ function useTap(source, path, expect) {
1202
1204
  if ("get" in source)
1203
1205
  return () => source.get();
1204
1206
  if ("prototype" in source)
1205
- return () => useInContext(source);
1207
+ return () => useLocal(source);
1206
1208
  else
1207
1209
  return source;
1208
1210
  }, [])();
@@ -1237,7 +1239,7 @@ class MVC extends Model {
1237
1239
  return useModel(this, arg, callback);
1238
1240
  }
1239
1241
  static get(required) {
1240
- return useInContext(this, required);
1242
+ return useLocal(this, required);
1241
1243
  }
1242
1244
  static tap(key, expect) {
1243
1245
  return useTap(this, key, expect);
@@ -1283,25 +1285,28 @@ class MVC extends Model {
1283
1285
  }
1284
1286
 
1285
1287
  const Oops$2 = issues({
1286
- BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
1288
+ BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
1287
1289
  });
1288
1290
  function Consumer(props) {
1289
- const { get, has, children, of: Control } = props;
1291
+ const { get, has, children, for: type } = props;
1290
1292
  if (typeof children == "function")
1291
- return children(useTap(Control));
1293
+ return children(useTap(type));
1292
1294
  const callback = has || get;
1293
1295
  if (typeof callback == "function")
1294
- callback(useInContext(Control, !!has));
1296
+ callback(useLocal(type, !!has));
1295
1297
  else
1296
- throw Oops$2.BadConsumerProps();
1298
+ throw Oops$2.BadProps();
1297
1299
  return null;
1298
1300
  }
1299
1301
 
1300
1302
  const Oops$1 = issues({
1301
- 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."
1302
1305
  });
1303
1306
  function Provider(props) {
1304
- const context = useNewContext(props.of);
1307
+ if ("of" in props)
1308
+ throw Oops$1.PropDeprecated();
1309
+ const context = useNewContext(props.for);
1305
1310
  const render = props.children;
1306
1311
  useAppliedProps(context, props);
1307
1312
  React__default["default"].useLayoutEffect(() => () => context.pop(), []);
@@ -1313,7 +1318,7 @@ function useNewContext(inject) {
1313
1318
  const from = useLookup();
1314
1319
  return React__default["default"].useMemo(() => {
1315
1320
  if (!inject)
1316
- throw Oops$1.NoProviderType();
1321
+ throw Oops$1.NoType();
1317
1322
  const context = from.push(inject);
1318
1323
  for (const instance of context.local)
1319
1324
  if (instance)
@@ -1327,7 +1332,7 @@ function useAppliedProps(within, props) {
1327
1332
  const targets = within.local;
1328
1333
  return function integrate(props) {
1329
1334
  for (const [key, value] of entries(props))
1330
- if (key != "of" && key != "children")
1335
+ if (["of", "for", "children"].indexOf(key) < 0)
1331
1336
  for (const into of targets)
1332
1337
  if (into && key in into)
1333
1338
  into[key] = value;
@@ -1348,15 +1353,15 @@ function RenderFunction(props) {
1348
1353
  }
1349
1354
 
1350
1355
  const Oops = issues({
1351
- 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.`,
1352
- 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.`
1353
1358
  });
1354
1359
  const Active = new WeakMap();
1355
1360
  class Global extends MVC {
1356
1361
  static create(...args) {
1357
1362
  const Type = this;
1358
1363
  if (Active.has(Type))
1359
- throw Oops.GlobalExists(this.name);
1364
+ throw Oops.AlreadyExists(this.name);
1360
1365
  const instance = super.create(...args);
1361
1366
  Active.set(Type, instance);
1362
1367
  return instance;
@@ -1374,7 +1379,7 @@ class Global extends MVC {
1374
1379
  static get(arg) {
1375
1380
  const instance = Active.get(this);
1376
1381
  if (!instance && arg !== false)
1377
- throw Oops.GlobalDoesNotExist(this.name);
1382
+ throw Oops.DoesNotExist(this.name);
1378
1383
  return (typeof arg == "string" ?
1379
1384
  instance[arg] :
1380
1385
  instance);
@@ -1410,7 +1415,7 @@ exports.set = set;
1410
1415
  exports.tap = tap;
1411
1416
  exports.use = use$1;
1412
1417
  exports.useFrom = useFrom;
1413
- exports.useInContext = useInContext;
1418
+ exports.useLocal = useLocal;
1414
1419
  exports.useModel = useModel;
1415
1420
  exports.useTap = useTap;
1416
1421
  //# sourceMappingURL=index.js.map