@expressive/mvc 0.2.4 → 0.3.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 +43 -47
- package/lib/index.esm.js +144 -117
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +144 -116
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -148,6 +148,9 @@ function applyUpdate(subject, keys) {
|
|
|
148
148
|
UPDATE.delete(subject);
|
|
149
149
|
}, 0);
|
|
150
150
|
};
|
|
151
|
+
}
|
|
152
|
+
function getUpdate(subject) {
|
|
153
|
+
return UPDATE.get(subject);
|
|
151
154
|
}
|
|
152
155
|
|
|
153
156
|
const CONTROL = Symbol("CONTROL");
|
|
@@ -179,21 +182,30 @@ class Model {
|
|
|
179
182
|
return control(this, control => {
|
|
180
183
|
if (typeof select == "function")
|
|
181
184
|
return control.addListener(select);
|
|
182
|
-
const
|
|
185
|
+
const selection = typeof select == "string" ? [select] :
|
|
183
186
|
!select.length ? getOwnPropertyNames(control.state) :
|
|
184
187
|
select;
|
|
185
|
-
ensure(control,
|
|
188
|
+
ensure(control, selection);
|
|
186
189
|
const callback = squash
|
|
187
|
-
?
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
? () => {
|
|
191
|
+
handler.call(this, getUpdate(this));
|
|
192
|
+
}
|
|
193
|
+
: () => {
|
|
194
|
+
getUpdate(this)
|
|
195
|
+
.filter(k => selection.includes(k))
|
|
196
|
+
.forEach(k => {
|
|
197
|
+
handler.call(this, control.state[k], k);
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
const onEvent = once
|
|
201
|
+
? () => {
|
|
202
|
+
remove();
|
|
203
|
+
callback();
|
|
204
|
+
}
|
|
193
205
|
: callback;
|
|
194
206
|
const remove = control.addListener(key => {
|
|
195
|
-
if (
|
|
196
|
-
return
|
|
207
|
+
if (selection.includes(key))
|
|
208
|
+
return onEvent;
|
|
197
209
|
});
|
|
198
210
|
return remove;
|
|
199
211
|
});
|
|
@@ -209,7 +221,7 @@ class Model {
|
|
|
209
221
|
const effect = createEffect(callback);
|
|
210
222
|
return control(this, control => {
|
|
211
223
|
let busy = false;
|
|
212
|
-
let inject = this.
|
|
224
|
+
let inject = this.is;
|
|
213
225
|
const invoke = () => {
|
|
214
226
|
if (busy)
|
|
215
227
|
return;
|
|
@@ -314,6 +326,7 @@ class Subscriber {
|
|
|
314
326
|
this.watch = {};
|
|
315
327
|
const parent = target instanceof Controller
|
|
316
328
|
? target : control(target);
|
|
329
|
+
const subject = parent.subject;
|
|
317
330
|
const proxy = create(parent.proxy);
|
|
318
331
|
let reset;
|
|
319
332
|
define(proxy, LOCAL, this);
|
|
@@ -332,8 +345,10 @@ class Subscriber {
|
|
|
332
345
|
if (typeof handler == "function")
|
|
333
346
|
handler();
|
|
334
347
|
const notify = this.onUpdate(key, parent);
|
|
335
|
-
const getWhy = (
|
|
336
|
-
|
|
348
|
+
const getWhy = () => {
|
|
349
|
+
const update = getUpdate(subject);
|
|
350
|
+
const applicable = update.filter(k => k in this.watch);
|
|
351
|
+
reset = applyUpdate(proxy, applicable);
|
|
337
352
|
};
|
|
338
353
|
if (notify) {
|
|
339
354
|
parent.requestUpdate(getWhy);
|
|
@@ -418,9 +433,9 @@ function from(source, arg1, arg2) {
|
|
|
418
433
|
}
|
|
419
434
|
}
|
|
420
435
|
function defer(_key, from) {
|
|
421
|
-
let pending = KEYS.get(from);
|
|
436
|
+
let pending = KEYS.get(from.frame);
|
|
422
437
|
if (!pending)
|
|
423
|
-
KEYS.set(from, pending = []);
|
|
438
|
+
KEYS.set(from.frame, pending = []);
|
|
424
439
|
if (info.parent !== from)
|
|
425
440
|
update();
|
|
426
441
|
else {
|
|
@@ -474,19 +489,17 @@ function ensure(on, keys) {
|
|
|
474
489
|
getter(true);
|
|
475
490
|
}
|
|
476
491
|
}
|
|
477
|
-
function flush(
|
|
478
|
-
const
|
|
479
|
-
const pending = KEYS.get(on);
|
|
492
|
+
function flush(frame) {
|
|
493
|
+
const pending = KEYS.get(frame);
|
|
480
494
|
if (!pending)
|
|
481
495
|
return;
|
|
482
496
|
while (pending.length) {
|
|
483
|
-
const why = [...handled];
|
|
484
497
|
const compute = pending.shift();
|
|
485
498
|
const { key } = INFO.get(compute);
|
|
486
|
-
if (!
|
|
487
|
-
compute(
|
|
499
|
+
if (!frame.has(key))
|
|
500
|
+
compute();
|
|
488
501
|
}
|
|
489
|
-
KEYS.delete(
|
|
502
|
+
KEYS.delete(frame);
|
|
490
503
|
}
|
|
491
504
|
|
|
492
505
|
const Oops$9 = issues({
|
|
@@ -500,41 +513,41 @@ class Controller {
|
|
|
500
513
|
this.subject = subject;
|
|
501
514
|
this.state = {};
|
|
502
515
|
this.frame = new Set();
|
|
503
|
-
this.waiting = new Set();
|
|
504
516
|
this.onDestroy = new Set();
|
|
517
|
+
this.waiting = new Set();
|
|
505
518
|
this.followers = new Set();
|
|
506
519
|
this.proxy = Object.create(subject);
|
|
507
520
|
}
|
|
508
521
|
start() {
|
|
509
522
|
READY.add(this);
|
|
510
523
|
for (const key in this.subject) {
|
|
511
|
-
const { value
|
|
512
|
-
if (typeof
|
|
524
|
+
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
525
|
+
if (typeof value == "function")
|
|
513
526
|
continue;
|
|
514
|
-
if (typeof
|
|
515
|
-
const instruction = PENDING.get(
|
|
527
|
+
if (typeof value == "symbol") {
|
|
528
|
+
const instruction = PENDING.get(value);
|
|
516
529
|
if (instruction)
|
|
517
530
|
instruction.call(this, key, this);
|
|
518
531
|
continue;
|
|
519
532
|
}
|
|
520
|
-
this.manage(key,
|
|
533
|
+
this.manage(key, value);
|
|
521
534
|
}
|
|
522
|
-
this.
|
|
535
|
+
this.flush();
|
|
523
536
|
}
|
|
524
537
|
stop() {
|
|
525
538
|
this.followers.clear();
|
|
526
539
|
this.onDestroy.forEach(x => x());
|
|
527
540
|
}
|
|
528
541
|
manage(key, value) {
|
|
529
|
-
const {
|
|
530
|
-
state[key] = value;
|
|
542
|
+
const { state } = this;
|
|
531
543
|
const set = this.ref(key);
|
|
532
|
-
|
|
544
|
+
state[key] = value;
|
|
545
|
+
defineProperty(this.subject, key, {
|
|
533
546
|
enumerable: false,
|
|
534
547
|
get: () => state[key],
|
|
535
548
|
set
|
|
536
549
|
});
|
|
537
|
-
defineProperty(proxy, key, {
|
|
550
|
+
defineProperty(this.proxy, key, {
|
|
538
551
|
enumerable: false,
|
|
539
552
|
get() {
|
|
540
553
|
const local = this[LOCAL];
|
|
@@ -566,53 +579,56 @@ class Controller {
|
|
|
566
579
|
this.followers.delete(listener);
|
|
567
580
|
};
|
|
568
581
|
}
|
|
569
|
-
emit(keys) {
|
|
570
|
-
const waiting = [...this.waiting];
|
|
571
|
-
this.waiting.clear();
|
|
572
|
-
applyUpdate(this.subject, keys)();
|
|
573
|
-
for (const callback of waiting)
|
|
574
|
-
try {
|
|
575
|
-
callback(keys);
|
|
576
|
-
}
|
|
577
|
-
catch (err) {
|
|
578
|
-
console.error(err);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
582
|
update(key, value) {
|
|
583
|
+
const { frame } = this;
|
|
582
584
|
if (1 in arguments)
|
|
583
585
|
this.state[key] = value;
|
|
584
|
-
if (
|
|
585
|
-
return;
|
|
586
|
-
if (!this.frame.size)
|
|
586
|
+
if (!frame.size)
|
|
587
587
|
setTimeout(() => {
|
|
588
|
-
flush(
|
|
589
|
-
|
|
590
|
-
this.frame.clear();
|
|
591
|
-
this.emit(keys);
|
|
588
|
+
flush(frame);
|
|
589
|
+
this.flush();
|
|
592
590
|
}, 0);
|
|
593
|
-
|
|
591
|
+
else if (frame.has(key))
|
|
592
|
+
return;
|
|
593
|
+
frame.add(key);
|
|
594
594
|
for (const callback of this.followers) {
|
|
595
595
|
const event = callback(key, this);
|
|
596
596
|
if (typeof event == "function")
|
|
597
597
|
this.waiting.add(event);
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
|
+
flush() {
|
|
601
|
+
const waiting = Array.from(this.waiting);
|
|
602
|
+
const keys = Array.from(this.frame);
|
|
603
|
+
this.frame.clear();
|
|
604
|
+
this.waiting.clear();
|
|
605
|
+
applyUpdate(this.subject, keys)();
|
|
606
|
+
for (const callback of waiting)
|
|
607
|
+
try {
|
|
608
|
+
callback();
|
|
609
|
+
}
|
|
610
|
+
catch (err) {
|
|
611
|
+
console.error(err);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
600
614
|
requestUpdate(arg) {
|
|
615
|
+
const { frame, subject, waiting } = this;
|
|
601
616
|
if (typeof arg == "function") {
|
|
602
|
-
|
|
617
|
+
waiting.add(arg);
|
|
603
618
|
return;
|
|
604
619
|
}
|
|
605
|
-
if (arg === true
|
|
620
|
+
if (!frame.size && arg === true)
|
|
606
621
|
return Promise.reject(Oops$9.StrictUpdate());
|
|
607
622
|
return {
|
|
608
623
|
then: (callback) => {
|
|
609
|
-
if (callback)
|
|
610
|
-
if (this.frame.size || arg !== false)
|
|
611
|
-
this.waiting.add(callback);
|
|
612
|
-
else
|
|
613
|
-
callback(false);
|
|
614
|
-
else
|
|
624
|
+
if (!callback)
|
|
615
625
|
throw Oops$9.NoChaining();
|
|
626
|
+
if (frame.size || arg !== false)
|
|
627
|
+
waiting.add(() => {
|
|
628
|
+
callback(getUpdate(subject));
|
|
629
|
+
});
|
|
630
|
+
else
|
|
631
|
+
callback(false);
|
|
616
632
|
}
|
|
617
633
|
};
|
|
618
634
|
}
|
|
@@ -835,65 +851,60 @@ const Oops$7 = issues({
|
|
|
835
851
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
836
852
|
Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
837
853
|
});
|
|
838
|
-
function
|
|
854
|
+
function put(factory, argument) {
|
|
839
855
|
return apply(function set(key) {
|
|
840
856
|
const { subject, state } = this;
|
|
841
857
|
const required = argument === true || argument === undefined;
|
|
842
858
|
let set;
|
|
843
859
|
let get;
|
|
844
|
-
let
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
pending =
|
|
856
|
-
|
|
857
|
-
.then(val => state[key] = val)
|
|
858
|
-
.finally(() => {
|
|
859
|
-
pending = undefined;
|
|
860
|
-
this.update(key);
|
|
861
|
-
});
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
return state[key] = output;
|
|
865
|
-
};
|
|
866
|
-
const suspend = () => {
|
|
867
|
-
if (required === false)
|
|
868
|
-
return undefined;
|
|
869
|
-
const issue = Oops$7.NotReady(subject, key);
|
|
870
|
-
Object.assign(pending, {
|
|
871
|
-
message: issue.message,
|
|
872
|
-
stack: issue.stack
|
|
860
|
+
let pending;
|
|
861
|
+
let error;
|
|
862
|
+
const init = () => {
|
|
863
|
+
const output = typeof factory == "function" ?
|
|
864
|
+
mayRetry(() => factory.call(subject, key, subject)) :
|
|
865
|
+
factory;
|
|
866
|
+
if (output instanceof Promise) {
|
|
867
|
+
pending = output
|
|
868
|
+
.catch(err => error = err)
|
|
869
|
+
.then(val => state[key] = val)
|
|
870
|
+
.finally(() => {
|
|
871
|
+
pending = undefined;
|
|
872
|
+
this.update(key);
|
|
873
873
|
});
|
|
874
|
-
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
}
|
|
896
|
-
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
return state[key] = output;
|
|
877
|
+
};
|
|
878
|
+
const suspend = () => {
|
|
879
|
+
if (required === false)
|
|
880
|
+
return undefined;
|
|
881
|
+
const issue = Oops$7.NotReady(subject, key);
|
|
882
|
+
Object.assign(pending, {
|
|
883
|
+
message: issue.message,
|
|
884
|
+
stack: issue.stack
|
|
885
|
+
});
|
|
886
|
+
throw pending;
|
|
887
|
+
};
|
|
888
|
+
if (required)
|
|
889
|
+
try {
|
|
890
|
+
init();
|
|
891
|
+
}
|
|
892
|
+
catch (err) {
|
|
893
|
+
Oops$7.Failed(subject, key).warn();
|
|
894
|
+
throw err;
|
|
895
|
+
}
|
|
896
|
+
get = () => {
|
|
897
|
+
if (pending)
|
|
898
|
+
return suspend();
|
|
899
|
+
if (error)
|
|
900
|
+
throw error;
|
|
901
|
+
if (key in state)
|
|
902
|
+
return state[key];
|
|
903
|
+
let output = init();
|
|
904
|
+
return pending
|
|
905
|
+
? suspend()
|
|
906
|
+
: output;
|
|
907
|
+
};
|
|
897
908
|
if (typeof argument == "function")
|
|
898
909
|
set = createValueEffect(argument);
|
|
899
910
|
else
|
|
@@ -903,8 +914,24 @@ function set(factory, argument) {
|
|
|
903
914
|
};
|
|
904
915
|
return {
|
|
905
916
|
set,
|
|
906
|
-
get
|
|
907
|
-
|
|
917
|
+
get
|
|
918
|
+
};
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function set(value, argument) {
|
|
923
|
+
if (!(1 in arguments)) {
|
|
924
|
+
argument = value;
|
|
925
|
+
value = undefined;
|
|
926
|
+
}
|
|
927
|
+
return apply(function set(key) {
|
|
928
|
+
if (value !== undefined)
|
|
929
|
+
this.state[key] = value;
|
|
930
|
+
return {
|
|
931
|
+
suspense: true,
|
|
932
|
+
set: typeof argument == "function"
|
|
933
|
+
? createValueEffect(argument)
|
|
934
|
+
: undefined
|
|
908
935
|
};
|
|
909
936
|
});
|
|
910
937
|
}
|
|
@@ -1410,6 +1437,7 @@ exports.array = array;
|
|
|
1410
1437
|
exports["default"] = MVC;
|
|
1411
1438
|
exports.from = from;
|
|
1412
1439
|
exports.parent = parent;
|
|
1440
|
+
exports.put = put;
|
|
1413
1441
|
exports.ref = ref;
|
|
1414
1442
|
exports.set = set;
|
|
1415
1443
|
exports.tap = tap;
|