@expressive/mvc 0.4.3 → 0.4.4

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.d.ts CHANGED
@@ -35,7 +35,7 @@ declare class Subscriber<T extends Stateful = any> {
35
35
  release: Callback;
36
36
  active: boolean;
37
37
  dependant: Set<Listener>;
38
- add: (key: any, value?: Callback) => void;
38
+ add: (key: any, value?: boolean | Callback) => void;
39
39
  constructor(parent: Controller<T>, onUpdate: Controller.OnEvent);
40
40
  }
41
41
 
@@ -220,6 +220,7 @@ declare namespace Instruction {
220
220
  get?: Getter<T>;
221
221
  set?: Setter<T> | false;
222
222
  suspense?: boolean;
223
+ destroy?: () => void;
223
224
  }
224
225
  interface ExplicitDescriptor extends PropertyDescriptor {
225
226
  explicit: true;
package/lib/index.esm.js CHANGED
@@ -164,11 +164,10 @@ const Oops$a = issues({
164
164
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
165
165
  });
166
166
  const INFO = new WeakMap();
167
- const USED = new WeakMap();
168
167
  const KEYS = new WeakMap();
168
+ const ORDER = new WeakMap();
169
169
  function from(source, arg1, arg2) {
170
170
  return apply(function from(key) {
171
- const parent = this;
172
171
  const { subject, state } = this;
173
172
  const required = arg2 === true || arg1 === true;
174
173
  let getSource;
@@ -189,14 +188,13 @@ function from(source, arg1, arg2) {
189
188
  else
190
189
  throw Oops$a.BadSource(subject, key, source);
191
190
  const setter = arg1;
192
- const info = { key, parent, priority: 1 };
191
+ const info = { key, parent: this };
193
192
  let sub;
194
- let register = USED.get(parent);
195
- if (!register)
196
- USED.set(parent, register = new Map());
193
+ let order = ORDER.get(this);
194
+ if (!order)
195
+ ORDER.set(this, order = []);
197
196
  state.set(key, undefined);
198
- register.set(key, info);
199
- function compute(initial) {
197
+ const compute = (initial) => {
200
198
  try {
201
199
  return setter.call(sub.proxy, sub.proxy);
202
200
  }
@@ -204,8 +202,8 @@ function from(source, arg1, arg2) {
204
202
  Oops$a.Failed(subject, key, initial).warn();
205
203
  throw err;
206
204
  }
207
- }
208
- function update() {
205
+ };
206
+ const refreshValue = () => {
209
207
  let value;
210
208
  try {
211
209
  value = compute(false);
@@ -215,26 +213,25 @@ function from(source, arg1, arg2) {
215
213
  }
216
214
  finally {
217
215
  if (state.get(key) !== value) {
218
- parent.state.set(key, value);
219
- parent.update(key);
216
+ state.set(key, value);
217
+ this.update(key);
220
218
  return value;
221
219
  }
222
220
  }
223
- }
224
- function defer(_key, from) {
225
- let pending = KEYS.get(from);
226
- if (!pending)
227
- KEYS.set(from, pending = []);
228
- if (info.parent !== from)
229
- update();
230
- else {
231
- const after = pending.findIndex(peer => (info.priority > INFO.get(peer).priority));
232
- pending.splice(after + 1, 0, update);
221
+ };
222
+ const dependancyDidUpdate = (_key, source) => {
223
+ if (source !== this) {
224
+ refreshValue();
225
+ return;
233
226
  }
234
- }
235
- function create() {
227
+ let pending = KEYS.get(this);
228
+ if (!pending)
229
+ KEYS.set(this, pending = []);
230
+ pending.push(refreshValue);
231
+ };
232
+ const create = () => {
236
233
  const control = getSource();
237
- sub = control.subscribe(defer);
234
+ sub = control.subscribe(dependancyDidUpdate);
238
235
  try {
239
236
  const value = compute(true);
240
237
  state.set(key, value);
@@ -245,14 +242,10 @@ function from(source, arg1, arg2) {
245
242
  }
246
243
  finally {
247
244
  sub.commit();
248
- for (const key of control.state.keys()) {
249
- const peer = register.get(key);
250
- if (peer && peer.priority >= info.priority)
251
- info.priority = peer.priority + 1;
252
- }
245
+ order.push(refreshValue);
253
246
  }
254
- }
255
- INFO.set(update, info);
247
+ };
248
+ INFO.set(refreshValue, info);
256
249
  return () => {
257
250
  const value = sub ? state.get(key) : create();
258
251
  if (value === undefined && required)
@@ -265,8 +258,11 @@ function flush(control) {
265
258
  const pending = KEYS.get(control);
266
259
  if (!pending)
267
260
  return;
261
+ const list = ORDER.get(control);
268
262
  while (pending.length) {
269
- const compute = pending.shift();
263
+ const compute = pending
264
+ .sort((a, b) => list.indexOf(b) - list.indexOf(a))
265
+ .pop();
270
266
  const { key } = INFO.get(compute);
271
267
  if (!control.frame.has(key))
272
268
  compute();
@@ -291,18 +287,16 @@ class Subscriber {
291
287
  }
292
288
  });
293
289
  const release = parent.addListener(key => {
294
- if (!this.active || !using.has(key))
290
+ if (!this.active)
295
291
  return;
296
292
  const handler = using.get(key);
297
293
  let notify;
298
294
  if (typeof handler == "function") {
299
295
  const callback = handler();
300
- if (typeof callback == "function")
301
- notify = callback;
302
- else if (callback === true)
296
+ if (callback === true)
303
297
  notify = this.onUpdate(key, parent);
304
298
  }
305
- else
299
+ else if (handler === true)
306
300
  notify = this.onUpdate(key, parent);
307
301
  const getWhy = () => {
308
302
  const update = getUpdate(parent.subject);
@@ -324,7 +318,7 @@ class Subscriber {
324
318
  release();
325
319
  };
326
320
  this.add = (key, value) => {
327
- if (value)
321
+ if (value !== undefined)
328
322
  using.set(key, value);
329
323
  else if (!using.has(key))
330
324
  using.set(key, true);
@@ -398,17 +392,15 @@ class Controller {
398
392
  else if (!frame.size)
399
393
  setTimeout(() => {
400
394
  flush(this);
401
- const callback = Array.from(waiting);
402
- const keys = Array.from(frame);
403
- frame.clear();
404
- waiting.clear();
405
- UPDATE.set(subject, keys);
395
+ UPDATE.set(subject, Array.from(frame));
406
396
  setTimeout(() => {
407
397
  UPDATE.delete(subject);
408
398
  }, 0);
409
- for (const cb of callback)
399
+ frame.clear();
400
+ for (const notify of waiting)
410
401
  try {
411
- cb();
402
+ waiting.delete(notify);
403
+ notify();
412
404
  }
413
405
  catch (err) {
414
406
  console.error(err);
@@ -659,6 +651,14 @@ function apply(fn, label) {
659
651
  const desc = output;
660
652
  if ("value" in desc)
661
653
  state.set(key, desc.value);
654
+ if ("destroy" in output) {
655
+ const { destroy } = output;
656
+ if (destroy)
657
+ this.addListener((key) => {
658
+ if (key == null)
659
+ destroy();
660
+ });
661
+ }
662
662
  const { get: onGet, set: onSet, enumerable, suspense } = desc;
663
663
  const set = onSet !== false
664
664
  ? this.ref(key, onSet)
@@ -940,39 +940,31 @@ const ANY$1 = Symbol("any");
940
940
  function managedMap(control, property, initial) {
941
941
  const managed = new ManagedMap(initial, emit);
942
942
  const context = new WeakMap();
943
- const lastUpdate = new Set();
943
+ const observers = new Set();
944
+ const frozen = new Set();
944
945
  function reset() {
945
- lastUpdate.clear();
946
+ frozen.clear();
946
947
  }
947
948
  function emit(key) {
948
- lastUpdate.add(key);
949
+ observers.forEach(notify => notify(key));
949
950
  control.update(property);
950
951
  control.waiting.add(reset);
951
952
  }
952
- function setValue(next) {
953
- control.state.set(property, next);
954
- managed.source = next;
955
- emit(ANY$1);
956
- }
957
- function getValue(local) {
958
- if (!local)
959
- return managed;
960
- if (context.has(local))
961
- return context.get(local);
962
- const refresh = local.onUpdate(property, control);
953
+ function init(local) {
963
954
  const proxy = create(managed);
964
955
  const using = new Set();
965
- const update = () => {
966
- if (using.has(ANY$1) || lastUpdate.has(ANY$1) && using.size)
967
- refresh();
968
- else
969
- for (const key of lastUpdate)
970
- if (using.has(key)) {
971
- refresh();
972
- break;
973
- }
974
- };
975
- local.add(property, () => update);
956
+ observers.add(key => {
957
+ if (frozen.has(local))
958
+ return;
959
+ if (using.has(key) || using.has(ANY$1) || key === ANY$1 && using.size) {
960
+ const refresh = local.onUpdate(property, control);
961
+ if (refresh) {
962
+ frozen.add(local);
963
+ refresh();
964
+ }
965
+ }
966
+ });
967
+ local.add(property, false);
976
968
  context.set(local, proxy);
977
969
  proxy.watch = (key) => {
978
970
  if (!local.active)
@@ -982,8 +974,21 @@ function managedMap(control, property, initial) {
982
974
  }
983
975
  return {
984
976
  value: initial,
985
- set: setValue,
986
- get: getValue
977
+ get(local) {
978
+ if (!local)
979
+ return managed;
980
+ if (context.has(local))
981
+ return context.get(local);
982
+ return init(local);
983
+ },
984
+ set(next) {
985
+ managed.source = next;
986
+ control.state.set(property, next);
987
+ emit(ANY$1);
988
+ },
989
+ destroy() {
990
+ observers.clear();
991
+ }
987
992
  };
988
993
  }
989
994
  class ManagedMap {
@@ -1045,39 +1050,31 @@ const ANY = Symbol("any");
1045
1050
  function managedSet(control, property, initial) {
1046
1051
  const managed = new ManagedSet(initial, emit);
1047
1052
  const context = new WeakMap();
1048
- const lastUpdate = new Set();
1053
+ const observers = new Set();
1054
+ const frozen = new Set();
1049
1055
  function reset() {
1050
- lastUpdate.clear();
1056
+ frozen.clear();
1051
1057
  }
1052
1058
  function emit(key) {
1053
- lastUpdate.add(key);
1059
+ observers.forEach(notify => notify(key));
1054
1060
  control.update(property);
1055
1061
  control.waiting.add(reset);
1056
1062
  }
1057
- function setValue(next) {
1058
- managed.source = next;
1059
- control.state.set(property, next);
1060
- emit(ANY);
1061
- }
1062
- function getValue(local) {
1063
- if (!local)
1064
- return managed;
1065
- if (context.has(local))
1066
- return context.get(local);
1067
- const refresh = local.onUpdate(property, control);
1063
+ function init(local) {
1068
1064
  const proxy = create(managed);
1069
1065
  const using = new Set();
1070
- const update = () => {
1071
- if (using.has(ANY) || lastUpdate.has(ANY) && using.size)
1072
- refresh();
1073
- else
1074
- for (const key of lastUpdate)
1075
- if (using.has(key)) {
1076
- refresh();
1077
- break;
1078
- }
1079
- };
1080
- local.add(property, () => update);
1066
+ observers.add(key => {
1067
+ if (frozen.has(local))
1068
+ return;
1069
+ if (using.has(key) || using.has(ANY) || key === ANY && using.size) {
1070
+ const refresh = local.onUpdate(property, control);
1071
+ if (refresh) {
1072
+ frozen.add(local);
1073
+ refresh();
1074
+ }
1075
+ }
1076
+ });
1077
+ local.add(property, false);
1081
1078
  context.set(local, proxy);
1082
1079
  proxy.watch = (key) => {
1083
1080
  if (!local.active)
@@ -1087,8 +1084,21 @@ function managedSet(control, property, initial) {
1087
1084
  }
1088
1085
  return {
1089
1086
  value: initial,
1090
- set: setValue,
1091
- get: getValue
1087
+ get(local) {
1088
+ if (!local)
1089
+ return managed;
1090
+ if (context.has(local))
1091
+ return context.get(local);
1092
+ return init(local);
1093
+ },
1094
+ set(next) {
1095
+ managed.source = next;
1096
+ control.state.set(property, next);
1097
+ emit(ANY);
1098
+ },
1099
+ destroy() {
1100
+ observers.clear();
1101
+ }
1092
1102
  };
1093
1103
  }
1094
1104
  class ManagedSet {
@@ -1098,8 +1108,9 @@ class ManagedSet {
1098
1108
  }
1099
1109
  watch(_key) { }
1100
1110
  add(key) {
1111
+ this.source.add(key);
1101
1112
  this.emit(key);
1102
- return this.source.add(key);
1113
+ return this;
1103
1114
  }
1104
1115
  ;
1105
1116
  delete(key) {