@expressive/mvc 0.19.2 → 0.20.0

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
@@ -2,10 +2,29 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
6
- /** Random alphanumberic of length 6; will always start with a letter. */
7
- function random() {
8
- return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
5
+ /******************************************************************************
6
+ Copyright (c) Microsoft Corporation.
7
+
8
+ Permission to use, copy, modify, and/or distribute this software for any
9
+ purpose with or without fee is hereby granted.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ ***************************************************************************** */
19
+
20
+ function __awaiter(thisArg, _arguments, P, generator) {
21
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
22
+ return new (P || (P = Promise))(function (resolve, reject) {
23
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
24
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
25
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
26
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
27
+ });
9
28
  }
10
29
 
11
30
  class Issue extends Error {
@@ -25,89 +44,27 @@ function issues(register) {
25
44
  return Library;
26
45
  }
27
46
 
28
- const REGISTER$1 = new WeakMap();
29
- class Subscriber {
30
- constructor(parent, onUpdate) {
31
- this.onUpdate = onUpdate;
32
- this.active = false;
33
- this.dependant = new Set();
34
- this.watch = new Map();
35
- if (!(parent instanceof Control))
36
- parent = Control.for(parent);
37
- const reset = () => this.latest = undefined;
38
- const proxy = create(parent.subject);
39
- REGISTER$1.set(proxy, this);
40
- defineProperty(this, "proxy", {
41
- configurable: true,
42
- get() {
43
- setTimeout(reset, 0);
44
- return proxy;
45
- }
46
- });
47
- this.parent = parent;
48
- this.clear = parent.addListener(key => {
49
- if (this.active)
50
- this.notify(key);
51
- });
52
- }
53
- get using() {
54
- return Array.from(this.watch.keys());
55
- }
56
- get(key, using) {
57
- this.follow(key);
58
- return using
59
- ? using(this)
60
- : this.parent.state.get(key);
61
- }
62
- follow(key, value) {
63
- if (value !== undefined)
64
- this.watch.set(key, value);
65
- else if (!this.watch.has(key))
66
- this.watch.set(key, true);
67
- }
68
- commit() {
69
- this.active = true;
70
- this.dependant.forEach(x => x.commit());
71
- }
72
- release() {
73
- this.clear();
74
- this.dependant.forEach(x => x.release());
75
- }
76
- notify(key) {
77
- const { parent, watch } = this;
78
- const handler = watch.get(key);
79
- if (!handler)
80
- return;
81
- if (typeof handler == "function")
82
- handler();
83
- const notify = this.onUpdate(key, parent);
84
- if (notify) {
85
- parent.waiting.add(update => {
86
- this.latest = update.filter(k => watch.has(k));
87
- });
88
- parent.waiting.add(notify);
89
- }
90
- }
91
- }
92
- function subscriber(from) {
93
- return REGISTER$1.get(from);
94
- }
47
+ const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
95
48
 
96
- const Oops$8 = issues({
49
+ const Oops$9 = issues({
97
50
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
51
+ Destoryed: () => "Model is destroyed."
98
52
  });
99
- function suspend(source, key) {
100
- const error = Oops$8.NotReady(source.subject, key);
101
- const promise = new Promise(resolve => {
102
- const release = source.addListener(forKey => {
103
- if (forKey == key)
53
+ function suspense(source, key) {
54
+ const error = Oops$9.NotReady(source.subject, key);
55
+ const promise = new Promise((resolve, reject) => {
56
+ const subs = source.observers.get(key);
57
+ const onUpdate = (key) => {
58
+ if (key)
104
59
  return () => {
105
- if (source.state.get(key) !== undefined) {
106
- release();
60
+ if (source.state[key] !== undefined) {
61
+ subs.delete(onUpdate);
107
62
  resolve();
108
63
  }
109
64
  };
110
- });
65
+ reject(Oops$9.Destoryed());
66
+ };
67
+ subs.add(onUpdate);
111
68
  });
112
69
  return assign(promise, {
113
70
  toString: () => String(error),
@@ -137,11 +94,12 @@ function mayRetry(fn) {
137
94
  return compute();
138
95
  }
139
96
 
140
- const Oops$7 = issues({
97
+ const Oops$8 = issues({
141
98
  BadCallback: () => `Callback for effect-callback may only return a function.`
142
99
  });
143
- function createEffect(model, callback, keys) {
144
- return control(model, controller => {
100
+ function createEffect(source, callback) {
101
+ return control(source, self => {
102
+ let { subject } = self;
145
103
  let unSet;
146
104
  let busy = false;
147
105
  function invoke() {
@@ -150,33 +108,23 @@ function createEffect(model, callback, keys) {
150
108
  const output = mayRetry(() => {
151
109
  if (typeof unSet == "function")
152
110
  unSet();
153
- unSet = callback.call(model, model);
111
+ unSet = callback.call(subject, subject);
154
112
  if (unSet instanceof Promise)
155
113
  unSet = undefined;
156
114
  if (unSet && typeof unSet !== "function")
157
- throw Oops$7.BadCallback();
115
+ throw Oops$8.BadCallback();
158
116
  });
159
117
  if (output instanceof Promise) {
160
118
  output.finally(() => busy = false);
161
119
  busy = true;
162
120
  }
163
121
  }
164
- if (Array.isArray(keys)) {
165
- invoke();
166
- return controller.addListener(key => {
167
- if (key === null) {
168
- if (!keys.length)
169
- invoke();
170
- }
171
- else if (keys.includes(key))
172
- return invoke;
173
- });
174
- }
175
- const sub = new Subscriber(controller, () => invoke);
176
- model = sub.proxy;
122
+ let refresh;
123
+ subject = watch(subject, () => refresh);
124
+ self.followers.add(key => (key === null || refresh === null ? refresh : undefined));
177
125
  invoke();
178
- sub.commit();
179
- return () => sub.release();
126
+ refresh = invoke;
127
+ return () => refresh = null;
180
128
  });
181
129
  }
182
130
  function createValueEffect(callback) {
@@ -192,162 +140,254 @@ function createValueEffect(callback) {
192
140
  if (typeof out == "function")
193
141
  unSet = out;
194
142
  else
195
- throw Oops$7.BadCallback();
143
+ throw Oops$8.BadCallback();
196
144
  };
197
145
  }
198
146
 
199
- const Oops$6 = issues({
200
- Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
201
- KeysExpected: (key) => `Key "${key}" was expected in current update.`,
202
- StrictUpdate: () => `Expected update but none in progress.`,
203
- StrictNoUpdate: () => `Update is not expected but one is in progress!`
147
+ const Oops$7 = issues({
148
+ KeysExpected: (key) => `Key "${key}" was expected in current update.`
204
149
  });
205
- function addEventListener(source, arg1, arg2, arg3) {
206
- if (typeof arg1 == "string")
207
- arg1 = [arg1];
208
- return control(source, controller => {
209
- for (const key of arg1)
210
- try {
211
- void source[key];
212
- }
213
- catch (e) { }
214
- const removeListener = controller.addListener(key => {
215
- if (!key && !arg1.length)
216
- arg2.call(source, []);
217
- if (arg1.includes(key)) {
218
- if (arg3)
150
+ function addEventListener(source, select, callback, once) {
151
+ return control(source, self => {
152
+ const { subject } = self;
153
+ if (typeof select == "string")
154
+ select = [select];
155
+ if (select)
156
+ for (const key of select)
157
+ try {
158
+ void subject[key];
159
+ }
160
+ catch (e) {
161
+ // TODO: should this be caught?
162
+ }
163
+ const removeListener = self.addListener(key => {
164
+ if (key === null)
165
+ callback.call(subject, null);
166
+ else if (!select || select.includes(key)) {
167
+ if (once)
219
168
  removeListener();
220
- return arg2.bind(source);
169
+ return () => callback.call(subject, self.latest);
221
170
  }
222
171
  });
223
172
  return removeListener;
224
173
  });
225
174
  }
226
- function awaitUpdate(source, arg1, arg2) {
227
- const single = typeof arg1 == "string";
228
- const keys = typeof arg1 == "string" ? [arg1] :
229
- typeof arg1 == "object" ? arg1 :
230
- undefined;
175
+ function awaitUpdate(source, select, timeout) {
231
176
  return new Promise((resolve, reject) => {
232
- const timeout = (message) => {
233
- const k = keys ? keys.join(", ") : "any";
234
- removeListener();
235
- reject(Oops$6.Timeout(k, message));
236
- };
237
- const removeListener = control(source, controller => {
238
- const pending = controller.frame;
239
- if (keys === null) {
240
- if (pending.size)
241
- reject(Oops$6.StrictNoUpdate());
242
- else
243
- resolve(null);
244
- return;
177
+ if (timeout === 0) {
178
+ const self = control(source, true);
179
+ if (!self.frame.size)
180
+ resolve(false);
181
+ else if (typeof select == "string" && !self.frame.has(select))
182
+ reject(Oops$7.KeysExpected(select));
183
+ else {
184
+ const remove = self.addListener(() => {
185
+ remove();
186
+ return () => resolve(self.latest);
187
+ });
245
188
  }
246
- if (keys) {
247
- if (keys.length) {
248
- if (arg2 === 0 && single && !pending.has(keys[0])) {
249
- reject(Oops$6.KeysExpected(keys[0]));
250
- return;
251
- }
252
- else
253
- for (const key of keys)
254
- try {
255
- void source[key];
256
- }
257
- catch (e) { }
258
- }
189
+ }
190
+ else {
191
+ const remove = addEventListener(source, select, resolve, true);
192
+ if (timeout > 0)
193
+ setTimeout(() => {
194
+ remove();
195
+ resolve(false);
196
+ }, timeout);
197
+ }
198
+ });
199
+ }
200
+
201
+ const Oops$6 = issues({
202
+ NotFound: (name) => `Could not find ${name} in context.`
203
+ });
204
+ function get$1(arg1, arg2) {
205
+ return Control.get(this, (refresh, context) => {
206
+ let onUpdate;
207
+ let value;
208
+ if (typeof arg1 !== "function") {
209
+ context(got => {
210
+ if (got)
211
+ value = arg1 === undefined
212
+ ? Control.watch(got, () => onUpdate)
213
+ : got;
214
+ else if (arg1 !== false)
215
+ throw Oops$6.NotFound(this);
216
+ });
217
+ return {
218
+ mount() {
219
+ onUpdate = refresh;
220
+ return () => onUpdate = null;
221
+ },
222
+ render: () => value
223
+ };
224
+ }
225
+ let compute = arg1;
226
+ let suspense;
227
+ let getValue;
228
+ let factory;
229
+ let proxy;
230
+ context(got => {
231
+ if (!got)
232
+ throw Oops$6.NotFound(this);
233
+ proxy = Control.watch(got, () => factory ? null : onUpdate);
234
+ getValue = () => compute.call(proxy, proxy, forceUpdate);
235
+ value = getValue();
236
+ function forceUpdate(action) {
237
+ if (typeof action == "function")
238
+ action = action();
239
+ if (getValue)
240
+ didUpdate(getValue());
241
+ else
242
+ refresh();
243
+ if (action)
244
+ return action.finally(refresh);
259
245
  }
260
- else if (!pending.size && arg1 === true || arg2 === 0) {
261
- reject(Oops$6.StrictUpdate());
262
- return;
246
+ });
247
+ if (value === null) {
248
+ getValue = undefined;
249
+ onUpdate = null;
250
+ return;
251
+ }
252
+ if (typeof value == "function") {
253
+ const get = value;
254
+ Control.watch(proxy, () => onUpdate);
255
+ factory = true;
256
+ compute = () => get();
257
+ value = get();
258
+ }
259
+ const didUpdate = (got) => {
260
+ value = got;
261
+ if (suspense) {
262
+ suspense();
263
+ suspense = undefined;
263
264
  }
264
265
  else
265
- controller.waiting.add(resolve);
266
- return controller.addListener(key => {
267
- if (!key) {
268
- if (keys && !keys.length)
269
- resolve([]);
270
- else
271
- timeout(`lifetime of ${source}`);
272
- }
273
- else if (!keys || keys.includes(key)) {
274
- removeListener();
275
- return keys => resolve(single ? controller.state.get(key) : keys);
266
+ refresh();
267
+ };
268
+ if (value instanceof Promise) {
269
+ onUpdate = null;
270
+ value.then(didUpdate);
271
+ value = undefined;
272
+ }
273
+ else
274
+ onUpdate = () => {
275
+ const next = getValue();
276
+ if (notEqual(value, next))
277
+ didUpdate(next);
278
+ };
279
+ return {
280
+ mount: () => () => {
281
+ onUpdate = null;
282
+ },
283
+ render: () => {
284
+ if (value !== undefined)
285
+ return value;
286
+ if (arg2)
287
+ throw new Promise(res => {
288
+ suspense = res;
289
+ });
290
+ return null;
291
+ }
292
+ };
293
+ });
294
+ }
295
+ /** Values are not equal for purposes of a refresh. */
296
+ const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
297
+ !Array.isArray(b) ||
298
+ a.length !== b.length ||
299
+ a.some((x, i) => x !== b[i])));
300
+
301
+ function use$1(arg1, arg2) {
302
+ const render = Control.use((refresh) => {
303
+ let onUpdate;
304
+ let applyProps = typeof arg1 === "object";
305
+ const instance = this.new();
306
+ const proxy = Control.watch(instance, () => onUpdate);
307
+ if (typeof arg1 == "function")
308
+ arg1(instance);
309
+ return {
310
+ instance,
311
+ mount() {
312
+ onUpdate = refresh;
313
+ return () => {
314
+ onUpdate = null;
315
+ instance.null();
316
+ };
317
+ },
318
+ render(props) {
319
+ if (applyProps) {
320
+ onUpdate = undefined;
321
+ applyProps = !!arg2;
322
+ for (const key in props)
323
+ if (instance.hasOwnProperty(key))
324
+ instance[key] = props[key];
325
+ instance.on(0).then(() => onUpdate = refresh);
276
326
  }
277
- });
278
- });
279
- if (arg2 && typeof arg2 == "number")
280
- setTimeout(() => timeout(`${arg2}ms`), arg2);
327
+ return proxy;
328
+ }
329
+ };
281
330
  });
331
+ return render(arg1);
282
332
  }
283
333
 
284
- const Oops$5 = issues({
285
- NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`,
286
- NoAdapter: (method) => `Can't call Model.${method} without an adapter.`
287
- });
288
334
  class Model {
289
335
  constructor(id) {
290
- new Control(this);
291
- defineProperty(this, "is", { value: this });
292
- defineProperty(this, "id", { value: id || random() });
336
+ new Control(this, id);
337
+ }
338
+ /**
339
+ * Reference to `this` without a subscription.
340
+ * Use to obtain full reference from a destructure.
341
+ */
342
+ get is() {
343
+ return this;
293
344
  }
294
345
  on(arg1, arg2, arg3) {
295
346
  if (typeof arg1 == "function")
296
- return createEffect(this.is, arg1, arg2);
297
- if (typeof arg2 != "function")
298
- return awaitUpdate(this.is, arg1, arg2);
299
- if (arg1)
300
- return addEventListener(this.is, arg1, arg2, arg3);
347
+ return createEffect(this, arg1);
348
+ if (typeof arg1 == "number") {
349
+ arg2 = arg1;
350
+ arg1 = undefined;
351
+ }
352
+ return typeof arg2 == "function"
353
+ ? addEventListener(this, arg1, arg2, arg3)
354
+ : awaitUpdate(this, arg1, arg2);
301
355
  }
302
356
  get(arg1, arg2) {
303
- const { state } = control(this);
304
- const extract = () => {
357
+ const { state } = control(this, true);
358
+ function values() {
305
359
  if (typeof arg1 == "string")
306
- return state.get(arg1);
360
+ return state[arg1];
361
+ if (!arg1)
362
+ return Object.assign({}, state);
307
363
  const output = {};
308
- for (const key of arg1 || state.keys())
309
- output[key] = state.get(key);
364
+ for (const key of arg1)
365
+ output[key] = state[key];
310
366
  return output;
311
- };
312
- if (!arg1 || arg2 === undefined)
313
- return extract();
314
- if (typeof arg2 == "function")
315
- return this.on(arg1, () => arg2(extract()));
316
- const timeout = typeof arg2 == "number" ? arg2 : undefined;
317
- return this.on(arg1, timeout).then(extract);
367
+ }
368
+ return typeof arg2 == "function"
369
+ ? this.on(arg1, () => arg2(values()))
370
+ : values();
318
371
  }
319
372
  set(arg1, arg2) {
320
- const controller = control(this);
373
+ const controller = control(this, true);
321
374
  const { state } = controller;
322
375
  if (typeof arg1 == "string") {
323
376
  controller.update(arg1);
324
- if (1 in arguments) {
325
- if (state.has(arg1))
326
- state.set(arg1, arg2);
327
- else if (arg1 in this) {
328
- const method = this[arg1];
329
- if (typeof method == "function")
330
- method.call(this, arg2);
331
- }
332
- }
377
+ if (1 in arguments && arg1 in state)
378
+ state[arg1] = arg2;
333
379
  }
334
380
  else if (typeof arg1 == "object")
335
- for (const key in arg1)
336
- if (arg2 === true || (arg2 ? arg2.includes(key) : state.has(key))) {
337
- state.set(key, arg1[key]);
381
+ for (const key in state)
382
+ if (key in arg1 && (!arg2 || arg2.includes(key))) {
383
+ state[key] = arg1[key];
338
384
  controller.update(key);
339
385
  }
340
- return {
341
- then: (callback) => {
342
- if (!callback)
343
- throw Oops$5.NoChaining();
344
- controller.waiting.add(callback);
345
- }
346
- };
386
+ return awaitUpdate(this, undefined, 0);
347
387
  }
348
388
  /** Mark this instance for garbage collection. */
349
- gc() {
350
- control(this).clear();
389
+ null() {
390
+ control(this, true).clear();
351
391
  }
352
392
  /**
353
393
  * Creates a new instance of this controller.
@@ -358,18 +398,9 @@ class Model {
358
398
  */
359
399
  static new(...args) {
360
400
  const instance = new this(...args);
361
- control(instance);
401
+ control(instance, true);
362
402
  return instance;
363
403
  }
364
- static find() {
365
- throw Oops$5.NoAdapter("find");
366
- }
367
- static get() {
368
- throw Oops$5.NoAdapter("get");
369
- }
370
- static use() {
371
- throw Oops$5.NoAdapter("use");
372
- }
373
404
  /**
374
405
  * Static equivalent of `x instanceof this`.
375
406
  *
@@ -380,10 +411,12 @@ class Model {
380
411
  maybe.prototype instanceof this);
381
412
  }
382
413
  }
414
+ Model.get = get$1;
415
+ Model.use = use$1;
383
416
  defineProperty(Model.prototype, "toString", {
384
417
  configurable: true,
385
418
  value() {
386
- return `${this.constructor.name}-${this.id}`;
419
+ return `${this.constructor.name}-${control(this).id}`;
387
420
  }
388
421
  });
389
422
  defineProperty(Model, "toString", {
@@ -392,129 +425,320 @@ defineProperty(Model, "toString", {
392
425
  }
393
426
  });
394
427
 
395
- /**
396
- * Run instruction as controller sets itself up.
397
- * This will specialize the behavior of a given property.
398
- */
399
- function add(instruction, label) {
400
- const name = label || instruction.name || "pending";
401
- const placeholder = Symbol(`${name} instruction`);
402
- PENDING.set(placeholder, (control, key) => {
403
- let output = instruction.call(control, key, control);
404
- if (!output)
405
- return undefined;
406
- if (typeof output == "function")
407
- output = { get: output };
428
+ const Oops$5 = issues({
429
+ BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
430
+ });
431
+ const INSTRUCTION = new Map();
432
+ const REGISTER = new WeakMap();
433
+ const OBSERVER = new WeakMap();
434
+ class Control {
435
+ constructor(subject, id = random()) {
436
+ this.subject = subject;
437
+ this.id = id;
438
+ this.frame = new Set();
439
+ this.followers = new Set();
440
+ this.observers = new Map([["", this.followers]]);
441
+ REGISTER.set(subject, this);
442
+ }
443
+ add(key) {
444
+ const { value } = getOwnPropertyDescriptor(this.subject, key);
445
+ const instruction = INSTRUCTION.get(value);
446
+ if (typeof instruction == "function") {
447
+ INSTRUCTION.delete(value);
448
+ instruction(key, this);
449
+ }
450
+ else if (value instanceof Model)
451
+ setRecursive(this, key, value);
452
+ else if (typeof value != "function")
453
+ this.watch(key, { value });
454
+ }
455
+ watch(key, output) {
456
+ const { state } = this;
457
+ const { get, set, enumerable } = output;
458
+ const subs = new Set();
459
+ this.observers.set(key, subs);
408
460
  if ("value" in output)
409
- control.state.set(key, output.value);
410
- let { enumerable, get, set } = output;
411
- defineProperty(control.subject, key, {
461
+ state[key] = output.value;
462
+ defineProperty(this.subject, key, {
412
463
  enumerable,
413
- set: (set === false
464
+ set: set === false
414
465
  ? undefined
415
- : control.ref(key, set)),
466
+ : this.ref(key, set),
416
467
  get() {
417
- const local = subscriber(this);
418
- return (local ? local.get(key, get) :
419
- get ? get(local) :
420
- control.state.get(key));
468
+ const event = OBSERVER.get(this);
469
+ if (event)
470
+ subs.add(event);
471
+ const value = get ? get(this) : state[key];
472
+ return event && value instanceof Model
473
+ ? watch(value, event)
474
+ : value;
421
475
  }
422
476
  });
477
+ }
478
+ ref(key, callback) {
479
+ const { state, subject } = this;
480
+ return (value) => {
481
+ if (value !== state[key])
482
+ switch (callback && callback.call(subject, value)) {
483
+ case undefined:
484
+ state[key] = value;
485
+ case true:
486
+ this.update(key);
487
+ }
488
+ };
489
+ }
490
+ update(key) {
491
+ const { frame } = this;
492
+ if (frame.has(key))
493
+ return;
494
+ if (!frame.size) {
495
+ this.latest = undefined;
496
+ requestUpdateFrame(() => {
497
+ this.latest = Array.from(frame);
498
+ this.followers.forEach(cb => {
499
+ const notify = cb(undefined, this);
500
+ if (notify)
501
+ requestUpdateFrame(notify);
502
+ });
503
+ frame.clear();
504
+ });
505
+ }
506
+ frame.add(key);
507
+ for (const k of ["", key]) {
508
+ const subs = this.observers.get(k);
509
+ subs && subs.forEach(cb => {
510
+ const notify = cb(key, this);
511
+ if (notify === null)
512
+ subs.delete(cb);
513
+ else if (notify)
514
+ requestUpdateFrame(notify);
515
+ });
516
+ }
517
+ }
518
+ addListener(fn) {
519
+ this.followers.add(fn);
520
+ return () => this.followers.delete(fn);
521
+ }
522
+ clear() {
523
+ this.observers.forEach(subs => {
524
+ subs.forEach(fn => {
525
+ const cb = fn(null, this);
526
+ cb && cb();
527
+ });
528
+ });
529
+ this.observers.clear();
530
+ }
531
+ }
532
+ Control.after = new Set();
533
+ Control.before = new Set();
534
+ Control.pending = new Set();
535
+ Control.for = control;
536
+ Control.apply = apply;
537
+ Control.watch = watch;
538
+ const PENDING_INIT = new WeakMap();
539
+ function control(subject, ready) {
540
+ const control = REGISTER.get(subject.is);
541
+ const onReady = typeof ready == "function" && ready;
542
+ if (!control.state && ready) {
543
+ let waiting = PENDING_INIT.get(control);
544
+ if (!waiting)
545
+ PENDING_INIT.set(control, waiting = new Set());
546
+ if (onReady) {
547
+ let callback;
548
+ waiting.add(() => callback = onReady(control));
549
+ return () => callback && callback();
550
+ }
551
+ control.state = {};
552
+ for (const key in control.subject)
553
+ control.add(key);
554
+ waiting.forEach(cb => cb());
555
+ }
556
+ return onReady ? onReady(control) : control;
557
+ }
558
+ function requestUpdateFrame(event) {
559
+ const { after, before, pending } = Control;
560
+ if (!pending.size)
561
+ setTimeout(() => {
562
+ before.forEach(x => x());
563
+ pending.forEach(notify => {
564
+ try {
565
+ notify();
566
+ }
567
+ catch (err) {
568
+ console.error(err);
569
+ }
570
+ });
571
+ pending.clear();
572
+ after.forEach(x => x());
573
+ }, 0);
574
+ pending.add(event);
575
+ }
576
+ function setRecursive(on, key, value) {
577
+ const set = (next) => {
578
+ if (next instanceof value.constructor) {
579
+ on.state[key] = next;
580
+ control(next).parent = on.subject;
581
+ control(next, true);
582
+ return true;
583
+ }
584
+ throw Oops$5.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
585
+ };
586
+ on.watch(key, { set });
587
+ set(value);
588
+ }
589
+ function watch(on, cb) {
590
+ if (!on.hasOwnProperty("is"))
591
+ on = defineProperty(create(on), "is", { value: on });
592
+ OBSERVER.set(on, cb);
593
+ return on;
594
+ }
595
+ function apply(instruction) {
596
+ const placeholder = Symbol("instruction");
597
+ INSTRUCTION.set(placeholder, (key, onto) => {
598
+ delete onto.subject[key];
599
+ const output = instruction.call(onto, key, onto);
600
+ if (output)
601
+ onto.watch(key, typeof output == "function" ? { get: output } : output);
423
602
  });
424
603
  return placeholder;
604
+ }
605
+ /** Random alphanumberic of length 6; will always start with a letter. */
606
+ function random() {
607
+ return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
425
608
  }
426
609
 
427
610
  const Oops$4 = issues({
611
+ DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
612
+ });
613
+ function run(task) {
614
+ return apply((key, control) => {
615
+ let pending = false;
616
+ const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
617
+ if (pending)
618
+ return Promise.reject(Oops$4.DuplicatePending(key));
619
+ pending = true;
620
+ control.update(key);
621
+ try {
622
+ return yield mayRetry(() => (task.apply(control.subject, args)));
623
+ }
624
+ finally {
625
+ pending = false;
626
+ control.update(key);
627
+ }
628
+ });
629
+ control.state[key] = undefined;
630
+ defineProperty(invoke, "active", {
631
+ get: () => pending
632
+ });
633
+ return {
634
+ value: invoke,
635
+ set: false
636
+ };
637
+ });
638
+ }
639
+
640
+ const Oops$3 = issues({
428
641
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
429
642
  Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
430
- Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
643
+ Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}.`,
644
+ Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
645
+ AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
431
646
  });
432
647
  function get(arg0, arg1) {
433
- const fetch = this || getParentForGetInstruction;
434
- return add(function get(key) {
435
- let { subject } = this;
648
+ return apply((key, control) => {
649
+ let { subject } = control;
436
650
  if (typeof arg0 == "symbol")
437
- throw Oops$4.PeerNotAllowed(subject, key);
651
+ throw Oops$3.PeerNotAllowed(subject, key);
438
652
  let source = cb => cb(subject);
439
653
  if (arg0 instanceof Model)
440
654
  subject = arg0;
441
- else if (Model.isTypeof(arg0))
442
- source = fetch(arg0, subject, arg1 !== false);
655
+ else if (Model.isTypeof(arg0)) {
656
+ const { parent } = control;
657
+ if (!parent) {
658
+ if (arg1 === true)
659
+ throw Oops$3.Required(arg0, subject);
660
+ source = callback => Control.has(arg0, subject, got => {
661
+ if (got)
662
+ callback(got);
663
+ else if (arg1 !== false)
664
+ throw Oops$3.AmbientRequired(arg0, subject);
665
+ });
666
+ }
667
+ else if (!arg0 || parent instanceof arg0)
668
+ subject = parent;
669
+ else
670
+ throw Oops$3.Unexpected(arg0, subject, parent);
671
+ }
443
672
  else if (typeof arg0 == "function")
444
673
  arg1 = arg0.call(subject, key, subject);
445
674
  return typeof arg1 == "function"
446
- ? computed(this, key, source, arg1)
447
- : recursive(this, key, source, arg1);
675
+ ? computed(control, key, source, arg1)
676
+ : recursive(control, key, source, arg1);
448
677
  });
449
678
  }
450
- function getParentForGetInstruction(type, relativeTo, required) {
451
- const item = getParent(relativeTo, type);
452
- return callback => {
453
- if (item)
454
- callback(item);
455
- else if (required)
456
- throw Oops$4.Required(type, relativeTo.constructor);
457
- };
458
- }
459
679
  function recursive(parent, key, source, required) {
460
- const getter = getRecursive(key, parent);
461
680
  let waiting;
462
- source((got) => {
463
- parent.state.set(key, got);
464
- if (waiting)
465
- parent.update(key);
466
- });
681
+ if (source)
682
+ source((got) => {
683
+ parent.state[key] = got;
684
+ if (waiting)
685
+ parent.update(key);
686
+ });
467
687
  waiting = true;
468
- return (local) => {
469
- const value = parent.state.get(key);
470
- if (!value && required !== false)
471
- parent.waitFor(key);
472
- return local ? getter(local) : value;
688
+ return () => {
689
+ const value = parent.state[key];
690
+ if (value)
691
+ return value;
692
+ if (required !== false)
693
+ throw suspense(parent, key);
473
694
  };
474
695
  }
696
+ const ORDER = new WeakMap();
697
+ const PENDING = new Set();
698
+ let OFFSET = 0;
475
699
  function computed(parent, key, source, setter) {
476
700
  const { state } = parent;
477
- let local;
701
+ let proxy;
478
702
  let active;
479
703
  let isAsync;
480
- let order = ORDER.get(parent);
481
- let pending = KEYS.get(parent);
482
- if (!order)
483
- ORDER.set(parent, order = new Map());
484
- if (!pending)
485
- KEYS.set(parent, pending = new Set());
486
- INFO.set(compute, key);
704
+ let reset;
487
705
  function compute(initial) {
706
+ if (parent.frame.has(key))
707
+ return;
488
708
  let next;
489
709
  try {
490
- next = setter.call(local.proxy, local.proxy);
710
+ next = setter.call(proxy, proxy);
491
711
  }
492
712
  catch (err) {
493
- Oops$4.Failed(parent.subject, key, initial).warn();
713
+ Oops$3.Failed(parent.subject, key, initial).warn();
494
714
  if (initial)
495
715
  throw err;
496
716
  console.error(err);
497
717
  }
498
- if (next !== state.get(key)) {
499
- state.set(key, next);
718
+ if (next !== state[key]) {
719
+ state[key] = next;
500
720
  if (!initial || isAsync)
501
721
  parent.update(key);
502
722
  }
503
723
  }
504
724
  function connect(model) {
505
- local = new Subscriber(model, (_, control) => {
725
+ if (reset)
726
+ reset();
727
+ let done;
728
+ reset = () => done = true;
729
+ proxy = watch(model, (_, control) => {
730
+ if (done)
731
+ return null;
506
732
  if (control !== parent)
507
733
  compute();
508
734
  else
509
- pending.add(compute);
735
+ PENDING.add(compute);
510
736
  });
511
- local.watch.set(key, false);
512
737
  try {
513
738
  compute(true);
514
739
  }
515
740
  finally {
516
- local.commit();
517
- order.set(compute, order.size);
741
+ ORDER.set(compute, OFFSET++);
518
742
  }
519
743
  }
520
744
  return () => {
@@ -523,297 +747,32 @@ function computed(parent, key, source, setter) {
523
747
  source(connect);
524
748
  isAsync = true;
525
749
  }
526
- if (!local)
527
- parent.waitFor(key);
528
- if (pending.delete(compute))
750
+ if (!proxy)
751
+ throw suspense(parent, key);
752
+ if (PENDING.delete(compute))
529
753
  compute();
530
- return state.get(key);
754
+ return state[key];
531
755
  };
532
756
  }
533
- const INFO = new WeakMap();
534
- const KEYS = new WeakMap();
535
- const ORDER = new WeakMap();
536
- function flushComputed(control) {
537
- const pending = KEYS.get(control);
538
- if (!pending || !pending.size)
539
- return;
540
- const priority = ORDER.get(control);
541
- while (pending.size) {
757
+ function flushComputed() {
758
+ while (PENDING.size) {
542
759
  let compute;
543
- for (const item of pending)
544
- if (!compute || priority.get(item) < priority.get(compute))
760
+ for (const item of PENDING)
761
+ if (!compute || ORDER.get(item) < ORDER.get(compute))
545
762
  compute = item;
546
- pending.delete(compute);
547
- const key = INFO.get(compute);
548
- if (!control.frame.has(key))
549
- compute();
763
+ PENDING.delete(compute);
764
+ compute();
550
765
  }
551
- pending.clear();
552
- }
553
- function using(fn) {
554
- return Object.assign(get.bind(fn), { using });
555
766
  }
556
- get.using = using;
557
-
558
- const REGISTER = new WeakMap();
559
- const PENDING = new Map();
560
- class Control {
561
- constructor(subject) {
562
- this.subject = subject;
563
- this.frame = new Set();
564
- this.waiting = new Set();
565
- this.followers = new Set();
566
- REGISTER.set(subject, this);
567
- }
568
- watch(key) {
569
- const { subject, state } = this;
570
- const { value } = getOwnPropertyDescriptor(subject, key);
571
- if (typeof value == "function")
572
- return;
573
- if (typeof value == "symbol") {
574
- const instruction = PENDING.get(value);
575
- if (instruction) {
576
- delete subject[key];
577
- PENDING.delete(value);
578
- instruction(this, key);
579
- }
580
- return;
581
- }
582
- state.set(key, value);
583
- if (value instanceof Model) {
584
- setRecursive(this, key, value);
585
- return;
586
- }
587
- defineProperty(subject, key, {
588
- enumerable: false,
589
- set: this.ref(key),
590
- get() {
591
- const local = subscriber(this);
592
- return local
593
- ? local.get(key)
594
- : state.get(key);
595
- }
596
- });
597
- }
598
- /** Throw suspense which resolves when key is set. */
599
- waitFor(key) {
600
- throw suspend(this, key);
601
- }
602
- addListener(listener) {
603
- this.followers.add(listener);
604
- return () => {
605
- this.followers.delete(listener);
606
- };
607
- }
608
- ref(key, handler) {
609
- const { subject, state } = this;
610
- return (value) => {
611
- if (state.get(key) == value)
612
- return;
613
- if (handler)
614
- switch (handler.call(subject, value)) {
615
- case true:
616
- this.update(key);
617
- case false:
618
- return;
619
- }
620
- state.set(key, value);
621
- this.update(key);
622
- };
623
- }
624
- update(key) {
625
- const { followers, frame, waiting } = this;
626
- if (frame.has(key))
627
- return;
628
- else if (!frame.size)
629
- setTimeout(() => {
630
- flushComputed(this);
631
- const keys = this.latest = Array.from(frame);
632
- setTimeout(() => this.latest = undefined, 0);
633
- frame.clear();
634
- for (const notify of waiting)
635
- try {
636
- waiting.delete(notify);
637
- notify(keys);
638
- }
639
- catch (err) {
640
- console.error(err);
641
- }
642
- }, 0);
643
- frame.add(key);
644
- for (const callback of followers) {
645
- const event = callback(key, this);
646
- if (typeof event == "function")
647
- waiting.add(event);
648
- }
649
- }
650
- clear() {
651
- const listeners = [...this.followers];
652
- this.followers.clear();
653
- listeners.forEach(x => x(null, this));
654
- }
655
- }
656
- Control.get = controller;
657
- Control.for = control;
658
- function controller(from) {
659
- if ("is" in from)
660
- from = from.is;
661
- return REGISTER.get(from);
662
- }
663
- function control(subject, cb) {
664
- const control = controller(subject) || new Control(subject);
665
- if (!control.state) {
666
- const { waiting } = control;
667
- if (cb) {
668
- let callback;
669
- waiting.add(() => {
670
- callback = cb(control);
671
- });
672
- return () => {
673
- if (callback)
674
- callback();
675
- };
676
- }
677
- control.state = new Map();
678
- for (const key in subject)
679
- control.watch(key);
680
- control.waiting = new Set();
681
- for (const cb of waiting)
682
- cb([]);
683
- }
684
- return cb ? cb(control) : control;
685
- }
686
-
687
- const Parent = new WeakMap();
688
- const Oops$3 = issues({
689
- BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
690
- Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
691
- });
692
- function getParent(from, type) {
693
- const value = Parent.get(from);
694
- if (value && type && !(value instanceof type))
695
- throw Oops$3.Unexpected(type, from, value);
696
- return value;
697
- }
698
- function getRecursive(key, from) {
699
- const context = new WeakMap();
700
- const { state } = from;
701
- return (local) => {
702
- if (!context.has(local)) {
703
- let reset;
704
- const init = () => {
705
- if (reset)
706
- reset();
707
- const value = state.get(key);
708
- if (value && controller(value)) {
709
- const child = new Subscriber(value, local.onUpdate);
710
- if (local.active)
711
- child.commit();
712
- local.dependant.add(child);
713
- context.set(local, child.proxy);
714
- reset = () => {
715
- child.release();
716
- local.dependant.delete(child);
717
- context.set(local, undefined);
718
- reset = undefined;
719
- };
720
- }
721
- };
722
- local.follow(key, init);
723
- init();
724
- }
725
- return context.get(local);
726
- };
727
- }
728
- function setRecursive(controller, key, initial) {
729
- const { state, subject } = controller;
730
- const Type = initial.constructor;
731
- let get;
732
- const onUpdate = (next) => {
733
- state.set(key, next);
734
- if (!(next instanceof Type))
735
- throw Oops$3.BadAssignment(`${subject}.${key}`, Type, String(next));
736
- const getter = getRecursive(key, controller);
737
- get = (local) => local ? getter(local) : state.get(key);
738
- Parent.set(next, subject);
739
- control(next);
740
- return true;
741
- };
742
- onUpdate(initial);
743
- defineProperty(subject, key, {
744
- set: controller.ref(key, onUpdate),
745
- get() {
746
- const local = subscriber(this);
747
- if (local)
748
- local.follow(key);
749
- return get(local);
750
- }
751
- });
752
- }
753
-
754
- /******************************************************************************
755
- Copyright (c) Microsoft Corporation.
756
-
757
- Permission to use, copy, modify, and/or distribute this software for any
758
- purpose with or without fee is hereby granted.
759
-
760
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
761
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
762
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
763
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
764
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
765
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
766
- PERFORMANCE OF THIS SOFTWARE.
767
- ***************************************************************************** */
768
-
769
- function __awaiter(thisArg, _arguments, P, generator) {
770
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
771
- return new (P || (P = Promise))(function (resolve, reject) {
772
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
773
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
774
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
775
- step((generator = generator.apply(thisArg, _arguments || [])).next());
776
- });
777
- }
778
-
779
- const Oops$2 = issues({
780
- DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
781
- });
782
- function run(task) {
783
- return add(function run(key) {
784
- let pending = false;
785
- const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
786
- if (pending)
787
- return Promise.reject(Oops$2.DuplicatePending(key));
788
- pending = true;
789
- this.update(key);
790
- try {
791
- return yield mayRetry(() => (task.apply(this.subject, args)));
792
- }
793
- finally {
794
- pending = false;
795
- this.update(key);
796
- }
797
- });
798
- this.state.set(key, undefined);
799
- defineProperty(invoke, "active", {
800
- get: () => pending
801
- });
802
- return {
803
- value: invoke,
804
- set: false
805
- };
806
- });
807
- }
767
+ Control.before.add(flushComputed);
808
768
 
809
769
  function ref(arg, mapper) {
810
- return add(function ref(key) {
770
+ return apply((key, source) => {
811
771
  let value = {};
812
- this.state.set(key, undefined);
813
772
  if (typeof arg != "object")
814
- value = createRef(this, key, arg);
773
+ value = createRef(source, key, arg);
815
774
  else
816
- control(arg).state.forEach((_val, key) => {
775
+ for (const key in control(arg, true).state) {
817
776
  defineProperty(value, key, mapper ? {
818
777
  configurable: true,
819
778
  get() {
@@ -822,28 +781,30 @@ function ref(arg, mapper) {
822
781
  return out;
823
782
  }
824
783
  } : {
825
- value: createRef(this, key)
784
+ value: createRef(source, key)
826
785
  });
827
- });
828
- defineProperty(this.subject, key, { value });
786
+ }
787
+ source.state[key] = undefined;
788
+ source.observers.set(key, new Set());
789
+ defineProperty(source.subject, key, { value });
829
790
  });
830
791
  }
831
792
  function createRef(src, key, cb) {
832
793
  const refObjectFunction = src.ref(key, cb && createValueEffect(cb));
833
794
  defineProperty(refObjectFunction, "current", {
834
795
  set: refObjectFunction,
835
- get: () => src.state.get(key)
796
+ get: () => src.state[key]
836
797
  });
837
798
  return refObjectFunction;
838
799
  }
839
800
 
840
- const Oops$1 = issues({
801
+ const Oops$2 = issues({
841
802
  ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
842
803
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
843
804
  });
844
805
  function set(value, argument) {
845
- return add(function set(key) {
846
- const { state, subject } = this;
806
+ return apply((key, control) => {
807
+ const { state, subject } = control;
847
808
  if (typeof value == "function" || value instanceof Promise) {
848
809
  const required = argument !== false;
849
810
  let getter;
@@ -854,24 +815,24 @@ function set(value, argument) {
854
815
  let pending;
855
816
  let error;
856
817
  if (value instanceof Promise) {
857
- state.set(key, undefined);
818
+ state[key] = undefined;
858
819
  pending = value
859
820
  .catch(err => error = err)
860
821
  .then(val => {
861
- state.set(key, val);
822
+ state[key] = val;
862
823
  return val;
863
824
  })
864
825
  .finally(() => {
865
826
  pending = undefined;
866
- this.update(key);
827
+ control.update(key);
867
828
  });
868
829
  }
869
830
  else
870
- state.set(key, value);
831
+ state[key] = value;
871
832
  const suspend = () => {
872
833
  if (required === false)
873
834
  return undefined;
874
- const issue = Oops$1.NotReady(subject, key);
835
+ const issue = Oops$2.NotReady(subject, key);
875
836
  assign(pending, {
876
837
  message: issue.message,
877
838
  stack: issue.stack
@@ -883,12 +844,11 @@ function set(value, argument) {
883
844
  throw error;
884
845
  if (pending)
885
846
  return suspend();
886
- if (state.has(key))
887
- return state.get(key);
847
+ return state[key];
888
848
  };
889
849
  }
890
850
  catch (err) {
891
- Oops$1.ComputeFailed(subject, key).warn();
851
+ Oops$2.ComputeFailed(subject, key).warn();
892
852
  throw err;
893
853
  }
894
854
  };
@@ -901,13 +861,13 @@ function set(value, argument) {
901
861
  };
902
862
  }
903
863
  if (value !== undefined)
904
- state.set(key, value);
864
+ state[key] = value;
905
865
  return {
906
866
  get: () => {
907
- if (state.has(key))
908
- return state.get(key);
867
+ if (key in state)
868
+ return state[key];
909
869
  else
910
- this.waitFor(key);
870
+ throw suspense(control, key);
911
871
  },
912
872
  set: typeof argument == "function"
913
873
  ? createValueEffect(argument)
@@ -916,180 +876,27 @@ function set(value, argument) {
916
876
  });
917
877
  }
918
878
 
919
- const ANY = Symbol("any");
920
- function keyed(control, property, initial) {
921
- const init = createProxy(emit, watch);
922
- const frozen = new Set();
923
- const context = new Map();
924
- const users = new Map();
925
- const watched = new WeakMap();
926
- const update = new Set();
927
- let managed = init(initial);
928
- function watch(on, key) {
929
- const include = watched.get(on);
930
- if (include)
931
- include.add(key);
932
- }
933
- function emit(key) {
934
- control.update(property);
935
- control.waiting.add(() => frozen.clear());
936
- update.forEach(notify => notify(key));
937
- }
938
- function subscribe(local) {
939
- const proxy = create(managed);
940
- let watch = users.get(local);
941
- if (!watch) {
942
- const using = watch = new Set();
943
- users.set(local, using);
944
- function onEvent(key) {
945
- if (frozen.has(local))
946
- return;
947
- if (key === ANY || using.has(key) || using.has(ANY)) {
948
- const refresh = local.onUpdate(property, control);
949
- if (refresh) {
950
- frozen.add(local);
951
- refresh();
952
- }
953
- }
954
- }
955
- local.follow(property, false);
956
- local.dependant.add({
957
- commit() {
958
- if (using.size === 0)
959
- using.add(ANY);
960
- update.add(onEvent);
961
- },
962
- release() {
963
- update.delete(onEvent);
964
- }
965
- });
966
- }
967
- watched.set(proxy, watch);
968
- context.set(local, proxy);
969
- return proxy;
970
- }
971
- control.addListener(key => {
972
- if (key === null) {
973
- update.clear();
974
- context.clear();
975
- }
976
- });
977
- return {
978
- value: initial,
979
- get(local) {
980
- return local ?
981
- context.get(local) || subscribe(local) :
982
- managed;
983
- },
984
- set(next) {
985
- control.state.set(property, next);
986
- managed = init(next);
987
- context.clear();
988
- emit(ANY);
989
- }
990
- };
991
- }
992
- function createProxy(emit, watch) {
993
- return (from) => {
994
- const proxy = create(from);
995
- assign(proxy, {
996
- from,
997
- delete(key) {
998
- // TODO: this commit's fix needs tests.
999
- // Was not cause by coverage.
1000
- const out = from.delete(key);
1001
- emit(key);
1002
- return out;
1003
- },
1004
- clear() {
1005
- from.clear();
1006
- emit(ANY);
1007
- },
1008
- has(key) {
1009
- watch(this, key);
1010
- return from.has(key);
1011
- },
1012
- keys() {
1013
- watch(this, ANY);
1014
- return from.keys();
1015
- },
1016
- values() {
1017
- watch(this, ANY);
1018
- return from.values();
1019
- },
1020
- entries() {
1021
- watch(this, ANY);
1022
- return from.entries();
1023
- },
1024
- forEach(callbackfn, thisArg) {
1025
- const acc = [];
1026
- from.forEach((a, b, c) => {
1027
- const result = callbackfn.call(thisArg, a, b, c);
1028
- if (result !== undefined)
1029
- acc.push(result);
1030
- });
1031
- watch(this, ANY);
1032
- return acc;
1033
- },
1034
- [Symbol.iterator]() {
1035
- watch(this, ANY);
1036
- return from[Symbol.iterator]();
1037
- },
1038
- }, from instanceof Set
1039
- ? {
1040
- add(key) {
1041
- from.add(key);
1042
- emit(key);
1043
- return this;
1044
- }
1045
- }
1046
- : {
1047
- get(key) {
1048
- watch(this, ANY);
1049
- return from.get(key);
1050
- },
1051
- set(key, value) {
1052
- from.set(key, value);
1053
- emit(key);
1054
- return this;
1055
- }
1056
- });
1057
- defineProperty(proxy, "size", {
1058
- get() {
1059
- watch(this, ANY);
1060
- return from.size;
1061
- }
1062
- });
1063
- return proxy;
1064
- };
1065
- }
1066
-
1067
- const Oops = issues({
879
+ const Oops$1 = issues({
1068
880
  BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
1069
881
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
1070
882
  });
1071
883
  function use(input, argument) {
1072
- return add(function use(key) {
1073
- const { state, subject } = this;
884
+ return apply((key, source) => {
885
+ const { state, subject } = source;
1074
886
  const required = argument !== false;
1075
887
  let pending;
1076
888
  let error;
1077
- let get = (_local) => state.get(key);
1078
889
  if (typeof input === "function") {
1079
890
  if ("prototype" in input && input === input.prototype.constructor)
1080
891
  input = new input();
1081
892
  }
1082
893
  else if (input && typeof input !== "object")
1083
- throw Oops.BadArgument(typeof input);
1084
- if (input instanceof Map || input instanceof Set)
1085
- return keyed(this, key, input);
894
+ throw Oops$1.BadArgument(typeof input);
1086
895
  const onUpdate = (next) => {
1087
- state.set(key, next);
896
+ state[key] = next;
1088
897
  if (next) {
1089
- const getter = getRecursive(key, this);
1090
- get = (local) => local ? getter(local) : state.get(key);
1091
- Parent.set(next, subject);
1092
- control(next);
898
+ control(next).parent = subject;
899
+ control(next, true);
1093
900
  }
1094
901
  if (typeof argument == "function")
1095
902
  argument(next);
@@ -1098,7 +905,7 @@ function use(input, argument) {
1098
905
  const suspend = () => {
1099
906
  if (required === false)
1100
907
  return;
1101
- const issue = Oops.NotReady(subject, key);
908
+ const issue = Oops$1.NotReady(subject, key);
1102
909
  assign(pending, {
1103
910
  message: issue.message,
1104
911
  stack: issue.stack
@@ -1111,14 +918,14 @@ function use(input, argument) {
1111
918
  input;
1112
919
  if (output instanceof Promise) {
1113
920
  pending = output
1114
- .catch(err => error = err)
1115
921
  .then(val => {
1116
922
  onUpdate(val);
1117
923
  return val;
1118
924
  })
925
+ .catch(err => error = err)
1119
926
  .finally(() => {
1120
927
  pending = undefined;
1121
- this.update(key);
928
+ source.update(key);
1122
929
  });
1123
930
  return;
1124
931
  }
@@ -1128,60 +935,28 @@ function use(input, argument) {
1128
935
  initialize();
1129
936
  return {
1130
937
  set: onUpdate,
1131
- get(local) {
938
+ get() {
1132
939
  if (pending)
1133
940
  return suspend();
1134
941
  if (error)
1135
942
  throw error;
1136
- if (!state.has(key))
943
+ if (!(key in state))
1137
944
  initialize();
1138
945
  if (pending)
1139
946
  return suspend();
1140
- return get(local);
947
+ return state[key];
1141
948
  }
1142
949
  };
1143
950
  });
1144
951
  }
1145
952
 
1146
- const LOCAL = "__local";
1147
- const STATE = "__state";
1148
- const UPDATE = "__update";
1149
- const CONTROL = "__control";
1150
- defineProperties(Model.prototype, {
1151
- [CONTROL]: {
1152
- get() {
1153
- return controller(this);
1154
- }
1155
- },
1156
- [LOCAL]: {
1157
- get() {
1158
- return subscriber(this);
1159
- }
1160
- },
1161
- [STATE]: {
1162
- get() {
1163
- const { state } = controller(this);
1164
- const output = {};
1165
- state.forEach((value, key) => output[key] = value);
1166
- return output;
1167
- }
1168
- },
1169
- [UPDATE]: {
1170
- get() {
1171
- return (subscriber(this) || controller(this)).latest;
1172
- }
1173
- }
953
+ const Oops = issues({
954
+ MultipleExist: (name) => `Did find ${name} in context, but multiple were defined.`
1174
955
  });
1175
- const Debug = {
1176
- CONTROL,
1177
- LOCAL,
1178
- STATE,
1179
- UPDATE
1180
- };
1181
-
1182
- class Register {
956
+ class Context {
1183
957
  constructor() {
1184
- this.table = new Map();
958
+ this.table = new WeakMap();
959
+ this.input = new Map();
1185
960
  }
1186
961
  has(T) {
1187
962
  let key = this.table.get(T);
@@ -1192,9 +967,16 @@ class Register {
1192
967
  return key;
1193
968
  }
1194
969
  get(Type) {
1195
- return this[this.has(Type)];
970
+ const result = this[this.has(Type)];
971
+ if (result === null)
972
+ throw Oops.MultipleExist(Type);
973
+ return result;
1196
974
  }
1197
975
  add(input, key) {
976
+ if (key && this.input.get(key) === input)
977
+ return typeof input == "object"
978
+ ? input
979
+ : this[this.has(input)];
1198
980
  let writable = true;
1199
981
  let T;
1200
982
  let I;
@@ -1217,12 +999,12 @@ class Register {
1217
999
  T = getPrototypeOf(T);
1218
1000
  } while (T !== Model);
1219
1001
  if (key !== undefined)
1220
- this.register.set(key, input);
1002
+ this.input.set(key, input);
1221
1003
  return I;
1222
1004
  }
1223
1005
  push() {
1224
1006
  const next = create(this);
1225
- next.register = new Map();
1007
+ next.input = new Map();
1226
1008
  return next;
1227
1009
  }
1228
1010
  pop() {
@@ -1234,21 +1016,48 @@ class Register {
1234
1016
  delete this[key];
1235
1017
  }
1236
1018
  for (const model of items)
1237
- model.gc();
1019
+ model.null();
1020
+ this.input.clear();
1238
1021
  }
1239
1022
  }
1240
1023
 
1241
- const Internal = {
1242
- getParent
1024
+ const STATE = "__state";
1025
+ const UPDATE = "__update";
1026
+ const CONTROL = "__control";
1027
+ const PARENT = "__parent";
1028
+ defineProperties(Model.prototype, {
1029
+ [CONTROL]: {
1030
+ get() {
1031
+ return control(this);
1032
+ }
1033
+ },
1034
+ [STATE]: {
1035
+ get() {
1036
+ return Object.assign({}, control(this).state);
1037
+ }
1038
+ },
1039
+ [UPDATE]: {
1040
+ get() {
1041
+ return control(this).latest;
1042
+ }
1043
+ },
1044
+ [PARENT]: {
1045
+ get() {
1046
+ return control(this).parent;
1047
+ }
1048
+ }
1049
+ });
1050
+ const Debug = {
1051
+ CONTROL,
1052
+ STATE,
1053
+ UPDATE,
1054
+ PARENT
1243
1055
  };
1244
1056
 
1057
+ exports.Context = Context;
1245
1058
  exports.Control = Control;
1246
1059
  exports.Debug = Debug;
1247
- exports.Internal = Internal;
1248
1060
  exports.Model = Model;
1249
- exports.Register = Register;
1250
- exports.Subscriber = Subscriber;
1251
- exports.add = add;
1252
1061
  exports["default"] = Model;
1253
1062
  exports.get = get;
1254
1063
  exports.issues = issues;