@expressive/mvc 0.4.3 → 0.4.6

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();
177
- function from(source, arg1, arg2) {
176
+ const ORDER = new WeakMap();
177
+ function get(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,18 +295,16 @@ 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
301
  let notify;
306
302
  if (typeof handler == "function") {
307
303
  const callback = handler();
308
- if (typeof callback == "function")
309
- notify = callback;
310
- else if (callback === true)
304
+ if (callback === true)
311
305
  notify = this.onUpdate(key, parent);
312
306
  }
313
- else
307
+ else if (handler === true)
314
308
  notify = this.onUpdate(key, parent);
315
309
  const getWhy = () => {
316
310
  const update = getUpdate(parent.subject);
@@ -332,7 +326,7 @@ class Subscriber {
332
326
  release();
333
327
  };
334
328
  this.add = (key, value) => {
335
- if (value)
329
+ if (value !== undefined)
336
330
  using.set(key, value);
337
331
  else if (!using.has(key))
338
332
  using.set(key, true);
@@ -406,17 +400,15 @@ class Controller {
406
400
  else if (!frame.size)
407
401
  setTimeout(() => {
408
402
  flush(this);
409
- const callback = Array.from(waiting);
410
- const keys = Array.from(frame);
411
- frame.clear();
412
- waiting.clear();
413
- UPDATE.set(subject, keys);
403
+ UPDATE.set(subject, Array.from(frame));
414
404
  setTimeout(() => {
415
405
  UPDATE.delete(subject);
416
406
  }, 0);
417
- for (const cb of callback)
407
+ frame.clear();
408
+ for (const notify of waiting)
418
409
  try {
419
- cb();
410
+ waiting.delete(notify);
411
+ notify();
420
412
  }
421
413
  catch (err) {
422
414
  console.error(err);
@@ -667,6 +659,14 @@ function apply(fn, label) {
667
659
  const desc = output;
668
660
  if ("value" in desc)
669
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
+ }
670
670
  const { get: onGet, set: onSet, enumerable, suspense } = desc;
671
671
  const set = onSet !== false
672
672
  ? this.ref(key, onSet)
@@ -944,172 +944,100 @@ function parent(Expects, required) {
944
944
  });
945
945
  }
946
946
 
947
- const ANY$1 = Symbol("any");
948
- function managedMap(control, property, initial) {
949
- const managed = new ManagedMap(initial, emit);
947
+ const ANY = Symbol("any");
948
+ function keyed(control, property, initial) {
949
+ const managed = new Stateful(initial, emit);
950
950
  const context = new WeakMap();
951
- const lastUpdate = new Set();
951
+ const observers = new Set();
952
+ const frozen = new Set();
952
953
  function reset() {
953
- lastUpdate.clear();
954
+ frozen.clear();
954
955
  }
955
956
  function emit(key) {
956
- lastUpdate.add(key);
957
- control.update(property);
958
957
  control.waiting.add(reset);
958
+ control.update(property);
959
+ observers.forEach(notify => notify(key));
959
960
  }
960
- function setValue(next) {
961
- control.state.set(property, next);
962
- managed.source = next;
963
- emit(ANY$1);
964
- }
965
- function getValue(local) {
966
- if (!local)
967
- return managed;
968
- if (context.has(local))
969
- return context.get(local);
970
- const refresh = local.onUpdate(property, control);
961
+ function init(local) {
971
962
  const proxy = create(managed);
972
963
  const using = new Set();
973
- const update = () => {
974
- if (using.has(ANY$1) || lastUpdate.has(ANY$1) && using.size)
975
- refresh();
976
- else
977
- for (const key of lastUpdate)
978
- if (using.has(key)) {
979
- refresh();
980
- break;
981
- }
982
- };
983
- local.add(property, () => update);
964
+ function onEvent(key) {
965
+ if (frozen.has(local))
966
+ return;
967
+ if (key === ANY || using.has(key) || using.has(ANY)) {
968
+ const refresh = local.onUpdate(property, control);
969
+ if (refresh) {
970
+ frozen.add(local);
971
+ refresh();
972
+ }
973
+ }
974
+ }
984
975
  context.set(local, proxy);
985
976
  proxy.watch = (key) => {
986
977
  if (!local.active)
987
978
  using.add(key);
988
979
  };
980
+ local.add(property, false);
981
+ local.dependant.add({
982
+ commit() {
983
+ if (using.size === 0)
984
+ using.add(ANY);
985
+ observers.add(onEvent);
986
+ },
987
+ release() {
988
+ observers.delete(onEvent);
989
+ }
990
+ });
989
991
  return proxy;
990
992
  }
991
993
  return {
992
994
  value: initial,
993
- set: setValue,
994
- get: getValue
995
+ get(local) {
996
+ return local ?
997
+ context.get(local) || init(local) :
998
+ managed;
999
+ },
1000
+ set(next) {
1001
+ managed.source = next;
1002
+ control.state.set(property, next);
1003
+ emit(ANY);
1004
+ },
1005
+ destroy() {
1006
+ observers.clear();
1007
+ }
995
1008
  };
996
1009
  }
997
- class ManagedMap {
1010
+ class Stateful {
998
1011
  constructor(source, emit) {
999
1012
  this.source = source;
1000
1013
  this.emit = emit;
1014
+ if (source instanceof Set)
1015
+ assign(this, {
1016
+ add(key) {
1017
+ source.add(key);
1018
+ emit(key);
1019
+ return this;
1020
+ }
1021
+ });
1022
+ else
1023
+ assign(this, {
1024
+ get(key) {
1025
+ this.watch(key);
1026
+ return source.get(key);
1027
+ },
1028
+ set(key, value) {
1029
+ source.set(key, value);
1030
+ emit(key);
1031
+ return this;
1032
+ }
1033
+ });
1001
1034
  }
1002
1035
  watch(_key) { }
1003
- set(key, value) {
1004
- this.source.set(key, value);
1005
- this.emit(key);
1006
- return this;
1007
- }
1008
- ;
1009
- delete(key) {
1010
- this.emit(key);
1011
- return this.source.delete(key);
1012
- }
1013
- ;
1014
- clear() {
1015
- this.emit(ANY$1);
1016
- this.source.clear();
1017
- }
1018
- get(key) {
1019
- this.watch(key);
1020
- return this.source.get(key);
1021
- }
1022
- ;
1023
1036
  has(key) {
1024
1037
  this.watch(key);
1025
1038
  return this.source.has(key);
1026
1039
  }
1027
1040
  ;
1028
- values() {
1029
- this.watch(ANY$1);
1030
- return this.source.values();
1031
- }
1032
- keys() {
1033
- this.watch(ANY$1);
1034
- return this.source.keys();
1035
- }
1036
- entries() {
1037
- this.watch(ANY$1);
1038
- return this.source.entries();
1039
- }
1040
- ;
1041
- [Symbol.iterator]() {
1042
- this.watch(ANY$1);
1043
- return this.source[Symbol.iterator]();
1044
- }
1045
- ;
1046
- get size() {
1047
- this.watch(ANY$1);
1048
- return this.source.size;
1049
- }
1050
- }
1051
-
1052
- const ANY = Symbol("any");
1053
- function managedSet(control, property, initial) {
1054
- const managed = new ManagedSet(initial, emit);
1055
- const context = new WeakMap();
1056
- const lastUpdate = new Set();
1057
- function reset() {
1058
- lastUpdate.clear();
1059
- }
1060
- function emit(key) {
1061
- lastUpdate.add(key);
1062
- control.update(property);
1063
- control.waiting.add(reset);
1064
- }
1065
- function setValue(next) {
1066
- managed.source = next;
1067
- control.state.set(property, next);
1068
- emit(ANY);
1069
- }
1070
- function getValue(local) {
1071
- if (!local)
1072
- return managed;
1073
- if (context.has(local))
1074
- return context.get(local);
1075
- const refresh = local.onUpdate(property, control);
1076
- const proxy = create(managed);
1077
- const using = new Set();
1078
- const update = () => {
1079
- if (using.has(ANY) || lastUpdate.has(ANY) && using.size)
1080
- refresh();
1081
- else
1082
- for (const key of lastUpdate)
1083
- if (using.has(key)) {
1084
- refresh();
1085
- break;
1086
- }
1087
- };
1088
- local.add(property, () => update);
1089
- context.set(local, proxy);
1090
- proxy.watch = (key) => {
1091
- if (!local.active)
1092
- using.add(key);
1093
- };
1094
- return proxy;
1095
- }
1096
- return {
1097
- value: initial,
1098
- set: setValue,
1099
- get: getValue
1100
- };
1101
- }
1102
- class ManagedSet {
1103
- constructor(source, emit) {
1104
- this.source = source;
1105
- this.emit = emit;
1106
- }
1107
- watch(_key) { }
1108
- add(key) {
1109
- this.emit(key);
1110
- return this.source.add(key);
1111
- }
1112
- ;
1113
1041
  delete(key) {
1114
1042
  this.emit(key);
1115
1043
  return this.source.delete(key);
@@ -1119,33 +1047,28 @@ class ManagedSet {
1119
1047
  this.emit(ANY);
1120
1048
  this.source.clear();
1121
1049
  }
1122
- has(key) {
1123
- this.watch(key);
1124
- return this.source.has(key);
1050
+ keys() {
1051
+ this.watch(ANY);
1052
+ return this.source.keys();
1125
1053
  }
1126
- ;
1127
1054
  values() {
1128
1055
  this.watch(ANY);
1129
1056
  return this.source.values();
1130
1057
  }
1131
- keys() {
1132
- this.watch(ANY);
1133
- return this.source.keys();
1134
- }
1135
1058
  entries() {
1136
1059
  this.watch(ANY);
1137
1060
  return this.source.entries();
1138
1061
  }
1139
1062
  ;
1063
+ get size() {
1064
+ this.watch(ANY);
1065
+ return this.source.size;
1066
+ }
1140
1067
  [Symbol.iterator]() {
1141
1068
  this.watch(ANY);
1142
1069
  return this.source[Symbol.iterator]();
1143
1070
  }
1144
1071
  ;
1145
- get size() {
1146
- this.watch(ANY);
1147
- return this.source.size;
1148
- }
1149
1072
  }
1150
1073
 
1151
1074
  const Oops$5 = issues({
@@ -1160,10 +1083,8 @@ function use$1(input, argument) {
1160
1083
  : input();
1161
1084
  else if (input && typeof input !== "object")
1162
1085
  throw Oops$5.BadArgument(typeof input);
1163
- if (input instanceof Map)
1164
- return managedMap(this, key, input);
1165
- if (input instanceof Set)
1166
- return managedSet(this, key, input);
1086
+ if (input instanceof Map || input instanceof Set)
1087
+ return keyed(this, key, input);
1167
1088
  function onUpdate(next) {
1168
1089
  state.set(key, next);
1169
1090
  if (next) {
@@ -1618,7 +1539,8 @@ exports.act = act;
1618
1539
  exports.apply = apply;
1619
1540
  exports.array = array;
1620
1541
  exports["default"] = MVC;
1621
- exports.from = from;
1542
+ exports.from = get;
1543
+ exports.get = get;
1622
1544
  exports.parent = parent;
1623
1545
  exports.put = put;
1624
1546
  exports.ref = ref;