@expressive/mvc 1.0.0-beta.20 → 1.0.0-beta.24
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 +1203 -0
- package/lib/index.esm.js.map +1 -0
- package/lib/index.js +325 -288
- package/lib/index.js.map +1 -0
- package/package.json +6 -6
- package/types/context.d.ts +4 -6
- package/types/index.d.ts +0 -1
- package/types/instructions.d.ts +55 -21
- package/types/model.d.ts +64 -60
- package/types/types.d.ts +2 -2
package/lib/index.js
CHANGED
|
@@ -313,18 +313,17 @@ function eventsFor(prefix) {
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
const CONTROL = Symbol("control");
|
|
316
|
-
const CREATE = Symbol("start");
|
|
317
316
|
const LOCAL = Symbol("local");
|
|
318
317
|
const STATE = Symbol("state");
|
|
319
|
-
const Pending = new Map();
|
|
320
318
|
function manage(src) {
|
|
321
319
|
return src[CONTROL];
|
|
322
320
|
}
|
|
323
|
-
|
|
324
|
-
|
|
321
|
+
const Pending = new Map();
|
|
322
|
+
function apply(fn, label) {
|
|
323
|
+
const name = label || fn.name || "pending";
|
|
325
324
|
const placeholder = Symbol(`${name} instruction`);
|
|
326
|
-
|
|
327
|
-
let output =
|
|
325
|
+
function setup(key) {
|
|
326
|
+
let output = fn.call(this, key, this);
|
|
328
327
|
if (typeof output == "function") {
|
|
329
328
|
const getter = output;
|
|
330
329
|
output = Object.assign(Object.assign({}, getOwnPropertyDescriptor(this.subject, key)), { get() {
|
|
@@ -333,7 +332,8 @@ function set(instruction, label) {
|
|
|
333
332
|
}
|
|
334
333
|
if (output)
|
|
335
334
|
defineProperty(this.subject, key, output);
|
|
336
|
-
}
|
|
335
|
+
}
|
|
336
|
+
Pending.set(placeholder, setup);
|
|
337
337
|
return placeholder;
|
|
338
338
|
}
|
|
339
339
|
class Controller {
|
|
@@ -345,14 +345,10 @@ class Controller {
|
|
|
345
345
|
this.waiting = [];
|
|
346
346
|
}
|
|
347
347
|
static setup(onto) {
|
|
348
|
-
const create = onto[CREATE];
|
|
349
348
|
const control = new this(onto);
|
|
350
|
-
const after = create && create.call(onto, control);
|
|
351
349
|
defineLazy(onto, CONTROL, () => {
|
|
352
350
|
onto[STATE] = control.state;
|
|
353
351
|
control.start();
|
|
354
|
-
if (after)
|
|
355
|
-
after();
|
|
356
352
|
if (onto.didCreate)
|
|
357
353
|
onto.didCreate();
|
|
358
354
|
return control;
|
|
@@ -457,56 +453,57 @@ function keys(from, using) {
|
|
|
457
453
|
return from.select(using);
|
|
458
454
|
}
|
|
459
455
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
456
|
+
function child(from, name) {
|
|
457
|
+
return apply(function child(key) {
|
|
458
|
+
const proxyCache = new WeakMap();
|
|
459
|
+
const getCurrent = from.call(this, key);
|
|
460
|
+
function subscribe(sub) {
|
|
461
|
+
let child;
|
|
462
|
+
function start() {
|
|
463
|
+
const instance = getCurrent();
|
|
464
|
+
if (instance) {
|
|
465
|
+
child = new Subscriber(instance, sub.onUpdate);
|
|
466
|
+
if (sub.active)
|
|
467
|
+
child.commit();
|
|
468
|
+
sub.dependant.add(child);
|
|
469
|
+
proxyCache.set(sub, child.proxy);
|
|
470
|
+
}
|
|
473
471
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
472
|
+
function refresh() {
|
|
473
|
+
if (child) {
|
|
474
|
+
child.release();
|
|
475
|
+
sub.dependant.delete(child);
|
|
476
|
+
proxyCache.set(sub, undefined);
|
|
477
|
+
child = undefined;
|
|
478
|
+
}
|
|
479
|
+
start();
|
|
480
|
+
sub.onUpdate();
|
|
481
481
|
}
|
|
482
482
|
start();
|
|
483
|
-
sub.
|
|
483
|
+
sub.follow(key, refresh);
|
|
484
484
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
return
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
};
|
|
495
|
-
}, name || from.name);
|
|
485
|
+
return (local) => {
|
|
486
|
+
if (!local)
|
|
487
|
+
return getCurrent();
|
|
488
|
+
if (!proxyCache.has(local))
|
|
489
|
+
subscribe(local);
|
|
490
|
+
return proxyCache.get(local);
|
|
491
|
+
};
|
|
492
|
+
}, name || from.name);
|
|
493
|
+
}
|
|
496
494
|
|
|
497
495
|
const Oops$7 = issues({
|
|
498
496
|
HasPropertyUndefined: (control, property) => `${control}.${property} is marked as required for this render.`
|
|
499
497
|
});
|
|
500
|
-
const useElementLifecycle = lifecycle("element");
|
|
501
498
|
function use$1(init) {
|
|
502
499
|
const [state, update] = react.useState(() => [
|
|
503
500
|
init(() => update(state.concat()))
|
|
504
501
|
]);
|
|
505
502
|
return state[0];
|
|
506
503
|
}
|
|
507
|
-
function useLazy(Type,
|
|
504
|
+
function useLazy(Type, callback) {
|
|
508
505
|
const instance = react.useMemo(() => {
|
|
509
|
-
const instance = Type.create(
|
|
506
|
+
const instance = Type.create();
|
|
510
507
|
if (callback)
|
|
511
508
|
callback(instance);
|
|
512
509
|
return instance;
|
|
@@ -533,14 +530,9 @@ function useWatcher(target, focus, expected) {
|
|
|
533
530
|
react.useLayoutEffect(() => hook.commit(), []);
|
|
534
531
|
return hook.proxy;
|
|
535
532
|
}
|
|
536
|
-
function
|
|
537
|
-
const hook = use$1(refresh => new Subscriber(target, refresh));
|
|
538
|
-
useElementLifecycle(hook, tag || 0);
|
|
539
|
-
return hook.proxy;
|
|
540
|
-
}
|
|
541
|
-
function useModel(Type, args, callback) {
|
|
533
|
+
function useModel(Type, callback) {
|
|
542
534
|
const hook = use$1(refresh => {
|
|
543
|
-
const instance = new Type(
|
|
535
|
+
const instance = new Type();
|
|
544
536
|
const control = manage(instance);
|
|
545
537
|
const sub = new Subscriber(control, refresh);
|
|
546
538
|
const release = control.addListener({
|
|
@@ -556,6 +548,56 @@ function useModel(Type, args, callback) {
|
|
|
556
548
|
return hook.proxy;
|
|
557
549
|
}
|
|
558
550
|
|
|
551
|
+
const Oops$6 = issues({
|
|
552
|
+
CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
553
|
+
AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
|
|
554
|
+
});
|
|
555
|
+
const PendingContext = new WeakMap();
|
|
556
|
+
const ContextWasUsed = new WeakMap();
|
|
557
|
+
function tap(type, argument) {
|
|
558
|
+
return child(function tap(key) {
|
|
559
|
+
return pendingAccess(this.subject, type, key, argument);
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
function pendingAccess(from, type, key, argument) {
|
|
563
|
+
if ("current" in type)
|
|
564
|
+
return () => type.current;
|
|
565
|
+
if ("current" in from.constructor)
|
|
566
|
+
throw Oops$6.CantAttachGlobal(from, type.name);
|
|
567
|
+
let instance;
|
|
568
|
+
getPending(from).push(context => {
|
|
569
|
+
instance = context.get(type);
|
|
570
|
+
if (typeof argument == "function") {
|
|
571
|
+
if (argument(instance) === false)
|
|
572
|
+
instance = undefined;
|
|
573
|
+
}
|
|
574
|
+
else if (!instance && argument)
|
|
575
|
+
throw Oops$6.AmbientRequired(type.name, from, key);
|
|
576
|
+
});
|
|
577
|
+
return () => instance;
|
|
578
|
+
}
|
|
579
|
+
function usePeerContext(subject) {
|
|
580
|
+
if (ContextWasUsed.has(subject)) {
|
|
581
|
+
if (ContextWasUsed.get(subject))
|
|
582
|
+
useLookup();
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
const pending = PendingContext.get(subject);
|
|
586
|
+
if (pending) {
|
|
587
|
+
const local = useLookup();
|
|
588
|
+
for (const init of pending)
|
|
589
|
+
init(local);
|
|
590
|
+
PendingContext.delete(subject);
|
|
591
|
+
}
|
|
592
|
+
ContextWasUsed.set(subject, !!pending);
|
|
593
|
+
}
|
|
594
|
+
function getPending(subject) {
|
|
595
|
+
let pending = PendingContext.get(subject);
|
|
596
|
+
if (!pending)
|
|
597
|
+
PendingContext.set(subject, pending = []);
|
|
598
|
+
return pending;
|
|
599
|
+
}
|
|
600
|
+
|
|
559
601
|
class Lookup {
|
|
560
602
|
constructor() {
|
|
561
603
|
this.table = new Map();
|
|
@@ -611,7 +653,7 @@ class Lookup {
|
|
|
611
653
|
}
|
|
612
654
|
}
|
|
613
655
|
|
|
614
|
-
const Oops$
|
|
656
|
+
const Oops$5 = issues({
|
|
615
657
|
NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`,
|
|
616
658
|
NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
|
|
617
659
|
BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
@@ -621,7 +663,7 @@ const useLookup = () => react.useContext(LookupContext);
|
|
|
621
663
|
function useFromContext(Type, strict) {
|
|
622
664
|
const instance = useLookup().get(Type);
|
|
623
665
|
if (!instance && strict)
|
|
624
|
-
throw Oops$
|
|
666
|
+
throw Oops$5.NothingInContext(Type.name);
|
|
625
667
|
return instance;
|
|
626
668
|
}
|
|
627
669
|
function Consumer(props) {
|
|
@@ -632,13 +674,13 @@ function Consumer(props) {
|
|
|
632
674
|
if (typeof callback == "function")
|
|
633
675
|
callback(Control.get(!!has));
|
|
634
676
|
else
|
|
635
|
-
throw Oops$
|
|
677
|
+
throw Oops$5.BadConsumerProps();
|
|
636
678
|
return null;
|
|
637
679
|
}
|
|
638
680
|
function useNewContext(from, inject) {
|
|
639
681
|
return react.useMemo(() => {
|
|
640
682
|
if (!inject)
|
|
641
|
-
throw Oops$
|
|
683
|
+
throw Oops$5.NoProviderType();
|
|
642
684
|
const context = from.push(inject);
|
|
643
685
|
for (const instance of context.local)
|
|
644
686
|
for (const apply of getPending(instance))
|
|
@@ -681,63 +723,88 @@ function Provider(props) {
|
|
|
681
723
|
: render);
|
|
682
724
|
}
|
|
683
725
|
|
|
684
|
-
const Oops$5 = issues({
|
|
685
|
-
CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
686
|
-
AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
|
|
687
|
-
});
|
|
688
|
-
const PendingContext = new WeakMap();
|
|
689
|
-
const ContextWasUsed = new WeakMap();
|
|
690
|
-
const tap = (type, argument) => attach(function tap(key) {
|
|
691
|
-
return pendingAccess(this.subject, type, key, argument);
|
|
692
|
-
});
|
|
693
|
-
function pendingAccess(from, type, key, argument) {
|
|
694
|
-
if ("current" in type)
|
|
695
|
-
return () => type.current;
|
|
696
|
-
if ("current" in from.constructor)
|
|
697
|
-
throw Oops$5.CantAttachGlobal(from, type.name);
|
|
698
|
-
let instance;
|
|
699
|
-
getPending(from).push(context => {
|
|
700
|
-
instance = context.get(type);
|
|
701
|
-
if (typeof argument == "function") {
|
|
702
|
-
if (argument(instance) === false)
|
|
703
|
-
instance = undefined;
|
|
704
|
-
}
|
|
705
|
-
else if (!instance && argument)
|
|
706
|
-
throw Oops$5.AmbientRequired(type.name, from, key);
|
|
707
|
-
});
|
|
708
|
-
return () => instance;
|
|
709
|
-
}
|
|
710
|
-
function usePeerContext(subject) {
|
|
711
|
-
if (ContextWasUsed.has(subject)) {
|
|
712
|
-
if (ContextWasUsed.get(subject))
|
|
713
|
-
useLookup();
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
716
|
-
const pending = PendingContext.get(subject);
|
|
717
|
-
if (pending) {
|
|
718
|
-
const local = useLookup();
|
|
719
|
-
for (const init of pending)
|
|
720
|
-
init(local);
|
|
721
|
-
PendingContext.delete(subject);
|
|
722
|
-
}
|
|
723
|
-
ContextWasUsed.set(subject, !!pending);
|
|
724
|
-
}
|
|
725
|
-
function getPending(subject) {
|
|
726
|
-
let pending = PendingContext.get(subject);
|
|
727
|
-
if (!pending)
|
|
728
|
-
PendingContext.set(subject, pending = []);
|
|
729
|
-
return pending;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
726
|
const Oops$4 = issues({
|
|
733
727
|
StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
|
|
734
728
|
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
735
729
|
});
|
|
736
|
-
|
|
730
|
+
const useElementLifecycle = lifecycle("element");
|
|
731
|
+
const useComponentLifecycle = lifecycle("component");
|
|
732
|
+
class Model {
|
|
737
733
|
constructor() {
|
|
738
|
-
Controller.setup(this);
|
|
734
|
+
const control = Controller.setup(this);
|
|
739
735
|
define(this, "get", this);
|
|
740
736
|
define(this, "set", this);
|
|
737
|
+
defer(control, "on");
|
|
738
|
+
defer(control, "effect");
|
|
739
|
+
control.include(() => {
|
|
740
|
+
delete this.on;
|
|
741
|
+
delete this.effect;
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
tap(path, expect) {
|
|
745
|
+
const proxy = useWatcher(this, path, expect);
|
|
746
|
+
this.update("willRender", true);
|
|
747
|
+
return proxy;
|
|
748
|
+
}
|
|
749
|
+
tag(id) {
|
|
750
|
+
const hook = use$1(refresh => {
|
|
751
|
+
return new Subscriber(this, refresh);
|
|
752
|
+
});
|
|
753
|
+
useElementLifecycle(hook, id || 0);
|
|
754
|
+
return hook.proxy;
|
|
755
|
+
}
|
|
756
|
+
use(callback) {
|
|
757
|
+
const hook = use$1(refresh => {
|
|
758
|
+
if (callback)
|
|
759
|
+
callback(this);
|
|
760
|
+
return new Subscriber(this, refresh);
|
|
761
|
+
});
|
|
762
|
+
useComponentLifecycle(hook);
|
|
763
|
+
return hook.proxy;
|
|
764
|
+
}
|
|
765
|
+
on(subset, handler, squash, once) {
|
|
766
|
+
const control = manage(this);
|
|
767
|
+
const set = keys(control, subset);
|
|
768
|
+
const batch = {};
|
|
769
|
+
const remove = control.addListener(batch);
|
|
770
|
+
const callback = squash
|
|
771
|
+
? handler.bind(this)
|
|
772
|
+
: (frame) => {
|
|
773
|
+
for (const key of frame)
|
|
774
|
+
if (set.includes(key))
|
|
775
|
+
handler.call(this, control.state[key], key);
|
|
776
|
+
};
|
|
777
|
+
const handle = once
|
|
778
|
+
? (k) => { remove(); callback(k); }
|
|
779
|
+
: callback;
|
|
780
|
+
for (const key of set)
|
|
781
|
+
batch[key] = handle;
|
|
782
|
+
ensure(control, set);
|
|
783
|
+
return remove;
|
|
784
|
+
}
|
|
785
|
+
once(select, callback, squash) {
|
|
786
|
+
if (callback)
|
|
787
|
+
return this.on(select, callback, squash, true);
|
|
788
|
+
else
|
|
789
|
+
return new Promise(resolve => {
|
|
790
|
+
this.on(select, resolve, true, true);
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
effect(callback, select) {
|
|
794
|
+
const control = manage(this);
|
|
795
|
+
let target = this;
|
|
796
|
+
const effect = createEffect(callback);
|
|
797
|
+
const invoke = () => effect.call(target, target);
|
|
798
|
+
if (select) {
|
|
799
|
+
invoke();
|
|
800
|
+
return this.on(select, invoke, true);
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
const sub = new Subscriber(control, invoke);
|
|
804
|
+
target = sub.proxy;
|
|
805
|
+
invoke();
|
|
806
|
+
return sub.commit();
|
|
807
|
+
}
|
|
741
808
|
}
|
|
742
809
|
import(from, subset) {
|
|
743
810
|
for (const key of keys(manage(this), subset))
|
|
@@ -788,34 +855,16 @@ class State {
|
|
|
788
855
|
toString() {
|
|
789
856
|
return this.constructor.name;
|
|
790
857
|
}
|
|
791
|
-
tap(path, expect) {
|
|
792
|
-
const proxy = useWatcher(this, path, expect);
|
|
793
|
-
this.update("willRender", true);
|
|
794
|
-
return proxy;
|
|
795
|
-
}
|
|
796
858
|
static create(...args) {
|
|
797
859
|
const instance = new this(...args);
|
|
798
860
|
manage(instance);
|
|
799
861
|
return instance;
|
|
800
862
|
}
|
|
801
|
-
static new(
|
|
802
|
-
const instance = useLazy(this,
|
|
863
|
+
static new(callback) {
|
|
864
|
+
const instance = useLazy(this, callback);
|
|
803
865
|
instance.update("willRender", true);
|
|
804
866
|
return instance;
|
|
805
867
|
}
|
|
806
|
-
static use(args, callback) {
|
|
807
|
-
return useModel(this, args, callback);
|
|
808
|
-
}
|
|
809
|
-
static uses(props, only) {
|
|
810
|
-
return this.use([], instance => {
|
|
811
|
-
instance.import(props, only);
|
|
812
|
-
});
|
|
813
|
-
}
|
|
814
|
-
static using(props, only) {
|
|
815
|
-
const instance = this.use([]);
|
|
816
|
-
instance.import(props, only);
|
|
817
|
-
return instance;
|
|
818
|
-
}
|
|
819
868
|
static find(strict) {
|
|
820
869
|
return useFromContext(this, strict);
|
|
821
870
|
}
|
|
@@ -830,86 +879,36 @@ class State {
|
|
|
830
879
|
static tap(key, expect) {
|
|
831
880
|
return this.find(true).tap(key, expect);
|
|
832
881
|
}
|
|
833
|
-
static
|
|
834
|
-
return (
|
|
835
|
-
maybe.prototype instanceof this);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
State.CONTROL = CONTROL;
|
|
839
|
-
State.STATE = STATE;
|
|
840
|
-
State.INIT = CREATE;
|
|
841
|
-
State.LOCAL = LOCAL;
|
|
842
|
-
|
|
843
|
-
const useComponentLifecycle = lifecycle("component");
|
|
844
|
-
class Model extends State {
|
|
845
|
-
[CREATE](using) {
|
|
846
|
-
defer(using, "on");
|
|
847
|
-
defer(using, "effect");
|
|
848
|
-
return () => {
|
|
849
|
-
delete this.on;
|
|
850
|
-
delete this.effect;
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
on(subset, handler, squash, once) {
|
|
854
|
-
const control = manage(this);
|
|
855
|
-
const set = keys(control, subset);
|
|
856
|
-
const batch = {};
|
|
857
|
-
const remove = control.addListener(batch);
|
|
858
|
-
const callback = squash
|
|
859
|
-
? handler.bind(this)
|
|
860
|
-
: (frame) => {
|
|
861
|
-
for (const key of frame)
|
|
862
|
-
if (set.includes(key))
|
|
863
|
-
handler.call(this, control.state[key], key);
|
|
864
|
-
};
|
|
865
|
-
const handle = once
|
|
866
|
-
? (k) => { remove(); callback(k); }
|
|
867
|
-
: callback;
|
|
868
|
-
for (const key of set)
|
|
869
|
-
batch[key] = handle;
|
|
870
|
-
ensure(control, set);
|
|
871
|
-
return remove;
|
|
872
|
-
}
|
|
873
|
-
once(select, callback, squash) {
|
|
874
|
-
if (callback)
|
|
875
|
-
return this.on(select, callback, squash, true);
|
|
876
|
-
else
|
|
877
|
-
return new Promise(resolve => {
|
|
878
|
-
this.on(select, resolve, true, true);
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
|
-
effect(callback, select) {
|
|
882
|
-
const control = manage(this);
|
|
883
|
-
let target = this;
|
|
884
|
-
const effect = createEffect(callback);
|
|
885
|
-
const invoke = () => effect.call(target, target);
|
|
886
|
-
if (select) {
|
|
887
|
-
invoke();
|
|
888
|
-
return this.on(select, invoke, true);
|
|
889
|
-
}
|
|
890
|
-
else {
|
|
891
|
-
const sub = new Subscriber(control, invoke);
|
|
892
|
-
target = sub.proxy;
|
|
893
|
-
invoke();
|
|
894
|
-
return sub.commit();
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
tag(id) {
|
|
898
|
-
return useSubscriber(this, id);
|
|
882
|
+
static tag(id) {
|
|
883
|
+
return this.find(true).tag(id);
|
|
899
884
|
}
|
|
900
|
-
static use(
|
|
901
|
-
const instance = useModel(this,
|
|
885
|
+
static use(callback) {
|
|
886
|
+
const instance = useModel(this, callback);
|
|
902
887
|
useComponentLifecycle(instance[LOCAL]);
|
|
903
888
|
usePeerContext(instance.get);
|
|
904
889
|
return instance;
|
|
905
890
|
}
|
|
906
|
-
static
|
|
907
|
-
return this.
|
|
891
|
+
static uses(props, only) {
|
|
892
|
+
return this.use(instance => {
|
|
893
|
+
instance.import(props, only);
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
static using(props, only) {
|
|
897
|
+
const instance = this.use();
|
|
898
|
+
instance.import(props, only);
|
|
899
|
+
return instance;
|
|
908
900
|
}
|
|
909
901
|
static meta(path) {
|
|
910
902
|
return useWatcher(this, path);
|
|
911
903
|
}
|
|
904
|
+
static isTypeof(maybe) {
|
|
905
|
+
return (typeof maybe == "function" &&
|
|
906
|
+
maybe.prototype instanceof this);
|
|
907
|
+
}
|
|
912
908
|
}
|
|
909
|
+
Model.CONTROL = CONTROL;
|
|
910
|
+
Model.STATE = STATE;
|
|
911
|
+
Model.LOCAL = LOCAL;
|
|
913
912
|
defineLazy(Model, CONTROL, function () {
|
|
914
913
|
return new Controller(this).start();
|
|
915
914
|
});
|
|
@@ -939,73 +938,86 @@ function bootstrap(object) {
|
|
|
939
938
|
defineProperty(control, key, breakdown[key]);
|
|
940
939
|
return control;
|
|
941
940
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
next
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
941
|
+
function use(input, argument) {
|
|
942
|
+
return child(function use(key) {
|
|
943
|
+
let instance;
|
|
944
|
+
const update = (next) => {
|
|
945
|
+
instance =
|
|
946
|
+
next instanceof Model ? next :
|
|
947
|
+
next && bootstrap(next);
|
|
948
|
+
if (instance) {
|
|
949
|
+
Parent.set(instance, this.subject);
|
|
950
|
+
manage(instance);
|
|
951
|
+
}
|
|
952
|
+
if (typeof argument == "function")
|
|
953
|
+
argument(instance);
|
|
954
|
+
else if (!instance && argument !== false)
|
|
955
|
+
throw Oops$3.UndefinedNotAllowed(key);
|
|
956
|
+
};
|
|
957
|
+
if (input) {
|
|
958
|
+
instance =
|
|
959
|
+
Model.isTypeof(input) ? new input() :
|
|
960
|
+
input instanceof Model ? input :
|
|
961
|
+
typeof input === "function" ? input() :
|
|
962
|
+
typeof input === "object" ? bootstrap(input) :
|
|
963
|
+
Oops$3.BadArgument(typeof input).throw();
|
|
964
|
+
if (instance)
|
|
965
|
+
update(instance);
|
|
951
966
|
}
|
|
952
|
-
|
|
953
|
-
argument
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
};
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
const parent = (Expects, required) => set(function parent() {
|
|
973
|
-
const child = this.subject;
|
|
974
|
-
const expected = Expects.name;
|
|
975
|
-
const value = Parent.get(this.subject);
|
|
976
|
-
if (!value) {
|
|
977
|
-
if (required)
|
|
978
|
-
throw Oops$3.ParentRequired(expected, child);
|
|
979
|
-
}
|
|
980
|
-
else if (!(value instanceof Expects))
|
|
981
|
-
throw Oops$3.UnexpectedParent(expected, child, value);
|
|
982
|
-
return { value };
|
|
983
|
-
});
|
|
967
|
+
else
|
|
968
|
+
argument = false;
|
|
969
|
+
this.manage(key, instance, update);
|
|
970
|
+
return () => instance;
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
function parent(Expects, required) {
|
|
974
|
+
return apply(function parent() {
|
|
975
|
+
const child = this.subject;
|
|
976
|
+
const expected = Expects.name;
|
|
977
|
+
const value = Parent.get(this.subject);
|
|
978
|
+
if (!value) {
|
|
979
|
+
if (required)
|
|
980
|
+
throw Oops$3.ParentRequired(expected, child);
|
|
981
|
+
}
|
|
982
|
+
else if (!(value instanceof Expects))
|
|
983
|
+
throw Oops$3.UnexpectedParent(expected, child, value);
|
|
984
|
+
return { value };
|
|
985
|
+
});
|
|
986
|
+
}
|
|
984
987
|
|
|
985
988
|
const Oops$2 = issues({
|
|
986
989
|
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
|
|
987
990
|
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
988
991
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
|
|
989
992
|
});
|
|
990
|
-
function
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
993
|
+
function createRef(key, cb) {
|
|
994
|
+
const refObjectFunction = this.setter(key, cb && createValueEffect(cb));
|
|
995
|
+
defineProperty(refObjectFunction, "current", {
|
|
996
|
+
set: refObjectFunction,
|
|
997
|
+
get: () => this.state[key]
|
|
998
|
+
});
|
|
999
|
+
return refObjectFunction;
|
|
1000
|
+
}
|
|
1001
|
+
function ref(arg) {
|
|
1002
|
+
return apply(function ref(key) {
|
|
1003
|
+
let value = {};
|
|
1004
|
+
if (typeof arg == "object") {
|
|
1005
|
+
const source = manage(arg);
|
|
1006
|
+
for (const key in source.state)
|
|
1007
|
+
defineLazy(value, key, createRef.bind(source, key));
|
|
1008
|
+
}
|
|
1009
|
+
else
|
|
1010
|
+
value = createRef.call(this, key, arg);
|
|
1011
|
+
return { value };
|
|
1000
1012
|
});
|
|
1001
1013
|
}
|
|
1002
1014
|
function on(initial, cb) {
|
|
1003
|
-
return
|
|
1015
|
+
return apply(function on(key) {
|
|
1004
1016
|
this.manage(key, initial, cb && createValueEffect(cb));
|
|
1005
1017
|
});
|
|
1006
1018
|
}
|
|
1007
1019
|
function memo(factory, defer) {
|
|
1008
|
-
return
|
|
1020
|
+
return apply(function memo(key) {
|
|
1009
1021
|
const source = this.subject;
|
|
1010
1022
|
const get = () => factory.call(source);
|
|
1011
1023
|
if (defer)
|
|
@@ -1015,7 +1027,7 @@ function memo(factory, defer) {
|
|
|
1015
1027
|
});
|
|
1016
1028
|
}
|
|
1017
1029
|
function lazy(value) {
|
|
1018
|
-
return
|
|
1030
|
+
return apply(function lazy(key) {
|
|
1019
1031
|
const source = this.subject;
|
|
1020
1032
|
source[key] = value;
|
|
1021
1033
|
defineProperty(this.state, key, {
|
|
@@ -1024,7 +1036,7 @@ function lazy(value) {
|
|
|
1024
1036
|
});
|
|
1025
1037
|
}
|
|
1026
1038
|
function act(task) {
|
|
1027
|
-
return
|
|
1039
|
+
return apply(function act(key) {
|
|
1028
1040
|
let pending = false;
|
|
1029
1041
|
const invoke = (...args) => {
|
|
1030
1042
|
if (pending)
|
|
@@ -1049,7 +1061,7 @@ function act(task) {
|
|
|
1049
1061
|
});
|
|
1050
1062
|
}
|
|
1051
1063
|
function from(source, setter, getter) {
|
|
1052
|
-
return
|
|
1064
|
+
return apply(function from(key) {
|
|
1053
1065
|
const { subject } = this;
|
|
1054
1066
|
let getSource;
|
|
1055
1067
|
// Easy mistake, using a peer, will always be unresolved.
|
|
@@ -1076,51 +1088,76 @@ function from(source, setter, getter) {
|
|
|
1076
1088
|
const Oops$1 = issues({
|
|
1077
1089
|
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
1078
1090
|
});
|
|
1091
|
+
function pending(source, compute) {
|
|
1092
|
+
return (source === undefined ?
|
|
1093
|
+
suspendForValue() :
|
|
1094
|
+
typeof source == "function" && !source.prototype ?
|
|
1095
|
+
suspendForAsync(source) :
|
|
1096
|
+
suspendForComputed(source, compute));
|
|
1097
|
+
}
|
|
1079
1098
|
/**
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1099
|
+
* Get value, suspend instead if undefined.
|
|
1100
|
+
*
|
|
1101
|
+
* Throws suspense promise also interpretable as an error.
|
|
1102
|
+
* React could handle it but other contexts probably not.
|
|
1082
1103
|
*/
|
|
1083
|
-
function
|
|
1084
|
-
const
|
|
1104
|
+
function pendingValue(via, key) {
|
|
1105
|
+
const value = via.state[key];
|
|
1106
|
+
if (value !== undefined)
|
|
1107
|
+
return value;
|
|
1108
|
+
const error = Oops$1.ValueNotReady(via.subject, key);
|
|
1085
1109
|
const promise = new Promise(resolve => {
|
|
1086
|
-
const release =
|
|
1087
|
-
|
|
1088
|
-
|
|
1110
|
+
const release = via.addListener({
|
|
1111
|
+
[key](value) {
|
|
1112
|
+
if (value !== undefined) {
|
|
1113
|
+
release();
|
|
1114
|
+
resolve();
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1089
1117
|
});
|
|
1090
1118
|
});
|
|
1091
|
-
|
|
1119
|
+
throw Object.assign(promise, {
|
|
1120
|
+
toString: () => String(error),
|
|
1121
|
+
message: error.message,
|
|
1122
|
+
stack: error.stack
|
|
1123
|
+
});
|
|
1092
1124
|
}
|
|
1093
|
-
function
|
|
1094
|
-
|
|
1095
|
-
return
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1125
|
+
function suspendForComputed(source, compute) {
|
|
1126
|
+
function getter(_value, key) {
|
|
1127
|
+
return pendingValue(manage(this), key);
|
|
1128
|
+
}
|
|
1129
|
+
return from(source, compute, getter);
|
|
1130
|
+
}
|
|
1131
|
+
function suspendForValue() {
|
|
1132
|
+
return apply(function pending(key) {
|
|
1133
|
+
this.state[key] = undefined;
|
|
1134
|
+
return {
|
|
1135
|
+
set: this.setter(key),
|
|
1136
|
+
get: () => pendingValue(this, key)
|
|
1137
|
+
};
|
|
1138
|
+
});
|
|
1102
1139
|
}
|
|
1103
1140
|
function suspendForAsync(source) {
|
|
1104
|
-
return
|
|
1141
|
+
return apply(function suspense(key) {
|
|
1142
|
+
const subject = this.subject;
|
|
1105
1143
|
let waiting = true;
|
|
1106
|
-
let
|
|
1144
|
+
let value;
|
|
1107
1145
|
let error;
|
|
1108
1146
|
return () => {
|
|
1109
|
-
if (waiting) {
|
|
1110
|
-
const issue = Oops$1.ValueNotReady(this.subject, key);
|
|
1111
|
-
const promise = source
|
|
1112
|
-
.call(this.subject, key)
|
|
1113
|
-
.catch(err => error = err)
|
|
1114
|
-
.then((value) => output = value)
|
|
1115
|
-
.finally(() => waiting = false);
|
|
1116
|
-
throw Object.assign(promise, {
|
|
1117
|
-
message: issue.message,
|
|
1118
|
-
stack: issue.stack
|
|
1119
|
-
});
|
|
1120
|
-
}
|
|
1121
1147
|
if (error)
|
|
1122
1148
|
throw error;
|
|
1123
|
-
|
|
1149
|
+
if (!waiting)
|
|
1150
|
+
return value;
|
|
1151
|
+
const issue = Oops$1.ValueNotReady(subject, key);
|
|
1152
|
+
let suspend = source
|
|
1153
|
+
.call(subject, key)
|
|
1154
|
+
.catch(err => error = err)
|
|
1155
|
+
.then(out => value = out)
|
|
1156
|
+
.finally(() => waiting = false);
|
|
1157
|
+
throw Object.assign(suspend, {
|
|
1158
|
+
message: issue.message,
|
|
1159
|
+
stack: issue.stack
|
|
1160
|
+
});
|
|
1124
1161
|
};
|
|
1125
1162
|
});
|
|
1126
1163
|
}
|
|
@@ -1170,9 +1207,9 @@ exports.Consumer = Consumer;
|
|
|
1170
1207
|
exports.Model = Model;
|
|
1171
1208
|
exports.Provider = Provider;
|
|
1172
1209
|
exports.Singleton = Singleton;
|
|
1173
|
-
exports.State = State;
|
|
1174
1210
|
exports.act = act;
|
|
1175
|
-
exports.
|
|
1211
|
+
exports.apply = apply;
|
|
1212
|
+
exports.child = child;
|
|
1176
1213
|
exports["default"] = Model;
|
|
1177
1214
|
exports.from = from;
|
|
1178
1215
|
exports.lazy = lazy;
|
|
@@ -1181,6 +1218,6 @@ exports.on = on;
|
|
|
1181
1218
|
exports.parent = parent;
|
|
1182
1219
|
exports.pending = pending;
|
|
1183
1220
|
exports.ref = ref;
|
|
1184
|
-
exports.set = set;
|
|
1185
1221
|
exports.tap = tap;
|
|
1186
1222
|
exports.use = use;
|
|
1223
|
+
//# sourceMappingURL=index.js.map
|