@expressive/mvc 0.8.0 → 0.8.1

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
@@ -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,47 @@ 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
- }
265
264
  class Control {
266
265
  constructor(subject) {
267
266
  this.subject = subject;
@@ -328,7 +327,8 @@ class Control {
328
327
  else if (!frame.size)
329
328
  setTimeout(() => {
330
329
  flush(this);
331
- setUpdate(this.subject, frame);
330
+ this.latest = Array.from(frame);
331
+ setTimeout(() => this.latest = undefined, 0);
332
332
  frame.clear();
333
333
  for (const notify of waiting)
334
334
  try {
@@ -379,12 +379,16 @@ class Control {
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")
@@ -937,7 +941,7 @@ class Model {
937
941
  }
938
942
  else if (keys.includes(key)) {
939
943
  removeListener();
940
- return () => resolve(single ? control.state.get(key) : getUpdate(this));
944
+ return () => resolve(single ? control.state.get(key) : control.latest);
941
945
  }
942
946
  });
943
947
  });
@@ -957,7 +961,7 @@ class Model {
957
961
  catch (e) { }
958
962
  const callback = single
959
963
  ? () => { argument.call(this, control.state.get(select), select); }
960
- : () => { argument.call(this, getUpdate(this)); };
964
+ : () => { argument.call(this, control.latest); };
961
965
  const onEvent = once
962
966
  ? () => {
963
967
  removeListener();
@@ -1042,7 +1046,7 @@ class Model {
1042
1046
  throw Oops$5.NoChaining();
1043
1047
  if (frame.size || arg1 !== false)
1044
1048
  waiting.add(() => {
1045
- callback(getUpdate(this));
1049
+ callback(control.latest);
1046
1050
  });
1047
1051
  else
1048
1052
  callback(false);
@@ -1235,14 +1239,8 @@ function useModel(source, arg, arg2) {
1235
1239
  return instance;
1236
1240
  }
1237
1241
  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
- }
1242
+ if (typeof arg == "object")
1243
+ local.assign(arg, arg2);
1246
1244
  React__default["default"].useLayoutEffect(() => {
1247
1245
  local.commit();
1248
1246
  return () => {
@@ -1332,10 +1330,10 @@ class MVC extends Model {
1332
1330
  }
1333
1331
  }
1334
1332
 
1335
- const LOCAL = Symbol("LOCAL");
1336
- const STATE = Symbol("STATE");
1337
- const UPDATE = Symbol("UPDATE");
1338
- const CONTROL = Symbol("CONTROL");
1333
+ const LOCAL = "$debug local";
1334
+ const STATE = "$debug state";
1335
+ const UPDATE = "$debug update";
1336
+ const CONTROL = "$debug controller";
1339
1337
  Object.defineProperties(Model.prototype, {
1340
1338
  [CONTROL]: {
1341
1339
  get() {
@@ -1357,7 +1355,8 @@ Object.defineProperties(Model.prototype, {
1357
1355
  },
1358
1356
  [UPDATE]: {
1359
1357
  get() {
1360
- return getUpdate(this);
1358
+ const source = Subscriber.get(this) || Control.get(this);
1359
+ return source && source.latest;
1361
1360
  }
1362
1361
  }
1363
1362
  });