@expressive/mvc 0.4.1 → 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.js CHANGED
@@ -172,11 +172,10 @@ const Oops$a = issues({
172
172
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
173
173
  });
174
174
  const INFO = new WeakMap();
175
- const USED = new WeakMap();
176
175
  const KEYS = new WeakMap();
176
+ const ORDER = new WeakMap();
177
177
  function from(source, arg1, arg2) {
178
178
  return apply(function from(key) {
179
- const parent = this;
180
179
  const { subject, state } = this;
181
180
  const required = arg2 === true || arg1 === true;
182
181
  let getSource;
@@ -197,14 +196,13 @@ function from(source, arg1, arg2) {
197
196
  else
198
197
  throw Oops$a.BadSource(subject, key, source);
199
198
  const setter = arg1;
200
- const info = { key, parent, priority: 1 };
199
+ const info = { key, parent: this };
201
200
  let sub;
202
- let register = USED.get(parent);
203
- if (!register)
204
- USED.set(parent, register = new Map());
201
+ let order = ORDER.get(this);
202
+ if (!order)
203
+ ORDER.set(this, order = []);
205
204
  state.set(key, undefined);
206
- register.set(key, info);
207
- function compute(initial) {
205
+ const compute = (initial) => {
208
206
  try {
209
207
  return setter.call(sub.proxy, sub.proxy);
210
208
  }
@@ -212,8 +210,8 @@ function from(source, arg1, arg2) {
212
210
  Oops$a.Failed(subject, key, initial).warn();
213
211
  throw err;
214
212
  }
215
- }
216
- function update() {
213
+ };
214
+ const refreshValue = () => {
217
215
  let value;
218
216
  try {
219
217
  value = compute(false);
@@ -223,26 +221,25 @@ function from(source, arg1, arg2) {
223
221
  }
224
222
  finally {
225
223
  if (state.get(key) !== value) {
226
- parent.state.set(key, value);
227
- parent.update(key);
224
+ state.set(key, value);
225
+ this.update(key);
228
226
  return value;
229
227
  }
230
228
  }
231
- }
232
- function defer(_key, from) {
233
- let pending = KEYS.get(from);
234
- if (!pending)
235
- KEYS.set(from, pending = []);
236
- if (info.parent !== from)
237
- update();
238
- else {
239
- const after = pending.findIndex(peer => (info.priority > INFO.get(peer).priority));
240
- pending.splice(after + 1, 0, update);
229
+ };
230
+ const dependancyDidUpdate = (_key, source) => {
231
+ if (source !== this) {
232
+ refreshValue();
233
+ return;
241
234
  }
242
- }
243
- function create() {
235
+ let pending = KEYS.get(this);
236
+ if (!pending)
237
+ KEYS.set(this, pending = []);
238
+ pending.push(refreshValue);
239
+ };
240
+ const create = () => {
244
241
  const control = getSource();
245
- sub = control.subscribe(defer);
242
+ sub = control.subscribe(dependancyDidUpdate);
246
243
  try {
247
244
  const value = compute(true);
248
245
  state.set(key, value);
@@ -253,14 +250,10 @@ function from(source, arg1, arg2) {
253
250
  }
254
251
  finally {
255
252
  sub.commit();
256
- for (const key of control.state.keys()) {
257
- const peer = register.get(key);
258
- if (peer && peer.priority >= info.priority)
259
- info.priority = peer.priority + 1;
260
- }
253
+ order.push(refreshValue);
261
254
  }
262
- }
263
- INFO.set(update, info);
255
+ };
256
+ INFO.set(refreshValue, info);
264
257
  return () => {
265
258
  const value = sub ? state.get(key) : create();
266
259
  if (value === undefined && required)
@@ -273,8 +266,11 @@ function flush(control) {
273
266
  const pending = KEYS.get(control);
274
267
  if (!pending)
275
268
  return;
269
+ const list = ORDER.get(control);
276
270
  while (pending.length) {
277
- const compute = pending.shift();
271
+ const compute = pending
272
+ .sort((a, b) => list.indexOf(b) - list.indexOf(a))
273
+ .pop();
278
274
  const { key } = INFO.get(compute);
279
275
  if (!control.frame.has(key))
280
276
  compute();
@@ -299,13 +295,17 @@ class Subscriber {
299
295
  }
300
296
  });
301
297
  const release = parent.addListener(key => {
302
- if (!this.active || !using.has(key))
298
+ if (!this.active)
303
299
  return;
304
300
  const handler = using.get(key);
305
- if (typeof handler == "function")
306
- if (handler() !== true)
307
- return;
308
- const notify = this.onUpdate(key, parent);
301
+ let notify;
302
+ if (typeof handler == "function") {
303
+ const callback = handler();
304
+ if (callback === true)
305
+ notify = this.onUpdate(key, parent);
306
+ }
307
+ else if (handler === true)
308
+ notify = this.onUpdate(key, parent);
309
309
  const getWhy = () => {
310
310
  const update = getUpdate(parent.subject);
311
311
  const applicable = update.filter(k => using.has(k));
@@ -326,7 +326,7 @@ class Subscriber {
326
326
  release();
327
327
  };
328
328
  this.add = (key, value) => {
329
- if (value)
329
+ if (value !== undefined)
330
330
  using.set(key, value);
331
331
  else if (!using.has(key))
332
332
  using.set(key, true);
@@ -400,17 +400,15 @@ class Controller {
400
400
  else if (!frame.size)
401
401
  setTimeout(() => {
402
402
  flush(this);
403
- const callback = Array.from(waiting);
404
- const keys = Array.from(frame);
405
- frame.clear();
406
- waiting.clear();
407
- UPDATE.set(subject, keys);
403
+ UPDATE.set(subject, Array.from(frame));
408
404
  setTimeout(() => {
409
405
  UPDATE.delete(subject);
410
406
  }, 0);
411
- for (const cb of callback)
407
+ frame.clear();
408
+ for (const notify of waiting)
412
409
  try {
413
- cb();
410
+ waiting.delete(notify);
411
+ notify();
414
412
  }
415
413
  catch (err) {
416
414
  console.error(err);
@@ -661,6 +659,14 @@ function apply(fn, label) {
661
659
  const desc = output;
662
660
  if ("value" in desc)
663
661
  state.set(key, desc.value);
662
+ if ("destroy" in output) {
663
+ const { destroy } = output;
664
+ if (destroy)
665
+ this.addListener((key) => {
666
+ if (key == null)
667
+ destroy();
668
+ });
669
+ }
664
670
  const { get: onGet, set: onSet, enumerable, suspense } = desc;
665
671
  const set = onSet !== false
666
672
  ? this.ref(key, onSet)
@@ -940,192 +946,217 @@ function parent(Expects, required) {
940
946
 
941
947
  const ANY$1 = Symbol("any");
942
948
  function managedMap(control, property, initial) {
943
- const lastUpdate = new Set();
949
+ const managed = new ManagedMap(initial, emit);
944
950
  const context = new WeakMap();
945
- const assoc = new WeakMap();
946
- let managed;
947
- let value;
951
+ const observers = new Set();
952
+ const frozen = new Set();
948
953
  function reset() {
949
- lastUpdate.clear();
954
+ frozen.clear();
950
955
  }
951
956
  function emit(key) {
952
- lastUpdate.add(key);
957
+ observers.forEach(notify => notify(key));
953
958
  control.update(property);
954
959
  control.waiting.add(reset);
955
960
  }
956
- function setValue(next, initial) {
957
- value = next;
958
- managed = create(next);
959
- control.state.set(property, next);
960
- if (!initial)
961
- emit(ANY$1);
962
- const watch = (key, on) => {
963
- const local = assoc.get(on);
964
- if (local)
965
- local(key);
966
- };
967
- managed.set = (k, v) => {
968
- emit(k);
969
- return value.set(k, v);
970
- };
971
- managed.delete = (k) => {
972
- emit(k);
973
- return value.delete(k);
974
- };
975
- managed.clear = () => {
976
- emit(ANY$1);
977
- value.clear();
978
- };
979
- managed.get = function (key) {
980
- watch(key, this);
981
- return value.get(key);
982
- };
983
- managed.has = function (key) {
984
- watch(key, this);
985
- return value.has(key);
986
- };
987
- managed.values = function () {
988
- watch(ANY$1, this);
989
- return value.values();
990
- };
991
- managed.keys = function () {
992
- watch(ANY$1, this);
993
- return value.keys();
994
- };
995
- managed.entries = function () {
996
- watch(ANY$1, this);
997
- return value.entries();
998
- };
999
- managed[Symbol.iterator] = function () {
1000
- watch(ANY$1, this);
1001
- return value[Symbol.iterator]();
1002
- };
1003
- defineProperty(managed, "size", {
1004
- get() {
1005
- watch(ANY$1, this);
1006
- return value.size;
961
+ function init(local) {
962
+ const proxy = create(managed);
963
+ const using = new Set();
964
+ observers.add(key => {
965
+ if (frozen.has(local))
966
+ return;
967
+ if (using.has(key) || using.has(ANY$1) || key === ANY$1 && using.size) {
968
+ const refresh = local.onUpdate(property, control);
969
+ if (refresh) {
970
+ frozen.add(local);
971
+ refresh();
972
+ }
1007
973
  }
1008
974
  });
1009
- }
1010
- function getValue(local) {
1011
- if (!local)
1012
- return managed;
1013
- if (context.has(local))
1014
- return context.get(local);
1015
- const proxy = Object.create(managed);
1016
- const using = new Set();
975
+ local.add(property, false);
1017
976
  context.set(local, proxy);
1018
- assoc.set(proxy, (key) => {
977
+ proxy.watch = (key) => {
1019
978
  if (!local.active)
1020
979
  using.add(key);
1021
- });
1022
- local.add(property, () => {
1023
- if (using.has(ANY$1) || lastUpdate.has(ANY$1) && using.size)
1024
- return true;
1025
- for (const key of lastUpdate)
1026
- if (using.has(key))
1027
- return true;
1028
- });
980
+ };
1029
981
  return proxy;
1030
982
  }
1031
- setValue(initial, true);
1032
983
  return {
1033
- set: setValue,
1034
- get: getValue
984
+ value: initial,
985
+ get(local) {
986
+ if (!local)
987
+ return managed;
988
+ if (context.has(local))
989
+ return context.get(local);
990
+ return init(local);
991
+ },
992
+ set(next) {
993
+ managed.source = next;
994
+ control.state.set(property, next);
995
+ emit(ANY$1);
996
+ },
997
+ destroy() {
998
+ observers.clear();
999
+ }
1035
1000
  };
1001
+ }
1002
+ class ManagedMap {
1003
+ constructor(source, emit) {
1004
+ this.source = source;
1005
+ this.emit = emit;
1006
+ }
1007
+ watch(_key) { }
1008
+ set(key, value) {
1009
+ this.source.set(key, value);
1010
+ this.emit(key);
1011
+ return this;
1012
+ }
1013
+ ;
1014
+ delete(key) {
1015
+ this.emit(key);
1016
+ return this.source.delete(key);
1017
+ }
1018
+ ;
1019
+ clear() {
1020
+ this.emit(ANY$1);
1021
+ this.source.clear();
1022
+ }
1023
+ get(key) {
1024
+ this.watch(key);
1025
+ return this.source.get(key);
1026
+ }
1027
+ ;
1028
+ has(key) {
1029
+ this.watch(key);
1030
+ return this.source.has(key);
1031
+ }
1032
+ ;
1033
+ values() {
1034
+ this.watch(ANY$1);
1035
+ return this.source.values();
1036
+ }
1037
+ keys() {
1038
+ this.watch(ANY$1);
1039
+ return this.source.keys();
1040
+ }
1041
+ entries() {
1042
+ this.watch(ANY$1);
1043
+ return this.source.entries();
1044
+ }
1045
+ ;
1046
+ [Symbol.iterator]() {
1047
+ this.watch(ANY$1);
1048
+ return this.source[Symbol.iterator]();
1049
+ }
1050
+ ;
1051
+ get size() {
1052
+ this.watch(ANY$1);
1053
+ return this.source.size;
1054
+ }
1036
1055
  }
1037
1056
 
1038
1057
  const ANY = Symbol("any");
1039
1058
  function managedSet(control, property, initial) {
1040
- const lastUpdate = new Set();
1059
+ const managed = new ManagedSet(initial, emit);
1041
1060
  const context = new WeakMap();
1042
- const assoc = new WeakMap();
1043
- let managed;
1044
- let value;
1061
+ const observers = new Set();
1062
+ const frozen = new Set();
1045
1063
  function reset() {
1046
- lastUpdate.clear();
1064
+ frozen.clear();
1047
1065
  }
1048
1066
  function emit(key) {
1049
- lastUpdate.add(key);
1067
+ observers.forEach(notify => notify(key));
1050
1068
  control.update(property);
1051
1069
  control.waiting.add(reset);
1052
1070
  }
1053
- function setValue(next, initial) {
1054
- value = next;
1055
- managed = create(next);
1056
- control.state.set(property, next);
1057
- if (!initial)
1058
- emit(ANY);
1059
- const watch = (key, on) => {
1060
- const local = assoc.get(on);
1061
- if (local)
1062
- local(key);
1063
- };
1064
- managed.add = (k) => {
1065
- emit(k);
1066
- return value.add(k);
1067
- };
1068
- managed.delete = (k) => {
1069
- emit(k);
1070
- return value.delete(k);
1071
- };
1072
- managed.clear = () => {
1073
- emit(ANY);
1074
- value.clear();
1075
- };
1076
- managed.has = function (key) {
1077
- watch(key, this);
1078
- return value.has(key);
1079
- };
1080
- managed.values = function () {
1081
- watch(ANY, this);
1082
- return value.values();
1083
- };
1084
- managed.keys = function () {
1085
- watch(ANY, this);
1086
- return value.keys();
1087
- };
1088
- managed.entries = function () {
1089
- watch(ANY, this);
1090
- return value.entries();
1091
- };
1092
- managed[Symbol.iterator] = function () {
1093
- watch(ANY, this);
1094
- return value[Symbol.iterator]();
1095
- };
1096
- defineProperty(managed, "size", {
1097
- get() {
1098
- watch(ANY, this);
1099
- return value.size;
1071
+ function init(local) {
1072
+ const proxy = create(managed);
1073
+ const using = new Set();
1074
+ observers.add(key => {
1075
+ if (frozen.has(local))
1076
+ return;
1077
+ if (using.has(key) || using.has(ANY) || key === ANY && using.size) {
1078
+ const refresh = local.onUpdate(property, control);
1079
+ if (refresh) {
1080
+ frozen.add(local);
1081
+ refresh();
1082
+ }
1100
1083
  }
1101
1084
  });
1102
- }
1103
- function getValue(local) {
1104
- if (!local)
1105
- return managed;
1106
- if (context.has(local))
1107
- return context.get(local);
1108
- const proxy = Object.create(managed);
1109
- const using = new Set();
1085
+ local.add(property, false);
1110
1086
  context.set(local, proxy);
1111
- assoc.set(proxy, (key) => {
1087
+ proxy.watch = (key) => {
1112
1088
  if (!local.active)
1113
1089
  using.add(key);
1114
- });
1115
- local.add(property, () => {
1116
- if (using.has(ANY) || lastUpdate.has(ANY) && using.size)
1117
- return true;
1118
- for (const key of lastUpdate)
1119
- if (using.has(key))
1120
- return true;
1121
- });
1090
+ };
1122
1091
  return proxy;
1123
1092
  }
1124
- setValue(initial, true);
1125
1093
  return {
1126
- set: setValue,
1127
- get: getValue
1094
+ value: initial,
1095
+ get(local) {
1096
+ if (!local)
1097
+ return managed;
1098
+ if (context.has(local))
1099
+ return context.get(local);
1100
+ return init(local);
1101
+ },
1102
+ set(next) {
1103
+ managed.source = next;
1104
+ control.state.set(property, next);
1105
+ emit(ANY);
1106
+ },
1107
+ destroy() {
1108
+ observers.clear();
1109
+ }
1128
1110
  };
1111
+ }
1112
+ class ManagedSet {
1113
+ constructor(source, emit) {
1114
+ this.source = source;
1115
+ this.emit = emit;
1116
+ }
1117
+ watch(_key) { }
1118
+ add(key) {
1119
+ this.source.add(key);
1120
+ this.emit(key);
1121
+ return this;
1122
+ }
1123
+ ;
1124
+ delete(key) {
1125
+ this.emit(key);
1126
+ return this.source.delete(key);
1127
+ }
1128
+ ;
1129
+ clear() {
1130
+ this.emit(ANY);
1131
+ this.source.clear();
1132
+ }
1133
+ has(key) {
1134
+ this.watch(key);
1135
+ return this.source.has(key);
1136
+ }
1137
+ ;
1138
+ values() {
1139
+ this.watch(ANY);
1140
+ return this.source.values();
1141
+ }
1142
+ keys() {
1143
+ this.watch(ANY);
1144
+ return this.source.keys();
1145
+ }
1146
+ entries() {
1147
+ this.watch(ANY);
1148
+ return this.source.entries();
1149
+ }
1150
+ ;
1151
+ [Symbol.iterator]() {
1152
+ this.watch(ANY);
1153
+ return this.source[Symbol.iterator]();
1154
+ }
1155
+ ;
1156
+ get size() {
1157
+ this.watch(ANY);
1158
+ return this.source.size;
1159
+ }
1129
1160
  }
1130
1161
 
1131
1162
  const Oops$5 = issues({