@expressive/mvc 0.4.2 → 0.4.5

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;
@@ -356,6 +357,10 @@ declare function set<T, S>(value: undefined, onUpdate: set.Callback<T, S>): T;
356
357
  declare function set<T>(value: T, onUpdate: set.Callback<T>): T;
357
358
  declare function set<T, S>(value: T, onUpdate: set.Callback<T, S>): T;
358
359
 
360
+ declare function use(initial: Set<unknown>): Set<any>;
361
+ declare function use(initial: Map<unknown, unknown>): Map<any, any>;
362
+ declare function use(from: () => Set<unknown>): Set<any>;
363
+ declare function use(from: () => Map<unknown, unknown>): Map<any, any>;
359
364
  /**
360
365
  * Create a placeholder for specified Model type.
361
366
  */
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)
@@ -938,202 +938,217 @@ function parent(Expects, required) {
938
938
 
939
939
  const ANY$1 = Symbol("any");
940
940
  function managedMap(control, property, initial) {
941
- const lastUpdate = new Set();
941
+ const managed = new ManagedMap(initial, emit);
942
942
  const context = new WeakMap();
943
- const assoc = new WeakMap();
944
- let managed;
945
- let value;
943
+ const observers = new Set();
944
+ const frozen = new Set();
946
945
  function reset() {
947
- lastUpdate.clear();
946
+ frozen.clear();
948
947
  }
949
948
  function emit(key) {
950
- lastUpdate.add(key);
949
+ observers.forEach(notify => notify(key));
951
950
  control.update(property);
952
951
  control.waiting.add(reset);
953
952
  }
954
- function setValue(next, initial) {
955
- value = next;
956
- managed = create(next);
957
- control.state.set(property, next);
958
- if (!initial)
959
- emit(ANY$1);
960
- const watch = (key, on) => {
961
- const local = assoc.get(on);
962
- if (local)
963
- local(key);
964
- };
965
- managed.set = (k, v) => {
966
- emit(k);
967
- return value.set(k, v);
968
- };
969
- managed.delete = (k) => {
970
- emit(k);
971
- return value.delete(k);
972
- };
973
- managed.clear = () => {
974
- emit(ANY$1);
975
- value.clear();
976
- };
977
- managed.get = function (key) {
978
- watch(key, this);
979
- return value.get(key);
980
- };
981
- managed.has = function (key) {
982
- watch(key, this);
983
- return value.has(key);
984
- };
985
- managed.values = function () {
986
- watch(ANY$1, this);
987
- return value.values();
988
- };
989
- managed.keys = function () {
990
- watch(ANY$1, this);
991
- return value.keys();
992
- };
993
- managed.entries = function () {
994
- watch(ANY$1, this);
995
- return value.entries();
996
- };
997
- managed[Symbol.iterator] = function () {
998
- watch(ANY$1, this);
999
- return value[Symbol.iterator]();
1000
- };
1001
- defineProperty(managed, "size", {
1002
- get() {
1003
- watch(ANY$1, this);
1004
- 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
+ }
1005
965
  }
1006
966
  });
1007
- }
1008
- function getValue(local) {
1009
- if (!local)
1010
- return managed;
1011
- if (context.has(local))
1012
- return context.get(local);
1013
- const refresh = local.onUpdate(property, control);
1014
- const proxy = Object.create(managed);
1015
- const using = new Set();
1016
- const update = () => {
1017
- if (using.has(ANY$1) || lastUpdate.has(ANY$1) && using.size)
1018
- refresh();
1019
- else
1020
- for (const key of lastUpdate)
1021
- if (using.has(key)) {
1022
- refresh();
1023
- break;
1024
- }
1025
- };
967
+ local.add(property, false);
1026
968
  context.set(local, proxy);
1027
- assoc.set(proxy, (key) => {
969
+ proxy.watch = (key) => {
1028
970
  if (!local.active)
1029
971
  using.add(key);
1030
- });
1031
- local.add(property, () => update);
972
+ };
1032
973
  return proxy;
1033
974
  }
1034
- setValue(initial, true);
1035
975
  return {
1036
- set: setValue,
1037
- 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
+ }
1038
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
+ }
1039
1047
  }
1040
1048
 
1041
1049
  const ANY = Symbol("any");
1042
1050
  function managedSet(control, property, initial) {
1043
- const lastUpdate = new Set();
1051
+ const managed = new ManagedSet(initial, emit);
1044
1052
  const context = new WeakMap();
1045
- const assoc = new WeakMap();
1046
- let managed;
1047
- let value;
1053
+ const observers = new Set();
1054
+ const frozen = new Set();
1048
1055
  function reset() {
1049
- lastUpdate.clear();
1056
+ frozen.clear();
1050
1057
  }
1051
1058
  function emit(key) {
1052
- lastUpdate.add(key);
1059
+ observers.forEach(notify => notify(key));
1053
1060
  control.update(property);
1054
1061
  control.waiting.add(reset);
1055
1062
  }
1056
- function setValue(next, initial) {
1057
- value = next;
1058
- managed = create(next);
1059
- control.state.set(property, next);
1060
- if (!initial)
1061
- emit(ANY);
1062
- const watch = (key, on) => {
1063
- const local = assoc.get(on);
1064
- if (local)
1065
- local(key);
1066
- };
1067
- managed.add = (k) => {
1068
- emit(k);
1069
- return value.add(k);
1070
- };
1071
- managed.delete = (k) => {
1072
- emit(k);
1073
- return value.delete(k);
1074
- };
1075
- managed.clear = () => {
1076
- emit(ANY);
1077
- value.clear();
1078
- };
1079
- managed.has = function (key) {
1080
- watch(key, this);
1081
- return value.has(key);
1082
- };
1083
- managed.values = function () {
1084
- watch(ANY, this);
1085
- return value.values();
1086
- };
1087
- managed.keys = function () {
1088
- watch(ANY, this);
1089
- return value.keys();
1090
- };
1091
- managed.entries = function () {
1092
- watch(ANY, this);
1093
- return value.entries();
1094
- };
1095
- managed[Symbol.iterator] = function () {
1096
- watch(ANY, this);
1097
- return value[Symbol.iterator]();
1098
- };
1099
- defineProperty(managed, "size", {
1100
- get() {
1101
- watch(ANY, this);
1102
- 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
+ }
1103
1075
  }
1104
1076
  });
1105
- }
1106
- function getValue(local) {
1107
- if (!local)
1108
- return managed;
1109
- if (context.has(local))
1110
- return context.get(local);
1111
- const refresh = local.onUpdate(property, control);
1112
- const proxy = Object.create(managed);
1113
- const using = new Set();
1114
- const update = () => {
1115
- if (using.has(ANY) || lastUpdate.has(ANY) && using.size)
1116
- refresh();
1117
- else
1118
- for (const key of lastUpdate)
1119
- if (using.has(key)) {
1120
- refresh();
1121
- break;
1122
- }
1123
- };
1077
+ local.add(property, false);
1124
1078
  context.set(local, proxy);
1125
- assoc.set(proxy, (key) => {
1079
+ proxy.watch = (key) => {
1126
1080
  if (!local.active)
1127
1081
  using.add(key);
1128
- });
1129
- local.add(property, () => update);
1082
+ };
1130
1083
  return proxy;
1131
1084
  }
1132
- setValue(initial, true);
1133
1085
  return {
1134
- set: setValue,
1135
- 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
+ }
1136
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
+ }
1137
1152
  }
1138
1153
 
1139
1154
  const Oops$5 = issues({