@expressive/mvc 0.10.0 → 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 +44 -40
- package/lib/index.esm.js +367 -318
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +367 -318
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -30,11 +30,11 @@ function issues(register) {
|
|
|
30
30
|
return Library;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
const Oops$
|
|
33
|
+
const Oops$f = issues({
|
|
34
34
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
35
35
|
});
|
|
36
36
|
function suspend(source, key) {
|
|
37
|
-
const error = Oops$
|
|
37
|
+
const error = Oops$f.NotReady(source.subject, key);
|
|
38
38
|
const promise = new Promise(resolve => {
|
|
39
39
|
const release = source.addListener(forKey => {
|
|
40
40
|
if (forKey == key)
|
|
@@ -74,7 +74,7 @@ function mayRetry(fn) {
|
|
|
74
74
|
return compute();
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const Oops$
|
|
77
|
+
const Oops$e = issues({
|
|
78
78
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
79
79
|
});
|
|
80
80
|
const INFO = new WeakMap();
|
|
@@ -94,7 +94,7 @@ function computeMode(self, source, setter, key, required) {
|
|
|
94
94
|
return setter.call(sub.proxy, sub.proxy);
|
|
95
95
|
}
|
|
96
96
|
catch (err) {
|
|
97
|
-
Oops$
|
|
97
|
+
Oops$e.Failed(subject, key, initial).warn();
|
|
98
98
|
throw err;
|
|
99
99
|
}
|
|
100
100
|
};
|
|
@@ -165,6 +165,152 @@ function flush(control) {
|
|
|
165
165
|
pending.clear();
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
const Oops$d = issues({
|
|
169
|
+
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
170
|
+
});
|
|
171
|
+
function createEffect(model, callback, keys) {
|
|
172
|
+
return Control.for(model, control => {
|
|
173
|
+
let unSet;
|
|
174
|
+
let busy = false;
|
|
175
|
+
function effect(value) {
|
|
176
|
+
if (typeof unSet == "function")
|
|
177
|
+
unSet();
|
|
178
|
+
unSet = callback.call(this, value);
|
|
179
|
+
if (unSet instanceof Promise)
|
|
180
|
+
unSet = undefined;
|
|
181
|
+
if (unSet && typeof unSet !== "function")
|
|
182
|
+
throw Oops$d.BadCallback();
|
|
183
|
+
}
|
|
184
|
+
function invoke() {
|
|
185
|
+
if (busy)
|
|
186
|
+
return;
|
|
187
|
+
const output = mayRetry(() => {
|
|
188
|
+
effect.call(model, model);
|
|
189
|
+
});
|
|
190
|
+
if (output instanceof Promise) {
|
|
191
|
+
output.finally(() => busy = false);
|
|
192
|
+
busy = true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (Array.isArray(keys)) {
|
|
196
|
+
invoke();
|
|
197
|
+
return control.addListener(key => {
|
|
198
|
+
if (key === null) {
|
|
199
|
+
if (!keys.length)
|
|
200
|
+
invoke();
|
|
201
|
+
}
|
|
202
|
+
else if (keys.includes(key))
|
|
203
|
+
return invoke;
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
const sub = control.subscribe(() => invoke);
|
|
207
|
+
model = sub.proxy;
|
|
208
|
+
invoke();
|
|
209
|
+
return sub.commit();
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function createValueEffect(callback) {
|
|
213
|
+
let unSet;
|
|
214
|
+
return function (value) {
|
|
215
|
+
if (typeof unSet == "function")
|
|
216
|
+
unSet(value);
|
|
217
|
+
const out = callback.call(this, value, this);
|
|
218
|
+
if (typeof out == "boolean")
|
|
219
|
+
return out;
|
|
220
|
+
if (!out || out instanceof Promise)
|
|
221
|
+
return;
|
|
222
|
+
if (typeof out == "function")
|
|
223
|
+
unSet = out;
|
|
224
|
+
else
|
|
225
|
+
throw Oops$d.BadCallback();
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const Oops$c = issues({
|
|
230
|
+
Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
|
|
231
|
+
KeysExpected: (key) => `Key "${key}" was expected in current update.`,
|
|
232
|
+
StrictUpdate: () => `Expected update but none in progress.`,
|
|
233
|
+
StrictNoUpdate: () => `Update is not expected but one is in progress!`
|
|
234
|
+
});
|
|
235
|
+
function addEventListener(source, arg1, arg2, arg3) {
|
|
236
|
+
if (typeof arg1 == "string")
|
|
237
|
+
arg1 = [arg1];
|
|
238
|
+
return Control.for(source, control => {
|
|
239
|
+
for (const key of arg1)
|
|
240
|
+
try {
|
|
241
|
+
void source[key];
|
|
242
|
+
}
|
|
243
|
+
catch (e) { }
|
|
244
|
+
const removeListener = control.addListener(key => {
|
|
245
|
+
if (!key && !arg1.length)
|
|
246
|
+
arg2.call(source, []);
|
|
247
|
+
if (arg1.includes(key)) {
|
|
248
|
+
if (arg3)
|
|
249
|
+
removeListener();
|
|
250
|
+
return arg2.bind(source);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
return removeListener;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function awaitUpdate(source, arg1, arg2) {
|
|
257
|
+
const single = typeof arg1 == "string";
|
|
258
|
+
const keys = typeof arg1 == "string" ? [arg1] :
|
|
259
|
+
typeof arg1 == "object" ? arg1 :
|
|
260
|
+
undefined;
|
|
261
|
+
return new Promise((resolve, reject) => {
|
|
262
|
+
const timeout = (message) => {
|
|
263
|
+
const k = keys ? keys.join(", ") : "any";
|
|
264
|
+
removeListener();
|
|
265
|
+
reject(Oops$c.Timeout(k, message));
|
|
266
|
+
};
|
|
267
|
+
const removeListener = Control.for(source, control => {
|
|
268
|
+
const pending = control.frame;
|
|
269
|
+
if (keys === null) {
|
|
270
|
+
if (pending.size)
|
|
271
|
+
reject(Oops$c.StrictNoUpdate());
|
|
272
|
+
else
|
|
273
|
+
resolve(null);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (keys) {
|
|
277
|
+
if (keys.length) {
|
|
278
|
+
if (arg2 === 0 && single && !pending.has(keys[0])) {
|
|
279
|
+
reject(Oops$c.KeysExpected(keys[0]));
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
else
|
|
283
|
+
for (const key of keys)
|
|
284
|
+
try {
|
|
285
|
+
void source[key];
|
|
286
|
+
}
|
|
287
|
+
catch (e) { }
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
else if (!pending.size && arg1 === true || arg2 === 0) {
|
|
291
|
+
reject(Oops$c.StrictUpdate());
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
else
|
|
295
|
+
control.waiting.add(resolve);
|
|
296
|
+
return control.addListener(key => {
|
|
297
|
+
if (!key) {
|
|
298
|
+
if (keys && !keys.length)
|
|
299
|
+
resolve([]);
|
|
300
|
+
else
|
|
301
|
+
timeout(`lifetime of ${source}`);
|
|
302
|
+
}
|
|
303
|
+
else if (!keys || keys.includes(key)) {
|
|
304
|
+
removeListener();
|
|
305
|
+
return keys => resolve(single ? control.state.get(key) : keys);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
if (arg2 && typeof arg2 == "number")
|
|
310
|
+
setTimeout(() => timeout(`${arg2}ms`), arg2);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
168
314
|
const REGISTER$1 = new WeakMap();
|
|
169
315
|
class Subscriber {
|
|
170
316
|
constructor(parent, onUpdate) {
|
|
@@ -237,6 +383,102 @@ class Subscriber {
|
|
|
237
383
|
}
|
|
238
384
|
}
|
|
239
385
|
|
|
386
|
+
const Oops$b = issues({
|
|
387
|
+
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
388
|
+
});
|
|
389
|
+
class Model {
|
|
390
|
+
constructor() {
|
|
391
|
+
new Control(this);
|
|
392
|
+
defineProperty(this, "is", { value: this });
|
|
393
|
+
}
|
|
394
|
+
on(arg1, arg2, arg3) {
|
|
395
|
+
if (typeof arg1 == "function")
|
|
396
|
+
return createEffect(this.is, arg1, arg2);
|
|
397
|
+
if (typeof arg2 != "function")
|
|
398
|
+
return awaitUpdate(this.is, arg1, arg2);
|
|
399
|
+
if (arg1)
|
|
400
|
+
return addEventListener(this.is, arg1, arg2, arg3);
|
|
401
|
+
}
|
|
402
|
+
get(arg1, arg2) {
|
|
403
|
+
const { state } = Control.for(this);
|
|
404
|
+
const extract = typeof arg1 == "string"
|
|
405
|
+
? () => state.get(arg1)
|
|
406
|
+
: () => {
|
|
407
|
+
const output = {};
|
|
408
|
+
for (const key of arg1 || state.keys())
|
|
409
|
+
output[key] = state.get(key);
|
|
410
|
+
return output;
|
|
411
|
+
};
|
|
412
|
+
if (!arg1 || arg2 === undefined)
|
|
413
|
+
return extract();
|
|
414
|
+
if (typeof arg2 == "function")
|
|
415
|
+
return this.on(arg1, () => arg2(extract()));
|
|
416
|
+
const timeout = typeof arg2 == "number" ? arg2 : undefined;
|
|
417
|
+
return this.on(arg1, timeout).then(extract);
|
|
418
|
+
}
|
|
419
|
+
set(arg1, arg2) {
|
|
420
|
+
const control = Control.for(this);
|
|
421
|
+
if (typeof arg1 == "object")
|
|
422
|
+
for (const key in arg1) {
|
|
423
|
+
if (arg2 === true || (arg2 ? arg2.includes(key) : control.state.has(key))) {
|
|
424
|
+
control.state.set(key, arg1[key]);
|
|
425
|
+
control.update(key);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
else if (typeof arg1 == "string") {
|
|
429
|
+
control.update(arg1);
|
|
430
|
+
if (1 in arguments) {
|
|
431
|
+
if (control.state.has(arg1))
|
|
432
|
+
control.state.set(arg1, arg2);
|
|
433
|
+
else if (arg1 in this) {
|
|
434
|
+
const method = this[arg1];
|
|
435
|
+
if (typeof method == "function")
|
|
436
|
+
method.call(this, arg2);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return {
|
|
441
|
+
then: (callback) => {
|
|
442
|
+
if (!callback)
|
|
443
|
+
throw Oops$b.NoChaining();
|
|
444
|
+
control.waiting.add(callback);
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Clean up side effects and mark this instance for garbage-collection.
|
|
450
|
+
*/
|
|
451
|
+
end() {
|
|
452
|
+
Control.for(this).clear();
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Creates a new instance of this controller.
|
|
456
|
+
*
|
|
457
|
+
* Beyond `new this(...)`, method will activate managed-state.
|
|
458
|
+
*
|
|
459
|
+
* @param args - arguments sent to constructor
|
|
460
|
+
*/
|
|
461
|
+
static new(...args) {
|
|
462
|
+
const instance = new this(...args);
|
|
463
|
+
Control.for(instance);
|
|
464
|
+
return instance;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Static equivalent of `x instanceof this`.
|
|
468
|
+
*
|
|
469
|
+
* Will determine if provided class is a subtype of this one.
|
|
470
|
+
*/
|
|
471
|
+
static isTypeof(maybe) {
|
|
472
|
+
return (typeof maybe == "function" &&
|
|
473
|
+
maybe.prototype instanceof this);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
defineProperty(Model.prototype, "toString", {
|
|
477
|
+
value() {
|
|
478
|
+
return this.constructor.name;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
|
|
240
482
|
const REGISTER = new WeakMap();
|
|
241
483
|
const PENDING = new Map();
|
|
242
484
|
class Control {
|
|
@@ -265,6 +507,10 @@ class Control {
|
|
|
265
507
|
return;
|
|
266
508
|
}
|
|
267
509
|
state.set(key, value);
|
|
510
|
+
if (value instanceof Model) {
|
|
511
|
+
setRecursive(this, key, value);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
268
514
|
defineProperty(subject, key, {
|
|
269
515
|
enumerable: false,
|
|
270
516
|
set: this.ref(key),
|
|
@@ -359,6 +605,68 @@ class Control {
|
|
|
359
605
|
}
|
|
360
606
|
}
|
|
361
607
|
|
|
608
|
+
const Parent = new WeakMap();
|
|
609
|
+
const Oops$a = issues({
|
|
610
|
+
BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
|
|
611
|
+
});
|
|
612
|
+
function getRecursive(key, from) {
|
|
613
|
+
const context = new WeakMap();
|
|
614
|
+
const { state } = from;
|
|
615
|
+
return (local) => {
|
|
616
|
+
if (!local)
|
|
617
|
+
return state.get(key);
|
|
618
|
+
if (!context.has(local)) {
|
|
619
|
+
let reset;
|
|
620
|
+
const init = () => {
|
|
621
|
+
if (reset)
|
|
622
|
+
reset();
|
|
623
|
+
const value = state.get(key);
|
|
624
|
+
if (Control.get(value)) {
|
|
625
|
+
const child = Control.for(value).subscribe(local.onUpdate);
|
|
626
|
+
if (local.active)
|
|
627
|
+
child.commit();
|
|
628
|
+
local.dependant.add(child);
|
|
629
|
+
context.set(local, child.proxy);
|
|
630
|
+
reset = () => {
|
|
631
|
+
child.release();
|
|
632
|
+
local.dependant.delete(child);
|
|
633
|
+
context.set(local, undefined);
|
|
634
|
+
reset = undefined;
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
return true;
|
|
638
|
+
};
|
|
639
|
+
local.add(key, init);
|
|
640
|
+
init();
|
|
641
|
+
}
|
|
642
|
+
return context.get(local);
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
function setRecursive(control, key, initial) {
|
|
646
|
+
const { state, subject } = control;
|
|
647
|
+
const Type = initial.constructor;
|
|
648
|
+
let get;
|
|
649
|
+
const onUpdate = (next) => {
|
|
650
|
+
state.set(key, next);
|
|
651
|
+
if (!(next instanceof Type))
|
|
652
|
+
throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
|
|
653
|
+
get = getRecursive(key, control);
|
|
654
|
+
Parent.set(next, subject);
|
|
655
|
+
Control.for(next);
|
|
656
|
+
return true;
|
|
657
|
+
};
|
|
658
|
+
onUpdate(initial);
|
|
659
|
+
defineProperty(subject, key, {
|
|
660
|
+
set: control.ref(key, onUpdate),
|
|
661
|
+
get() {
|
|
662
|
+
const local = Subscriber.get(this);
|
|
663
|
+
if (local)
|
|
664
|
+
local.add(key);
|
|
665
|
+
return get(local);
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
|
|
362
670
|
/**
|
|
363
671
|
* Run instruction as controller sets itself up.
|
|
364
672
|
* This will specialize the behavior of a given property.
|
|
@@ -393,9 +701,9 @@ function add(instruction, label) {
|
|
|
393
701
|
const control = this;
|
|
394
702
|
defineProperty(subject, key, {
|
|
395
703
|
enumerable: output.enumerable,
|
|
396
|
-
set: onSet
|
|
397
|
-
?
|
|
398
|
-
:
|
|
704
|
+
set: onSet === false
|
|
705
|
+
? undefined
|
|
706
|
+
: this.ref(key, onSet),
|
|
399
707
|
get() {
|
|
400
708
|
if (!state.has(key) && shouldSuspend)
|
|
401
709
|
throw suspend(control, key);
|
|
@@ -410,38 +718,6 @@ function add(instruction, label) {
|
|
|
410
718
|
}
|
|
411
719
|
PENDING.set(placeholder, setup);
|
|
412
720
|
return placeholder;
|
|
413
|
-
}
|
|
414
|
-
function getRecursive(key, from) {
|
|
415
|
-
const context = new WeakMap();
|
|
416
|
-
return (local) => {
|
|
417
|
-
if (!local)
|
|
418
|
-
return from.state.get(key);
|
|
419
|
-
if (!context.has(local)) {
|
|
420
|
-
let reset;
|
|
421
|
-
const init = () => {
|
|
422
|
-
if (reset)
|
|
423
|
-
reset();
|
|
424
|
-
const value = from.state.get(key);
|
|
425
|
-
if (Control.get(value)) {
|
|
426
|
-
const child = Control.for(value).subscribe(local.onUpdate);
|
|
427
|
-
if (local.active)
|
|
428
|
-
child.commit();
|
|
429
|
-
local.dependant.add(child);
|
|
430
|
-
context.set(local, child.proxy);
|
|
431
|
-
reset = () => {
|
|
432
|
-
child.release();
|
|
433
|
-
local.dependant.delete(child);
|
|
434
|
-
context.set(local, undefined);
|
|
435
|
-
reset = undefined;
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
return true;
|
|
439
|
-
};
|
|
440
|
-
local.add(key, init);
|
|
441
|
-
init();
|
|
442
|
-
}
|
|
443
|
-
return context.get(local);
|
|
444
|
-
};
|
|
445
721
|
}
|
|
446
722
|
|
|
447
723
|
/*! *****************************************************************************
|
|
@@ -469,7 +745,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
469
745
|
});
|
|
470
746
|
}
|
|
471
747
|
|
|
472
|
-
const Oops$
|
|
748
|
+
const Oops$9 = issues({
|
|
473
749
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
474
750
|
});
|
|
475
751
|
function run(task) {
|
|
@@ -477,7 +753,7 @@ function run(task) {
|
|
|
477
753
|
let pending = false;
|
|
478
754
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
479
755
|
if (pending)
|
|
480
|
-
return Promise.reject(Oops$
|
|
756
|
+
return Promise.reject(Oops$9.DuplicatePending(key));
|
|
481
757
|
pending = true;
|
|
482
758
|
this.update(key);
|
|
483
759
|
try {
|
|
@@ -499,7 +775,7 @@ function run(task) {
|
|
|
499
775
|
});
|
|
500
776
|
}
|
|
501
777
|
|
|
502
|
-
const Oops$
|
|
778
|
+
const Oops$8 = issues({
|
|
503
779
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
504
780
|
});
|
|
505
781
|
function factoryMode(self, output, key, required) {
|
|
@@ -523,7 +799,7 @@ function factoryMode(self, output, key, required) {
|
|
|
523
799
|
const suspend = () => {
|
|
524
800
|
if (required === false)
|
|
525
801
|
return undefined;
|
|
526
|
-
const issue = Oops$
|
|
802
|
+
const issue = Oops$8.NotReady(subject, key);
|
|
527
803
|
assign(pending, {
|
|
528
804
|
message: issue.message,
|
|
529
805
|
stack: issue.stack
|
|
@@ -540,7 +816,7 @@ function factoryMode(self, output, key, required) {
|
|
|
540
816
|
};
|
|
541
817
|
}
|
|
542
818
|
|
|
543
|
-
const Oops$
|
|
819
|
+
const Oops$7 = issues({
|
|
544
820
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
545
821
|
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
546
822
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
@@ -553,7 +829,7 @@ function get(arg0, arg1, arg2) {
|
|
|
553
829
|
let getter;
|
|
554
830
|
// Easy mistake, using a peer, will always be unresolved.
|
|
555
831
|
if (typeof arg0 == "symbol")
|
|
556
|
-
throw Oops$
|
|
832
|
+
throw Oops$7.PeerNotAllowed(subject, key);
|
|
557
833
|
// if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
|
|
558
834
|
// throw Oops.BadSource(subject, key, arg0);
|
|
559
835
|
this.state.set(key, undefined);
|
|
@@ -587,7 +863,7 @@ function get(arg0, arg1, arg2) {
|
|
|
587
863
|
init();
|
|
588
864
|
}
|
|
589
865
|
catch (err) {
|
|
590
|
-
Oops$
|
|
866
|
+
Oops$7.ComputeFailed(subject, key).warn();
|
|
591
867
|
throw err;
|
|
592
868
|
}
|
|
593
869
|
return () => {
|
|
@@ -598,67 +874,6 @@ function get(arg0, arg1, arg2) {
|
|
|
598
874
|
});
|
|
599
875
|
}
|
|
600
876
|
|
|
601
|
-
const Oops$9 = issues({
|
|
602
|
-
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
603
|
-
});
|
|
604
|
-
function createEffect(model, callback, keys) {
|
|
605
|
-
return Control.for(model, control => {
|
|
606
|
-
let unSet;
|
|
607
|
-
let busy = false;
|
|
608
|
-
function effect(value) {
|
|
609
|
-
if (typeof unSet == "function")
|
|
610
|
-
unSet();
|
|
611
|
-
unSet = callback.call(this, value);
|
|
612
|
-
if (unSet instanceof Promise)
|
|
613
|
-
unSet = undefined;
|
|
614
|
-
if (unSet && typeof unSet !== "function")
|
|
615
|
-
throw Oops$9.BadCallback();
|
|
616
|
-
}
|
|
617
|
-
function invoke() {
|
|
618
|
-
if (busy)
|
|
619
|
-
return;
|
|
620
|
-
const output = mayRetry(() => {
|
|
621
|
-
effect.call(model, model);
|
|
622
|
-
});
|
|
623
|
-
if (output instanceof Promise) {
|
|
624
|
-
output.finally(() => busy = false);
|
|
625
|
-
busy = true;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
if (Array.isArray(keys)) {
|
|
629
|
-
invoke();
|
|
630
|
-
return control.addListener(key => {
|
|
631
|
-
if (key === null) {
|
|
632
|
-
if (!keys.length)
|
|
633
|
-
invoke();
|
|
634
|
-
}
|
|
635
|
-
else if (keys.includes(key))
|
|
636
|
-
return invoke;
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
const sub = control.subscribe(() => invoke);
|
|
640
|
-
model = sub.proxy;
|
|
641
|
-
invoke();
|
|
642
|
-
return sub.commit();
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
function createValueEffect(callback) {
|
|
646
|
-
let unSet;
|
|
647
|
-
return function (value) {
|
|
648
|
-
if (typeof unSet == "function")
|
|
649
|
-
unSet(value);
|
|
650
|
-
const out = callback.call(this, value, this);
|
|
651
|
-
if (typeof out == "boolean")
|
|
652
|
-
return out;
|
|
653
|
-
if (!out || out instanceof Promise)
|
|
654
|
-
return;
|
|
655
|
-
if (typeof out == "function")
|
|
656
|
-
unSet = out;
|
|
657
|
-
else
|
|
658
|
-
throw Oops$9.BadCallback();
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
|
|
662
877
|
function ref(arg, mapper) {
|
|
663
878
|
return add(function ref(key) {
|
|
664
879
|
let value = {};
|
|
@@ -853,8 +1068,7 @@ function createProxy(emit, watch) {
|
|
|
853
1068
|
};
|
|
854
1069
|
}
|
|
855
1070
|
|
|
856
|
-
const
|
|
857
|
-
const Oops$8 = issues({
|
|
1071
|
+
const Oops$6 = issues({
|
|
858
1072
|
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
859
1073
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
860
1074
|
});
|
|
@@ -866,12 +1080,11 @@ function use$1(input, argument) {
|
|
|
866
1080
|
let error;
|
|
867
1081
|
let get = (_local) => state.get(key);
|
|
868
1082
|
if (typeof input === "function") {
|
|
869
|
-
if ("prototype" in input &&
|
|
870
|
-
input === input.prototype.constructor)
|
|
1083
|
+
if ("prototype" in input && input === input.prototype.constructor)
|
|
871
1084
|
input = new input();
|
|
872
1085
|
}
|
|
873
1086
|
else if (input && typeof input !== "object")
|
|
874
|
-
throw Oops$
|
|
1087
|
+
throw Oops$6.BadArgument(typeof input);
|
|
875
1088
|
if (input instanceof Map || input instanceof Set)
|
|
876
1089
|
return keyed(this, key, input);
|
|
877
1090
|
const onUpdate = (next) => {
|
|
@@ -888,7 +1101,7 @@ function use$1(input, argument) {
|
|
|
888
1101
|
const suspend = () => {
|
|
889
1102
|
if (required === false)
|
|
890
1103
|
return;
|
|
891
|
-
const issue = Oops$
|
|
1104
|
+
const issue = Oops$6.NotReady(subject, key);
|
|
892
1105
|
assign(pending, {
|
|
893
1106
|
message: issue.message,
|
|
894
1107
|
stack: issue.stack
|
|
@@ -933,7 +1146,7 @@ function use$1(input, argument) {
|
|
|
933
1146
|
});
|
|
934
1147
|
}
|
|
935
1148
|
|
|
936
|
-
const Oops$
|
|
1149
|
+
const Oops$5 = issues({
|
|
937
1150
|
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
938
1151
|
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
939
1152
|
});
|
|
@@ -944,195 +1157,14 @@ function has(Type, required) {
|
|
|
944
1157
|
const expected = Type.name;
|
|
945
1158
|
if (!value) {
|
|
946
1159
|
if (required !== false)
|
|
947
|
-
throw Oops$
|
|
1160
|
+
throw Oops$5.Required(expected, child);
|
|
948
1161
|
}
|
|
949
1162
|
else if (!(value instanceof Type))
|
|
950
|
-
throw Oops$
|
|
1163
|
+
throw Oops$5.Unexpected(expected, child, value);
|
|
951
1164
|
return { value };
|
|
952
1165
|
});
|
|
953
1166
|
}
|
|
954
1167
|
|
|
955
|
-
const Oops$6 = issues({
|
|
956
|
-
Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
|
|
957
|
-
KeysExpected: (key) => `Key "${key}" was expected in current update.`,
|
|
958
|
-
StrictUpdate: () => `Expected update but none in progress.`,
|
|
959
|
-
StrictNoUpdate: () => `Update is not expected but one is in progress!`
|
|
960
|
-
});
|
|
961
|
-
function addEventListener(source, arg1, arg2, arg3) {
|
|
962
|
-
if (typeof arg1 == "string")
|
|
963
|
-
arg1 = [arg1];
|
|
964
|
-
return Control.for(source, control => {
|
|
965
|
-
for (const key of arg1)
|
|
966
|
-
try {
|
|
967
|
-
void source[key];
|
|
968
|
-
}
|
|
969
|
-
catch (e) { }
|
|
970
|
-
const removeListener = control.addListener(key => {
|
|
971
|
-
if (!key && !arg1.length)
|
|
972
|
-
arg2.call(source, []);
|
|
973
|
-
if (arg1.includes(key)) {
|
|
974
|
-
if (arg3)
|
|
975
|
-
removeListener();
|
|
976
|
-
return arg2.bind(source);
|
|
977
|
-
}
|
|
978
|
-
});
|
|
979
|
-
return removeListener;
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
function awaitUpdate(source, arg1, arg2) {
|
|
983
|
-
const single = typeof arg1 == "string";
|
|
984
|
-
const keys = typeof arg1 == "string" ? [arg1] :
|
|
985
|
-
typeof arg1 == "object" ? arg1 :
|
|
986
|
-
undefined;
|
|
987
|
-
return new Promise((resolve, reject) => {
|
|
988
|
-
const timeout = (message) => {
|
|
989
|
-
const k = keys ? keys.join(", ") : "any";
|
|
990
|
-
removeListener();
|
|
991
|
-
reject(Oops$6.Timeout(k, message));
|
|
992
|
-
};
|
|
993
|
-
const removeListener = Control.for(source, control => {
|
|
994
|
-
const pending = control.frame;
|
|
995
|
-
if (keys === null) {
|
|
996
|
-
if (pending.size)
|
|
997
|
-
reject(Oops$6.StrictNoUpdate());
|
|
998
|
-
else
|
|
999
|
-
resolve(null);
|
|
1000
|
-
return;
|
|
1001
|
-
}
|
|
1002
|
-
if (keys) {
|
|
1003
|
-
if (keys.length) {
|
|
1004
|
-
if (arg2 === 0 && single && !pending.has(keys[0])) {
|
|
1005
|
-
reject(Oops$6.KeysExpected(keys[0]));
|
|
1006
|
-
return;
|
|
1007
|
-
}
|
|
1008
|
-
else
|
|
1009
|
-
for (const key of keys)
|
|
1010
|
-
try {
|
|
1011
|
-
void source[key];
|
|
1012
|
-
}
|
|
1013
|
-
catch (e) { }
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
else if (!pending.size && arg1 === true || arg2 === 0) {
|
|
1017
|
-
reject(Oops$6.StrictUpdate());
|
|
1018
|
-
return;
|
|
1019
|
-
}
|
|
1020
|
-
else
|
|
1021
|
-
control.waiting.add(resolve);
|
|
1022
|
-
return control.addListener(key => {
|
|
1023
|
-
if (!key) {
|
|
1024
|
-
if (keys && !keys.length)
|
|
1025
|
-
resolve([]);
|
|
1026
|
-
else
|
|
1027
|
-
timeout(`lifetime of ${source}`);
|
|
1028
|
-
}
|
|
1029
|
-
else if (!keys || keys.includes(key)) {
|
|
1030
|
-
removeListener();
|
|
1031
|
-
return keys => resolve(single ? control.state.get(key) : keys);
|
|
1032
|
-
}
|
|
1033
|
-
});
|
|
1034
|
-
});
|
|
1035
|
-
if (arg2 && typeof arg2 == "number")
|
|
1036
|
-
setTimeout(() => timeout(`${arg2}ms`), arg2);
|
|
1037
|
-
});
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
const Oops$5 = issues({
|
|
1041
|
-
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
1042
|
-
});
|
|
1043
|
-
class Model {
|
|
1044
|
-
constructor() {
|
|
1045
|
-
new Control(this);
|
|
1046
|
-
defineProperty(this, "is", { value: this });
|
|
1047
|
-
}
|
|
1048
|
-
on(arg1, arg2, arg3) {
|
|
1049
|
-
if (typeof arg1 == "function")
|
|
1050
|
-
return createEffect(this.is, arg1, arg2);
|
|
1051
|
-
if (typeof arg2 != "function")
|
|
1052
|
-
return awaitUpdate(this.is, arg1, arg2);
|
|
1053
|
-
if (arg1)
|
|
1054
|
-
return addEventListener(this.is, arg1, arg2, arg3);
|
|
1055
|
-
}
|
|
1056
|
-
get(arg1, arg2) {
|
|
1057
|
-
const { state } = Control.for(this);
|
|
1058
|
-
const extract = typeof arg1 == "string"
|
|
1059
|
-
? () => state.get(arg1)
|
|
1060
|
-
: () => {
|
|
1061
|
-
const output = {};
|
|
1062
|
-
for (const key of arg1 || state.keys())
|
|
1063
|
-
output[key] = state.get(key);
|
|
1064
|
-
return output;
|
|
1065
|
-
};
|
|
1066
|
-
if (!arg1 || arg2 === undefined)
|
|
1067
|
-
return extract();
|
|
1068
|
-
if (typeof arg2 == "function")
|
|
1069
|
-
return this.on(arg1, () => arg2(extract()));
|
|
1070
|
-
const timeout = typeof arg2 == "number" ? arg2 : undefined;
|
|
1071
|
-
return this.on(arg1, timeout).then(extract);
|
|
1072
|
-
}
|
|
1073
|
-
set(arg1, arg2) {
|
|
1074
|
-
const control = Control.for(this);
|
|
1075
|
-
if (typeof arg1 == "object")
|
|
1076
|
-
for (const key in arg1) {
|
|
1077
|
-
if (arg2 === true || (arg2 ? arg2.includes(key) : control.state.has(key))) {
|
|
1078
|
-
control.state.set(key, arg1[key]);
|
|
1079
|
-
control.update(key);
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
else if (typeof arg1 == "string") {
|
|
1083
|
-
control.update(arg1);
|
|
1084
|
-
if (1 in arguments) {
|
|
1085
|
-
if (control.state.has(arg1))
|
|
1086
|
-
control.state.set(arg1, arg2);
|
|
1087
|
-
else if (arg1 in this) {
|
|
1088
|
-
const method = this[arg1];
|
|
1089
|
-
if (typeof method == "function")
|
|
1090
|
-
method.call(this, arg2);
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
return {
|
|
1095
|
-
then: (callback) => {
|
|
1096
|
-
if (!callback)
|
|
1097
|
-
throw Oops$5.NoChaining();
|
|
1098
|
-
control.waiting.add(callback);
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
1101
|
-
}
|
|
1102
|
-
/**
|
|
1103
|
-
* Clean up side effects and mark this instance for garbage-collection.
|
|
1104
|
-
*/
|
|
1105
|
-
end() {
|
|
1106
|
-
Control.for(this).clear();
|
|
1107
|
-
}
|
|
1108
|
-
/**
|
|
1109
|
-
* Creates a new instance of this controller.
|
|
1110
|
-
*
|
|
1111
|
-
* Beyond `new this(...)`, method will activate managed-state.
|
|
1112
|
-
*
|
|
1113
|
-
* @param args - arguments sent to constructor
|
|
1114
|
-
*/
|
|
1115
|
-
static new(...args) {
|
|
1116
|
-
const instance = new this(...args);
|
|
1117
|
-
Control.for(instance);
|
|
1118
|
-
return instance;
|
|
1119
|
-
}
|
|
1120
|
-
/**
|
|
1121
|
-
* Static equivalent of `x instanceof this`.
|
|
1122
|
-
*
|
|
1123
|
-
* Will determine if provided class is a subtype of this one.
|
|
1124
|
-
*/
|
|
1125
|
-
static isTypeof(maybe) {
|
|
1126
|
-
return (typeof maybe == "function" &&
|
|
1127
|
-
maybe.prototype instanceof this);
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
defineProperty(Model.prototype, "toString", {
|
|
1131
|
-
value() {
|
|
1132
|
-
return this.constructor.name;
|
|
1133
|
-
}
|
|
1134
|
-
});
|
|
1135
|
-
|
|
1136
1168
|
const Oops$4 = issues({
|
|
1137
1169
|
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1138
1170
|
});
|
|
@@ -1154,7 +1186,19 @@ class Lookup {
|
|
|
1154
1186
|
get(T) {
|
|
1155
1187
|
return this[this.key(T)];
|
|
1156
1188
|
}
|
|
1157
|
-
add(
|
|
1189
|
+
add(input) {
|
|
1190
|
+
let writable = true;
|
|
1191
|
+
let T;
|
|
1192
|
+
let I;
|
|
1193
|
+
if (typeof input == "function") {
|
|
1194
|
+
T = input;
|
|
1195
|
+
I = input.new();
|
|
1196
|
+
}
|
|
1197
|
+
else {
|
|
1198
|
+
I = input;
|
|
1199
|
+
T = I.constructor;
|
|
1200
|
+
writable = false;
|
|
1201
|
+
}
|
|
1158
1202
|
do {
|
|
1159
1203
|
const key = this.key(T);
|
|
1160
1204
|
const conflict = this.hasOwnProperty(key);
|
|
@@ -1165,6 +1209,10 @@ class Lookup {
|
|
|
1165
1209
|
});
|
|
1166
1210
|
T = getPrototypeOf(T);
|
|
1167
1211
|
} while (T !== Model);
|
|
1212
|
+
Control.for(I).state.forEach(value => {
|
|
1213
|
+
if (value instanceof Model)
|
|
1214
|
+
this.add(value);
|
|
1215
|
+
});
|
|
1168
1216
|
}
|
|
1169
1217
|
push() {
|
|
1170
1218
|
return create(this);
|
|
@@ -1254,9 +1302,9 @@ function use(init) {
|
|
|
1254
1302
|
function useNew(source, arg1, arg2) {
|
|
1255
1303
|
const instance = React__default["default"].useMemo(() => {
|
|
1256
1304
|
const callback = arg2 || arg1;
|
|
1257
|
-
const instance = Model.isTypeof(source)
|
|
1258
|
-
source
|
|
1259
|
-
source();
|
|
1305
|
+
const instance = Model.isTypeof(source)
|
|
1306
|
+
? new source()
|
|
1307
|
+
: source();
|
|
1260
1308
|
Control.for(instance);
|
|
1261
1309
|
if (typeof callback == "function")
|
|
1262
1310
|
callback(instance);
|
|
@@ -1332,9 +1380,11 @@ function useValue(source, compute, suspend) {
|
|
|
1332
1380
|
}
|
|
1333
1381
|
defineProperty(sub, "proxy", {
|
|
1334
1382
|
get() {
|
|
1335
|
-
if (value
|
|
1383
|
+
if (value !== undefined)
|
|
1384
|
+
return value;
|
|
1385
|
+
if (suspend)
|
|
1336
1386
|
throw new Promise(res => retry = res);
|
|
1337
|
-
return
|
|
1387
|
+
return null;
|
|
1338
1388
|
}
|
|
1339
1389
|
});
|
|
1340
1390
|
return sub;
|
|
@@ -1462,28 +1512,22 @@ function useNewContext(include, assign) {
|
|
|
1462
1512
|
if (!include)
|
|
1463
1513
|
throw Oops.NoType();
|
|
1464
1514
|
const next = ambient.push();
|
|
1465
|
-
function register(I) {
|
|
1466
|
-
if (I instanceof Model)
|
|
1467
|
-
next.add(I.constructor, I, false);
|
|
1468
|
-
else
|
|
1469
|
-
next.add(I, I.new(), true);
|
|
1470
|
-
}
|
|
1471
1515
|
if (include instanceof Model || typeof include == "function")
|
|
1472
|
-
|
|
1516
|
+
next.add(include);
|
|
1473
1517
|
else
|
|
1474
|
-
values(include).forEach(
|
|
1518
|
+
values(include).forEach(x => next.add(x));
|
|
1475
1519
|
for (const instance of next.local)
|
|
1476
|
-
if (instance)
|
|
1520
|
+
if (instance) {
|
|
1521
|
+
if (assign)
|
|
1522
|
+
assignWeak(instance, assign);
|
|
1477
1523
|
for (const apply of getPending(instance))
|
|
1478
1524
|
apply(next);
|
|
1525
|
+
}
|
|
1479
1526
|
return next;
|
|
1480
1527
|
}, []);
|
|
1481
|
-
if (assign)
|
|
1482
|
-
for (const
|
|
1483
|
-
|
|
1484
|
-
if (into && key in into)
|
|
1485
|
-
into[key] = assign[key];
|
|
1486
|
-
}
|
|
1528
|
+
if (assign)
|
|
1529
|
+
for (const into of context.local)
|
|
1530
|
+
assignWeak(into, assign);
|
|
1487
1531
|
return context;
|
|
1488
1532
|
}
|
|
1489
1533
|
function RenderFunction(props) {
|
|
@@ -1496,6 +1540,11 @@ function RenderFunction(props) {
|
|
|
1496
1540
|
if (hook.commit)
|
|
1497
1541
|
React__default["default"].useLayoutEffect(hook.commit, []);
|
|
1498
1542
|
return props.render(hook.proxy);
|
|
1543
|
+
}
|
|
1544
|
+
function assignWeak(into, from) {
|
|
1545
|
+
for (const K in from)
|
|
1546
|
+
if (K in into)
|
|
1547
|
+
into[K] = from[K];
|
|
1499
1548
|
}
|
|
1500
1549
|
|
|
1501
1550
|
class Global extends MVC {
|