@expressive/mvc 0.10.1 → 0.11.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.d.ts +1 -1
- package/lib/index.esm.js +364 -317
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +364 -317
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.esm.js
CHANGED
|
@@ -22,11 +22,11 @@ function issues(register) {
|
|
|
22
22
|
return Library;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const Oops$
|
|
25
|
+
const Oops$f = issues({
|
|
26
26
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
27
27
|
});
|
|
28
28
|
function suspend(source, key) {
|
|
29
|
-
const error = Oops$
|
|
29
|
+
const error = Oops$f.NotReady(source.subject, key);
|
|
30
30
|
const promise = new Promise(resolve => {
|
|
31
31
|
const release = source.addListener(forKey => {
|
|
32
32
|
if (forKey == key)
|
|
@@ -66,7 +66,7 @@ function mayRetry(fn) {
|
|
|
66
66
|
return compute();
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
const Oops$
|
|
69
|
+
const Oops$e = issues({
|
|
70
70
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
71
71
|
});
|
|
72
72
|
const INFO = new WeakMap();
|
|
@@ -86,7 +86,7 @@ function computeMode(self, source, setter, key, required) {
|
|
|
86
86
|
return setter.call(sub.proxy, sub.proxy);
|
|
87
87
|
}
|
|
88
88
|
catch (err) {
|
|
89
|
-
Oops$
|
|
89
|
+
Oops$e.Failed(subject, key, initial).warn();
|
|
90
90
|
throw err;
|
|
91
91
|
}
|
|
92
92
|
};
|
|
@@ -157,6 +157,152 @@ function flush(control) {
|
|
|
157
157
|
pending.clear();
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
const Oops$d = issues({
|
|
161
|
+
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
162
|
+
});
|
|
163
|
+
function createEffect(model, callback, keys) {
|
|
164
|
+
return Control.for(model, control => {
|
|
165
|
+
let unSet;
|
|
166
|
+
let busy = false;
|
|
167
|
+
function effect(value) {
|
|
168
|
+
if (typeof unSet == "function")
|
|
169
|
+
unSet();
|
|
170
|
+
unSet = callback.call(this, value);
|
|
171
|
+
if (unSet instanceof Promise)
|
|
172
|
+
unSet = undefined;
|
|
173
|
+
if (unSet && typeof unSet !== "function")
|
|
174
|
+
throw Oops$d.BadCallback();
|
|
175
|
+
}
|
|
176
|
+
function invoke() {
|
|
177
|
+
if (busy)
|
|
178
|
+
return;
|
|
179
|
+
const output = mayRetry(() => {
|
|
180
|
+
effect.call(model, model);
|
|
181
|
+
});
|
|
182
|
+
if (output instanceof Promise) {
|
|
183
|
+
output.finally(() => busy = false);
|
|
184
|
+
busy = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (Array.isArray(keys)) {
|
|
188
|
+
invoke();
|
|
189
|
+
return control.addListener(key => {
|
|
190
|
+
if (key === null) {
|
|
191
|
+
if (!keys.length)
|
|
192
|
+
invoke();
|
|
193
|
+
}
|
|
194
|
+
else if (keys.includes(key))
|
|
195
|
+
return invoke;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const sub = control.subscribe(() => invoke);
|
|
199
|
+
model = sub.proxy;
|
|
200
|
+
invoke();
|
|
201
|
+
return sub.commit();
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function createValueEffect(callback) {
|
|
205
|
+
let unSet;
|
|
206
|
+
return function (value) {
|
|
207
|
+
if (typeof unSet == "function")
|
|
208
|
+
unSet(value);
|
|
209
|
+
const out = callback.call(this, value, this);
|
|
210
|
+
if (typeof out == "boolean")
|
|
211
|
+
return out;
|
|
212
|
+
if (!out || out instanceof Promise)
|
|
213
|
+
return;
|
|
214
|
+
if (typeof out == "function")
|
|
215
|
+
unSet = out;
|
|
216
|
+
else
|
|
217
|
+
throw Oops$d.BadCallback();
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const Oops$c = issues({
|
|
222
|
+
Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
|
|
223
|
+
KeysExpected: (key) => `Key "${key}" was expected in current update.`,
|
|
224
|
+
StrictUpdate: () => `Expected update but none in progress.`,
|
|
225
|
+
StrictNoUpdate: () => `Update is not expected but one is in progress!`
|
|
226
|
+
});
|
|
227
|
+
function addEventListener(source, arg1, arg2, arg3) {
|
|
228
|
+
if (typeof arg1 == "string")
|
|
229
|
+
arg1 = [arg1];
|
|
230
|
+
return Control.for(source, control => {
|
|
231
|
+
for (const key of arg1)
|
|
232
|
+
try {
|
|
233
|
+
void source[key];
|
|
234
|
+
}
|
|
235
|
+
catch (e) { }
|
|
236
|
+
const removeListener = control.addListener(key => {
|
|
237
|
+
if (!key && !arg1.length)
|
|
238
|
+
arg2.call(source, []);
|
|
239
|
+
if (arg1.includes(key)) {
|
|
240
|
+
if (arg3)
|
|
241
|
+
removeListener();
|
|
242
|
+
return arg2.bind(source);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
return removeListener;
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
function awaitUpdate(source, arg1, arg2) {
|
|
249
|
+
const single = typeof arg1 == "string";
|
|
250
|
+
const keys = typeof arg1 == "string" ? [arg1] :
|
|
251
|
+
typeof arg1 == "object" ? arg1 :
|
|
252
|
+
undefined;
|
|
253
|
+
return new Promise((resolve, reject) => {
|
|
254
|
+
const timeout = (message) => {
|
|
255
|
+
const k = keys ? keys.join(", ") : "any";
|
|
256
|
+
removeListener();
|
|
257
|
+
reject(Oops$c.Timeout(k, message));
|
|
258
|
+
};
|
|
259
|
+
const removeListener = Control.for(source, control => {
|
|
260
|
+
const pending = control.frame;
|
|
261
|
+
if (keys === null) {
|
|
262
|
+
if (pending.size)
|
|
263
|
+
reject(Oops$c.StrictNoUpdate());
|
|
264
|
+
else
|
|
265
|
+
resolve(null);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (keys) {
|
|
269
|
+
if (keys.length) {
|
|
270
|
+
if (arg2 === 0 && single && !pending.has(keys[0])) {
|
|
271
|
+
reject(Oops$c.KeysExpected(keys[0]));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
else
|
|
275
|
+
for (const key of keys)
|
|
276
|
+
try {
|
|
277
|
+
void source[key];
|
|
278
|
+
}
|
|
279
|
+
catch (e) { }
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else if (!pending.size && arg1 === true || arg2 === 0) {
|
|
283
|
+
reject(Oops$c.StrictUpdate());
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
else
|
|
287
|
+
control.waiting.add(resolve);
|
|
288
|
+
return control.addListener(key => {
|
|
289
|
+
if (!key) {
|
|
290
|
+
if (keys && !keys.length)
|
|
291
|
+
resolve([]);
|
|
292
|
+
else
|
|
293
|
+
timeout(`lifetime of ${source}`);
|
|
294
|
+
}
|
|
295
|
+
else if (!keys || keys.includes(key)) {
|
|
296
|
+
removeListener();
|
|
297
|
+
return keys => resolve(single ? control.state.get(key) : keys);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
if (arg2 && typeof arg2 == "number")
|
|
302
|
+
setTimeout(() => timeout(`${arg2}ms`), arg2);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
160
306
|
const REGISTER$1 = new WeakMap();
|
|
161
307
|
class Subscriber {
|
|
162
308
|
constructor(parent, onUpdate) {
|
|
@@ -229,6 +375,102 @@ class Subscriber {
|
|
|
229
375
|
}
|
|
230
376
|
}
|
|
231
377
|
|
|
378
|
+
const Oops$b = issues({
|
|
379
|
+
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
380
|
+
});
|
|
381
|
+
class Model {
|
|
382
|
+
constructor() {
|
|
383
|
+
new Control(this);
|
|
384
|
+
defineProperty(this, "is", { value: this });
|
|
385
|
+
}
|
|
386
|
+
on(arg1, arg2, arg3) {
|
|
387
|
+
if (typeof arg1 == "function")
|
|
388
|
+
return createEffect(this.is, arg1, arg2);
|
|
389
|
+
if (typeof arg2 != "function")
|
|
390
|
+
return awaitUpdate(this.is, arg1, arg2);
|
|
391
|
+
if (arg1)
|
|
392
|
+
return addEventListener(this.is, arg1, arg2, arg3);
|
|
393
|
+
}
|
|
394
|
+
get(arg1, arg2) {
|
|
395
|
+
const { state } = Control.for(this);
|
|
396
|
+
const extract = typeof arg1 == "string"
|
|
397
|
+
? () => state.get(arg1)
|
|
398
|
+
: () => {
|
|
399
|
+
const output = {};
|
|
400
|
+
for (const key of arg1 || state.keys())
|
|
401
|
+
output[key] = state.get(key);
|
|
402
|
+
return output;
|
|
403
|
+
};
|
|
404
|
+
if (!arg1 || arg2 === undefined)
|
|
405
|
+
return extract();
|
|
406
|
+
if (typeof arg2 == "function")
|
|
407
|
+
return this.on(arg1, () => arg2(extract()));
|
|
408
|
+
const timeout = typeof arg2 == "number" ? arg2 : undefined;
|
|
409
|
+
return this.on(arg1, timeout).then(extract);
|
|
410
|
+
}
|
|
411
|
+
set(arg1, arg2) {
|
|
412
|
+
const control = Control.for(this);
|
|
413
|
+
if (typeof arg1 == "object")
|
|
414
|
+
for (const key in arg1) {
|
|
415
|
+
if (arg2 === true || (arg2 ? arg2.includes(key) : control.state.has(key))) {
|
|
416
|
+
control.state.set(key, arg1[key]);
|
|
417
|
+
control.update(key);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
else if (typeof arg1 == "string") {
|
|
421
|
+
control.update(arg1);
|
|
422
|
+
if (1 in arguments) {
|
|
423
|
+
if (control.state.has(arg1))
|
|
424
|
+
control.state.set(arg1, arg2);
|
|
425
|
+
else if (arg1 in this) {
|
|
426
|
+
const method = this[arg1];
|
|
427
|
+
if (typeof method == "function")
|
|
428
|
+
method.call(this, arg2);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
then: (callback) => {
|
|
434
|
+
if (!callback)
|
|
435
|
+
throw Oops$b.NoChaining();
|
|
436
|
+
control.waiting.add(callback);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Clean up side effects and mark this instance for garbage-collection.
|
|
442
|
+
*/
|
|
443
|
+
end() {
|
|
444
|
+
Control.for(this).clear();
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Creates a new instance of this controller.
|
|
448
|
+
*
|
|
449
|
+
* Beyond `new this(...)`, method will activate managed-state.
|
|
450
|
+
*
|
|
451
|
+
* @param args - arguments sent to constructor
|
|
452
|
+
*/
|
|
453
|
+
static new(...args) {
|
|
454
|
+
const instance = new this(...args);
|
|
455
|
+
Control.for(instance);
|
|
456
|
+
return instance;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Static equivalent of `x instanceof this`.
|
|
460
|
+
*
|
|
461
|
+
* Will determine if provided class is a subtype of this one.
|
|
462
|
+
*/
|
|
463
|
+
static isTypeof(maybe) {
|
|
464
|
+
return (typeof maybe == "function" &&
|
|
465
|
+
maybe.prototype instanceof this);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
defineProperty(Model.prototype, "toString", {
|
|
469
|
+
value() {
|
|
470
|
+
return this.constructor.name;
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
|
|
232
474
|
const REGISTER = new WeakMap();
|
|
233
475
|
const PENDING = new Map();
|
|
234
476
|
class Control {
|
|
@@ -257,6 +499,10 @@ class Control {
|
|
|
257
499
|
return;
|
|
258
500
|
}
|
|
259
501
|
state.set(key, value);
|
|
502
|
+
if (value instanceof Model) {
|
|
503
|
+
setRecursive(this, key, value);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
260
506
|
defineProperty(subject, key, {
|
|
261
507
|
enumerable: false,
|
|
262
508
|
set: this.ref(key),
|
|
@@ -351,6 +597,68 @@ class Control {
|
|
|
351
597
|
}
|
|
352
598
|
}
|
|
353
599
|
|
|
600
|
+
const Parent = new WeakMap();
|
|
601
|
+
const Oops$a = issues({
|
|
602
|
+
BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
|
|
603
|
+
});
|
|
604
|
+
function getRecursive(key, from) {
|
|
605
|
+
const context = new WeakMap();
|
|
606
|
+
const { state } = from;
|
|
607
|
+
return (local) => {
|
|
608
|
+
if (!local)
|
|
609
|
+
return state.get(key);
|
|
610
|
+
if (!context.has(local)) {
|
|
611
|
+
let reset;
|
|
612
|
+
const init = () => {
|
|
613
|
+
if (reset)
|
|
614
|
+
reset();
|
|
615
|
+
const value = state.get(key);
|
|
616
|
+
if (Control.get(value)) {
|
|
617
|
+
const child = Control.for(value).subscribe(local.onUpdate);
|
|
618
|
+
if (local.active)
|
|
619
|
+
child.commit();
|
|
620
|
+
local.dependant.add(child);
|
|
621
|
+
context.set(local, child.proxy);
|
|
622
|
+
reset = () => {
|
|
623
|
+
child.release();
|
|
624
|
+
local.dependant.delete(child);
|
|
625
|
+
context.set(local, undefined);
|
|
626
|
+
reset = undefined;
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
return true;
|
|
630
|
+
};
|
|
631
|
+
local.add(key, init);
|
|
632
|
+
init();
|
|
633
|
+
}
|
|
634
|
+
return context.get(local);
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
function setRecursive(control, key, initial) {
|
|
638
|
+
const { state, subject } = control;
|
|
639
|
+
const Type = initial.constructor;
|
|
640
|
+
let get;
|
|
641
|
+
const onUpdate = (next) => {
|
|
642
|
+
state.set(key, next);
|
|
643
|
+
if (!(next instanceof Type))
|
|
644
|
+
throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
|
|
645
|
+
get = getRecursive(key, control);
|
|
646
|
+
Parent.set(next, subject);
|
|
647
|
+
Control.for(next);
|
|
648
|
+
return true;
|
|
649
|
+
};
|
|
650
|
+
onUpdate(initial);
|
|
651
|
+
defineProperty(subject, key, {
|
|
652
|
+
set: control.ref(key, onUpdate),
|
|
653
|
+
get() {
|
|
654
|
+
const local = Subscriber.get(this);
|
|
655
|
+
if (local)
|
|
656
|
+
local.add(key);
|
|
657
|
+
return get(local);
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
|
|
354
662
|
/**
|
|
355
663
|
* Run instruction as controller sets itself up.
|
|
356
664
|
* This will specialize the behavior of a given property.
|
|
@@ -385,9 +693,9 @@ function add(instruction, label) {
|
|
|
385
693
|
const control = this;
|
|
386
694
|
defineProperty(subject, key, {
|
|
387
695
|
enumerable: output.enumerable,
|
|
388
|
-
set: onSet
|
|
389
|
-
?
|
|
390
|
-
:
|
|
696
|
+
set: onSet === false
|
|
697
|
+
? undefined
|
|
698
|
+
: this.ref(key, onSet),
|
|
391
699
|
get() {
|
|
392
700
|
if (!state.has(key) && shouldSuspend)
|
|
393
701
|
throw suspend(control, key);
|
|
@@ -401,39 +709,7 @@ function add(instruction, label) {
|
|
|
401
709
|
});
|
|
402
710
|
}
|
|
403
711
|
PENDING.set(placeholder, setup);
|
|
404
|
-
return placeholder;
|
|
405
|
-
}
|
|
406
|
-
function getRecursive(key, from) {
|
|
407
|
-
const context = new WeakMap();
|
|
408
|
-
return (local) => {
|
|
409
|
-
if (!local)
|
|
410
|
-
return from.state.get(key);
|
|
411
|
-
if (!context.has(local)) {
|
|
412
|
-
let reset;
|
|
413
|
-
const init = () => {
|
|
414
|
-
if (reset)
|
|
415
|
-
reset();
|
|
416
|
-
const value = from.state.get(key);
|
|
417
|
-
if (Control.get(value)) {
|
|
418
|
-
const child = Control.for(value).subscribe(local.onUpdate);
|
|
419
|
-
if (local.active)
|
|
420
|
-
child.commit();
|
|
421
|
-
local.dependant.add(child);
|
|
422
|
-
context.set(local, child.proxy);
|
|
423
|
-
reset = () => {
|
|
424
|
-
child.release();
|
|
425
|
-
local.dependant.delete(child);
|
|
426
|
-
context.set(local, undefined);
|
|
427
|
-
reset = undefined;
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
return true;
|
|
431
|
-
};
|
|
432
|
-
local.add(key, init);
|
|
433
|
-
init();
|
|
434
|
-
}
|
|
435
|
-
return context.get(local);
|
|
436
|
-
};
|
|
712
|
+
return placeholder;
|
|
437
713
|
}
|
|
438
714
|
|
|
439
715
|
/*! *****************************************************************************
|
|
@@ -461,7 +737,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
461
737
|
});
|
|
462
738
|
}
|
|
463
739
|
|
|
464
|
-
const Oops$
|
|
740
|
+
const Oops$9 = issues({
|
|
465
741
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
466
742
|
});
|
|
467
743
|
function run(task) {
|
|
@@ -469,7 +745,7 @@ function run(task) {
|
|
|
469
745
|
let pending = false;
|
|
470
746
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
471
747
|
if (pending)
|
|
472
|
-
return Promise.reject(Oops$
|
|
748
|
+
return Promise.reject(Oops$9.DuplicatePending(key));
|
|
473
749
|
pending = true;
|
|
474
750
|
this.update(key);
|
|
475
751
|
try {
|
|
@@ -491,7 +767,7 @@ function run(task) {
|
|
|
491
767
|
});
|
|
492
768
|
}
|
|
493
769
|
|
|
494
|
-
const Oops$
|
|
770
|
+
const Oops$8 = issues({
|
|
495
771
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
496
772
|
});
|
|
497
773
|
function factoryMode(self, output, key, required) {
|
|
@@ -515,7 +791,7 @@ function factoryMode(self, output, key, required) {
|
|
|
515
791
|
const suspend = () => {
|
|
516
792
|
if (required === false)
|
|
517
793
|
return undefined;
|
|
518
|
-
const issue = Oops$
|
|
794
|
+
const issue = Oops$8.NotReady(subject, key);
|
|
519
795
|
assign(pending, {
|
|
520
796
|
message: issue.message,
|
|
521
797
|
stack: issue.stack
|
|
@@ -532,7 +808,7 @@ function factoryMode(self, output, key, required) {
|
|
|
532
808
|
};
|
|
533
809
|
}
|
|
534
810
|
|
|
535
|
-
const Oops$
|
|
811
|
+
const Oops$7 = issues({
|
|
536
812
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
537
813
|
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
538
814
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
@@ -545,7 +821,7 @@ function get(arg0, arg1, arg2) {
|
|
|
545
821
|
let getter;
|
|
546
822
|
// Easy mistake, using a peer, will always be unresolved.
|
|
547
823
|
if (typeof arg0 == "symbol")
|
|
548
|
-
throw Oops$
|
|
824
|
+
throw Oops$7.PeerNotAllowed(subject, key);
|
|
549
825
|
// if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
|
|
550
826
|
// throw Oops.BadSource(subject, key, arg0);
|
|
551
827
|
this.state.set(key, undefined);
|
|
@@ -579,7 +855,7 @@ function get(arg0, arg1, arg2) {
|
|
|
579
855
|
init();
|
|
580
856
|
}
|
|
581
857
|
catch (err) {
|
|
582
|
-
Oops$
|
|
858
|
+
Oops$7.ComputeFailed(subject, key).warn();
|
|
583
859
|
throw err;
|
|
584
860
|
}
|
|
585
861
|
return () => {
|
|
@@ -590,67 +866,6 @@ function get(arg0, arg1, arg2) {
|
|
|
590
866
|
});
|
|
591
867
|
}
|
|
592
868
|
|
|
593
|
-
const Oops$9 = issues({
|
|
594
|
-
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
595
|
-
});
|
|
596
|
-
function createEffect(model, callback, keys) {
|
|
597
|
-
return Control.for(model, control => {
|
|
598
|
-
let unSet;
|
|
599
|
-
let busy = false;
|
|
600
|
-
function effect(value) {
|
|
601
|
-
if (typeof unSet == "function")
|
|
602
|
-
unSet();
|
|
603
|
-
unSet = callback.call(this, value);
|
|
604
|
-
if (unSet instanceof Promise)
|
|
605
|
-
unSet = undefined;
|
|
606
|
-
if (unSet && typeof unSet !== "function")
|
|
607
|
-
throw Oops$9.BadCallback();
|
|
608
|
-
}
|
|
609
|
-
function invoke() {
|
|
610
|
-
if (busy)
|
|
611
|
-
return;
|
|
612
|
-
const output = mayRetry(() => {
|
|
613
|
-
effect.call(model, model);
|
|
614
|
-
});
|
|
615
|
-
if (output instanceof Promise) {
|
|
616
|
-
output.finally(() => busy = false);
|
|
617
|
-
busy = true;
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
if (Array.isArray(keys)) {
|
|
621
|
-
invoke();
|
|
622
|
-
return control.addListener(key => {
|
|
623
|
-
if (key === null) {
|
|
624
|
-
if (!keys.length)
|
|
625
|
-
invoke();
|
|
626
|
-
}
|
|
627
|
-
else if (keys.includes(key))
|
|
628
|
-
return invoke;
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
const sub = control.subscribe(() => invoke);
|
|
632
|
-
model = sub.proxy;
|
|
633
|
-
invoke();
|
|
634
|
-
return sub.commit();
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
function createValueEffect(callback) {
|
|
638
|
-
let unSet;
|
|
639
|
-
return function (value) {
|
|
640
|
-
if (typeof unSet == "function")
|
|
641
|
-
unSet(value);
|
|
642
|
-
const out = callback.call(this, value, this);
|
|
643
|
-
if (typeof out == "boolean")
|
|
644
|
-
return out;
|
|
645
|
-
if (!out || out instanceof Promise)
|
|
646
|
-
return;
|
|
647
|
-
if (typeof out == "function")
|
|
648
|
-
unSet = out;
|
|
649
|
-
else
|
|
650
|
-
throw Oops$9.BadCallback();
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
|
|
654
869
|
function ref(arg, mapper) {
|
|
655
870
|
return add(function ref(key) {
|
|
656
871
|
let value = {};
|
|
@@ -845,8 +1060,7 @@ function createProxy(emit, watch) {
|
|
|
845
1060
|
};
|
|
846
1061
|
}
|
|
847
1062
|
|
|
848
|
-
const
|
|
849
|
-
const Oops$8 = issues({
|
|
1063
|
+
const Oops$6 = issues({
|
|
850
1064
|
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
851
1065
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
852
1066
|
});
|
|
@@ -858,12 +1072,11 @@ function use$1(input, argument) {
|
|
|
858
1072
|
let error;
|
|
859
1073
|
let get = (_local) => state.get(key);
|
|
860
1074
|
if (typeof input === "function") {
|
|
861
|
-
if ("prototype" in input &&
|
|
862
|
-
input === input.prototype.constructor)
|
|
1075
|
+
if ("prototype" in input && input === input.prototype.constructor)
|
|
863
1076
|
input = new input();
|
|
864
1077
|
}
|
|
865
1078
|
else if (input && typeof input !== "object")
|
|
866
|
-
throw Oops$
|
|
1079
|
+
throw Oops$6.BadArgument(typeof input);
|
|
867
1080
|
if (input instanceof Map || input instanceof Set)
|
|
868
1081
|
return keyed(this, key, input);
|
|
869
1082
|
const onUpdate = (next) => {
|
|
@@ -880,7 +1093,7 @@ function use$1(input, argument) {
|
|
|
880
1093
|
const suspend = () => {
|
|
881
1094
|
if (required === false)
|
|
882
1095
|
return;
|
|
883
|
-
const issue = Oops$
|
|
1096
|
+
const issue = Oops$6.NotReady(subject, key);
|
|
884
1097
|
assign(pending, {
|
|
885
1098
|
message: issue.message,
|
|
886
1099
|
stack: issue.stack
|
|
@@ -925,7 +1138,7 @@ function use$1(input, argument) {
|
|
|
925
1138
|
});
|
|
926
1139
|
}
|
|
927
1140
|
|
|
928
|
-
const Oops$
|
|
1141
|
+
const Oops$5 = issues({
|
|
929
1142
|
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
930
1143
|
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
931
1144
|
});
|
|
@@ -936,195 +1149,14 @@ function has(Type, required) {
|
|
|
936
1149
|
const expected = Type.name;
|
|
937
1150
|
if (!value) {
|
|
938
1151
|
if (required !== false)
|
|
939
|
-
throw Oops$
|
|
1152
|
+
throw Oops$5.Required(expected, child);
|
|
940
1153
|
}
|
|
941
1154
|
else if (!(value instanceof Type))
|
|
942
|
-
throw Oops$
|
|
1155
|
+
throw Oops$5.Unexpected(expected, child, value);
|
|
943
1156
|
return { value };
|
|
944
1157
|
});
|
|
945
1158
|
}
|
|
946
1159
|
|
|
947
|
-
const Oops$6 = issues({
|
|
948
|
-
Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
|
|
949
|
-
KeysExpected: (key) => `Key "${key}" was expected in current update.`,
|
|
950
|
-
StrictUpdate: () => `Expected update but none in progress.`,
|
|
951
|
-
StrictNoUpdate: () => `Update is not expected but one is in progress!`
|
|
952
|
-
});
|
|
953
|
-
function addEventListener(source, arg1, arg2, arg3) {
|
|
954
|
-
if (typeof arg1 == "string")
|
|
955
|
-
arg1 = [arg1];
|
|
956
|
-
return Control.for(source, control => {
|
|
957
|
-
for (const key of arg1)
|
|
958
|
-
try {
|
|
959
|
-
void source[key];
|
|
960
|
-
}
|
|
961
|
-
catch (e) { }
|
|
962
|
-
const removeListener = control.addListener(key => {
|
|
963
|
-
if (!key && !arg1.length)
|
|
964
|
-
arg2.call(source, []);
|
|
965
|
-
if (arg1.includes(key)) {
|
|
966
|
-
if (arg3)
|
|
967
|
-
removeListener();
|
|
968
|
-
return arg2.bind(source);
|
|
969
|
-
}
|
|
970
|
-
});
|
|
971
|
-
return removeListener;
|
|
972
|
-
});
|
|
973
|
-
}
|
|
974
|
-
function awaitUpdate(source, arg1, arg2) {
|
|
975
|
-
const single = typeof arg1 == "string";
|
|
976
|
-
const keys = typeof arg1 == "string" ? [arg1] :
|
|
977
|
-
typeof arg1 == "object" ? arg1 :
|
|
978
|
-
undefined;
|
|
979
|
-
return new Promise((resolve, reject) => {
|
|
980
|
-
const timeout = (message) => {
|
|
981
|
-
const k = keys ? keys.join(", ") : "any";
|
|
982
|
-
removeListener();
|
|
983
|
-
reject(Oops$6.Timeout(k, message));
|
|
984
|
-
};
|
|
985
|
-
const removeListener = Control.for(source, control => {
|
|
986
|
-
const pending = control.frame;
|
|
987
|
-
if (keys === null) {
|
|
988
|
-
if (pending.size)
|
|
989
|
-
reject(Oops$6.StrictNoUpdate());
|
|
990
|
-
else
|
|
991
|
-
resolve(null);
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
if (keys) {
|
|
995
|
-
if (keys.length) {
|
|
996
|
-
if (arg2 === 0 && single && !pending.has(keys[0])) {
|
|
997
|
-
reject(Oops$6.KeysExpected(keys[0]));
|
|
998
|
-
return;
|
|
999
|
-
}
|
|
1000
|
-
else
|
|
1001
|
-
for (const key of keys)
|
|
1002
|
-
try {
|
|
1003
|
-
void source[key];
|
|
1004
|
-
}
|
|
1005
|
-
catch (e) { }
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
else if (!pending.size && arg1 === true || arg2 === 0) {
|
|
1009
|
-
reject(Oops$6.StrictUpdate());
|
|
1010
|
-
return;
|
|
1011
|
-
}
|
|
1012
|
-
else
|
|
1013
|
-
control.waiting.add(resolve);
|
|
1014
|
-
return control.addListener(key => {
|
|
1015
|
-
if (!key) {
|
|
1016
|
-
if (keys && !keys.length)
|
|
1017
|
-
resolve([]);
|
|
1018
|
-
else
|
|
1019
|
-
timeout(`lifetime of ${source}`);
|
|
1020
|
-
}
|
|
1021
|
-
else if (!keys || keys.includes(key)) {
|
|
1022
|
-
removeListener();
|
|
1023
|
-
return keys => resolve(single ? control.state.get(key) : keys);
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
});
|
|
1027
|
-
if (arg2 && typeof arg2 == "number")
|
|
1028
|
-
setTimeout(() => timeout(`${arg2}ms`), arg2);
|
|
1029
|
-
});
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
const Oops$5 = issues({
|
|
1033
|
-
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
1034
|
-
});
|
|
1035
|
-
class Model {
|
|
1036
|
-
constructor() {
|
|
1037
|
-
new Control(this);
|
|
1038
|
-
defineProperty(this, "is", { value: this });
|
|
1039
|
-
}
|
|
1040
|
-
on(arg1, arg2, arg3) {
|
|
1041
|
-
if (typeof arg1 == "function")
|
|
1042
|
-
return createEffect(this.is, arg1, arg2);
|
|
1043
|
-
if (typeof arg2 != "function")
|
|
1044
|
-
return awaitUpdate(this.is, arg1, arg2);
|
|
1045
|
-
if (arg1)
|
|
1046
|
-
return addEventListener(this.is, arg1, arg2, arg3);
|
|
1047
|
-
}
|
|
1048
|
-
get(arg1, arg2) {
|
|
1049
|
-
const { state } = Control.for(this);
|
|
1050
|
-
const extract = typeof arg1 == "string"
|
|
1051
|
-
? () => state.get(arg1)
|
|
1052
|
-
: () => {
|
|
1053
|
-
const output = {};
|
|
1054
|
-
for (const key of arg1 || state.keys())
|
|
1055
|
-
output[key] = state.get(key);
|
|
1056
|
-
return output;
|
|
1057
|
-
};
|
|
1058
|
-
if (!arg1 || arg2 === undefined)
|
|
1059
|
-
return extract();
|
|
1060
|
-
if (typeof arg2 == "function")
|
|
1061
|
-
return this.on(arg1, () => arg2(extract()));
|
|
1062
|
-
const timeout = typeof arg2 == "number" ? arg2 : undefined;
|
|
1063
|
-
return this.on(arg1, timeout).then(extract);
|
|
1064
|
-
}
|
|
1065
|
-
set(arg1, arg2) {
|
|
1066
|
-
const control = Control.for(this);
|
|
1067
|
-
if (typeof arg1 == "object")
|
|
1068
|
-
for (const key in arg1) {
|
|
1069
|
-
if (arg2 === true || (arg2 ? arg2.includes(key) : control.state.has(key))) {
|
|
1070
|
-
control.state.set(key, arg1[key]);
|
|
1071
|
-
control.update(key);
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
else if (typeof arg1 == "string") {
|
|
1075
|
-
control.update(arg1);
|
|
1076
|
-
if (1 in arguments) {
|
|
1077
|
-
if (control.state.has(arg1))
|
|
1078
|
-
control.state.set(arg1, arg2);
|
|
1079
|
-
else if (arg1 in this) {
|
|
1080
|
-
const method = this[arg1];
|
|
1081
|
-
if (typeof method == "function")
|
|
1082
|
-
method.call(this, arg2);
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
return {
|
|
1087
|
-
then: (callback) => {
|
|
1088
|
-
if (!callback)
|
|
1089
|
-
throw Oops$5.NoChaining();
|
|
1090
|
-
control.waiting.add(callback);
|
|
1091
|
-
}
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
/**
|
|
1095
|
-
* Clean up side effects and mark this instance for garbage-collection.
|
|
1096
|
-
*/
|
|
1097
|
-
end() {
|
|
1098
|
-
Control.for(this).clear();
|
|
1099
|
-
}
|
|
1100
|
-
/**
|
|
1101
|
-
* Creates a new instance of this controller.
|
|
1102
|
-
*
|
|
1103
|
-
* Beyond `new this(...)`, method will activate managed-state.
|
|
1104
|
-
*
|
|
1105
|
-
* @param args - arguments sent to constructor
|
|
1106
|
-
*/
|
|
1107
|
-
static new(...args) {
|
|
1108
|
-
const instance = new this(...args);
|
|
1109
|
-
Control.for(instance);
|
|
1110
|
-
return instance;
|
|
1111
|
-
}
|
|
1112
|
-
/**
|
|
1113
|
-
* Static equivalent of `x instanceof this`.
|
|
1114
|
-
*
|
|
1115
|
-
* Will determine if provided class is a subtype of this one.
|
|
1116
|
-
*/
|
|
1117
|
-
static isTypeof(maybe) {
|
|
1118
|
-
return (typeof maybe == "function" &&
|
|
1119
|
-
maybe.prototype instanceof this);
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
defineProperty(Model.prototype, "toString", {
|
|
1123
|
-
value() {
|
|
1124
|
-
return this.constructor.name;
|
|
1125
|
-
}
|
|
1126
|
-
});
|
|
1127
|
-
|
|
1128
1160
|
const Oops$4 = issues({
|
|
1129
1161
|
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1130
1162
|
});
|
|
@@ -1146,7 +1178,19 @@ class Lookup {
|
|
|
1146
1178
|
get(T) {
|
|
1147
1179
|
return this[this.key(T)];
|
|
1148
1180
|
}
|
|
1149
|
-
add(
|
|
1181
|
+
add(input) {
|
|
1182
|
+
let writable = true;
|
|
1183
|
+
let T;
|
|
1184
|
+
let I;
|
|
1185
|
+
if (typeof input == "function") {
|
|
1186
|
+
T = input;
|
|
1187
|
+
I = input.new();
|
|
1188
|
+
}
|
|
1189
|
+
else {
|
|
1190
|
+
I = input;
|
|
1191
|
+
T = I.constructor;
|
|
1192
|
+
writable = false;
|
|
1193
|
+
}
|
|
1150
1194
|
do {
|
|
1151
1195
|
const key = this.key(T);
|
|
1152
1196
|
const conflict = this.hasOwnProperty(key);
|
|
@@ -1157,6 +1201,10 @@ class Lookup {
|
|
|
1157
1201
|
});
|
|
1158
1202
|
T = getPrototypeOf(T);
|
|
1159
1203
|
} while (T !== Model);
|
|
1204
|
+
Control.for(I).state.forEach(value => {
|
|
1205
|
+
if (value instanceof Model)
|
|
1206
|
+
this.add(value);
|
|
1207
|
+
});
|
|
1160
1208
|
}
|
|
1161
1209
|
push() {
|
|
1162
1210
|
return create(this);
|
|
@@ -1246,9 +1294,9 @@ function use(init) {
|
|
|
1246
1294
|
function useNew(source, arg1, arg2) {
|
|
1247
1295
|
const instance = React.useMemo(() => {
|
|
1248
1296
|
const callback = arg2 || arg1;
|
|
1249
|
-
const instance = Model.isTypeof(source)
|
|
1250
|
-
source
|
|
1251
|
-
source();
|
|
1297
|
+
const instance = Model.isTypeof(source)
|
|
1298
|
+
? new source()
|
|
1299
|
+
: source();
|
|
1252
1300
|
Control.for(instance);
|
|
1253
1301
|
if (typeof callback == "function")
|
|
1254
1302
|
callback(instance);
|
|
@@ -1456,28 +1504,22 @@ function useNewContext(include, assign) {
|
|
|
1456
1504
|
if (!include)
|
|
1457
1505
|
throw Oops.NoType();
|
|
1458
1506
|
const next = ambient.push();
|
|
1459
|
-
function register(I) {
|
|
1460
|
-
if (I instanceof Model)
|
|
1461
|
-
next.add(I.constructor, I, false);
|
|
1462
|
-
else
|
|
1463
|
-
next.add(I, I.new(), true);
|
|
1464
|
-
}
|
|
1465
1507
|
if (include instanceof Model || typeof include == "function")
|
|
1466
|
-
|
|
1508
|
+
next.add(include);
|
|
1467
1509
|
else
|
|
1468
|
-
values(include).forEach(
|
|
1510
|
+
values(include).forEach(x => next.add(x));
|
|
1469
1511
|
for (const instance of next.local)
|
|
1470
|
-
if (instance)
|
|
1512
|
+
if (instance) {
|
|
1513
|
+
if (assign)
|
|
1514
|
+
assignWeak(instance, assign);
|
|
1471
1515
|
for (const apply of getPending(instance))
|
|
1472
1516
|
apply(next);
|
|
1517
|
+
}
|
|
1473
1518
|
return next;
|
|
1474
1519
|
}, []);
|
|
1475
|
-
if (assign)
|
|
1476
|
-
for (const
|
|
1477
|
-
|
|
1478
|
-
if (into && key in into)
|
|
1479
|
-
into[key] = assign[key];
|
|
1480
|
-
}
|
|
1520
|
+
if (assign)
|
|
1521
|
+
for (const into of context.local)
|
|
1522
|
+
assignWeak(into, assign);
|
|
1481
1523
|
return context;
|
|
1482
1524
|
}
|
|
1483
1525
|
function RenderFunction(props) {
|
|
@@ -1490,6 +1532,11 @@ function RenderFunction(props) {
|
|
|
1490
1532
|
if (hook.commit)
|
|
1491
1533
|
React.useLayoutEffect(hook.commit, []);
|
|
1492
1534
|
return props.render(hook.proxy);
|
|
1535
|
+
}
|
|
1536
|
+
function assignWeak(into, from) {
|
|
1537
|
+
for (const K in from)
|
|
1538
|
+
if (K in into)
|
|
1539
|
+
into[K] = from[K];
|
|
1493
1540
|
}
|
|
1494
1541
|
|
|
1495
1542
|
class Global extends MVC {
|