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