@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.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,13 +287,17 @@ 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
- if (typeof handler == "function")
298
- if (handler() !== true)
299
- return;
300
- const notify = this.onUpdate(key, parent);
293
+ let notify;
294
+ if (typeof handler == "function") {
295
+ const callback = handler();
296
+ if (callback === true)
297
+ notify = this.onUpdate(key, parent);
298
+ }
299
+ else if (handler === true)
300
+ notify = this.onUpdate(key, parent);
301
301
  const getWhy = () => {
302
302
  const update = getUpdate(parent.subject);
303
303
  const applicable = update.filter(k => using.has(k));
@@ -318,7 +318,7 @@ class Subscriber {
318
318
  release();
319
319
  };
320
320
  this.add = (key, value) => {
321
- if (value)
321
+ if (value !== undefined)
322
322
  using.set(key, value);
323
323
  else if (!using.has(key))
324
324
  using.set(key, true);
@@ -392,17 +392,15 @@ class Controller {
392
392
  else if (!frame.size)
393
393
  setTimeout(() => {
394
394
  flush(this);
395
- const callback = Array.from(waiting);
396
- const keys = Array.from(frame);
397
- frame.clear();
398
- waiting.clear();
399
- UPDATE.set(subject, keys);
395
+ UPDATE.set(subject, Array.from(frame));
400
396
  setTimeout(() => {
401
397
  UPDATE.delete(subject);
402
398
  }, 0);
403
- for (const cb of callback)
399
+ frame.clear();
400
+ for (const notify of waiting)
404
401
  try {
405
- cb();
402
+ waiting.delete(notify);
403
+ notify();
406
404
  }
407
405
  catch (err) {
408
406
  console.error(err);
@@ -653,6 +651,14 @@ function apply(fn, label) {
653
651
  const desc = output;
654
652
  if ("value" in desc)
655
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
+ }
656
662
  const { get: onGet, set: onSet, enumerable, suspense } = desc;
657
663
  const set = onSet !== false
658
664
  ? this.ref(key, onSet)
@@ -932,192 +938,217 @@ function parent(Expects, required) {
932
938
 
933
939
  const ANY$1 = Symbol("any");
934
940
  function managedMap(control, property, initial) {
935
- const lastUpdate = new Set();
941
+ const managed = new ManagedMap(initial, emit);
936
942
  const context = new WeakMap();
937
- const assoc = new WeakMap();
938
- let managed;
939
- let value;
943
+ const observers = new Set();
944
+ const frozen = new Set();
940
945
  function reset() {
941
- lastUpdate.clear();
946
+ frozen.clear();
942
947
  }
943
948
  function emit(key) {
944
- lastUpdate.add(key);
949
+ observers.forEach(notify => notify(key));
945
950
  control.update(property);
946
951
  control.waiting.add(reset);
947
952
  }
948
- function setValue(next, initial) {
949
- value = next;
950
- managed = create(next);
951
- control.state.set(property, next);
952
- if (!initial)
953
- emit(ANY$1);
954
- const watch = (key, on) => {
955
- const local = assoc.get(on);
956
- if (local)
957
- local(key);
958
- };
959
- managed.set = (k, v) => {
960
- emit(k);
961
- return value.set(k, v);
962
- };
963
- managed.delete = (k) => {
964
- emit(k);
965
- return value.delete(k);
966
- };
967
- managed.clear = () => {
968
- emit(ANY$1);
969
- value.clear();
970
- };
971
- managed.get = function (key) {
972
- watch(key, this);
973
- return value.get(key);
974
- };
975
- managed.has = function (key) {
976
- watch(key, this);
977
- return value.has(key);
978
- };
979
- managed.values = function () {
980
- watch(ANY$1, this);
981
- return value.values();
982
- };
983
- managed.keys = function () {
984
- watch(ANY$1, this);
985
- return value.keys();
986
- };
987
- managed.entries = function () {
988
- watch(ANY$1, this);
989
- return value.entries();
990
- };
991
- managed[Symbol.iterator] = function () {
992
- watch(ANY$1, this);
993
- return value[Symbol.iterator]();
994
- };
995
- defineProperty(managed, "size", {
996
- get() {
997
- watch(ANY$1, this);
998
- return value.size;
953
+ function init(local) {
954
+ const proxy = create(managed);
955
+ const using = new Set();
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
+ }
999
965
  }
1000
966
  });
1001
- }
1002
- function getValue(local) {
1003
- if (!local)
1004
- return managed;
1005
- if (context.has(local))
1006
- return context.get(local);
1007
- const proxy = Object.create(managed);
1008
- const using = new Set();
967
+ local.add(property, false);
1009
968
  context.set(local, proxy);
1010
- assoc.set(proxy, (key) => {
969
+ proxy.watch = (key) => {
1011
970
  if (!local.active)
1012
971
  using.add(key);
1013
- });
1014
- local.add(property, () => {
1015
- if (using.has(ANY$1) || lastUpdate.has(ANY$1) && using.size)
1016
- return true;
1017
- for (const key of lastUpdate)
1018
- if (using.has(key))
1019
- return true;
1020
- });
972
+ };
1021
973
  return proxy;
1022
974
  }
1023
- setValue(initial, true);
1024
975
  return {
1025
- set: setValue,
1026
- get: getValue
976
+ value: initial,
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
+ }
1027
992
  };
993
+ }
994
+ class ManagedMap {
995
+ constructor(source, emit) {
996
+ this.source = source;
997
+ this.emit = emit;
998
+ }
999
+ watch(_key) { }
1000
+ set(key, value) {
1001
+ this.source.set(key, value);
1002
+ this.emit(key);
1003
+ return this;
1004
+ }
1005
+ ;
1006
+ delete(key) {
1007
+ this.emit(key);
1008
+ return this.source.delete(key);
1009
+ }
1010
+ ;
1011
+ clear() {
1012
+ this.emit(ANY$1);
1013
+ this.source.clear();
1014
+ }
1015
+ get(key) {
1016
+ this.watch(key);
1017
+ return this.source.get(key);
1018
+ }
1019
+ ;
1020
+ has(key) {
1021
+ this.watch(key);
1022
+ return this.source.has(key);
1023
+ }
1024
+ ;
1025
+ values() {
1026
+ this.watch(ANY$1);
1027
+ return this.source.values();
1028
+ }
1029
+ keys() {
1030
+ this.watch(ANY$1);
1031
+ return this.source.keys();
1032
+ }
1033
+ entries() {
1034
+ this.watch(ANY$1);
1035
+ return this.source.entries();
1036
+ }
1037
+ ;
1038
+ [Symbol.iterator]() {
1039
+ this.watch(ANY$1);
1040
+ return this.source[Symbol.iterator]();
1041
+ }
1042
+ ;
1043
+ get size() {
1044
+ this.watch(ANY$1);
1045
+ return this.source.size;
1046
+ }
1028
1047
  }
1029
1048
 
1030
1049
  const ANY = Symbol("any");
1031
1050
  function managedSet(control, property, initial) {
1032
- const lastUpdate = new Set();
1051
+ const managed = new ManagedSet(initial, emit);
1033
1052
  const context = new WeakMap();
1034
- const assoc = new WeakMap();
1035
- let managed;
1036
- let value;
1053
+ const observers = new Set();
1054
+ const frozen = new Set();
1037
1055
  function reset() {
1038
- lastUpdate.clear();
1056
+ frozen.clear();
1039
1057
  }
1040
1058
  function emit(key) {
1041
- lastUpdate.add(key);
1059
+ observers.forEach(notify => notify(key));
1042
1060
  control.update(property);
1043
1061
  control.waiting.add(reset);
1044
1062
  }
1045
- function setValue(next, initial) {
1046
- value = next;
1047
- managed = create(next);
1048
- control.state.set(property, next);
1049
- if (!initial)
1050
- emit(ANY);
1051
- const watch = (key, on) => {
1052
- const local = assoc.get(on);
1053
- if (local)
1054
- local(key);
1055
- };
1056
- managed.add = (k) => {
1057
- emit(k);
1058
- return value.add(k);
1059
- };
1060
- managed.delete = (k) => {
1061
- emit(k);
1062
- return value.delete(k);
1063
- };
1064
- managed.clear = () => {
1065
- emit(ANY);
1066
- value.clear();
1067
- };
1068
- managed.has = function (key) {
1069
- watch(key, this);
1070
- return value.has(key);
1071
- };
1072
- managed.values = function () {
1073
- watch(ANY, this);
1074
- return value.values();
1075
- };
1076
- managed.keys = function () {
1077
- watch(ANY, this);
1078
- return value.keys();
1079
- };
1080
- managed.entries = function () {
1081
- watch(ANY, this);
1082
- return value.entries();
1083
- };
1084
- managed[Symbol.iterator] = function () {
1085
- watch(ANY, this);
1086
- return value[Symbol.iterator]();
1087
- };
1088
- defineProperty(managed, "size", {
1089
- get() {
1090
- watch(ANY, this);
1091
- return value.size;
1063
+ function init(local) {
1064
+ const proxy = create(managed);
1065
+ const using = new Set();
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
+ }
1092
1075
  }
1093
1076
  });
1094
- }
1095
- function getValue(local) {
1096
- if (!local)
1097
- return managed;
1098
- if (context.has(local))
1099
- return context.get(local);
1100
- const proxy = Object.create(managed);
1101
- const using = new Set();
1077
+ local.add(property, false);
1102
1078
  context.set(local, proxy);
1103
- assoc.set(proxy, (key) => {
1079
+ proxy.watch = (key) => {
1104
1080
  if (!local.active)
1105
1081
  using.add(key);
1106
- });
1107
- local.add(property, () => {
1108
- if (using.has(ANY) || lastUpdate.has(ANY) && using.size)
1109
- return true;
1110
- for (const key of lastUpdate)
1111
- if (using.has(key))
1112
- return true;
1113
- });
1082
+ };
1114
1083
  return proxy;
1115
1084
  }
1116
- setValue(initial, true);
1117
1085
  return {
1118
- set: setValue,
1119
- get: getValue
1086
+ value: initial,
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
+ }
1120
1102
  };
1103
+ }
1104
+ class ManagedSet {
1105
+ constructor(source, emit) {
1106
+ this.source = source;
1107
+ this.emit = emit;
1108
+ }
1109
+ watch(_key) { }
1110
+ add(key) {
1111
+ this.source.add(key);
1112
+ this.emit(key);
1113
+ return this;
1114
+ }
1115
+ ;
1116
+ delete(key) {
1117
+ this.emit(key);
1118
+ return this.source.delete(key);
1119
+ }
1120
+ ;
1121
+ clear() {
1122
+ this.emit(ANY);
1123
+ this.source.clear();
1124
+ }
1125
+ has(key) {
1126
+ this.watch(key);
1127
+ return this.source.has(key);
1128
+ }
1129
+ ;
1130
+ values() {
1131
+ this.watch(ANY);
1132
+ return this.source.values();
1133
+ }
1134
+ keys() {
1135
+ this.watch(ANY);
1136
+ return this.source.keys();
1137
+ }
1138
+ entries() {
1139
+ this.watch(ANY);
1140
+ return this.source.entries();
1141
+ }
1142
+ ;
1143
+ [Symbol.iterator]() {
1144
+ this.watch(ANY);
1145
+ return this.source[Symbol.iterator]();
1146
+ }
1147
+ ;
1148
+ get size() {
1149
+ this.watch(ANY);
1150
+ return this.source.size;
1151
+ }
1121
1152
  }
1122
1153
 
1123
1154
  const Oops$5 = issues({