@expressive/mvc 1.0.0-beta.32 → 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) {
@@ -98,6 +98,13 @@ class Subscriber {
98
98
  this.active = false;
99
99
  this.handle = {};
100
100
  this.dependant = new Set();
101
+ this.debug = () => {
102
+ const update = [];
103
+ this.notify = keys => {
104
+ update.splice(0, update.length, ...keys.filter(k => k in this.handle));
105
+ };
106
+ return update;
107
+ };
101
108
  this.listen = (key, from) => {
102
109
  const handler = this.handle[key];
103
110
  if (!handler)
@@ -107,28 +114,16 @@ class Subscriber {
107
114
  const notify = this.onUpdate(key, from);
108
115
  if (notify)
109
116
  from.waiting.add(notify);
117
+ if (this.notify)
118
+ from.waiting.add(this.notify);
110
119
  };
111
120
  if (!(parent instanceof Controller))
112
121
  parent = manage(parent);
113
- const subject = this.source =
114
- parent.subject;
115
- const proxy = this.proxy =
116
- create(subject);
117
122
  this.parent = parent;
123
+ this.source = parent.subject;
124
+ this.proxy = create(parent.subject);
118
125
  define(this.proxy, LOCAL, this);
119
- defineProperty(this.proxy, UPDATE, {
120
- get: () => (this.parent.handled.filter(key => key in this.handle))
121
- });
122
- if ("update" in subject) {
123
- define(proxy, "update", (...args) => {
124
- if (!args.length) {
125
- const refresh = this.onUpdate("", parent);
126
- if (refresh)
127
- refresh([]);
128
- }
129
- return subject.update(...args);
130
- });
131
- }
126
+ defineLazy(this.proxy, UPDATE, this.debug);
132
127
  for (const key in parent.state)
133
128
  this.spy(key);
134
129
  }
@@ -162,7 +157,7 @@ class Subscriber {
162
157
  }
163
158
  }
164
159
 
165
- const Oops$7 = issues({
160
+ const Oops$8 = issues({
166
161
  ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
167
162
  ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
168
163
  });
@@ -181,14 +176,14 @@ function prepare(parent, key, source, setter, getter) {
181
176
  }
182
177
  register.set(key, info);
183
178
  const current = getter
184
- ? () => getter.call(subject, state[key], key)
179
+ ? () => getter(parent, key)
185
180
  : () => state[key];
186
181
  function compute(initial) {
187
182
  try {
188
183
  return setter.call(sub.proxy, sub.proxy);
189
184
  }
190
185
  catch (err) {
191
- Oops$7.ComputeFailed(subject, key, !!initial).warn();
186
+ Oops$8.ComputeFailed(subject, key, !!initial).warn();
192
187
  throw err;
193
188
  }
194
189
  }
@@ -234,7 +229,7 @@ function prepare(parent, key, source, setter, getter) {
234
229
  }
235
230
  catch (e) {
236
231
  if (early)
237
- Oops$7.ComputedEarly(key).warn();
232
+ Oops$8.ComputedEarly(key).warn();
238
233
  throw e;
239
234
  }
240
235
  finally {
@@ -360,30 +355,16 @@ class Controller {
360
355
  this.state = {};
361
356
  this.frame = new Set();
362
357
  this.waiting = new Set();
363
- this.handled = [];
364
358
  this.followers = new Set();
365
359
  }
366
360
  static setup(onto) {
367
361
  const control = new this(onto);
368
- defineProperty(onto, CONTROL, {
369
- configurable: true,
370
- get() {
371
- defineProperty(onto, CONTROL, {
372
- value: control
373
- });
374
- defineProperty(onto, STATE, {
375
- get: () => (Object.assign({}, control.state)),
376
- configurable: true
377
- });
378
- defineProperty(onto, UPDATE, {
379
- get: () => [...control.handled],
380
- configurable: true
381
- });
382
- control.start();
383
- if (onto.didCreate)
384
- onto.didCreate();
385
- return control;
386
- }
362
+ defineLazy(onto, CONTROL, () => {
363
+ onto[STATE] = control.state;
364
+ control.start();
365
+ if (onto.didCreate)
366
+ onto.didCreate();
367
+ return control;
387
368
  });
388
369
  return control;
389
370
  }
@@ -462,14 +443,17 @@ class Controller {
462
443
  }
463
444
  emit() {
464
445
  flush(this);
446
+ const keys = Object.freeze([...this.frame]);
465
447
  const handle = new Set(this.waiting);
466
- const handled = this.handled =
467
- Object.freeze([...this.frame]);
468
448
  this.waiting.clear();
469
449
  this.frame.clear();
450
+ defineProperty(this.subject, UPDATE, {
451
+ configurable: true,
452
+ value: keys
453
+ });
470
454
  handle.forEach(callback => {
471
455
  try {
472
- callback(handled);
456
+ callback(keys);
473
457
  }
474
458
  catch (e) { }
475
459
  });
@@ -526,6 +510,61 @@ function child(source, name) {
526
510
  }, name || source.name);
527
511
  }
528
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
+
529
568
  const Oops$6 = issues({
530
569
  CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
531
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.`
@@ -628,10 +667,13 @@ function act(task) {
628
667
  };
629
668
  });
630
669
  }
631
- function from(source, setter, getter) {
670
+ function from(source, setter, argument) {
632
671
  return apply(function from(key) {
633
672
  const { subject } = this;
634
673
  let getSource;
674
+ let getter = argument === true
675
+ ? pendingValue
676
+ : argument || undefined;
635
677
  // Easy mistake, using a peer, will always be unresolved.
636
678
  if (typeof source == "symbol")
637
679
  throw Oops$5.PeerNotAllowed(subject, key);
@@ -646,7 +688,7 @@ function from(source, setter, getter) {
646
688
  // is a peer Model (constructor)
647
689
  else if (Model.isTypeof(source))
648
690
  getSource = pendingAccess(subject, source, key, true);
649
- // Regular function is to ambiguous so not allowed.
691
+ // Regular function is too ambiguous so not allowed.
650
692
  else
651
693
  throw Oops$5.BadComputedSource(subject, key, source);
652
694
  prepare(this, key, getSource, setter, getter);
@@ -656,12 +698,14 @@ function from(source, setter, getter) {
656
698
  const Oops$4 = issues({
657
699
  ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
658
700
  });
701
+ /* deprecated - ignore coverage */
702
+ /* istanbul ignore next */
659
703
  function pending(source, compute) {
660
- return (source === undefined ?
661
- suspendForValue() :
662
- typeof source == "function" && !source.prototype ?
663
- suspendForAsync(source) :
664
- 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);
665
709
  }
666
710
  /**
667
711
  * Get value, suspend instead if undefined.
@@ -675,6 +719,40 @@ function pendingValue(via, key) {
675
719
  throw suspend(via, key);
676
720
  return value;
677
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
+ }
678
756
  function suspend(source, key) {
679
757
  const error = Oops$4.ValueNotReady(source.subject, key);
680
758
  const promise = new Promise(resolve => {
@@ -694,45 +772,6 @@ function suspend(source, key) {
694
772
  message: error.message,
695
773
  stack: error.stack
696
774
  });
697
- }
698
- function suspendForComputed(source, compute) {
699
- function getter(_value, key) {
700
- return pendingValue(manage(this), key);
701
- }
702
- return from(source, compute, getter);
703
- }
704
- function suspendForValue() {
705
- return apply(function pending(key) {
706
- this.state[key] = undefined;
707
- return {
708
- set: this.setter(key),
709
- get: () => pendingValue(this, key)
710
- };
711
- });
712
- }
713
- function suspendForAsync(source) {
714
- return apply(function suspense(key) {
715
- const subject = this.subject;
716
- let waiting = true;
717
- let value;
718
- let error;
719
- return () => {
720
- if (error)
721
- throw error;
722
- if (!waiting)
723
- return value;
724
- const issue = Oops$4.ValueNotReady(subject, key);
725
- let suspend = source
726
- .call(subject, key)
727
- .catch(err => error = err)
728
- .then(out => value = out)
729
- .finally(() => waiting = false);
730
- throw Object.assign(suspend, {
731
- message: issue.message,
732
- stack: issue.stack
733
- });
734
- };
735
- });
736
775
  }
737
776
 
738
777
  function use$1(init) {
@@ -973,9 +1012,7 @@ class Model {
973
1012
  return proxy;
974
1013
  }
975
1014
  tag(id) {
976
- const hook = use$1(refresh => {
977
- return new Subscriber(this, () => refresh);
978
- });
1015
+ const hook = use$1(refresh => (new Subscriber(this, () => refresh)));
979
1016
  useElementLifecycle(hook, id || 0);
980
1017
  return hook.proxy;
981
1018
  }
@@ -1023,12 +1060,10 @@ class Model {
1023
1060
  invoke();
1024
1061
  return this.on(select, invoke, true);
1025
1062
  }
1026
- else {
1027
- const sub = new Subscriber(control, () => invoke);
1028
- target = sub.proxy;
1029
- invoke();
1030
- return sub.commit();
1031
- }
1063
+ const sub = new Subscriber(control, () => invoke);
1064
+ target = sub.proxy;
1065
+ invoke();
1066
+ return sub.commit();
1032
1067
  }
1033
1068
  import(from, subset) {
1034
1069
  for (const key of keys(manage(this), subset))
@@ -1224,31 +1259,6 @@ function parent(Expects, required) {
1224
1259
  });
1225
1260
  }
1226
1261
 
1227
- function on(initial, cb) {
1228
- return apply(function on(key) {
1229
- this.manage(key, initial, cb && createValueEffect(cb));
1230
- });
1231
- }
1232
- function memo(factory, defer) {
1233
- return apply(function memo(key) {
1234
- const source = this.subject;
1235
- const get = () => factory.call(source);
1236
- if (defer)
1237
- defineLazy(source, key, get);
1238
- else
1239
- define(source, key, get());
1240
- });
1241
- }
1242
- function lazy(value) {
1243
- return apply(function lazy(key) {
1244
- const source = this.subject;
1245
- source[key] = value;
1246
- defineProperty(this.state, key, {
1247
- get: () => source[key]
1248
- });
1249
- });
1250
- }
1251
-
1252
1262
  const Oops = issues({
1253
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.`,
1254
1264
  GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
@@ -1300,11 +1310,12 @@ exports.child = child;
1300
1310
  exports["default"] = Model;
1301
1311
  exports.from = from;
1302
1312
  exports.lazy = lazy;
1303
- exports.memo = memo;
1313
+ exports.memo = set;
1304
1314
  exports.on = on;
1305
1315
  exports.parent = parent;
1306
1316
  exports.pending = pending;
1307
1317
  exports.ref = ref;
1318
+ exports.set = set;
1308
1319
  exports.tap = tap;
1309
1320
  exports.use = use;
1310
1321
  //# sourceMappingURL=index.js.map