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