@expressive/mvc 0.8.0 → 0.8.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
@@ -25,7 +25,7 @@ function issues(register) {
25
25
  return Library;
26
26
  }
27
27
 
28
- const Oops$c = issues({
28
+ const Oops$d = issues({
29
29
  BadCallback: () => `Callback for effect-callback may only return a function.`
30
30
  });
31
31
  const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
@@ -38,7 +38,7 @@ function createEffect(callback) {
38
38
  if (unSet instanceof Promise)
39
39
  unSet = undefined;
40
40
  if (unSet && typeof unSet !== "function")
41
- throw Oops$c.BadCallback();
41
+ throw Oops$d.BadCallback();
42
42
  };
43
43
  }
44
44
  function createValueEffect(callback) {
@@ -54,15 +54,15 @@ function createValueEffect(callback) {
54
54
  if (typeof out == "function")
55
55
  unSet = out;
56
56
  else
57
- throw Oops$c.BadCallback();
57
+ throw Oops$d.BadCallback();
58
58
  };
59
59
  }
60
60
 
61
- const Oops$b = issues({
61
+ const Oops$c = issues({
62
62
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
63
63
  });
64
64
  function suspend(source, key) {
65
- const error = Oops$b.NotReady(source.subject, key);
65
+ const error = Oops$c.NotReady(source.subject, key);
66
66
  const promise = new Promise(resolve => {
67
67
  const release = source.addListener(forKey => {
68
68
  if (forKey == key)
@@ -102,7 +102,7 @@ function mayRetry(fn) {
102
102
  return compute();
103
103
  }
104
104
 
105
- const Oops$a = issues({
105
+ const Oops$b = issues({
106
106
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
107
107
  });
108
108
  const INFO = new WeakMap();
@@ -119,7 +119,7 @@ function computeMode(self, source, setter, key, required) {
119
119
  return setter.call(sub.proxy, sub.proxy);
120
120
  }
121
121
  catch (err) {
122
- Oops$a.Failed(subject, key, initial).warn();
122
+ Oops$b.Failed(subject, key, initial).warn();
123
123
  throw err;
124
124
  }
125
125
  };
@@ -195,20 +195,21 @@ class Subscriber {
195
195
  this.onUpdate = onUpdate;
196
196
  this.active = false;
197
197
  this.dependant = new Set();
198
- const proxy = create(parent.subject);
199
- const using = new Map();
200
- REGISTER$1.set(proxy, this);
201
- defineProperty(this, "proxy", {
202
- configurable: true,
203
- get() {
204
- hasUpdate(proxy);
205
- return proxy;
206
- }
207
- });
208
- const release = parent.addListener(key => {
198
+ this.watch = new Map();
199
+ this.commit = () => {
200
+ const release = this.parent.addListener(this.event);
201
+ this.active = true;
202
+ this.dependant.forEach(x => x.commit());
203
+ return this.release = () => {
204
+ this.dependant.forEach(x => x.release());
205
+ release();
206
+ };
207
+ };
208
+ this.event = (key) => {
209
209
  if (!this.active)
210
210
  return;
211
- const handler = using.get(key);
211
+ const { parent, watch } = this;
212
+ const handler = watch.get(key);
212
213
  let notify;
213
214
  if (typeof handler == "function") {
214
215
  const callback = handler();
@@ -219,49 +220,48 @@ class Subscriber {
219
220
  notify = this.onUpdate(key, parent);
220
221
  if (!notify)
221
222
  return;
222
- parent.waiting.add(() => addUpdate(proxy, using));
223
+ parent.waiting.add(() => {
224
+ this.latest = parent.latest.filter(k => watch.has(k));
225
+ });
223
226
  parent.waiting.add(notify);
224
- });
225
- this.add = (key, value) => {
226
- if (value !== undefined)
227
- using.set(key, value);
228
- else if (!using.has(key))
229
- using.set(key, true);
230
- };
231
- this.commit = () => {
232
- this.active = true;
233
- this.dependant.forEach(x => x.commit());
234
- return this.release;
235
- };
236
- this.release = () => {
237
- this.dependant.forEach(x => x.release());
238
- release();
239
227
  };
228
+ const proxy = create(parent.subject);
229
+ const reset = () => this.latest = undefined;
230
+ REGISTER$1.set(proxy, this);
231
+ defineProperty(this, "proxy", {
232
+ configurable: true,
233
+ get() {
234
+ setTimeout(reset, 0);
235
+ return proxy;
236
+ }
237
+ });
240
238
  }
241
239
  static get(from) {
242
240
  return REGISTER$1.get(from);
243
241
  }
242
+ get using() {
243
+ return Array.from(this.watch.keys());
244
+ }
245
+ assign(apply, keys) {
246
+ const { waiting, subject } = this.parent;
247
+ this.active = false;
248
+ if (typeof keys !== "object")
249
+ keys = getOwnPropertyNames(subject);
250
+ for (const key of keys)
251
+ if (key in apply)
252
+ subject[key] = apply[key];
253
+ waiting.add(() => this.active = true);
254
+ }
255
+ add(key, value) {
256
+ if (value !== undefined)
257
+ this.watch.set(key, value);
258
+ else if (!this.watch.has(key))
259
+ this.watch.set(key, true);
260
+ }
244
261
  }
245
262
 
246
263
  const REGISTER = new WeakMap();
247
- const UPDATE$1 = new WeakMap();
248
- function getUpdate(subject) {
249
- return UPDATE$1.get(subject);
250
- }
251
- function setUpdate(subject, keys) {
252
- UPDATE$1.set(subject, Array.from(keys));
253
- setTimeout(() => UPDATE$1.delete(subject), 0);
254
- }
255
- /** Ensure a local update is dropped after use. */
256
- function hasUpdate(proxy) {
257
- if (UPDATE$1.has(proxy))
258
- setTimeout(() => UPDATE$1.delete(proxy), 0);
259
- }
260
- /** Set local update for a subscribed context. */
261
- function addUpdate(proxy, using) {
262
- const parent = UPDATE$1.get(getPrototypeOf(proxy));
263
- UPDATE$1.set(proxy, parent.filter(k => using.has(k)));
264
- }
264
+ const PENDING = new Map();
265
265
  class Control {
266
266
  constructor(subject) {
267
267
  this.subject = subject;
@@ -328,7 +328,8 @@ class Control {
328
328
  else if (!frame.size)
329
329
  setTimeout(() => {
330
330
  flush(this);
331
- setUpdate(this.subject, frame);
331
+ this.latest = Array.from(frame);
332
+ setTimeout(() => this.latest = undefined, 0);
332
333
  frame.clear();
333
334
  for (const notify of waiting)
334
335
  try {
@@ -378,13 +379,16 @@ class Control {
378
379
  }
379
380
  }
380
381
 
381
- const PENDING = new Map();
382
- function add(fn, label) {
383
- const name = label || fn.name || "pending";
382
+ /**
383
+ * Run instruction as controller sets itself up.
384
+ * This will specialize the behavior of a given property.
385
+ */
386
+ function add(instruction, label) {
387
+ const name = label || instruction.name || "pending";
384
388
  const placeholder = Symbol(`${name} instruction`);
385
389
  function setup(key) {
386
390
  const { subject, state } = this;
387
- let output = fn.call(this, key, this);
391
+ let output = instruction.call(this, key, this);
388
392
  if (typeof output == "function")
389
393
  output = { get: output };
390
394
  if (typeof output != "object")
@@ -485,7 +489,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
485
489
  });
486
490
  }
487
491
 
488
- const Oops$9 = issues({
492
+ const Oops$a = issues({
489
493
  DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
490
494
  });
491
495
  function act(task) {
@@ -493,7 +497,7 @@ function act(task) {
493
497
  let pending = false;
494
498
  const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
495
499
  if (pending)
496
- return Promise.reject(Oops$9.DuplicatePending(key));
500
+ return Promise.reject(Oops$a.DuplicatePending(key));
497
501
  pending = true;
498
502
  this.update(key);
499
503
  try {
@@ -515,6 +519,9 @@ function act(task) {
515
519
  });
516
520
  }
517
521
 
522
+ const Oops$9 = issues({
523
+ NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
524
+ });
518
525
  function factoryMode(self, output, key, required) {
519
526
  const { subject, state } = self;
520
527
  let pending;
@@ -536,7 +543,7 @@ function factoryMode(self, output, key, required) {
536
543
  const suspend = () => {
537
544
  if (required === false)
538
545
  return undefined;
539
- const issue = Oops$8.NotReady(subject, key);
546
+ const issue = Oops$9.NotReady(subject, key);
540
547
  assign(pending, {
541
548
  message: issue.message,
542
549
  stack: issue.stack
@@ -554,12 +561,8 @@ function factoryMode(self, output, key, required) {
554
561
  }
555
562
 
556
563
  const Oops$8 = issues({
557
- // BadSource: (model, property, got) =>
558
- // `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
559
564
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
560
565
  ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
561
- NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
562
- FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
563
566
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
564
567
  });
565
568
  function get(arg0, arg1, arg2) {
@@ -937,7 +940,7 @@ class Model {
937
940
  }
938
941
  else if (keys.includes(key)) {
939
942
  removeListener();
940
- return () => resolve(single ? control.state.get(key) : getUpdate(this));
943
+ return () => resolve(single ? control.state.get(key) : control.latest);
941
944
  }
942
945
  });
943
946
  });
@@ -957,7 +960,7 @@ class Model {
957
960
  catch (e) { }
958
961
  const callback = single
959
962
  ? () => { argument.call(this, control.state.get(select), select); }
960
- : () => { argument.call(this, getUpdate(this)); };
963
+ : () => { argument.call(this, control.latest); };
961
964
  const onEvent = once
962
965
  ? () => {
963
966
  removeListener();
@@ -1042,7 +1045,7 @@ class Model {
1042
1045
  throw Oops$5.NoChaining();
1043
1046
  if (frame.size || arg1 !== false)
1044
1047
  waiting.add(() => {
1045
- callback(getUpdate(this));
1048
+ callback(control.latest);
1046
1049
  });
1047
1050
  else
1048
1051
  callback(false);
@@ -1235,14 +1238,8 @@ function useModel(source, arg, arg2) {
1235
1238
  return instance;
1236
1239
  }
1237
1240
  const local = use(refresh => (Control.for(instance).subscribe(() => refresh)));
1238
- if (typeof arg == "object") {
1239
- local.active = false;
1240
- if (typeof arg2 !== "object")
1241
- arg2 = getOwnPropertyNames(instance);
1242
- for (const key of arg2)
1243
- if (key in arg)
1244
- instance[key] = arg[key];
1245
- }
1241
+ if (typeof arg == "object")
1242
+ local.assign(arg, arg2);
1246
1243
  React__default["default"].useLayoutEffect(() => {
1247
1244
  local.commit();
1248
1245
  return () => {
@@ -1299,10 +1296,10 @@ function useTap(source, arg1, arg2) {
1299
1296
  const instance = React.useMemo(() => {
1300
1297
  if (typeof source == "object")
1301
1298
  return () => source;
1302
- if (MVC.isTypeof(source))
1303
- return () => source.get(true);
1304
1299
  if (Model.isTypeof(source))
1305
- return () => useContext(source);
1300
+ return "get" in source
1301
+ ? () => source.get(true)
1302
+ : () => useContext(source);
1306
1303
  return source;
1307
1304
  }, [])();
1308
1305
  if (typeof arg1 == "function")
@@ -1332,10 +1329,10 @@ class MVC extends Model {
1332
1329
  }
1333
1330
  }
1334
1331
 
1335
- const LOCAL = Symbol("LOCAL");
1336
- const STATE = Symbol("STATE");
1337
- const UPDATE = Symbol("UPDATE");
1338
- const CONTROL = Symbol("CONTROL");
1332
+ const LOCAL = "$debug local";
1333
+ const STATE = "$debug state";
1334
+ const UPDATE = "$debug update";
1335
+ const CONTROL = "$debug controller";
1339
1336
  Object.defineProperties(Model.prototype, {
1340
1337
  [CONTROL]: {
1341
1338
  get() {
@@ -1357,7 +1354,8 @@ Object.defineProperties(Model.prototype, {
1357
1354
  },
1358
1355
  [UPDATE]: {
1359
1356
  get() {
1360
- return getUpdate(this);
1357
+ const source = Subscriber.get(this) || Control.get(this);
1358
+ return source && source.latest;
1361
1359
  }
1362
1360
  }
1363
1361
  });